Skip to content

Commit 87be1a3

Browse files
authored
Fix/add/test Mat bindings (#620)
1 parent f69b38b commit 87be1a3

5 files changed

Lines changed: 117 additions & 22 deletions

File tree

bindings/SofaTypes/src/SofaPython3/SofaTypes/Binding_Mat.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ template <sofa::Size S> static void bindSquaredMat(py::class_<Mat<S, S, double>>
4949
p.def("transpose", (void (MatClass::*)()) & MatClass::transpose);
5050
p.def("inverted", [](MatClass &mat){ return mat.inverted(); });
5151
p.def("invert", [](MatClass &dest, MatClass &from){ return dest.invert(from); });
52+
p.def("trace", [](const MatClass& mat){ return sofa::type::trace(mat); });
5253
}
5354

5455
template <sofa::Size R, sofa::Size C>
@@ -150,8 +151,14 @@ static void addMat(py::module & /*m*/, py::class_<Mat<R, C, double>> &p) {
150151
p.def(py::self * double());
151152
p.def(double() * py::self);
152153
p.def(py::self / double());
153-
p.def(py::self *= double());
154-
p.def(py::self /= double());
154+
p.def("__imul__", [](MatClass& self, double value) -> MatClass& {
155+
self *= value;
156+
return self;
157+
}, py::return_value_policy::reference_internal);
158+
p.def("__itruediv__", [](MatClass& self, double value) -> MatClass& {
159+
self /= value;
160+
return self;
161+
}, py::return_value_policy::reference_internal);
155162

156163
p.def(py::self += py::self);
157164
p.def(py::self -= py::self);
@@ -163,6 +170,16 @@ static void addMat(py::module & /*m*/, py::class_<Mat<R, C, double>> &p) {
163170
p.def("__repr__", [](MatClass &self) { return pyMat::__str__(self, true); });
164171
}
165172

173+
template <sofa::Size R_1, sofa::Size C_1, sofa::Size R_2, sofa::Size C_2>
174+
static void addMatProduct(py::module & /*m*/, py::class_<Mat<R_1, C_1, double>> &p)
175+
{
176+
using LHS = Mat<R_1, C_1, double>;
177+
using RHS = Mat<R_2, C_2, double>;
178+
p.def("__mul__", [](const LHS &self, const RHS &m) {
179+
return self * m;
180+
});
181+
}
182+
166183
// Generic bindings for Matrices
167184
template <sofa::Size R, sofa::Size C> struct MATRIX {
168185
static void addMat(py::module &m) {
@@ -205,6 +222,8 @@ template <> struct MATRIX<1, 1> {
205222
return std::unique_ptr<MatClass>(mat);
206223
}));
207224
::addMat(m, p);
225+
226+
addMatProduct<1,1, 1,1>(m, p);
208227
}
209228
};
210229

@@ -234,6 +253,8 @@ template <> struct MATRIX<2, 2> {
234253
return std::unique_ptr<MatClass>(mat);
235254
}));
236255
::addMat(m, p);
256+
257+
addMatProduct<2,2, 2,2>(m, p);
237258
}
238259
};
239260

@@ -263,6 +284,8 @@ template <> struct MATRIX<3, 3> {
263284
return std::unique_ptr<MatClass>(mat);
264285
}));
265286
::addMat(m, p);
287+
288+
addMatProduct<3,3, 3,3>(m, p);
266289
}
267290
};
268291

@@ -292,6 +315,8 @@ template <> struct MATRIX<4, 4> {
292315
return std::unique_ptr<MatClass>(mat);
293316
}));
294317
::addMat(m, p);
318+
319+
addMatProduct<4,4, 4,4>(m, p);
295320
}
296321
};
297322

bindings/SofaTypes/src/SofaPython3/SofaTypes/Binding_Vec.cpp

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ void setFromPartialSequence(const VecClass& s, py::list t)
8787
for(unsigned int i=0;i<N;i++) { t[i] = s[i]; }
8888
}
8989

90-
template <sofa::Size N, class T>
91-
py::class_<Vec<N,T>> addVec(py::module &m)
90+
template <sofa::Size N, class T, template<sofa::Size, class> class V = sofa::type::Vec>
91+
py::class_<V<N,T>> addVec(py::module &m)
9292
{
93-
typedef Vec<N, T> VecClass;
94-
py::class_<Vec<N, T>> p(m, sofa::defaulttype::DataTypeInfo< Vec<N, T> >::name().c_str());
93+
typedef V<N, T> VecClass;
94+
py::class_<V<N, T>> p(m, sofa::defaulttype::DataTypeInfo< V<N, T> >::name().c_str());
9595

9696
p.def(py::init<>()); // empty ctor
9797
p.def(py::init<const VecClass &>()); // copy ctor
@@ -230,26 +230,30 @@ T addCross(T p)
230230
return p;
231231
}
232232

