8
8
*/
9
9
10
10
#include " pybind11_tests.h"
11
+ #include " constructor_stats.h"
11
12
#include < pybind11/eigen.h>
12
13
#include < Eigen/Cholesky>
13
14
14
- Eigen::VectorXf double_col (const Eigen::VectorXf& x)
15
- { return 2 .0f * x; }
15
+ using MatrixXdR = Eigen::Matrix<double , Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
16
16
17
- Eigen::RowVectorXf double_row (const Eigen::RowVectorXf& x)
18
- { return 2 .0f * x; }
17
+ // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
18
+ Eigen::MatrixXd cholesky1 (Eigen::Ref<MatrixXdR> x) { return x.llt ().matrixL (); }
19
+ Eigen::MatrixXd cholesky2 (const Eigen::Ref<const MatrixXdR> &x) { return x.llt ().matrixL (); }
20
+ Eigen::MatrixXd cholesky3 (const Eigen::Ref<MatrixXdR> &x) { return x.llt ().matrixL (); }
21
+ Eigen::MatrixXd cholesky4 (Eigen::Ref<const MatrixXdR> x) { return x.llt ().matrixL (); }
19
22
20
- Eigen::MatrixXf double_mat_cm (const Eigen::MatrixXf& x)
21
- { return 2 .0f * x; }
23
+ // Mutators: these add some value to the given element using Eigen, but Eigen should be mapping into
24
+ // the numpy array data and so the result should show up there. There are three versions: one that
25
+ // works on a contiguous-row matrix (numpy's default), one for a contiguous-column matrix, and one
26
+ // for any matrix.
27
+ void add_rm (Eigen::Ref<MatrixXdR> x, int r, int c, double v) { x (r,c) += v; }
28
+ void add_cm (Eigen::Ref<Eigen::MatrixXd> x, int r, int c, double v) { x (r,c) += v; }
29
+ void add_any (Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> x, int r, int c, double v) { x (r,c) += v; }
22
30
23
- // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
24
- Eigen::MatrixXd cholesky1 (Eigen::Ref<Eigen::MatrixXd> &x) { return x.llt ().matrixL (); }
25
- Eigen::MatrixXd cholesky2 (const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.llt ().matrixL (); }
26
- Eigen::MatrixXd cholesky3 (const Eigen::Ref<Eigen::MatrixXd> &x) { return x.llt ().matrixL (); }
27
- Eigen::MatrixXd cholesky4 (Eigen::Ref<const Eigen::MatrixXd> &x) { return x.llt ().matrixL (); }
28
- Eigen::MatrixXd cholesky5 (Eigen::Ref<Eigen::MatrixXd> x) { return x.llt ().matrixL (); }
29
- Eigen::MatrixXd cholesky6 (Eigen::Ref<const Eigen::MatrixXd> x) { return x.llt ().matrixL (); }
31
+ template <typename M> void reset_ref (M &x) {
32
+ for (int i = 0 ; i < x.rows (); i++) for (int j = 0 ; j < x.cols (); j++)
33
+ x (i, j) = 11 + 10 *i + j;
34
+ }
35
+
36
+ Eigen::MatrixXd &get_cm () {
37
+ static Eigen::MatrixXd *x;
38
+ if (!x) {
39
+ x = new Eigen::MatrixXd (3 , 3 );
40
+ reset_ref (*x);
41
+ }
42
+ return *x;
43
+ }
44
+ MatrixXdR &get_rm () {
45
+ static MatrixXdR *x;
46
+ if (!x) {
47
+ x = new MatrixXdR (3 , 3 );
48
+ reset_ref (*x);
49
+ }
50
+ return *x;
51
+ }
52
+
53
+ // Returns a slice of get_cm matrix:
54
+ py::EigenDMap<Eigen::Matrix2d> get_cm_corners () {
55
+ auto &x = get_cm ();
56
+ return py::EigenDMap<Eigen::Matrix2d>(
57
+ x.data (),
58
+ py::EigenDStride (x.outerStride () * (x.rows () - 1 ), x.innerStride () * (x.cols () - 1 )));
59
+ }
60
+
61
+ py::EigenDMap<const Eigen::Matrix2d> get_cm_corners_const () {
62
+ const auto &x = get_cm ();
63
+ return py::EigenDMap<const Eigen::Matrix2d>(
64
+ x.data (),
65
+ py::EigenDStride (x.outerStride () * (x.rows () - 1 ), x.innerStride () * (x.cols () - 1 )));
66
+ }
30
67
31
- typedef Eigen::Matrix<float , Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> MatrixXfRowMajor;
32
- MatrixXfRowMajor double_mat_rm (const MatrixXfRowMajor& x)
33
- { return 2 .0f * x; }
68
+ void reset_refs () {
69
+ reset_ref (get_cm ());
70
+ reset_ref (get_rm ());
71
+ }
72
+
73
+ // These return a Eigen::Ref<> that numpy is allowed to mutate to change Eigen's values
74
+ Eigen::Ref<Eigen::MatrixXd> get_cm_ref () { return get_cm (); }
75
+ Eigen::Ref<MatrixXdR> get_rm_ref () { return get_rm (); }
76
+ // These return a Eigen::Ref<const> that should become read-only on the numpy side
77
+ Eigen::Ref<const Eigen::MatrixXd> get_cm_const_ref () { return get_cm (); }
78
+ Eigen::Ref<const MatrixXdR> get_rm_const_ref () { return get_rm (); }
79
+
80
+ // Increments all elements in a matrix by some value then returns the same reference
81
+ Eigen::Ref<Eigen::MatrixXd> incr_matrix (Eigen::Ref<Eigen::MatrixXd> m, double v) {
82
+ m += Eigen::MatrixXd::Constant (m.rows (), m.cols (), v);
83
+ return m;
84
+ }
85
+ // Same, but takes any strides
86
+ Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> incr_matrix_any (Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> m, double v) {
87
+ m += Eigen::MatrixXd::Constant (m.rows (), m.cols (), v);
88
+ return m;
89
+ }
90
+
91
+ // Returns an eigen slice of even rows
92
+ Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> even_rows (Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> m) {
93
+ return Eigen::Map<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>>(m.data (), (m.rows () + 1 ) / 2 , m.cols (),
94
+ Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>(m.outerStride (), 2 * m.innerStride ()));
95
+ }
96
+ // Returns an eigen slice of even columns
97
+ Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> even_cols (Eigen::Ref<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>> m) {
98
+ return Eigen::Map<Eigen::MatrixXd, 0 , Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>>(m.data (), m.rows (), (m.cols () + 1 ) / 2 ,
99
+ Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>(2 * m.outerStride (), m.innerStride ()));
100
+ }
34
101
35
102
test_initializer eigen ([](py::module &m) {
36
103
typedef Eigen::Matrix<float , 5 , 6 , Eigen::RowMajor> FixedMatrixR;
@@ -51,16 +118,46 @@ test_initializer eigen([](py::module &m) {
51
118
mat << 0 , 3 , 0 , 0 , 0 , 11 , 22 , 0 , 0 , 0 , 17 , 11 , 7 , 5 , 0 , 1 , 0 , 11 , 0 ,
52
119
0 , 0 , 0 , 0 , 11 , 0 , 0 , 14 , 0 , 8 , 11 ;
53
120
54
- m.def (" double_col" , &double_col);
55
- m.def (" double_row" , &double_row);
56
- m.def (" double_mat_cm" , &double_mat_cm);
57
- m.def (" double_mat_rm" , &double_mat_rm);
121
+ m.def (" double_col" , [](const Eigen::VectorXf &x) -> Eigen::VectorXf { return 2 .0f * x; });
122
+ m.def (" double_row" , [](const Eigen::RowVectorXf &x) -> Eigen::RowVectorXf { return 2 .0f * x; });
123
+ m.def (" double_threec" , [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2 ; });
124
+ m.def (" double_threer" , [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2 ; });
125
+ m.def (" double_mat_cm" , [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2 .0f * x; });
126
+ m.def (" double_mat_rm" , [](DenseMatrixR x) -> DenseMatrixR { return 2 .0f * x; });
58
127
m.def (" cholesky1" , &cholesky1);
59
128
m.def (" cholesky2" , &cholesky2);
60
129
m.def (" cholesky3" , &cholesky3);
61
130
m.def (" cholesky4" , &cholesky4);
62
- m.def (" cholesky5" , &cholesky5);
63
- m.def (" cholesky6" , &cholesky6);
131
+
132
+ // Mutators (Eigen maps into numpy variables):
133
+ m.def (" add_rm" , add_rm); // Only takes row-contiguous
134
+ m.def (" add_cm" , add_cm); // Only takes column-contiguous
135
+ m.def (" add_any" , add_any); // Accepts anything
136
+ // Overloaded versions that will accept either row or column contiguous:
137
+ m.def (" add1" , add_rm);
138
+ m.def (" add1" , add_cm);
139
+ m.def (" add2" , add_cm);
140
+ m.def (" add2" , add_rm);
141
+
142
+ // Return mutable references (numpy maps into eigen varibles)
143
+ m.def (" get_cm_ref" , []() { return Eigen::Ref<Eigen::MatrixXd>(get_cm ()); });
144
+ m.def (" get_rm_ref" , []() { return Eigen::Ref<MatrixXdR>(get_rm ()); });
145
+ // The same references, but non-mutable (numpy maps into eigen variables, but is !writeable)
146
+ m.def (" get_cm_const_ref" , []() { return Eigen::Ref<const Eigen::MatrixXd>(get_cm ()); });
147
+ m.def (" get_rm_const_ref" , []() { return Eigen::Ref<const MatrixXdR>(get_rm ()); });
148
+ // Just the corners (via a Map instead of a Ref):
149
+ m.def (" get_cm_corners" , get_cm_corners);
150
+ m.def (" get_cm_corners_const" , get_cm_corners_const);
151
+
152
+ m.def (" reset_refs" , reset_refs); // Restores get_{cm,rm}_ref to original values
153
+
154
+ // Increments and returns ref to matrix
155
+ m.def (" incr_matrix" , incr_matrix, py::return_value_policy::reference);
156
+ m.def (" incr_matrix_any" , incr_matrix_any, py::return_value_policy::reference);
157
+
158
+ // Even row/column slicing
159
+ m.def (" even_rows" , even_rows, py::return_value_policy::reference);
160
+ m.def (" even_cols" , even_cols, py::return_value_policy::reference);
64
161
65
162
// Returns diagonals: a vector-like object with an inner stride != 1
66
163
m.def (" diagonal" , [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal (); });
@@ -72,6 +169,52 @@ test_initializer eigen([](py::module &m) {
72
169
return x.block (start_row, start_col, block_rows, block_cols);
73
170
});
74
171
172
+ // return value referencing/copying tests:
173
+ class ReturnTester {
174
+ Eigen::MatrixXd mat = create();
175
+ public:
176
+ ReturnTester () { print_created (this ); }
177
+ ~ReturnTester () { print_destroyed (this ); }
178
+ static Eigen::MatrixXd create () { return Eigen::MatrixXd::Ones (10 , 10 ); }
179
+ static const Eigen::MatrixXd createConst () { return Eigen::MatrixXd::Ones (10 , 10 ); }
180
+ Eigen::MatrixXd &get () { return mat; }
181
+ Eigen::MatrixXd *getPtr () { return &mat; }
182
+ const Eigen::MatrixXd &view () { return mat; }
183
+ const Eigen::MatrixXd *viewPtr () { return &mat; }
184
+ Eigen::Ref<Eigen::MatrixXd> ref () { return mat; }
185
+ Eigen::Ref<const Eigen::MatrixXd> refConst () { return mat; }
186
+ Eigen::Block<Eigen::MatrixXd> block (int r, int c, int nrow, int ncol) { return mat.block (r, c, nrow, ncol); }
187
+ Eigen::Block<const Eigen::MatrixXd> blockConst (int r, int c, int nrow, int ncol) const { return mat.block (r, c, nrow, ncol); }
188
+ py::EigenDMap<Eigen::Matrix2d> corners () { return py::EigenDMap<Eigen::Matrix2d>(mat.data (),
189
+ py::EigenDStride (mat.outerStride () * (mat.outerSize ()-1 ), mat.innerStride () * (mat.innerSize ()-1 ))); }
190
+ py::EigenDMap<const Eigen::Matrix2d> cornersConst () const { return py::EigenDMap<const Eigen::Matrix2d>(mat.data (),
191
+ py::EigenDStride (mat.outerStride () * (mat.outerSize ()-1 ), mat.innerStride () * (mat.innerSize ()-1 ))); }
192
+ };
193
+ using rvp = py::return_value_policy;
194
+ py::class_<ReturnTester>(m, " ReturnTester" )
195
+ .def (py::init<>())
196
+ .def_static (" create" , &ReturnTester::create)
197
+ .def_static (" create_const" , &ReturnTester::createConst)
198
+ .def (" get" , &ReturnTester::get, rvp::reference_internal)
199
+ .def (" get_ptr" , &ReturnTester::getPtr, rvp::reference_internal)
200
+ .def (" view" , &ReturnTester::view, rvp::reference_internal)
201
+ .def (" view_ptr" , &ReturnTester::view, rvp::reference_internal)
202
+ .def (" copy_get" , &ReturnTester::get) // Default rvp: copy
203
+ .def (" copy_view" , &ReturnTester::view) // "
204
+ .def (" ref" , &ReturnTester::ref) // Default for Ref is to reference
205
+ .def (" ref_const" , &ReturnTester::refConst) // Likewise, but const
206
+ .def (" ref_safe" , &ReturnTester::ref, rvp::reference_internal)
207
+ .def (" ref_const_safe" , &ReturnTester::refConst, rvp::reference_internal)
208
+ .def (" copy_ref" , &ReturnTester::ref, rvp::copy)
209
+ .def (" copy_ref_const" , &ReturnTester::refConst, rvp::copy)
210
+ .def (" block" , &ReturnTester::block)
211
+ .def (" block_safe" , &ReturnTester::block, rvp::reference_internal)
212
+ .def (" block_const" , &ReturnTester::blockConst, rvp::reference_internal)
213
+ .def (" copy_block" , &ReturnTester::block, rvp::copy)
214
+ .def (" corners" , &ReturnTester::corners, rvp::reference_internal)
215
+ .def (" corners_const" , &ReturnTester::cornersConst, rvp::reference_internal)
216
+ ;
217
+
75
218
// Returns a DiagonalMatrix with diagonal (1,2,3,...)
76
219
m.def (" incr_diag" , [](int k) {
77
220
Eigen::DiagonalMatrix<int , Eigen::Dynamic> m (k);
@@ -92,18 +235,26 @@ test_initializer eigen([](py::module &m) {
92
235
return FixedMatrixR (mat);
93
236
});
94
237
238
+ m.def (" fixed_r_const" , [mat]() -> const FixedMatrixR {
239
+ return FixedMatrixR (mat);
240
+ });
241
+
95
242
m.def (" fixed_c" , [mat]() -> FixedMatrixC {
96
243
return FixedMatrixC (mat);
97
244
});
98
245
99
- m.def (" fixed_passthrough_r " , [](const FixedMatrixR &m) -> FixedMatrixR {
246
+ m.def (" fixed_copy_r " , [](const FixedMatrixR &m) -> FixedMatrixR {
100
247
return m;
101
248
});
102
249
103
- m.def (" fixed_passthrough_c " , [](const FixedMatrixC &m) -> FixedMatrixC {
250
+ m.def (" fixed_copy_c " , [](const FixedMatrixC &m) -> FixedMatrixC {
104
251
return m;
105
252
});
106
253
254
+ m.def (" fixed_mutator_r" , [](Eigen::Ref<FixedMatrixR>) {});
255
+ m.def (" fixed_mutator_c" , [](Eigen::Ref<FixedMatrixC>) {});
256
+ m.def (" fixed_mutator_a" , [](py::EigenDRef<FixedMatrixC>) {});
257
+
107
258
m.def (" dense_r" , [mat]() -> DenseMatrixR {
108
259
return DenseMatrixR (mat);
109
260
});
@@ -112,11 +263,11 @@ test_initializer eigen([](py::module &m) {
112
263
return DenseMatrixC (mat);
113
264
});
114
265
115
- m.def (" dense_passthrough_r " , [](const DenseMatrixR &m) -> DenseMatrixR {
266
+ m.def (" dense_copy_r " , [](const DenseMatrixR &m) -> DenseMatrixR {
116
267
return m;
117
268
});
118
269
119
- m.def (" dense_passthrough_c " , [](const DenseMatrixC &m) -> DenseMatrixC {
270
+ m.def (" dense_copy_c " , [](const DenseMatrixC &m) -> DenseMatrixC {
120
271
return m;
121
272
});
122
273
@@ -128,24 +279,24 @@ test_initializer eigen([](py::module &m) {
128
279
return Eigen::SparseView<Eigen::MatrixXf>(mat);
129
280
});
130
281
131
- m.def (" sparse_passthrough_r " , [](const SparseMatrixR &m) -> SparseMatrixR {
282
+ m.def (" sparse_copy_r " , [](const SparseMatrixR &m) -> SparseMatrixR {
132
283
return m;
133
284
});
134
285
135
- m.def (" sparse_passthrough_c " , [](const SparseMatrixC &m) -> SparseMatrixC {
286
+ m.def (" sparse_copy_c " , [](const SparseMatrixC &m) -> SparseMatrixC {
136
287
return m;
137
288
});
138
289
139
- m.def (" partial_passthrough_four_rm_r " , [](const FourRowMatrixR &m) -> FourRowMatrixR {
290
+ m.def (" partial_copy_four_rm_r " , [](const FourRowMatrixR &m) -> FourRowMatrixR {
140
291
return m;
141
292
});
142
- m.def (" partial_passthrough_four_rm_c " , [](const FourColMatrixR &m) -> FourColMatrixR {
293
+ m.def (" partial_copy_four_rm_c " , [](const FourColMatrixR &m) -> FourColMatrixR {
143
294
return m;
144
295
});
145
- m.def (" partial_passthrough_four_cm_r " , [](const FourRowMatrixC &m) -> FourRowMatrixC {
296
+ m.def (" partial_copy_four_cm_r " , [](const FourRowMatrixC &m) -> FourRowMatrixC {
146
297
return m;
147
298
});
148
- m.def (" partial_passthrough_four_cm_c " , [](const FourColMatrixC &m) -> FourColMatrixC {
299
+ m.def (" partial_copy_four_cm_c " , [](const FourColMatrixC &m) -> FourColMatrixC {
149
300
return m;
150
301
});
151
302
});
0 commit comments