Eigen 简明教程

∥☆過路亽.° 提交于 2020-02-14 13:34:10

Eigen Quick Reference

一个 Eigen 的参考手册,包含 Python(Numpy) 与 Eigen 的对应用法,以及一些练习题。持续更新中。

Eigen array, matrix and vector types

在 Eigen 中,Matrix 用来表示数学意义上的矩阵和向量,Array 用来表示 1D 和 2D 的数组,你可以这样定义它们:

typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyMatrixType;
typedef Array<Scalar, RowsAtCompileTime, ColsAtCompileTime, Options> MyArrayType;
  • Scalar 表示系数的类型(例如float, double, boll, int 等等)。
  • RowsAtCompileTimeColsAtCompileTime 表示矩阵行数和列数(必须在编译时期给定),或者使用 Dynamic 表示其行数或者列数在运行时期给定。
  • Options 可以是 ColMajor 或者 RowMajor,它们表示存储数据的顺序,默认是 ColMajor。( 这里 有存储顺序的更多介绍)

你可以随意的组合上面的参数来创建 Matrix,例如

Matrix<double, 6, Dynamic>                  // 动态列数(堆分配)
Matrix<double, Dynamic, 2>                  // 动态行数(堆分配)
Matrix<double, Dynamic, Dynamic, RowMajor>  // 动态大小,RowMajor(堆大小) 
Matrix<double, 13, 3>                       // 固定大小(通常是栈大小)

你还可以使用更加简易形式来表示一些常用的 Matrix 或者 Array,例如

Matrices Arrays
Matrix<float, Dynamic, Dynamic> <=> MatrixXf Array<float,Dynamic,Dynamic> <=> ArrayXXf
Matrix<double, Dynamic, 1> <=> VectorXd Array<double,Dynamic,1> <=> ArrayXd
Matrix<int, 1, Dynamic> <=> RowVectorXi Array<int,1,Dynamic> <=> RowArrayXi
Matrix<float, 3, 3> <=> Matrix3f Array<float,3,3> <=> Array33f
Matrix<float, 4, 1> <=> Vector4f Array<float,4,1> <=> Array4f

Which should I choose: matrix or array

如果你也有类似的困惑,很大几率是因为你比较熟悉 Python(NumPy) 或者 MATLAB。

在 MATLAB 中所有变量都是多维数组,矩阵是指通常用来进行线性代数运算的二维数组(它还是个数组),MATALB 具有两种运算:数组运算和矩阵运算。所以 MATLAB 并不区分数组类型或者矩阵类型,它只区分数组操作或者矩阵操作。

在 Python(NumPy)中,你可以用 np.matrix 创建矩阵,np.array 创建数组,但是官方推荐用 np.array,原因是:

Use arrays.

  • They are the standard vector/matrix/tensor type of numpy. Many numpy functions return arrays, not matrices.
  • There is a clear distinction between element-wise operations and linear algebra operations.
  • You can have standard vectors or row/column vectors if you like.

Until Python 3.5 the only disadvantage of using the array type was that you had to use dot instead of * to multiply (reduce) two tensors (scalar product, matrix vector multiplication etc.). Since Python 3.5 you can use the matrix multiplication @ operator.
Given the above, we intend to deprecate matrix eventually.

由于 NumPy 的便利性,我们通常用 np.array 也能够完成线性代数相关的任务,进一步导致 np.matrix 存在感很弱。

但在 Eigen 中 matrix 与 array 是有明确区别的,总的来说,Eigen 中的 matrix 与线性代数息息相关,它设计的初衷就是为了解决线性代数问题,例如解线性方程组、求矩阵特征值、矩阵的秩、QR分解等等。而 array 则负责系数运算,例如所有系数加上一个常数或者两个 array 系数相乘。

因此,如果你需要线性代数的操作时,请使用 matrix;如果你需要系数操作时,请使用 array。但有时候事情不会那么简单,你可能需要同时使用 matrix 和 array,这种情况下,你需要对 matrix 和 array 进行相互转换。
一个 matrix 通过 .array() 来得到一个 array 表达式;相似的,一个 array 通过 .matrix() 来得到一个 matrix 表达式。.array().matrix() 不会有任何运行时开销,它们是在编译期完成的。

