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.
Related
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;
}
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
I was doing Exercise of Chapter 3 (Functions) from a Book Called C++ Modules for Gaming.
It is this one question I am not able to Do is to find atanf(4/2) of (2,4) which according to the book and my calculator should give back '63.42' degrees.
Instead it gives me 1.107 degrees.
Here is my code:
#include "stdafx.h"
#include <iostream>
#include <cmath>
using namespace std;
void tani(float a,float b) //Finds the Tan inverse
{
float res;
res = atanf(b / a);
cout << res << endl;
}
int main()
{
cout << "Enter The Points X and Y: " << endl;
float x, y;
cin >> x >> y; //Input
tani(x,y); //calling Function
}
atanf, and the other trigonometric functions in c++ return results in radians. 1.107 radians are 63.426428 degress, so your code is correct.
You can convert radians to degrees by multiplying by 180 and dividing by Pi (the M_PI constant provided by <cmath>):
cout << res * 180.0 / M_PI << endl;
It is giving you correct answer in radians.Simply Convert it to Degree!
void tani(float a, float b) //Finds the Tan inverse
{
float res;
res = atanf(b/ a);
cout << res *(180 / 3.14) << endl;
}
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.