Eigen-Basic (1)


1. The role of each header file in Eigen

insert image description here

2. Basics of using Eigen

2.1 Hello World

 #include<iostream>
 #include<Eigen/Dense> // Eigen header file, including all functions and classes in the Eigen library
 ​
 int main()
 {
     Eigen::MatrixXd m(2,3); // MatrixXd: dynamic array, specify the row and column of the array during initialization
     m(0,0) = 3;
     m(1,0) = 2.5;
     ...;
     std::cout << m << std::endl; // Eigen overloads the << operator, which can directly output the value of the Eigen matrix
 }

2.2 Matrices and Vectors

 #include<iostream>
 #include<Eigen/Dense> 
 ​
 using namespace std;
 using namespace Eigen;
 int main()
 {
     MatrixXd m = MatrixXd::Random(3,3); // initialize dynamic array
     m = (m + MtrixXd::Constant(3,3,1.2)) * 50;
     cout<<"m = "<<endl<<m<<endl;
     VectorXd v(3);
     v<<1,2,3; // comma initialization
     cout<< "m * v = "<< endl << m * v << endl;
 }

2.3 comma-initializer

 RowVectorXd vec1(3);
 vec1 << 1,2,3;
 std::cout<<"vec1 = "<< vec1 << std::endl;
 ​
 RowVectorXd vec2(4);
 vec1 << 1,2,3,4;
 std::cout<<"vec2 = "<< vec2 << std::endl;
 ​
 RowVectorXd joined(7);
 joined << vec1,vec2;
 std::cout<<"joined = "<< joined << std::endl;

2.4 Commonly used initialization methods (initialized to 0, initialized to 1, initialized to the identity matrix)

 #include<iostream>
 #include<Eigen/Dense> 
 ​
 using namespace std;
 using namespace Eigen;
 int main()
 {
     MatrixXd m0 = MatrixXd::Random(3,3); // Random initialization, the value is (-1,1)
     MatrixXd m1 = MatrixXd::Constant(3,3,2.4); // Constant initialization, all values ​​are 2.4
     MatrixXd m2 = MatrixXd::Zero(); // zero initialization
     MatrixXd m3 = MatrixXd::Ones(); // initialize 1
     MatrixXd m4 = MatrixXd:Identity();// Initialize to identity matrix
 }

2.5 Resizing the Matrix

The current size of the matrix can be obtained with rows(), cols() and size(). Resizing a dynamically sized matrix is ​​achieved through the resize() method. A dynamic matrix can resize the matrix at will, and a fixed-size matrix cannot be resized.

     MatrixXd m0(x,x);
     m0.resize(4,4);
     VectorXd v(3);
     v.resize(5);

2.6 Selection of fixed size and dynamic size

Use fixed sizes for very small sizes whenever possible, and dynamic sizes for larger sizes when possible. For small sizes, especially for sizes smaller than (approximately) 16, there is a huge performance benefit to using a fixed size. Because it makes Eigen avoid dynamic memory allocation and unroll loops. Internally, a fixed-size eigenmatrix is ​​just an array of golden eggs.

3 matrix class

In Eigen, all matrices and vectors are objects of the Matrix template class. Vectors are just a special case of matrices, with 1 row and 1 column.

3.1 The first three template parameters of Matrix

The matrix class needs to leave a template parameter, but generally you only need to understand the first three parameters. The remaining three parameters have default values. Three required template parameters for Matrix: Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> Scalar is a scalar type, ie the type of the coefficients. RowsAtCompileTime/ColsAtCompileTime is the number of rows and columns of the matrix known at compile time.

 typedef Matrix<int, 1, 2> RowVector2i;
 typedef Matrix<double,Dynamic,Dynamic> MatrixXd;
 typedef Matrix<int, Dynamic, 1> VectorXi;
 ​
 typedef Array<float, Dynamic, Dynamic> ArrayXXf;
 typedef Array<double, Dynamic,1> ArrayXd;
 typedef Array<int, 1, Dynamic> RowArrayXi;
 typedef Array<float, 3, 3> Array33f;
 typedef Array<float, 4,1> Array4f;
 ...

3.2 vectors

In Eigen, vectors are just a special case of Matrix, with 1 row or 1 column. It is most common that they have only 1 column, such vectors are called column vectors, often abbreviated as vectors. A vector with only 1 row is called a row vector.

3.3 Dynamic Matrix

The size of the dynamic matrix is ​​not known at compile time, and its size needs to be determined at runtime. typedef Matrix<dobule, Dynamic, Dynamic> MatrixXd;

4 Introduction to the Array class