Matrix 和 Array 之间可以相互转换:

Array44f a1, a1;
Matrix4f m1, m2;
m1 = a1 * a2;               // 系数相乘,隐式地从 Array 转到 Matrix
a1 = m1 * m2;               // 矩阵相乘,隐式地从 Matrix 转到 Array
a2 = a1 + m1.array();        // Array 和 Matrix 混合使用是不被允许的,需要显式地转换
m2 = a1.matrix() + m1;       
ArrayWrapper<Matrix4f> m1a(m1); // m1a 是 m1 的别名,它们共享同样的数据
MatrixWrapper<Array44f> a1m(a1);// a1m 是 a1 的别名,它们共享同样的数据

Initialization

int rows = 5;
int cols = 3;
int size = 3;
// fixed-size array
{
    Array33f  a1 = Array33f::Zero();                    // np.zeros((3,3))
    Array33f  a2 = Array33f::Random();                  // np.random.rand(3,3)
    Array33f  a3 = Array33f::Ones();                    // np.ones((3,3))
    Array3f   a4 = Array3f::LinSpaced(3, 0, 2);         // np.linspace(0,2,3)
    Array33f  a5 = Array33f::Constant(1.0);             // np.full((3,3), 1.0)
}

// one-dimensional dynamic-size
{
    ArrayXf a1 = ArrayXf::Zero(cols);                   // np.zeros(cols)
    ArrayXf a2 = ArrayXf::Random(cols);                 // np.random.rand(cols)
    ArrayXf a3 = ArrayXf::Ones(cols);                   // np.ones(cols)
    ArrayXf a4 = ArrayXf::LinSpaced(size, 0, 2);        // np.linspace(0,2,size)
    ArrayXf a5 = ArrayXf::Constant(cols, 1.0);          // np.full(cols, 1.0)
}

// two-dimensional dynamic-size
{
    ArrayXXf a1  = ArrayXXf::Zero(rows,cols);           // np.zeros((rows, cols)))
    ArrayXXf a2  = ArrayXXf::Random(rows,cols);         // np.random.rand(rows, cols)
    ArrayXXf a3  = ArrayXXf::Ones(rows, cols);          // np.ones((rows, cols))
    ArrayXXf a4  = ArrayXXf::Constant(rows, cols, 1.0); // np.full((rows, cols), 1.0)
    
    MatrixXf m1  = MatrixXf::Identity(rows, cols);      // np.eye(rows, cols)
    MatrixXf m2  = Vector3f{1,2,3}.asDiagonal();        // np.diag((1,2,3))
}

Repeating

ArrayXXf a(2,2);
a << 1,2,
     3,4;

a.replicate(2, 1); // np.tile(a, (2,1)), repeat array by row
a.replicate(1, 2); // np.tile(a, (1,2)), repeat array by column
a.replicate(2, 3); // np.tile(a, (2,3))

Miss those elements out

ArrayXf a = ArrayXf::Random(10);
                                   // NumPy
a.head(2);                         // a[:2], the first two element
a.tail(a.size() - 1);              // a[1:], miss the first element
a.segment(1, 2);                   // a[1:3], middle element
a.tail(1);                         // a[-1], last element
a.tail(2);                         // a[-2:], last two element

ArrayXXf A = ArrayXXf::Random(10,10);
A.leftCols(2);                     // a[:, :2], the first two columns
A.topRows(2);                      // a[:2, :], the first two rows

A.bottomRows(A.rows() - 1);        // a[1:, :], miss the first row
A.rightCols(A.cols() - 1);         // a[:, 1:], miss the first column

A.middleCols(1, 2);                // a[:, 1:3], middle columns
A.middleRows(1, 2);                // a[1:3, :], middle rows

A.rightCols(1);                    // a[:, -1], last column
A.bottomRows(1);                   // a[-1, :], last row

A.rightCols(2);                    // a[:, -2:], last two column
A.bottomRows(2);                   // a[-2:, :], last two row

Slicing

ArrayXf a = ArrayXf::LinSpaced(20, 0, 19);
Map<ArrayXf, 0, InnerStride<2>> v1(a.data(), a.size()/2);        // a[::2]
Map<ArrayXf, 0, InnerStride<2>> v2(a.middleRows(1, 6).data(), 3);// a[1:7:2]

