SparseMatrix and Vector addition broadcasting in Eigen - c++

I want to add a dense VectorXf to a SparseMatrix, and I know that I could do matrix + vector easily for dense matrix, like this
Eigen::MatrixXf mat(2,4);
Eigen::VectorXf v(2);
mat << 1, 2, 6, 9,
3, 1, 7, 2;
v << 0,
1;
//add v to each column of m
mat.colwise() += v;
but how to do this for sparse matrix?

The simplest way to do this is to iterate over all columns and add a sparse vector to your sparse matrix. And you should keep in mind, that if you need colwise operation, your matrix should be stored as Column-Major.
// allocate dense object
Eigen::MatrixXd M(2,4);
Eigen::VectorXd v(2);
// allocate sparse vector
Eigen::SparseVector<double> spV(2);
// allocate Column-major sparse matrix
Eigen::SparseMatrix<double, Eigen::ColMajor> spM(2, 4);
// initialize dense objects values
M << 1, 0, 0, 2,
4, 5, 0, 0;
v << 1,
3;
// convert dense objects to sparse representation
spM = M2.sparseView();
spV = v2.sparseView();
// iterate over sparse Matrix columns
for(int i = 0; i< spM.cols(); ++i) {
spM.col(i) += spV;
}
It can't be done in such way for dense vector and one of the reason is that this operation does not make any sense, since the resulting matrix will be dense. In this case you will need to create some dense matrix and perform colwise operation with your dense vector like this:
Eigen::MatrixXd(spM).colwise() + v

Related

Best way to broadcast Armadillo matrix operations similar to Numpy

Consider the matrices A and B where A is a 5x5 matrix and B is a 1x5 matrix (or a row vector). If I try to do A + B in Numpy, its broadcasting capabilities will implicitly create a 5x5 matrix where each row has the values of B and then do normal matrix addition between those two matrices. This can be written in Armadillo like this;
mat A = randu<mat>(4,5);
mat B = randu<mat>(1,5);
A + B;
But this fails. And I have looked at the documentation and couldn't find a built-in way to do broadcasting. So I want to know the best (fastest) way to do an operation similar to the above.
Of course, I could manually resize the smaller matrix into the size of the larger, and copy the first-row value to each other row using a for loop and use the overloaded + operator in Armadillo. But, I'm hoping that there is a more efficient method to achieve this. Any help would be appreciated!
Expanding on the note from Claes Rolen. Broadcasting for matrices in Armadillo is done using .each_col() and .each_row(). Broadcasting for cubes is done with .each_slice().
mat A(4, 5, fill::randu);
colvec V(4, fill::randu);
rowvec R(5, fill::randu);
mat X = A.each_col() + V; // or A.each_col() += V for in-place operation
mat Y = A.each_row() + R; // or A.each_row() += R for in-place operation
cube C(4, 5, 2, fill::randu);
cube D = C.each_slice() + A; // or C.each_slice() += A for in-place operation

Eigen::Vector; Initialize Vector with Values of Eigen::Matrix3f in a function, bigger than 4 entries