Eigen not only provides Matrix and Vector structures, but also Array structures. The difference is as follows: Matrix and Vector are matrices and vectors defined in linear algebra, and all mathematical operations are consistent with mathematics. But there is a problem that the mathematical definition does not necessarily fully meet the actual requirements. For example, the addition operation of a matrix and a scalar is not defined mathematically. But if we want to add the same number to each element of a matrix, then this operation needs to be implemented by ourselves, which is obviously inconvenient. Array provides an Array class, which provides us with a large number of undefined operations of the matrix, and it is easy to convert between Array and Matrix, so it is equivalent to providing more methods for the matrix, and also provides different needs for users. more choices. Array<typename Scalar, int row, int cols>

4.1 Array initialization, addition, subtraction, multiplication and division operations

The Eigen::Array class overloads the +-*/ operator, and these operators can be directly used to operate on the Array object. The multiplication operation is the multiplication of the corresponding numbers, and the division operation is the division of the corresponding elements.

 ArrayXXf a(3,3);
 ArrayXXf b(,3,3);
 a<<1,2,3,4,5,6,7,8,9;
 b<<1,2,3,1,2,3,1,2,3;
 cout<<"a + b = "<<endl<<a + b<<endl;
 cout<<"a - 2 = "<<endl<<a - 2<<endl; // subtract 2 from all elements
 cout<<"a * b = "<<endl <<a * b<<endl; // multiply corresponding elements
 cout<<"a / b = "<<endl <<a / b<<endl; // corresponding element division

4.2 Other operations of the Array class

The Eigen::Array class also defines the absolute value abs(), the square root sqrt() and the operation min() to find the minimum value of the corresponding element.

 ArrayXXf a = ArrayXXf::Random(3,3);
 a *= 2;
 cout<<"a = "<<endl<<a<<endl;
 cout<<"a.abs() = "<<endl<<a.abs()<<endl;
 cout<<"a.abs().sqrt()"<<endl<<a.abs().sqrt()<<endl;
 cout<<"a.min(a.abs().sqrt()) = "<<endl<<a.min(a.abs().sqrt())<<endl;

6. Mutual conversion between Matrix and Array

The Matrix class and the Array class can be converted to each other, and the conversion must be displayed before they can be added, subtracted, multiplied and divided.

array44f a1,a2;
Matrix4f m1,m2;
m1 = a1 * a2;
a1 = m1 * m2;
a2 = a1 + m1.array();
m2 = a1.matrix() + m1;
ArrayWrapper<Matrix4f> m1a(m1);// m1a is an alias of m1.array(), they share the same coefficient
MatrixWrapper<Array44f>a1m(a1);

7. Matrix transpose, conjugate, conjugate transpose

Some operations on matrices are described below.

7.1 Transpose and Conjugation

The transpose, conjugate and conjugate transpose of the matrix are implemented by member functions transpose()/conjugate()/adjoint().

MatrixXcf a = MatrixXcf::Random(2,2);
cout<<"a = "<<endl <<a <<endl;
cout<<"a.transpose = "<<endl<<a.transpose()<<endl;
cout<<"a.conjugate = "<<endl<<a.conjugate()<<endl;
cout<<"a.adjoint = "<<endl<<a.adjoint()<<endl;

7.2 Matters needing attention for transposition

a = a.tanspose(); won't work, it's called an aliasing problem. Such problems are automatically detected in Debug mode when assertions are not disabled. To avoid errors, you can use in-place transposition.

Matrix2i a;
a<<1,2,3,4;
cout<<" a = \n"<<a<<endl;
// a = a.transpose();// Don't write code like this, it won't work
a.transposeInPlace();
cout<<"a.transpose = \n"<<a<<endl;

8. Dot and cross products

For dot and cross products, use the dot() and cross() methods directly.

Vector3d v(1,2,3);
Vector3d w(0,1,2);
cout<<"Dot product: "<<v.dot(w)<<endl;
double dp = v.adjoint() * w; 
cout<<"Dot product via a matrix product:"<<dp <<endl;
cout<<"Cross product:\n"<<v.cross(w) <<endl;

Note: the cross product is only used for vectors of size 3! The dot product can be used for vectors of any size, and when complex numbers are used, Eigen's dot product is conjugate linear as the first variable and linear as the second.

9. Basic arithmetic with matrices (sum, average, etc.)

Eigen provides some reduction operations for matrices or vectors, such as sum(), prod(), maxCoeff(), minCoeff()

Eigen::Matrix2d with;
mat<<1,2,3,4;
cout<<"mat.sum: "<<mat.sum() <<endl;
cout<<"mat.prod: "<<mat.prod() <<endl;
cout<<"mat.mean: "<<mat.mean() <<endl;
cout<<"mat.minCoeff: "<<mat.minCoeff() <<endl;
cout<<"mat.maxCoeff: "<<mat.maxCoeff() <<endl;
cout<<"mat.trace: "<<mat.trace() <<endl;

10. Eigen block operation

10.1 Basic Block Operations

