| 80 | }; |
| 81 | |
| 82 | TEST_SUBMODULE(eigen_matrix, m) { |
| 83 | using FixedMatrixR = Eigen::Matrix<float, 5, 6, Eigen::RowMajor>; |
| 84 | using FixedMatrixC = Eigen::Matrix<float, 5, 6>; |
| 85 | using DenseMatrixR = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>; |
| 86 | using DenseMatrixC = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>; |
| 87 | using FourRowMatrixC = Eigen::Matrix<float, 4, Eigen::Dynamic>; |
| 88 | using FourColMatrixC = Eigen::Matrix<float, Eigen::Dynamic, 4>; |
| 89 | using FourRowMatrixR = Eigen::Matrix<float, 4, Eigen::Dynamic>; |
| 90 | using FourColMatrixR = Eigen::Matrix<float, Eigen::Dynamic, 4>; |
| 91 | using SparseMatrixR = Eigen::SparseMatrix<float, Eigen::RowMajor>; |
| 92 | using SparseMatrixC = Eigen::SparseMatrix<float>; |
| 93 | |
| 94 | // various tests |
| 95 | m.def("double_col", [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2.0f * x; }); |
| 96 | m.def("double_row", |
| 97 | [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2.0f * x; }); |
| 98 | m.def("double_complex", |
| 99 | [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); |
| 100 | m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; }); |
| 101 | m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; }); |
| 102 | m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; }); |
| 103 | m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; }); |
| 104 | |
| 105 | // test_eigen_ref_to_python |
| 106 | // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended |
| 107 | m.def("cholesky1", |
| 108 | [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); |
| 109 | m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { |
| 110 | return x.llt().matrixL(); |
| 111 | }); |
| 112 | m.def("cholesky3", |
| 113 | [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); |
| 114 | m.def("cholesky4", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { |
| 115 | return x.llt().matrixL(); |
| 116 | }); |
| 117 | |
| 118 | // test_eigen_ref_mutators |
| 119 | // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping |
| 120 | // into the numpy array data and so the result should show up there. There are three versions: |
| 121 | // one that works on a contiguous-row matrix (numpy's default), one for a contiguous-column |
| 122 | // matrix, and one for any matrix. |
| 123 | auto add_rm = [](Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x(r, c) += v; }; |
| 124 | auto add_cm = [](Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; }; |
| 125 | |
| 126 | // Mutators (Eigen maps into numpy variables): |
| 127 | m.def("add_rm", add_rm); // Only takes row-contiguous |
| 128 | m.def("add_cm", add_cm); // Only takes column-contiguous |
| 129 | // Overloaded versions that will accept either row or column contiguous: |
| 130 | m.def("add1", add_rm); |
| 131 | m.def("add1", add_cm); |
| 132 | m.def("add2", add_cm); |
| 133 | m.def("add2", add_rm); |
| 134 | // This one accepts a matrix of any stride: |
| 135 | m.def("add_any", |
| 136 | [](py::EigenDRef<Eigen::MatrixXd> x, int r, int c, double v) { x(r, c) += v; }); |
| 137 | |
| 138 | // Return mutable references (numpy maps into eigen variables) |
| 139 | m.def("get_cm_ref", []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm()); }); |