233-
template<class T>
233+
template<class T, template<sofa::Size, class> class V = sofa::type::Vec>
234234
void addVectorsFor(py::module& m)
235235
{
236-
addVec<1, T>(m);
237-
addCross( addVec<2, T>(m) );
238-
addCross( addVec<3, T>(m) );
239-
addVec<4, T>(m);
240-
addVec<5, T>(m);
241-
addVec<6, T>(m);
242-
addVec<7, T>(m);
243-
addVec<8, T>(m);
244-
addVec<9, T>(m);
245-
addVec<10, T>(m);
246-
addVec<11, T>(m);
247-
addVec<12, T>(m);
236+
addVec<1, T, V>(m);
237+
addCross( addVec<2, T, V>(m) );
238+
addCross( addVec<3, T, V>(m) );
239+
addVec<4, T, V>(m);
240+
addVec<5, T, V>(m);
241+
addVec<6, T, V>(m);
242+
addVec<7, T, V>(m);
243+
addVec<8, T, V>(m);
244+
addVec<9, T, V>(m);
245+
addVec<10, T, V>(m);
246+
addVec<11, T, V>(m);
247+
addVec<12, T, V>(m);
248248
}
249249

250250
void moduleAddVec(py::module &m)
251251
{
252-
addVectorsFor<int>(m);
253-
addVectorsFor<double>(m);
254-
addVectorsFor<float>(m);
252+
addVectorsFor<int, sofa::type::Vec>(m);
253+
addVectorsFor<double, sofa::type::Vec>(m);
254+
addVectorsFor<float, sofa::type::Vec>(m);
255+
256+
addVectorsFor<int, sofa::type::VecNoInit>(m);
257+
addVectorsFor<double, sofa::type::VecNoInit>(m);
258+
addVectorsFor<float, sofa::type::VecNoInit>(m);
255259
}

bindings/SofaTypes/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ set(SOURCE_FILES
66

77
set(PYTHON_FILES
88
${CMAKE_CURRENT_SOURCE_DIR}/pyfiles/vector_test.py
9+
${CMAKE_CURRENT_SOURCE_DIR}/pyfiles/mat_test.py
910
)
1011

1112
find_package(Sofa.Testing REQUIRED)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import math
2+
import unittest
3+
4+
import Sofa
5+
from SofaTypes import Mat1x1, Mat2x2, Mat3x3, Vec2d
6+
7+
class TestMaterialMatrix(unittest.TestCase):
8+
9+
def test_Constructors(self):
10+
# --- Mat1x1 (Scalar/Row Vector) Construction ---
11+
m = Mat1x1() # Empty constructor
12+
self.assertEqual(m[0][0], 0.0)
13+
14+
m = Mat1x1([[math.pi]]) # list ctor (or direct assignment)
15+
self.assertEqual(m[0][0], math.pi)
16+
17+
# --- Mat2x2 Construction ---
18+
m = Mat2x2([[1.0, 2.0], [3.0, 4.0]]) # list of lists ctor
19+
self.assertEqual(m[0][0], 1.0)
20+
self.assertEqual(m[0][1], 2.0)
21+
self.assertEqual(m[1][0], 3.0)
22+
self.assertEqual(m[1][1], 4.0)
23+
24+
# --- Mat3x3 Construction ---
25+
m = Mat3x3([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])
26+
self.assertEqual(m[0][0], 1.0)
27+
self.assertEqual(m[0][1], 2.0)
28+
self.assertEqual(m[0][2], 3.0)
29+
self.assertEqual(m[1][0], 4.0)
30+
self.assertEqual(m[1][1], 5.0)
31+
self.assertEqual(m[1][2], 6.0)
32+
self.assertEqual(m[2][0], 7.0)
33+
self.assertEqual(m[2][1], 8.0)
34+
self.assertEqual(m[2][2], 9.0)
35+
36+
def test_Operators(self):
37+
m1 = Mat2x2([[1.0, 2.0], [3.0, 4.0]])
38+
m2 = Mat2x2([[5.0, 6.0], [7.0, 8.0]])
39+
40+
# Matrix addition
41+
sum_mat = m1 + m2
42+
expected_sum = Mat2x2([[6.0, 8.0], [10.0, 12.0]])
43+
self.assertEqual(sum_mat, expected_sum)
44+
45+
# Matrix subtraction
46+
diff_mat = m1 - m2
47+
expected_diff = Mat2x2([[-4.0, -4.0], [-4.0, -4.0]])
48+
self.assertEqual(diff_mat, expected_diff)
49+
50+
# Scalar multiplication (A * 2.0)
51+
scaled_mat = m1 * 2.0
52+
expected_scale = Mat2x2([[2.0, 4.0], [6.0, 8.0]])
53+
self.assertEqual(scaled_mat, expected_scale)
54+
55+
# Matrix multiplication (A * B)
56+
mat_product = m1 * m2
57+
expected_mat_product = Mat2x2([[1.0 * 5.0 + 2.0 * 7.0, 1.0 * 6.0 + 2.0 * 8.0], [3.0 * 5.0 + 4.0 * 7.0, 3.0 * 6.0 + 4.0 * 8.0]])
58+
self.assertEqual(mat_product, expected_mat_product)
59+
60+
# Testing assignment/in-place modification if available (e.g., /=)
61+
m_test = Mat2x2([[1.0, 2.0], [3.0, 4.0]])
62+
m_test /= 2.0
63+
expected_inplace_div = Mat2x2([[0.5, 1.0], [1.5, 2.0]])
64+
self.assertEqual(m_test, expected_inplace_div)

bindings/SofaTypes/tests/pyfiles/vector_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import math
22
import unittest
33

4+
import Sofa
45
import SofaTypes
56
from SofaTypes import Vec1d, Vec2d, Vec3d, Vec4d, Vec4i
67

0 commit comments

Comments
 (0)