A block refers to a rectangular area in a matrix or an array. A block expression can be used for lvalues ​​or rvalues. It also does not consume runtime and is optimized by the compiler. The most commonly used fast operation in Eigen is the block() method, which has two versionsinsert image description here

Indexes start at 0, and both versions are available for matrices and arrays of fixed or dynamic size. These two expressions are semantically identical, the only difference being that the fixed-size version of the block operation runs faster if the block size is smaller, but requires the size to be known at the toilet stage.

#include <Eigen/Dense>
#include <iostream>
using namespace std;
int main() 
{
    Own::MatrixXf m(4, 4);
    // Initialize the m matrix
    for (int i = 0; i < 4; ++i) 
    {
        for (int j = 0; j < 4; ++j) 
        {
            m(i, j) = j + 1 + i * 4;
        }
    }
    cout << "m: " << endl << m << endl;
    cout << "Block in the middle" << endl;
    cout << m.block<2, 2>(1, 1) << endl << endl;// m.block<i,j> (a,b) means starting from line (a+1) (b+ 1) Start from the column, screenshot i line, j column
    for (int i = 1; i <= 3; ++i) 
    {
        cout << "Block of size " << i << "x" << i << endl;
        cout << m.block(0, 0, i, i) << endl << endl;// m.block(a,b,i,j) means from line (a+1) (b+1) Column start, screenshot i line, j column
    }
}

Note: m.block<i,j>(a,b) means starting from the (a+1) row (b+1) column, cutting i row j column. The block operation method in the above example is used as an rvalue of the expression, which means it is read-only. However, the fast operation can also be used as an lvalue, which means that its magnitude can be given. The following example illustrates this point, of course The same is true for matrices.

#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main() 
{
    Array22f m;
    m << 1, 2, 3, 4;
    Array44f a = Array44f::Constant(0.6);
    cout << "Here is the array a:" << endl << a << endl << endl;
    a.block<2, 2>(1, 1) = m;
    cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl;
    a.block(0, 0, 2, 3) = a.block(2, 1, 2, 3);
    cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x2 block:" << endl << a << endl << endl;
}

Although the block() method can be used for any kind of block operation, there are special methods for special cases, mainly for better performance. When it comes to performance, the most important thing is to give EIgen as much information as possible during the compilation phase. For example, if your block is a column in a matrix, it would be better to use the col() method.

10.2 Rows and columns

Rows and columns are special blocks, and Eigen provides special methods: col() and row().

insert image description here

#include <Eigen/Dense>
#include <iostream>
using namespace std;
int main() 
{
    Own::MatrixXf m(4, 4);
    // array initialization
    for (int i = 0; i < 4; ++i) 
    {
        for (int j = 0; j < 4; ++j) 
        {
            m(i, j) = j + 1 + i * 4;
        }
    }
    cout << "Here is the matrix m:" << endl << m << endl;
    cout << "2nd Row: " << m.row(1) << endl;
    m.col(2) += 3 * m.col(0);
    cout << "After adding 3 times the first column into the third column, the matrix m is:\n";
    cout << m << endl;
}

10.3 Corner-related operations

Eigen also provides special operation methods for the sides and corners next to the matrix or array. For example, the topLeftCorner() method can be used to operate the area at the upper left corner of the matrix. Summarized as follows:

img

    Eigen::Matrix4f m;
    m << 1, 2, 3, 4,
            5, 6, 7, 8,
            9, 10, 11, 12,
            13, 14, 15, 16;
    cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl;
    cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl;
    m.topLeftCorner(1, 3) = m.bottomRightCorner(3, 1).transpose();
    cout << "After assignment, m = " << endl << m << endl;

10.4 Block operations on vectors

Eigen also provides some block manipulation methods for vectors and one-dimensional arrays:

insert image description here

    Own::ArrayXf v(6);
    v << 1, 2, 3, 4, 5, 6;
    cout << "v.head(3) =" << endl << v.head(3) << endl << endl;
    cout << "v.tail<3>() = " << endl << v.tail<3>() << endl << endl;
    v.segment(1,4) *= 2;
    cout << "after 'v.segment(1,4) *= 2', v =" << endl << v << endl;

11 Norm calculation

The square norm of the vector is obtained by squaredNorm(), which is equivalent to the dot product of the vector itself, and is also equivalent to the sum of the squares of all elements. Eigen also provides the norm() norm, which returns the root of squaredNorm(). These operations also work with matrices. If you want to use other element-level norms, use the lpNorm() method. When seeking the infinite norm, the template parameter p can take the special value Infinity, and the maximum absolute value of all elements is obtained.