ArrayXXf A = ArrayXXf::Random(8,10);// Column-major storage
Map<ArrayXXf, 0, OuterStride<>> A1(A.data(), A.rows(), (A.cols() + 1)/2, OuterStride<>(A.outerStride()*2));               // A[:,::2]

typedef Array<float, Dynamic, Dynamic, RowMajor> RowMajorArrayXXf;
RowMajorArrayXXf A2(A);
Map<RowMajorArrayXXf, 0, OuterStride<>> A3(A2.data(), (A2.rows() + 1)/2, A2.cols(), OuterStride<>(A2.outerStride()*2));   // A[::2, :]

Indexing and accessing elements

更多关于索引和元素访问的细节请参看 block operations

ArrayXXf a = ArrayXXf::Random(3,4);
                               // NumPy
a(1,2);                        // a[1,2], element 1,2
a.row(0);                      // a[0,],  first row
a.col(0);                      // a[:,0], first column
a.middleRows(1, 2);            // a[1:3,], middle row

a.middleRows(1, a.rows()-1);   // a[1:,], all, except first row
a.bottomRows(a.rows()-1);

a.bottomRows(2);               // a[-2:,], last tow rows

Maximum and minimum

ArrayXXf a = ArrayXXf::Random(3,3);
ArrayXXf b = ArrayXXf::Random(3,3);

a.maxCoeff();             // np.max(a), max in array
a.colwise().maxCoeff();   // np.amax(a, axis=0), max in each column
a.rowwise().maxCoeff();   // np.amax(a, axis=1), max in each row

a.max(b);                 // np.maximum(a,b), pairwise max

Assignment

ArrayXXf a = ArrayXXf::Random(3,3);
                                 // NumPy
a.col(0) = 99;                   // a[:,0] = 99;
a.col(0) = Array3f{99,98,97};    // a[:,0] = np.array([99, 98, 97])
(a > 90).select(a, 90);          // (a>90).choose(a, 90)

Concatenation

// Concatenation(vectors)
Array3f a{1,1,1};
Array3f b{2,2,2};

ArrayXf c( a.size() + b.size() );   
c << a, b;                              // np.concatenate((a,b))

// Concatenation(matrix)
int rows = 3;
int cols = 3;
ArrayXXf A = ArrayXXf::Constant(rows, cols, 1.0f);
ArrayXXf B = ArrayXXf::Constant(rows, cols, 2.0f);

ArrayXXf BindRows(A.rows() + B.rows(), cols);
BindRows << A,B;                        // np.concatenate((A,B), axis=0)  
                                        // or np.vstack((a,b))


ArrayXXf BindCols(rows, A.cols() + B.cols());
BindCols << A,B;                        // np.concatenate((A,B), axis=1) 
                                        // or np.hstack((a,b))

ArrayXf C(A.size() + B.size());         // np.concatenate((a,b), axis=None)
C << Map<ArrayXf>(A.data(), A.size()),  // concatenate matrices into a 1d array
            Map<ArrayXf>(B.data(), B.size());

Reshape and flatten matrices

ArrayXXf a = ArrayXXf::Random(3,4);           // Column-major storage
                                              // NumPy
Map<ArrayXXf> b(a.data(), 2, 6);              // np.reshape(a, (2,6))
Map<ArrayXf> v(a.data(), a.size());           // a.flatten("F"),  flatten in column-major

Coefficient-wise math functions

下面列举一些常用的 coefficient-wise 数学运算函数,更多详细的内容请参看 Catalog of coefficient-wise math functions

Basic operatoins

Python Eigen Description
abs(a) a.abs(); Eigen::abs(a); m.cwiseAbs() absolute value (ai\vert a_i\vert)
reciprocal(a) a.inverse(); Eigen::inverse(a); m.cwiseInverse() inverse vaule(1/ai1/a_i)
a.conj() a.conjugate(); Eigen::conj(a); m.conjugate(); complex conjugate(aiˉ\bar{a_i})

Exponential and logarithm

