C++ Boost: determinant and inversion of complex matrix - c++

Do you know whether boost has functions that can calculate the determinant and the inversion of a complex matrix? The matrix dimension isn't large (less than 50).
Inversion:
Input: matrix M = A +i*B with A,B two real matrices of dimension (n x n) with n <50.
Output:
Inversion:
matrix N = C + iD with C,D two real matrices of dimension (n x n) such that: (A +iB)^T (C+ i*D) = I (I: the identity matrix)
Determinant:
det(A+iB)
I googled but didn't succeed.
Thank you in advance.

Finally I know why these operators on inversion and determinant of matrices aren't implemented. It's because we have closed-form solution of these 2 operators from classical operators on real matrices.
For matrix inversion: we have this closed-form solution https://fr.mathworks.com/matlabcentral/fileexchange/49373-complex-matrix-inversion-by-real-matrix-inversion
For matrix determinant, we have:
det((A+iB))= det (A * (I + i A1.B)) (with A1 is the inversed matrix of A)
= det(A) * det (I + i A1.B))
= det(A) * det (U1 (I + iD) U2) (with U1 = A1.B, U2 is the invered matrix of U1, D is the diagonal matrix of U1) = det(A) *det(I +iD). It's easy to calculated the determinant of I +iD which is a diagonal matrix.
So, det(A+iB) = det(A) * det(I +iD) with D: the matrix of eigenvalues of (A^(-1) * B)

Related

How to compute a 4x4 matrix bridge (i.e. A * C = B, find C)