#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main() 
{
    VectorXf v(2);
    MatrixXf m(2, 2), n(2, 2);
    v << -1, 2;
    m << 1, -2, -3, 4;
    cout << "v.squaredNorm() = " << v.squaredNorm() << endl;
    cout << "v.norm() = " << v.norm() << endl;
    cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << endl;
    cout << "v.lpNorm<Infinity>() = " << v.lpNorm<Infinity>() << endl;
    cout << endl;
    cout << "m.squaredNorm() = " << m.squaredNorm() << endl;
    cout << "m.norm() = " << m.norm() << endl;
    cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << endl;
    cout << "m.lpNorm<Infinity>() = " << m.lpNorm<Infinity>() << endl;
}

The 1-norm and infinite-norm of a matrix can also be calculated using the following methods:

#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
using namespace std;
int main()
{
  MatrixXf m(2,2);
  m << 1,-2,
       -3,4;
  cout << "1-norm(m)     = " << m.cwiseAbs().colwise().sum().maxCoeff()
       << " == "             << m.colwise().lpNorm<1>().maxCoeff() << endl;
  cout << "infty-norm(m) = " << m.cwiseAbs().rowwise().sum().maxCoeff()
       << " == "             << m.rowwise().lpNorm<1>().maxCoeff() << endl;
}

12 Boolean statute

The following operations get Boolean values ​​all() returns true, if all elements of the matrix or array are true any() returns true, if at least one element of the matrix or array is true count() returns the number of elements that are true

#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main()
{
  ArrayXXf a(2,2); 
  a << 1,2,3,4;
  cout << "(a > 0).all()   = " << (a > 0).all() << endl;
  cout << "(a > 0).any()   = " << (a > 0).any() << endl;
  cout << "(a > 0).count() = " << (a > 0).count() << endl;
  cout << endl;
  cout << "(a > 2).all()   = " << (a > 2).all() << endl;
  cout << "(a > 2).any()   = " << (a > 2).any() << endl;
  cout << "(a > 2).count() = " << (a > 2).count() << endl;
}

13 iterations

Iteration is used when the position of an element in a matrix or array needs to be obtained.

#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
  Own::MatrixXf m(2,2);
  m << 1, 2,3, 4;
  //get location of maximum
  MatrixXf::Index maxRow, maxCol;
  float max = m.maxCoeff(&maxRow, &maxCol);
  //get location of minimum
  MatrixXf::Index minRow, minCol;
  float min = m.minCoeff(&minRow, &minCol);
  cout << "Max: " << max <<  ", at: " <<
     maxRow << "," << maxCol << endl;
  cout << "Min: " << min << ", at: " <<
     minRow << "," << minCol << endl;
}

14 part statute

Partial reduction refers to the operation of matrix or array by row or column. When reducing each column or row, a column or row vector is obtained. The following example gets the maximum value of each column of the matrix and stores it in a row vector.

#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
  Eigen::MatrixXf with(2,4);
  mat << 1, 2, 6, 9, 3, 1, 7, 2; 
  std::cout << "Column's maximum: \n" <<mat.colwise().maxCoeff() << std::endl;
}

It is also possible to get the maximum value of each row and return a column vector.

#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
  Eigen::MatrixXf with(2,4);
  mat << 1, 2, 6, 9, 3, 1, 7, 2;
  std::cout << "Row's maximum: " << std::endl
   << mat.rowwise().maxCoeff() << std::endl;
}

15 broadcast mechanism

The concept of broadcasting is similar to partial reduction, except that broadcasting interprets vectors as matrices by copying them in one direction. The following example adds a column vector to each column of a matrix.

#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
  Eigen::MatrixXf with(2,4);
  Own::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;
  std::cout << "Broadcasting result: " << std::endl;
  std::cout << mat << std::endl;
}

You can understand mat.colwise()+=v as two equivalent ways, it adds the column vector to each column of the matrix; or copies the column vector 4 times to get a 2x4 matrix, and then performs the correlation of the matrix Add operation:

The +=, +, and - operators can also operate column-wise or row-wise. The =, /=, and / operators can also be used in arrays to perform element-wise row or column multiplication and division. But it can't be used on matrices, if you want to multiply v(0) by the 0th column of the matrix, v(1) by the 1st column of the matrix... use mat = mat v.asDiagonal( ).

Combining Broadcast and Other Operations

Broadcasting can also be combined with other operations, such as matrix or array operations, reduction, and partial reduction operations. A more complex example is presented below, which demonstrates finding the closest column to a given vector in a matrix, using the Euclidean distance.

#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
  Own::MatrixXf m(2,4);
  Own::VectorXf v(2);
  
  m << 1, 23, 6, 9,
       3, 11, 7, 2;
       
  v << 2,
       3;
  MatrixXf::Index index;
  // find nearest neighbour
  (m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
  cout << "Nearest neighbour is column " << index << ":" << endl;
  cout << m.col(index) << endl;
}

Guess you like

Origin blog.csdn.net/liangfei868/article/details/125938148