Python Eigen Description
math.log(a) a.log(); log(a) logarithm, base ee(natural)
math.log10(a) a.log10(); log10(a) logarithm, base 10
math.exp(a) a.exp(); exp(a) exponential function
math.log1p(a) a.log1p(); log1p(a) natural (base ee) logarithm of 1 plus the given number ( ln(1+ai)\ln({1+a_i}))

Round off

Python Eigen Description
around(a) or math.round(a) a.round() Round
ceil(a) a.ceil() Round up
floor(a) a.floor() Round down

Power functions

Python Eigen Description
power(a,b) a.pow(b) power, aibia_i ^ {b_i}
math.sqrt(a) a.sqrt(); Eigen::sqrt(a); m.cwiseSqrt() square root ((ai)\sqrt(a_i))
square(a) a.square(); Eigen::square(a) square power(ai2a_i^2)
power(a,3) a.cube(); Eigen::cube(a) cubic power(ai3a_i^3)
abs(a).square() a.abs2(); Eigen::abs2(a);m.cwiseAbs2() squared absolute value(ai2\vert a_i \vert^2)

Trigonometric functions

Python Eigen Description
sin(a) a.sin(); Eigen::sin(a) computes sine
cos(a) a.cos(); Eigen::cos(a) computes cosine
tan(a) a.tan(); Eigen::tan(a) computes tangent
arcsin(a) a.asin(); Eigen::asin(a) computes arc sine(sin1ai\sin^{-1} a_i)
arccos(a) a.acos(); Eigen::acos(a) computes arc cosine(cos1ai\cos^{-1} a_i)
arctan(a) a.atan(); Eigen::atan(a) computes arc tangent(tan1ai\tan^{-1} a_i)

Eigen exercise

/*
 * Eigen exercise
 *
 * This is quick reference of Eigen.
 *
 * We use Eigen to implement 100 Numpy(some of them) (https://github.com/rougier/numpy-100)
 *
 * It is highly recommended to read Eigen document before starting if you never read it
 *
 */

#include <Eigen/Core>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <map>
#include <unsupported/Eigen/CXX11/Tensor>
#include <complex>
#include <cmath>
using namespace std;
using namespace Eigen;

void exercise_2()
{
    // 2. Print the eigen version
    cout << "Eigen version " << EIGEN_MAJOR_VERSION << "."
         << EIGEN_MINOR_VERSION << endl;
}

void exercise_3()
{
    // 3 Create a null vector of size 10 (★☆☆)
    VectorXf Z = VectorXf::Zero(10);
    cout << Z << endl;
}

void exercise_4()
{
    // 4. How to find the memory size of any array (★☆☆)
    MatrixXf Z = MatrixXf::Zero(10, 10);
    cout << Z.size() * sizeof(MatrixXf::Scalar) << endl;
}

void exercise_6()
{
    // 6. Create a null vector of size 10 but the fifth value which is 1 (★☆☆)
    VectorXf Z = VectorXf::Zero(10);
    Z(4) = 1;

    cout << Z << endl;
}

void exercise_7()
{
    // 7. Create a vector with values ranging from 10 to 49 (★☆☆)
    const int start = 10;
    const int end = 49;
    const int size = end - start + 1;

    VectorXf Z = VectorXf::LinSpaced(size, start, end);

    cout << Z << endl;
}

void exercise_8()
{
    // 8. Reverse a vector (first element becomes last) (★☆☆)
    VectorXf Z = VectorXf::LinSpaced(10, 1, 10);
    Z = Z.reverse().eval();
    cout << Z << endl;

    // Z = Z.reverse() is aliasing
    // you can use .eval() or inplace to solve this:
    //           Z = Z.reverse().eval()
    //           Z.reverseInPlace()
}

void exercise_9()
{
    //9. Create a 3x3 matrix with values ranging from 0 to 8 (★☆☆)

    // Eigen does not expose convenient methods to take slices or to reshape a matrix yet.
    // Nonetheless, such features can easily be emulated using the Map class.
    VectorXf Z1 = VectorXf::LinSpaced(9, 1, 9);
    Map<MatrixXf> Z2(Z1.data(), 3, 3);
    cout << Z2 << endl;
}

