I have a coursework that involves implementing two classes, one to store Matrix objects and a child of this for SquareMatrix objects. We have to implement member functions to be able to solve an equation of the form Ax = b, with A being the matrix, x being the vector we want to find and b being a known vector.
I've implemented this in the case of a SquareMatrix since it is not too hard to do with Gaussian elimination. The method that the coursework says we should use to solve the case with a non-square matrix is to solve A'Ax = A'b with ' meaning transpose. A'A is now a square matrix so this can be solved using Gaussian elimination also.
What I wanted to know was whether it is a valid thing to do to create a SquareMatrix object in the Matrix solve function and then use the SquareMatrix member solve to solve the system. So for instance if in SquareMatrix I have
Matrix SquareMatrix::solve(Matrix& b){
//stuff that solves (*this) * x = b for x and returns x
}
Could I then in Matrix.cpp have
Matrix Matrix::solve(Matrix& b){
//make the matrix into a square
SquareMatrix AtransposeA = (this->transpose())*(*this);
//update rhs of equation accordingly
Matrix Atransposeb = (this->transpose()) * b;
//Call SquareMatrix solve to solve the problem.
Matrix x = AtransposeA.solve(Atransposeb);
return x;
}
So I'm making the matrix square by multiplying by its transpose and then calling the SquareMatrix solve function. I'm relatively new to C++ and haven't 100% gotten my head around inheritance so I'm not sure if this a valid, or sensible thing to do.
I'm not sure if this a valid, or sensible thing to do.
It is valid to use a derived class, to implement a function of parent class in some cases.
Whether it makes sense for SquareMatrix to be derived from Matrix is another consideration. To know the answer to that question, you'll need to consider your design, and outline all class invariants and member function pre- and post-conditions of Matrix and then consider whether SquareMatrix can satisfy them all.
Related
Let's say I have two different implementations of mathematical vectors (and other mathematical structures such as matrices):
class SparseVector {
double dotproduct(SparseVector& other);
};
class DenseVector {
double dotproduct(DenseVector& other);
};
I would like to implement algorithm that are using either exclusively sparse or dense algebra. Of course I would like to only implement a generic version of the algorithm what can deal with either of the two.
The first idea was to create a virtual vector class (code below for the concept, it wouldn't actually work this way):
class Vector {
virtual double dotproduct(Vector& other);
};
class SparseVector : public Vector {
double dotproduct(SparseVector& other) override;
};
class DenseVector : public Vector {
double dotproduct(DenseVector& other) override;
};
However that doesn't work because each of the Vector implementations can only work with other vectors of the same type. (That is, the implementation should not allow a dotproduct between a sparse and a dense vector).
Is there a good implementation strategy or design pattern that prevents me having to implement algorithms twice?
The question is not the same as this one, as I do not want to support dotproducts between a sparse and a dense vector.
I was thinking about using templates:
template<class T>
class algorithm {
}
but I don't know how to restrict T to be one of SparseVector/DenseVector, so the compiler knows that there exists a suitable dotproduct() function.
The thing you're looking for is called Visitor Pattern or Double Dispatch. You should be able to easily locate further infor online. However, the gist is basically this: With regular virtual functions or OOP, the invoked code depends on the type of one object. With the Visitor Pattern, you get to pick the code depending on two objects (hence also the name Double Dispatch), which is basically what you need.
I'm looking for advice as to how to proceed with this class hierarchy I'm building in C++.
Base class is Matrix:
class Matrix
{
protected:
int rows;
int columns;
double* values;
public:
\\lots of stuff goes here. bla di bla di bla.
virtual Matrix operator+(const Matrix& addend) const;
\\etc.
}
Squarematrix is inherited from Matrix
class Squarematrix : public Matrix
{
public:
Squarematrix operator+(const Squarematrix& addend) const;
}
Operator+ returns a matrix or a squarematrix respectively. Since operator+ is a virtual function this wont compile, as it must have the same return type in all classes.
So what are my options?
I could use an ordinary function instead of virtual. This is a bit annoying, but wouldn't cause a problem under most circumstances.
I could return a matrix in all cases. This would basically make my squarematrix class a right pain in the *** to use, as I would have to constantly downcast from matrix to squarematrix.
I could return a reference to a squarematrix. Then the matrix would have to be stored on the heap and there's no way to make sure its deleted safely. Especially if I do something like this:
squarematrix a=b+(c+d);
(c+d) will be stored on the heap and have no pointer to it so will be leaked.
Is there any way to keep virtual functions and still have different return types?
What would you advise in this situation?
Thanks for your help. Looking forward to hearing from you.
I would recommend:
Remove Squarematrix.
Add a constructor to Matrix to construct a square matrix.
If the knowledge of whether a matrix is square matrix is helpful for your application, add a member function in Matrix to answer that query.
class Matrix
{
public:
Matrix(int r); // Construct a square matrix.
Matrix(int r, int c); // Construct a rectangular matrix.
bool isSquareMatrix() const { return (rows == columns); }
Matrix operator+(const Matrix& addend) const;
private:
int rows;
int columns;
double* values;
}
This is known as return type covariance (https://en.wikipedia.org/wiki/Covariant_return_type).
It was not supported by old compilers, but is supported by many now. For example my code compiles fine in Visual Studio 2017. Here is an article on its use and limitations in c++: https://aycchen.wordpress.com/2009/08/17/covariant-return-type-in-cpp/.
It is not supported in C# yet, but is being considered for a future version. See https://github.com/dotnet/csharplang/issues/49.
It is also supported by newer versions of Java. See https://blogs.oracle.com/sundararajan/covariant-return-types-in-java.
Other than implementation issues, as far as I know there is no reason for it not to be added to a polymorphic language. I don't believe it can cause errors, although due to an imperfect implementation in Java it can cause bugs-see https://dzone.com/articles/covariant-return-type-abyssal.
Problem statement: Let Matrix be a base class which is subclassed by DenseMatrix and SparseMatrix (and possibly others). What I would like to achieve is the following:
Matrix *A = new DenseMatrix();
Matrix *B = new SparseMatrix();
Matrix C = (*A) + (*B); // dense + sparse
Matrix D = (*A) + (*A); // dense + dense
Matrix E = (*B) + (*B); // sparse + sparse
Even better, I would like to have the following:
DenseMatrix C = (*A) + (*B);
DenseMatrix D = (*A) + (*A);
SparseMatrix E = (*B) + (*B);
Now, when adding a DenseMatrix with a SparseMatrix having declared both as Matrix implies that there must be an operator+ definition in Matrix.
I have already read this answer which makes use of an interface AddEnabled<Foo>, but doesn't seem to be a good solution when (almost) any possible combination of summands. I could possibly define in DenseMatrix the following functions:
friend DenseMatrix operator+ (DenseMatrix const& left, DenseMatrix const& right);
But then again it will be impossible to add two instances of DenseMatrix declared as Matrix (i.e., Matrix *A = new DenseMatrix();).
From various similar questions and answers I suspect that the pimpl idiom could be relevant, but I don't see how.
Note: I'm coding in C++98, not C++11.
Update: As Dieter Lücking suggested in his answer an opeator+ needs to be introduced in the base class. This makes sense, but the problem is that Matrix, being abstract, does not allow methods which return abstract types. However, it is possible to return a pointer or a reference to Matrix; this way we would have a definition like:
Matrix& operator+(const Matrix& right) const;
To an extent this would work, but users of my code would expect a + to return a Matrix instead of a reference to one.
You may give the base class a state indicating the matrix layout - having that, dispatch matrix operations (on the base class) accordingly. Keep the special matrices classes for construction, but they will elide to the base matrix after applying an operation.
Example:
Matrix = IdentityMatrix operation DiagonalMatrix
This would elide the argument types and result in a matrix having a state 'Diagonal'
You might need to declare your Matrix::operator+ as virtual if you re-define it in your sub-classes and you initialize them as
Matrix *A = new DenseMatrix();
Also why is operator+ not a member of DenseMatrix? What I mean is
DenseMatrix DenseMatrix::operator+ (DenseMatrix const& right) const;
instead of
friend DenseMatrix operator+ (DenseMatrix const& left, DenseMatrix const& right);
Are you sure you need to re-overload operator+ in you derived classes again?
Can't you just inherit operator+ from your base class Matrix?
Edit:
If your base class does not have an operator+, but your derived ones do, you still need to declare (but not define) one as virtual in the base class, otherwise the derived classes cannot override it when they are pointed to by a Matrix* and not a DenseMatrix*.
Not sure why you want multiple + operators. Matrix addition is the same, no matter what the matrix representation:
1. Ensure the matrices being added have the same dimensions.
2. Add corresponding entries from the input matrices to produce the values in the output matrix.
These operations will be done in the base class operator +.
Then all you need is to implement getDimensions() in each subclass and, if they are equal, perform:
result.put(x, y, inputA.get(x, y) + inputB.get(x, y));
for each entry in the matrices.
The Problem
I want to implement a number of algorithms that work on a graph and return scores for node-pairs indicating whether those nodes are similar. The algorithms should work on a single node-pair and on all possible node-pairs. In the latter case a collection/matrix should be returned.
My Approach
The algorithms derive from
class SimilarityAlgorithm {
public:
Base(const Graph& G);
virtual double run(node u, node v) = 0; // indices for nodes in the graph
virtual ScoreCollection& runAll() = 0;
}
Now the algorithms differ in memory usage. Some algorithms might be symmetric and the scores for (u, v) and (v, u) are identical. This requires different ScoreCollection-types that should be returned. An example would be a sparse-matrix and a triangular matrix that both derive from ScoreCollection.
This would boil down to covariant return types:
class SpecificAlgorithm : SimilarityAlgorithm {
public:
double run(node u, node v);
// The specific algorithm is symmetric and thus uses a symmetric matrix to save memory
SymmetricScoreCollection& runAll();
}
Question
Is this design approach a good idea for this problem?
Should the fact that the collections are all implemented as matrices be exposed?
Your design seems appropriate for the problem you describe.
Problem:
However, there is a problem with your SpecificAlgorithm : runAll() doesn't return the same type as the virtual function of the base class. So it won't be called (or more probably, your code won't compile because of a missing virtual function).
Solution:
Use also a polymorphic approach for the ScoreCollection, by making SymmetricScoreCollection a derived class of ScoreCollection :
class SymetricScoreCollection: public ScoreCollection {
//define the member functions to access the values virtual
...
};
class SpecificAlgorithm : public SimilarityAlgorithm {
public:
double run(node u, node v);
// The specific algorithm is symmetric and thus uses a symmetric matrix to save memory
ScoreCollection& runAll();
};
In fact it's an application of the factory method pattern, with the following roles:
SimilarityAlgorithm is the factory,
SpecificAlgorithm is the concrete factory
ScoreCollection is the product
SymetricScoreCollection is the concrete product
Additional remark:
Returning a reference to ScoreCollection from runAll() brings in some risks. Suppose sa is a specific algorithm.
In the following statement :
ScoreCollection sc = sa.runAll();
sa.runAll() returns a reference to a SymetricScoreCollection, but it would copy the referred object to sc, making it a ScoreCollection. Slicing occurs, and polymorphism will fail to work.
The following statement would however succeed:
ScoreCollection& rsc = sa.runAll();
because rsc is a reference and it would still refer to the original SymetricScoreCollection object returned by sa.runAll(), and everything would work as designed.
You see that it's very easy to have unnoticed mistakes when returning references. I'd suggest to return a pointer instead of a reference.
I want to implement a representation of matrices. for that I have two types of matrices - regular and sparse, which differ in their implementation - one holds a vector, and the second a map of indices and value, both inherit from Matrix class.
For that, I'm using the strategy pattern, where I create the base abstract class Matrix, two classes that inherit from Matrix - RegMatrix and SparseMatrix, and MyMatrix that holds a pointer to a Matrix.
I want to implement the + operator, which operates on Matrix and receives another Matrix. but when I implement the + operator, I might receive as parameter sparse/regular matrix.
so I have 2 questions:
The only hint I have is to create an iterator of type "matrix", and implement the iterator for each type of matrix (regular and sparse).
how can I do such a thing?
Let's say I implemented an iterator for both types of "matrix". how can I use the different iterators, in case I have to add two different types of matrices? do I have to implement all 4 different cases?
The operator+ looks like:
Matrix& operator+(const Matrix& other)
{
.....
}
Prefer not to implement the functionality in the base class.
Implement the functionality in each of the child classes. This will allow for use of optimal algorithms.
Or you could declare getters and setters as abstract in the Base class and use them in your base class implementation:
struct Matrix_Base
{
virtual int get_value(unsigned int row, unsigned int column) = 0;
virtual void set_value(int value, unsigned int row, unsigned int column) = 0;
Matrix_Base operator+(const Matrix_Base& other)
{
// perform addition
int sum = get_value(row, column) + other.get_value(column, row);
set_value(sum, row, column);
//...
}
};
Remember, when passing a Matrix, the receiving function can only use common functions (interface) of the Matrix. For specifics, functions will have to use specialized (descendants) in the parameter lists.
You may implement + operator only for RegMatrix and 2 conversion operators:
1. From RegMatrix to SparseMatrix
2. From SparseMatrix to RegMatrix
What are performance requirements?