I am trying to implement a C++ function that, given (4x4) Matrix A and Matrix B, can generate Matrix C such that A*C=B.
After some research, I produced this:
Matrix Matrix::GetBridge(Matrix* theOther)
{
Matrix aIMat=GetInvert();
if (!theOther) return Identity();
Matrix aResult=*theOther;
aResult*=aIMat;
return aResult;
}
The result this produces is... kinda correct. It produces the correct numbers, but with different sign. Here is the output:
Matrix A: 1,0,0,0
0,0.9063,0.4226,0
0,-0.4226,0.9063,0
0,0,0,1
Matrix B: 0,0,-1,0
0,1,0,0
1,0,0,0
0,0,0,1
Matrix C: 0,-0.4226,-0.9063,0
0,0.9063,-0.4226,0
1,0,0,0
0,0,0,1
Matrix B * C: -1,-0,-0,0
0,0.9063,-0.4226,0
0,-0.4226,-0.9063,0
0,0,0,1
So B*C = A for the numbers, but not the sign. I'm trying to use this to find what I need to multiply a certain matrix by in order to orient to another matrix (in 3D space).
How do I fix this function?
(Edit)
Here's the code that produces the above results:
Matrix aM1;aM1.RotateX(25);
Matrix aM2;aM2.RotateY(90);
Matrix aM3=aM1.GetBridge(&aM2);
aM1.Debug("$Matrix A:");
aM2.Debug("$Matrix B:");
aM3.Debug("$Matrix C:");
Matrix aM4=aM2;
aM4*=aM3;
aM4.Debug("!Matrix B * C:");
...and here are the contents of GetInvert, in case the error is there:
Matrix& Matrix::Invert()
{
float aInv[16];
aInv[0]=mData.mm[5]*mData.mm[10]*mData.mm[15]-mData.mm[5]*mData.mm[11]*mData.mm[14]-mData.mm[9]*mData.mm[6]*mData.mm[15]+mData.mm[9]*mData.mm[7]*mData.mm[14]+mData.mm[13]*mData.mm[6]*mData.mm[11]-mData.mm[13]*mData.mm[7]*mData.mm[10];
aInv[4]=-mData.mm[4]*mData.mm[10]*mData.mm[15]+mData.mm[4]*mData.mm[11]*mData.mm[14]+mData.mm[8]*mData.mm[6]*mData.mm[15]-mData.mm[8]*mData.mm[7]*mData.mm[14]-mData.mm[12]*mData.mm[6]*mData.mm[11]+mData.mm[12]*mData.mm[7]*mData.mm[10];
aInv[8]=mData.mm[4]*mData.mm[9]*mData.mm[15]-mData.mm[4]*mData.mm[11]*mData.mm[13]-mData.mm[8]*mData.mm[5]*mData.mm[15]+mData.mm[8]*mData.mm[7]*mData.mm[13]+mData.mm[12]*mData.mm[5]*mData.mm[11]-mData.mm[12]*mData.mm[7]*mData.mm[9];
aInv[12]=-mData.mm[4]*mData.mm[9]*mData.mm[14]+mData.mm[4]*mData.mm[10]*mData.mm[13]+mData.mm[8]*mData.mm[5]*mData.mm[14]-mData.mm[8]*mData.mm[6]*mData.mm[13]-mData.mm[12]*mData.mm[5]*mData.mm[10]+mData.mm[12]*mData.mm[6]*mData.mm[9];
aInv[1]=-mData.mm[1]*mData.mm[10]*mData.mm[15]+mData.mm[1]*mData.mm[11]*mData.mm[14]+mData.mm[9]*mData.mm[2]*mData.mm[15]-mData.mm[9]*mData.mm[3]*mData.mm[14]-mData.mm[13]*mData.mm[2]*mData.mm[11]+mData.mm[13]*mData.mm[3]*mData.mm[10];
aInv[5]=mData.mm[0]*mData.mm[10]*mData.mm[15]-mData.mm[0]*mData.mm[11]*mData.mm[14]-mData.mm[8]*mData.mm[2]*mData.mm[15]+mData.mm[8]*mData.mm[3]*mData.mm[14]+mData.mm[12]*mData.mm[2]*mData.mm[11]-mData.mm[12]*mData.mm[3]*mData.mm[10];
aInv[9]=-mData.mm[0]*mData.mm[9]*mData.mm[15]+mData.mm[0]*mData.mm[11]*mData.mm[13]+mData.mm[8]*mData.mm[1]*mData.mm[15]-mData.mm[8]*mData.mm[3]*mData.mm[13]-mData.mm[12]*mData.mm[1]*mData.mm[11]+mData.mm[12]*mData.mm[3]*mData.mm[9];
aInv[13]=mData.mm[0]*mData.mm[9]*mData.mm[14]-mData.mm[0]*mData.mm[10]*mData.mm[13]-mData.mm[8]*mData.mm[1]*mData.mm[14]+mData.mm[8]*mData.mm[2]*mData.mm[13]+mData.mm[12]*mData.mm[1]*mData.mm[10]-mData.mm[12]*mData.mm[2]*mData.mm[9];
aInv[2]=mData.mm[1]*mData.mm[6]*mData.mm[15]-mData.mm[1]*mData.mm[7]*mData.mm[14]-mData.mm[5]*mData.mm[2]*mData.mm[15]+mData.mm[5]*mData.mm[3]*mData.mm[14]+mData.mm[13]*mData.mm[2]*mData.mm[7]-mData.mm[13]*mData.mm[3]*mData.mm[6];
aInv[6]=-mData.mm[0]*mData.mm[6]*mData.mm[15]+mData.mm[0]*mData.mm[7]*mData.mm[14]+mData.mm[4]*mData.mm[2]*mData.mm[15]-mData.mm[4]*mData.mm[3]*mData.mm[14]-mData.mm[12]*mData.mm[2]*mData.mm[7]+mData.mm[12]*mData.mm[3]*mData.mm[6];
aInv[10]=mData.mm[0]*mData.mm[5]*mData.mm[15]-mData.mm[0]*mData.mm[7]*mData.mm[13]-mData.mm[4]*mData.mm[1]*mData.mm[15]+mData.mm[4]*mData.mm[3]*mData.mm[13]+mData.mm[12]*mData.mm[1]*mData.mm[7]-mData.mm[12]*mData.mm[3]*mData.mm[5];
aInv[14]=-mData.mm[0]*mData.mm[5]*mData.mm[14]+mData.mm[0]*mData.mm[6]*mData.mm[13]+mData.mm[4]*mData.mm[1]*mData.mm[14]-mData.mm[4]*mData.mm[2]*mData.mm[13]-mData.mm[12]*mData.mm[1]*mData.mm[6]+mData.mm[12]*mData.mm[2]*mData.mm[5];
aInv[3]=-mData.mm[1]*mData.mm[6]*mData.mm[11]+mData.mm[1]*mData.mm[7]*mData.mm[10]+mData.mm[5]*mData.mm[2]*mData.mm[11]-mData.mm[5]*mData.mm[3]*mData.mm[10]-mData.mm[9]*mData.mm[2]*mData.mm[7]+mData.mm[9]*mData.mm[3]*mData.mm[6];
aInv[7]=mData.mm[0]*mData.mm[6]*mData.mm[11]-mData.mm[0]*mData.mm[7]*mData.mm[10]-mData.mm[4]*mData.mm[2]*mData.mm[11]+mData.mm[4]*mData.mm[3]*mData.mm[10]+mData.mm[8]*mData.mm[2]*mData.mm[7]-mData.mm[8]*mData.mm[3]*mData.mm[6];
aInv[11]=-mData.mm[0]*mData.mm[5]*mData.mm[11]+mData.mm[0]*mData.mm[7]*mData.mm[9]+mData.mm[4]*mData.mm[1]*mData.mm[11]-mData.mm[4]*mData.mm[3]*mData.mm[9]-mData.mm[8]*mData.mm[1]*mData.mm[7]+mData.mm[8]*mData.mm[3]*mData.mm[5];
aInv[15]=mData.mm[0]*mData.mm[5]*mData.mm[10]-mData.mm[0]*mData.mm[6]*mData.mm[9]-mData.mm[4]*mData.mm[1]*mData.mm[10]+mData.mm[4]*mData.mm[2]*mData.mm[9]+mData.mm[8]*mData.mm[1]*mData.mm[6]-mData.mm[8]*mData.mm[2]*mData.mm[5];
float aDet=mData.mm[0]*aInv[0]+mData.mm[1]*aInv[4]+mData.mm[2]*aInv[8]+ mData.mm[3]*aInv[12];
if (aDet!=0) {aDet=1.0f/aDet;for (int aCount=0;aCount<16;aCount++) mData.mm[aCount]=aInv[aCount]*aDet;}
return *this;
}
inline Matrix GetInvert() {Matrix aMat=*this;aMat.Invert();return aMat;}
(Note: This Invert function works for all other purposes I have put it to, i.e. to move coordinates into local space, so I don't expect the error to be there)
The equation you need is:
A * (A-1 * B) = B
because
A * (A-1 * B) = (A * A-1) * B = I * B = B
So the "bridge matrix" is (A-1 * B). A-1 means the inverse of A.
However, it looks like your code is computing (B * A-1) which is not, generally, the same matrix. It should multiply in the opposite order.

Eigen library, Jacobi SVD

I'm trying to estimate a 3D rotation matrix between two sets of points, and I want to do that by computing the SVD of the covariance matrix, say C, as follows:
U,S,V = svd(C)
R = V * U^T
C in my case is 3x3 . I am using the Eigen's JacobiSVD module for this and I only recently found out that it stores matrices in column-major format. So that has had me confused.
So, when using Eigen, should I do:
V*U.transpose() or V.transpose()*U ?
Additionally, the rotation is accurate upto changing the sign of the column of U corresponding to the smallest singular value,such that determinant of R is positive. Let's say the index of the smallest singular value is minIndex .
So when the determinant is negative, because of the column major confusion, should I do:
U.col(minIndex) *= -1 or U.row(minIndex) *= -1
Thanks!
This has nothing to do with matrices being stored row-major or column major. svd(C) gives you:
U * S.asDiagonal() * V.transpose() == C
so the closest rotation R to C is:
R = U * V.transpose();
If you want to apply R to a point p (stored as column-vector), then you do:
q = R * p;
Now whether you are interested R or its inverse R.transpose()==V.transpose()*U is up to you.
The singular values scale the columns of U, so you should invert the columns to get det(U)=1. Again, nothing to do with storage layout.

Solving for Lx=b and Px=b when A=LLt

I am decomposing a sparse SPD matrix A using Eigen. It will either be a LLt or a LDLt deomposition (Cholesky), so we can assume the matrix will be decomposed as A = P-1 LDLt P where P is a permutation matrix, L is triangular lower and D diagonal (possibly identity). If I do
SolverClassName<SparseMatrix<double> > solver;
solver.compute(A);
To solve Lx=b then is it efficient to do the following?
solver.matrixL().TriangularView<Lower>().solve(b)
Similarly, to solve Px=b then is it efficient to do the following?
solver.permutationPinv()*b
I would like to do this in order to compute bt A-1 b efficiently and stably.
Have a look how _solve_impl is implemented for SimplicialCholesky. Essentially, you can simply write:
Eigen::VectorXd x = solver.permutationP()*b; // P not Pinv!
solver.matrixL().solveInPlace(x); // matrixL is already a triangularView
// depending on LLt or LDLt use either:
double res_llt = x.squaredNorm();
double res_ldlt = x.dot(solver.vectorD().asDiagonal().inverse()*x);
Note that you need to multiply by P and not Pinv, since the inverse of
A = P^-1 L D L^t P is
P^-1 L^-t D^-1 L^-1 P
because the order of matrices reverses when taking the inverse of a product.

Multiplying matrices in Eigen c++ gives wrong dimensions

I'm having trouble understanding why I am getting a 10x10 matrix as a result from multiplying a 10x3 matrix with a 3x10 matrix using the Eigen library in c++.
By following the documentation at http://eigen.tuxfamily.org/dox-devel/group__TutorialMatrixArithmetic.html I came up with
const int NUM_OBSERVATIONS = 10;
const int NUM_DIMENSIONS = 3;
MatrixXf localspace(NUM_DIMENSIONS, NUM_OBSERVATIONS);
MatrixXf rotatedlocalspace(NUM_OBSERVATIONS, NUM_DIMENSIONS);
MatrixXf covariance(NUM_DIMENSIONS, NUM_DIMENSIONS);
covariance = (rotatedlocalspace * localspace) / (NUM_OBSERVATIONS - 1);
cout << covariance << endl;
Output gives a 10x10 matrix, when I am trying to obtain a 3x3 covariance matrix for each dimension (These are mean centered XYZ points). "localspace" and "rotatedlocalspace" are both filled with float values when covariance is calculated.
How do I get the correct covariance matrix?
Eigen is correct, as it reproduces basic math: if A is a matrix of dimension n x m and B has dimension m x k, then A*B has the dimension n x k.
Applied to your problem, if your matrix rotatedlocalspace is of dimension 10 x 3 and localspace has dimension 3 x 10, then rotatedlocalspace*localspace has dimension
(10 x 3) * (3 x 10) -> 10 x 10.
The scalar division you apply further doesn't change the dimension.
If you expect a different dimension, then try to commute the factors in the matrix product. This you will obtain a 3x3 matrix.

Eigen - divide each (sparse) matrix row by its corresponding diagonal element

Using the Eigen library in C++, given a sparse matrix A, what is the most efficient way (row-wise operations? how to?) to compute a sparse matrix B such that B(i, j) = A(i, j) / A(i, i) ? That is, divide each row i by the corresponding diagonal element A(i, i).
It would be helpful to know how to do it both in-place (replacing entries in A) and out-of-place (creating a new sparse matrix B).
My sparse matrix is defined as:
typedef double Real;
typedef Eigen::SparseMatrix<Real> SparseMatrixR;
Thank you,
m.
In other words you want to extract the diagonal of A, view it as a diagonal matrix, and apply its inverse to A:
A = A.diagonal().asDiagonal().inverse() * A;
This operation should be slightly more efficient if A is rowmajor.