Does armadillo offer functions that apply element-wise operations only on the diagonal elements of a matrix? Say I want to run an inverse on it then I get infs on off-diagonals. I know that I can get it with arma::inv(m), but for diagonal matrices it seems faster to run it element-wise.
Minimal example:
#include <iostream>
#include <armadillo>
int main() {
arma::Col<double> v = {1.2, 3.14, 2.71, 0.1};
arma::Mat<double> m = arma::diagmat(v);
std::cout << " A diagonal matrix:\n" << m << "\n\n";
std::cout << " It's elemenet-wise inverse:\n" << 1.0/m << std::endl;
return 0;
}
Related
problem description
I'm using Eigen for some matrix task. Say I have matrix A whose size is 4x3, then its transpose A^T is 3x4 size, then A^T * A is 3x3 size, thus the inverse, (A^T * A)^(-1), is also 3x3 size.
I would like to get (A^T * A)^(-1). By using the mentioned formula, and by manually defining A^T * A matrix then do inverse, I got different result for (A^T * A)^(-1) matrix. Curious why this two results mismatch and differs very much.
Reproduce
Eigen version: git commit 972cf0c28a8d2ee0808c1277dea2c5c206591ce6
System: Ubuntu 20.04
Compiler: Clang++, 10.0.0
Code:
#include <iostream>
#include <Eigen/Dense>
int main() {
{
printf("----- A^T * A by calculate\n");
Eigen::MatrixXd A(4, 3);
A << 1.70023e+06, 1303.93, 1,
1.99113e+06, 1411.07, 1,
1.97211e+06, 1404.32, 1,
1.69433e+06, 1301.67, 1;
std::cout << "A:" << std::endl << A << std::endl;
Eigen::MatrixXd AT = A.transpose();
std::cout << "A^T:" << std::endl << AT << std::endl;
Eigen::MatrixXd ATA = AT * A;
std::cout << "A^T * A:" << std::endl << ATA << std::endl;
std::cout << "(A^T * A)^(-1):" << std::endl << ATA.inverse() << std::endl;
}
{
printf("----- A^T * A by define\n");
Eigen::MatrixXd ATA(3, 3);
ATA << 1.36154e+13, 1.00015e+10, 7.3578e+06,
1.00015e+10, 7.3578e+06, 5420.99,
7.3578e+06, 5420.99, 4;
std::cout << "A^T * A:" << std::endl << ATA << std::endl;
std::cout << "(A^T * A)^(-1):" << std::endl << ATA.inverse() << std::endl;
}
return 0;
}
The actual outputs:
----- A^T * A by calculate
A:
1.70023e+06 1303.93 1
1.99113e+06 1411.07 1
1.97211e+06 1404.32 1
1.69433e+06 1301.67 1
A^T:
1.70023e+06 1.99113e+06 1.97211e+06 1.69433e+06
1303.93 1411.07 1404.32 1301.67
1 1 1 1
A^T * A:
1.36154e+13 1.00015e+10 7.3578e+06
1.00015e+10 7.35781e+06 5420.99
7.3578e+06 5420.99 4
(A^T * A)^(-1):
3.49282e-06 -0.00946871 6.40758
-0.00946871 25.6689 -17370.5
6.40758 -17370.5 1.17549e+07
----- A^T * A by define
A^T * A:
1.36154e+13 1.00015e+10 7.3578e+06
1.00015e+10 7.3578e+06 5420.99
7.3578e+06 5420.99 4
(A^T * A)^(-1):
6.1435e-09 -1.66513e-05 0.0112659
-1.66513e-05 0.0452221 -30.658
0.0112659 -30.658 20826.4
This is just a matter of numerical accuracy. As pointed out by #Damien in the comment, the matrix is ill-conditioned, and thus a small difference in the input can lead to a large change in the results. By copying from the output only the first five digits and using them to manually define the second matrix, a significant part is discarded that is handled internally but not displayed with the standard accuracy of std::cout.
Take for instance the entry ATA(0,0). By using is ATA << 1.36154e+13,..., any value of the order of 1.e7 or lower is not considered. This is, however, the order of the other entries in the matrix.
In short, both results are correct, but your manually defined matrix ATA is not the same as the one that is calculated in the first part. (You can take the difference between the two to verify this).
My today practice for inverse matrix 3x3 is using
template<typename Derived>
template<typename ResultType>
inline void MatrixBase<Derived>::computeInverseAndDetWithCheck(
ResultType& inverse,
typename ResultType::Scalar& determinant,
bool& invertible,
const RealScalar& absDeterminantThreshold
) const
Set manual absDeterminantThreshold is default:
1)for float 1e-5
2)for double 1e-12
3)for long double 1e-15
For example your CODE:
Eigen::Matrix3d ATA_inv;
bool invertible = false;
double determinant = 0.;
double Threshold = abs(ATA.diagonal().prod());//maybe any test
ATA.computeInverseAndDetWithCheck(ATA_inv,determinant,invertible,Threshold<1e-12?Threshold*0.1:1e-12);
I'm using eigen3 to take the inverse of the matrix,but the inverse is wrong.
I tried several examples,but the following this is wrong.
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main(){
Matrix3d Mat1;
Mat1 << 99.999999999999972 ,-29024.672261149386 ,29024.848775176863,-29024.672261149386, 8629880.2300641891 ,-8629930.2299046051,29024.848775176863,-8629930.2299046051 , 8629980.2300641891 ;
cout << "Mat1=\n" << Mat1 << endl;
Matrix3d Mat2=Mat1.inverse();
cout << "Mat1逆矩阵:\n" << Mat2 << endl;
cout << "Mat1*Mat2:\n" << Mat1*Mat2 << endl;
cout << "Mat2*Mat1:\n" << Mat2*Mat1 << endl;
cout << "Mat1行列式:\n" << Mat1.determinant() << endl;
the result is:
Mat1=
100 -29024.7 29024.8
-29024.7 8.62988e+06 -8.62993e+06
29024.8 -8.62993e+06 8.62998e+06
Mat1逆矩阵:
44.3313 -12557.7 -12557.8
-12557.7 3.58199e+06 3.58201e+06
-12557.8 3.58201e+06 3.58204e+06
Mat1*Mat2:
1 -0.000198364 0.000823975
-80.0958 0.785156 -0.242188
80.0963 -0.0634151 0.972687
Mat2*Mat1:
1 -80.0958 80.0963
-0.000198364 0.785156 -0.0625
0.000818345 -0.243301 0.972687
Mat1行列式:
5.73875
Shouldn't mat1*mat2 be a unit matrix?
Try using pseudo-inverse instead. That problem maybe a precision issues as #paddy said.
Got that code from here
#include <Eigen/QR>
Eigen::MatrixXd A = ... // fill in A
Eigen::MatrixXd pinv = A.completeOrthogonalDecomposition().pseudoInverse();
My result:
Mat3*Mat1:
1 3.05176e-05 -3.05176e-05
0 1 -0.0078125
2.88524e-05 -0.0137121 1.00454
Mat1*Mat3:
1.00004 -0.0101929 -0.0101624
-3.05176e-05 1.00781 0
5.83113e-05 -0.0134087 0.996313
Before anything else I must say that I've studied Comparing two matrices with eigen
but my question is not the same. Suppose I have two eigen matrices A and B, and I want to edit A in following way:
if (A(i,j) > B(i,j)) A(i,j) = A(i,j)
otherwise A(i,j) = B(i,j)
I guess it is possible to do it without an explicit for loop. But I am not very proficient with Eigen yet. What whould be the best approach?
It's A.cwiseMax(B).
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Matrix2i A = Eigen::Matrix2i::Random();
Eigen::Matrix2i B = Eigen::Matrix2i::Random();
std::cout << "A =\n" << A << "\nB =\n" << B << "\n";
A = A.cwiseMax(B);
std::cout << "max(A,B) =\n" << A << "\n";
}
Output on my machine is
A =
730547559 607950953
-226810938 640895091
B =
884005969 -353856438
-649503489 576018668
max(A,B) =
884005969 607950953
-226810938 640895091
There is this:
https://codeyarns.com/2016/02/16/how-to-compare-eigen-matrices-for-equality/
But there is no isApprox for tensors.
The following doesn't do what I want:
#include <Eigen/Core>
#include <unsupported/Eigen/CXX11/Tensor>
#include <array>
#include <iostream>
using namespace Eigen;
using namespace std;
int main()
{
// Create 2 matrices using tensors of rank 2
Eigen::Tensor<int, 2> a(2, 3);
Eigen::Tensor<int, 2>* b = &a;
cerr<<(*b==*b)<<endl;
}
because it does coordinate wise comparison and returns a tensor of the same dimension instead of a true/false vale.
How do I check if two tensors are identical? No isApprox for tensors.
I could write my own function, but I want to be able to use GPU power when available, and it seems like Eigen has built-in GPU support.
For an exact comparison of 2 tensors A and B, you can use the comparison operator followed by a boolean reduction:
Tensor<bool, 0> eq = (A==B).all();
This will return a tensor of rank 0 (i.e. a scalar) that contains a boolean value that's true iff each coefficient of A is equal to the corresponding coefficient of B.
There is no approximate comparison at the moment, although it wouldn't be difficult to add.
You can always use a couple of Eigen::Maps to do the isApprox checks.
#include <iostream>
#include <unsupported/Eigen/CXX11/Tensor>
using namespace Eigen;
int main()
{
Tensor<double, 3> t(2, 3, 4);
Tensor<double, 3> r(2, 3, 4);
t.setConstant(2.1);
r.setConstant(2.1);
t(1, 2, 3) = 2.2;
std::cout << "Size: " << r.size() << "\n";
std::cout << "t: " << t << "\n";
std::cout << "r: " << r << "\n";
Map<VectorXd> mt(t.data(), t.size());
Map<VectorXd> mr(r.data(), r.size());
std::cout << "Default isApprox: " << mt.isApprox(mr) << "\n";
std::cout << "Coarse isApprox: " << mt.isApprox(mr, 0.11) << "\n";
return 0;
}
P.S./N.B. Regarding Eigen's built in GPU support... Last I checked it is fairly limited and with good reason. It is/was limited to fixed size matrices as dynamic allocation on a GPU is really something you want to avoid like the common cold (if not like the plague). I take it back. It looks like the Tensor module supports GPUs pretty well.
The Eigen Library supports creating a matrix with axis-angle arguments. How do you perform the opposite and determine the axis-angle from a matrix (I'm not interested in the Euler set, just a single axis-angle result).
Eigen supplies an AngleAxis constructor that takes a matrix as an argument. So, it is simply:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Geometry>
int main()
{
Eigen::Vector3d axis;
axis.setRandom();
std::cout << axis << "\n\n";
axis.normalize();
std::cout << axis << "\n\n";
Eigen::Matrix3d mat;
mat = Eigen::AngleAxisd(0.256, axis);
Eigen::AngleAxisd newAngleAxis(mat);
std::cout << newAngleAxis.angle() << "\n" << newAngleAxis.axis() << "\n\n";
return 0;
}
Which outputs:
-0.997497
0.127171
-0.613392
-0.846852
0.107965
-0.520755
0.256
-0.846852
0.107965
-0.520755
or something similar.