void exercise_10()
{
    // 10. Find indices of non-zero elements from [1,2,0,0,4,0] (★☆☆)
    VectorXf Z(6);
    Z << 1,2,0,0,4,0;

    std::vector<Index> nz;
    for(Index i = 0; i < Z.size(); ++i)
    {
        if(Z(i))
        {
            nz.push_back(i);
        }
    }

    Map<Matrix<Index , 1, Dynamic>> nzz(nz.data(), nz.size());

    cout << nzz;
}

void exercise_11()
{
    // 11. Create a 3x3 identity matrix (★☆☆)
    MatrixXf Z = MatrixXf::Identity(3,3);

    cout << Z << endl;
}

void exercise_12()
{
    // 12. Create a 3x3x3 array with random values (★☆☆)

    // NOTE: Tensor is unsupported module in 3.3.7
    Tensor<float,3> T(3,3,3);
    T.setRandom();

    cout << T << endl;

    // 12.1 Create a 3x3 array with random values (★☆☆)
    MatrixXf Z = MatrixXf::Random(3,3);
    cout << Z << endl;
}

void exercise_13()
{
    // 13. Create a 10x10 array with random values and find the minimum and maximum values (★☆☆)
    MatrixXf Z = MatrixXf::Random(10, 10);

    cout << Z.maxCoeff() << "," << Z.minCoeff() << endl;
}

void exercise_14()
{
    // 14. Create a random vector of size 30 and find the mean value (★☆☆)

    VectorXf Z = VectorXf::Random(30);

    cout << Z.mean() << endl;
}

void exercise_15()
{
    // 15. Create a 2d array with 1 on the border and 0 inside (★☆☆)
    MatrixXf Z = MatrixXf::Zero(5, 5);
    VectorXf padding = VectorXf::Constant(5, -1);

    Z.topRows<1>() = padding;
    Z.bottomRows<1>() = padding;
    Z.leftCols<1>() = padding;
    Z.rightCols<1>() = padding;

    cout << Z << endl;
}

void exercise_16()
{
    // 16. How to add a border (filled with 0's) around an existing array? (★☆☆)
    MatrixXf Z = MatrixXf::Ones(5, 5);

    Z.conservativeResize(6,6);
    VectorXf padding = VectorXf::Zero(6);

    Z.topRows<1>() = padding;
    Z.bottomRows<1>() = padding;
    Z.leftCols<1>() = padding;
    Z.rightCols<1>() = padding;

    cout << Z << endl;
}

void exercise_18()
{
    // 18. Create a 5x5 matrix with values 1,2,3,4 just below the diagonal (★☆☆)

    // Is difficult to implement in Eigen, but create a diagonal is easy
    VectorXf V(4);
    V << 1, 2, 3, 4;

    MatrixXf Z = V.asDiagonal();

    cout << Z << endl;
}

void exercise_21()
{
    // 21. Create a checkerboard 8x8 matrix using the tile function (★☆☆)
    MatrixXf Z(2,2);
    Z << 0,1,
        1,0;

    cout <<  Z.replicate(4, 4) << endl;
}

void exercise_22()
{
    // 22. Normalize a 5x5 random matrix (★☆☆)
    MatrixXf Z = MatrixXf::Random(5,5);
    float mean = Z.mean();
    float std = std::sqrt( (Z.array() - mean).square().sum() / (Z.size() - 1) );
    Z = (Z.array() - mean) / (std);

    cout << Z << endl;
}


void exercise_24()
{
    // 24. Multiply a 5x3 matrix by a 3x2 matrix (real matrix product) (★☆☆)
    MatrixXf A = MatrixXf::Ones(5,3);
    MatrixXf B = MatrixXf::Ones(3,2);

    MatrixXf Z = A * B;

    cout << Z << endl;
}
void exercise_25()
{
    // 25. Given a 1D array, negate all elements which are between 3 and 8, in place. (★☆☆)

    VectorXf Z = VectorXf::LinSpaced(11, 0, 10);
    Matrix<float, Dynamic, 1> B = (3 < Z.array() && Z.array() <= 8).cast<float>() * -1.0;
    Matrix<float, Dynamic, 1> C = B.array() + 1.0;

    cout << Z.array() * B.array() + Z.array() * C.array() << endl;
}