im interested in building up a 1x6 Vector, which i want to concatenate with another 1x6 Vector to a 2x6 Matrix. I know it will be a Row Vector, so therefore i thought about initializing a Eigen::RowVectorXf vec, but maybe a simple Eigen::VectorXf would be enough, idk.
(Further on, this should be concatenated to an even bigger 2Nx6 Matrix, for SVD-Operations)
My Input is a 3x3 Matrix of type Eigen::Matrix3f Mat
I thought of using a function, because i have in total ~20 (number isn't that important) input matrices, for each i do have to build 2 vectors, in this manner ( Yep, this will be a 40x6 Matrix in the end):
Question:
How do i initialize vec with entries of mat, especially if its not only the entries, but the products of entries, or sums of products of entries.
Example:
// Inputvalue Mat, which i have
Eigen::Matrix<float, 3, 3> mat = [ 1 2 3; 4 5 6; 7 8 9];
// Outputvalue vec, which i need
Eigen::RowVectorXf = ( mat(0,0)*mat(1,1), mat(1,2)*mat(2,1)+mat(1,0)*mat(0,1), .... );
My inputs of mat(col,row) are arbitrary, but i have a pattern for col,row, which i want to test, and therefore i want to build up those vectors. I've already done it in MATLAB, but im interested in doing it with Eigen in C++.
RowVectorXf build_Vec(Eigen::Matrix3f Mat)
{
Eigen::RowVectorCf vec = ( ..., ..., ..., ..., ..., ...;);
return vec;
}
Anyone some hints for me?
Thanks in advance
For dynamically filling a big matrix at runtime you can't use the CommaInitializer (without abusing it). Just allocate a matrix large enough and set individual blocks:
Matrix<float, Dynamic, 6> Vges(2*views, 6);
for(int i=0; i<views; ++i) {
Matrix<float, 2, 6> foo;
foo << 1,2,3,4,5,6,7,8,9,10,11,12; // or combine from two Matrix<float, 1, 6>
Vges.middleRows<2>(2*i) = foo;
}
You may also consider computing Vges.transpose() * Vges on-the-fly (i.e., by accumulating foo.transpose()*foo into a 6x6 matrix and do a SelfAdjointEigendecomposition instead of a SVD (perhaps use double instead of single precision then).
Eigen::Matrix<double, 6, 6> VtV; VtV.setZero();
for(int i=0; i<views; ++i) {
foo = ...;
VtV.selfadjointView<Upper>().rankUpdate(foo);
}

C++ Eigen Library: Mutliplying vector with elements from row vector

I am trying to obtain a matrix consisting of the product between a vector and respective elements from a row vector like this:
Eigen::Vector3f vec;
vec << 1,
2,
3;
Eigen::RowVectorXf val;
val.setLinSpaced(5, 1, 5); //val = [1,2,3,4,5]
//result should be
//1,2,3,4,5
//2,4,6,8,10
//3,6,9,12,15
After seeing this question, I have tried
val.array().colwise()*vec.array()
and
vec.array().rowwise()*val.array()
but they just don't work.
val is a 1xn vector.
You want a standard matrix product:
MatrixXf res = vec * val;

Matrix and vector multiplication, outputting incorrect product

I've created a Vector and Matrix class and I am trying to perform operations such as the multiplication of a matrix and vector, the multiplication of a matrix and matrix, and the multiplication of a matrix and a float (scalar). I seem to be having problem getting the right product for the matrix * vector and matrix * matrix.
Here is the part of Matrix class meant to handle those operations:
// Matrix * vector, result vector
Vector Matrix::operator*(const Vector & other) const
{
if (other.getDimensions() == 4)
{
float floats[4];
const float* temp = other.getData();
for (int j = 0; j < 4; j++)
{
Vector myCol = column(j);
floats[j] = (temp[0] * myCol.getData(0)) + (temp[1] * myCol.getData(1)) + (temp[2] * myCol.getData(2)) + (temp[3] * myCol.getData(3));
}
return Vector(floats[0], floats[1], floats[2], floats[3]);
}
else
{
return Vector();
}
}
// Matrix * scalar, result matrix
Matrix Matrix::operator*(float c) const
{
Matrix myMatrix;
for (int i = 0; i < 16; i++)
{
myMatrix.data[i] = this->data[i] * c;
}
return myMatrix;
}
In my main.cpp,
Matrix m = Matrix(Vector(1, 0, 0, 1), Vector(0, 1, 0, 2), Vector(0, 0, 1, 3), Vector(0, 0, 0, 1));
Is the value of the matrix and
v = Vector(1, 0, -1, 1);
Is the value of the vector.
When I multiply m * v I get <1, 0, -1, -1>, but the answer is <2, 2, 2, 1>.
And when doing the matrix * scalar with the same m matrix above and vector v with the values
v = Vector(1, 0, -1, 0);
I get m*v to be <1, 0, -1, 2> when it should be <1, 0, -1, 0>.
My Vector class works fine so I'm suspecting I messed up somewhere with the math for implementing the matrix operations.
To expand on #Klaus answer, mathematically in the expression M*V the vector V is a column, and the elements of the result are (dot-)products of matrix rows and V. Replace column(j) with row(j).
I calculated your example by hand now, and if you expect the result to be <2, 2, 2, 1>, then you definitely swapped rows and columns in your matrix. When you multiply a matrix with a vector you want to put the products of the rows of the matrix and the vector in a result vector. Kind of:
Vector Matrix::operator*(const Vector & other) const
{
float floats[4];
const float* temp = other.getData();
for (int j = 0; j < 4; j++)
{
Vector my_row = row(j);
floats[j] = 0;
for(int i=0; i!=4; ++i)
floats[j]+=temp[i] * myCol.getData(i);
}
//(maybe provide a better constructor to take an array)
return Vector(floats[0], floats[1], floats[2], floats[3]);
}
For the example with the scalar, I don't get the point. I don't understand how you expect a multiplication of a matrix with a scalar if you are multiplying a matrix with a vector.
Also you could improve the error handling by only accepting vectors of size 4 (imposing that as a requirement in your vector class), if you just use vectors of size 4.
PS: maybe you should also put your addition code in the loop, into a second loop, so that it is more readable and expandable.

Does the SymEigsShiftSolver of Spectra not return eigenvectors?

I have implemented the SymEigsShiftSolver for computing the eigenvalues of a large sparse matrix, however it does not return me the eigenvectors. Has it not been implemented as of yet?
void Eigens::computeEigenvectors(Matrices m)
{
SparseSymShiftSolve<double> op(m.Lpl);
SymEigsShiftSolver< double, SMALLEST_MAGN, SparseSymShiftSolve<double> >
eigs(&op, k, 4, 0.0);
eigs.init();
int nconv = eigs.compute();
VectorXd evalues;
evalues.resize(k);
if(eigs.info() == SUCCESSFUL)
evalues = eigs.eigenvalues();
cout << "Eigenvalues found:\n" << evalues << endl;
cout <<"\nHere is the matrix whose columns are eigenvectors of the Laplacian Matrix \n"
<<"corresponding to these eigenvalues: \n"
<<eigs.eigenvectors()<<endl;
}
I'm not sure why you've added the "armadillo" tag, since you're using the eigen library. I've provided the following response if you are indeed interested in an Armadillo based solution.
Both Armadillo and Spectra use very similar underlying code for sparse eigendecomposition (the code was written by the same author), but Armadillo has a simplified user interface. To compute the eigenvectors of a symmetric sparse matrix using Armadillo, use the eigs_sym() function:
// generate sparse symmetric matrix
sp_mat A = sprandu<sp_mat>(5000, 5000, 0.1);
sp_mat B = A.t()*A;
vec eigval;
mat eigvec;
eigs_sym(eigval, eigvec, B, 5); // find 5 eigenvectors with largest magnitude
eigs_sym(eigval, eigvec, B, 5, "sm"); // find 5 eigenvectors with smallest magnitude
If you have a non-symmetric matrix, the eigs_gen() function can be used in a similar manner:
sp_mat A = sprandu<sp_mat>(5000, 5000, 0.1);
cx_vec eigval;
cx_mat eigvec;
eigs_gen(eigval, eigvec, A, 5); // find 5 eigenvalues/eigenvectors
A sparse matrix can be constructed from a 1D array in a simple manner:
double data[nrows * ncols]; // 1D array representation of your matrix
sp_mat X = sp_mat( mat(data, nrows, ncols, false) );
I figured out the issue. The SymEigsShiftSolver requires a sigma value of >0 in order to return the eigenvectors.
SymEigsShiftSolver< double, SMALLEST_MAGN, SparseSymShiftSolve<double> >
eigs(&op, k, 4, 1.0);