void exercise_30()
{
    // 30. How to find common values between two arrays? (★☆☆)
    std::mt19937 gen(0);
    std::uniform_int_distribution<int> dis(0, 10);

    // generate random int numbers in range [0, 10]
    auto func = [&](int x){return dis(gen);};
    VectorXi A = VectorXd::Zero(10).unaryExpr(func);
    VectorXi B = VectorXd::Zero(10).unaryExpr(func);

    std::set<int> commom_values_set;
    auto find_common_values = [&](int x){
      if( (B.array() == x).any() )
      {
          commom_values_set.insert(x);
      }
      return x;
    };

    A = A.unaryExpr(find_common_values);

    for(const auto& v : commom_values_set)
    {
        cout << v << " ";
    }
}

void exercise_39()
{
    // 39. Create a vector of size 10 with values ranging from 0 to 1, both excluded (★★☆)¶
    VectorXf Z = VectorXf::LinSpaced(12, 0, 1);
    Z = Z.segment(1, 10);
    cout << Z << endl;
}

void exercise_40()
{
    // 40. Create a random vector of size 10 and sort it (★★☆)
    VectorXf Z = VectorXf::Random(10);

    sort(Z.data(), Z.data()+Z.size(), [](float x, float y){return x < y;});

    cout << Z << endl;
}

void exercise_40_1()
{
    // 40_1. Create a random matrix of size 10x10 and sort it row by row (★★☆)
    MatrixXf Z = MatrixXf::Random(10, 10);

    auto sort_func = [](float x, float y){return x<y;};

    std::vector<MatrixXf::Scalar> data(Z.cols());
    for(int i = 0; i < Z.rows(); ++i)
    {
        // copy row to data array
        for(int j = 0; j < Z.cols(); ++j)
        {
            data[j] = Z(i, j);
        }

        // sort data array
        sort(data.begin(), data.end(), sort_func);

        // copy back to row
        for(int j = 0; j < Z.cols(); ++j)
        {
            Z(i, j) = data[j];
        }
    }

    cout << Z << endl;
}

void exercise_40_2()
{
    // 40_2. Create a random matrix of size 10x10 and sort it col by col (★★☆)
    MatrixXf Z = MatrixXf::Random(10, 10);

    auto sort_func = [](float x, float y){return x<y;};

    std::vector<MatrixXf::Scalar> data(Z.rows());
    for(int i = 0; i < Z.cols(); ++i)
    {
        // copy row to data array
        for(int j = 0; j < Z.rows(); ++j)
        {
            data[j] = Z(j, i);
        }

        // sort data array
        sort(data.begin(), data.end(), sort_func);

        // copy back to row
        for(int j = 0; j < Z.rows(); ++j)
        {
            Z(j, i) = data[j];
        }
    }

    cout << Z << endl;

}


void exercise_42()
{
    // 42. Consider two random array A and B, check if they are equal (★★☆)
    MatrixXf A = MatrixXf::Random(5,5);
    MatrixXf B = MatrixXf::Random(5,5);

    bool equal = (A.array() == B.array()).all();

    cout << equal << endl;
}

void exercise_44()
{
    // 44. Consider a random 10x2 matrix representing cartesian coordinates, convert them to polar coordinates (★★☆)
    MatrixXf Z = MatrixXf::Random(10, 2);
    VectorXf X = Z.col(0);
    VectorXf Y = Z.col(1);

    VectorXf R = (X.array().square() + Y.array().square()).sqrt();
    VectorXf T = (Y.array()/X.array()).atan();

    cout << "R:\n" << R << endl;
    cout << "T:\n" << T << endl;
}

void exercise_45()
{
    // 45. Create random vector of size 10 and replace the maximum value by 0 (★★☆)
    VectorXf Z = VectorXf::Random(10);
    VectorXf::Index max_index;

    Z.maxCoeff(&max_index);

    Z(max_index) = 0.0;

    cout << Z << endl;
}

void exercise_47()
{
    // 47. Given two arrays, X and Y, construct the Cauchy matrix C (Cij =1/(xi - yj))
    VectorXf X = VectorXf::LinSpaced(8, 0, 7);
    VectorXf Y = X.array() + 0.5;

    MatrixXf C(X.size(), Y.size());

    for(int i = 0; i < C.cols(); ++i)
    {
        C.col(i) = 1.0/(X.array() - Y(i));
    }

    cout << C << endl;
}

void exercise_50()
{
    // 50. How to find the closest value (to a given scalar) in a vector? (★★☆)
    VectorXf Z = VectorXf::LinSpaced(100, 0, 99);
    float v = 10;
    VectorXf::Index index;

    (Z.array() - v).abs().minCoeff(&index);

    cout << index << endl;
}

void exercise_52()
{
    //    52. Consider a random vector with shape (10,2) representing coordinates, find point by point distances (★★☆)
    MatrixXf Z = MatrixXf::Random(10, 2);
    Matrix<float, Dynamic, 1> X = Z.col(0);
    Matrix<float, Dynamic, 1> Y = Z.col(1);

    MatrixXf XX = X.rowwise().replicate(10);
    MatrixXf YY = Y.rowwise().replicate(10);

    MatrixXf D = (XX - XX.transpose()).array().square() + (YY - YY.transpose()).array().square();

    cout << D.cwiseSqrt() << endl; // D.cwiseSqrt() = D.array().sqrt()
}

void exercise_56()
{
    // 56. Generate a generic 2D Gaussian-like array (★★☆)
//    Matrix<float,Dynamic,1> X =
    VectorXf V = VectorXf::LinSpaced(10, -1, 1);

    MatrixXf Y = V.rowwise().replicate(10);
    MatrixXf X = Y.transpose();

    MatrixXf G = (X.array().square() + Y.array().square()).cwiseSqrt();

    float sigma = 1.0;
    float mu = 0.0;

    MatrixXf result = ( -(G.array() - mu).square() / (2.0 * sigma*sigma) ).exp();

    cout << result << endl;
}

void exercise_58()
{
    // 58. Subtract the mean of each row of a matrix (★★☆)¶
    MatrixXf Z = MatrixXf::Random(5, 10);
    VectorXf mean = Z.rowwise().mean();

    cout << Z.colwise() - mean << endl;
}

void exercise_59()
{
    // 59. How to sort an array by the nth column? (★★☆)
    MatrixXf Z = MatrixXf::Random(3,3);
    cout << Z << endl << endl;

    int n = 1; // first column
    auto compare_nth = [&n](const VectorXf& lhs, const VectorXf& rhs){
      return lhs(n) < rhs(n);
    };

    std::vector<VectorXf> vec;
    for(int i = 0; i < Z.rows(); ++i)
    {
        vec.emplace_back(Z.row(i));
    }

    std::sort(vec.begin(), vec.end(), compare_nth);

    for(int i = 0; i < Z.rows(); ++i)
    {
        Z.row(i) = vec[i];
    }

    cout << Z << endl;
}

void exercise_60()
{
    // 60. How to tell if a given 2D array has null columns? (★★☆)
    MatrixXf Z = MatrixXf::Random(5,5);
    Z(0,0) = sqrt(-1); // genenrate a nan

    cout << Eigen::isnan(Z.array()).any() << endl;
    cout << Eigen::isnan(Z.array()).select(0, Z) << endl;
}

void exercise_61()
{
    // 61. Find the nearest value from a given value in an array (★★☆)
    VectorXf Z = VectorXf::Random(10);
    float z = 0.5;

    VectorXf::Index min_index;
    (Z.array() - z).abs().minCoeff(&min_index);

    cout << Z(min_index) << endl;
}

void exercise_64()
{
    // 64. Consider a given vector, how to add 1 to each element indexed by a second vector (be careful with repeated indices)? (★★★)
    VectorXf Z = VectorXf::Ones(10);
    VectorXi I(20);
    I << 7, 4, 2, 6, 4, 8, 6, 3, 0, 8, 1, 0, 5, 1, 9, 7, 5, 1, 8, 7;

    std::map<int, int> bins;
    for(int i = 0; i < I.size(); ++i)
    {
        const int key = I(i);
        if(bins.find(key) != bins.end())
        {
            ++bins[key];
        } else
        {
            bins[key] = 1;
        }
    }

    for(int i = 0; i < Z.size(); ++i)
    {
        Z(i) += bins[i];
    }

    cout << Z << endl;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!