Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/src/core/codac2_py_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ PYBIND11_MODULE(_core, m)
m.doc() = string(FOR_MATLAB ? "Matlab" : "Python") + " binding of Codac (core)";
m.attr("oo") = oo;
m.attr("PI") = PI;
m.attr("FOR_MATLAB") = FOR_MATLAB;

export_TimePropag(m);

Expand Down
25 changes: 25 additions & 0 deletions python/src/core/domains/tube/codac2_py_SlicedTube_operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@ namespace
SLICEDTUBE_T_REF_OPERATORMULEQ_SLICEDTUBE_T_REF_CONST_SLICEDTUBE_INTERVAL_REF,
py::return_value_policy::reference_internal,
py::is_operator());

if constexpr(!FOR_MATLAB && std::is_same_v<T,IntervalMatrix>)
{
pyclass
.def("__matmul__", (SlicedTube<T>(*)(const SlicedTube<T>&,const SlicedTube<T>&)) &codac2::operator*,
SLICEDTUBE_INTERVALMATRIX_OPERATORMUL_CONST_SLICEDTUBE_INTERVALMATRIX_REF_CONST_SLICEDTUBE_INTERVALMATRIX_REF,
py::is_operator())

.def("__matmul__", (SlicedTube<T>(*)(const SlicedTube<T>&,const T&)) &codac2::operator*,
SLICEDTUBE_T_OPERATORMUL_CONST_SLICEDTUBE_T_REF_CONST_Q_REF,
py::is_operator())

.def("__rmatmul__",
[](const SlicedTube<T>& x2, const T& x1) { return x1 * x2; },
SLICEDTUBE_T_OPERATORMUL_CONST_Q_REF_CONST_SLICEDTUBE_T_REF,
py::is_operator());
}
}
}

Expand Down Expand Up @@ -401,6 +418,14 @@ void export_SlicedTube_operations(
SLICEDTUBE_INTERVALVECTOR_OPERATORMUL_CONST_SLICEDTUBE_INTERVALMATRIX_REF_CONST_SLICEDTUBE_INTERVALVECTOR_REF,
py::is_operator());

if constexpr(!FOR_MATLAB)
{
py_SlicedTube_IntervalMatrix
.def("__matmul__", (SlicedTube<IntervalVector>(*)(const SlicedTube<IntervalMatrix>&,const SlicedTube<IntervalVector>&)) &codac2::operator*,
SLICEDTUBE_INTERVALVECTOR_OPERATORMUL_CONST_SLICEDTUBE_INTERVALMATRIX_REF_CONST_SLICEDTUBE_INTERVALVECTOR_REF,
py::is_operator());
}

bind_scalar_slicedtube_functions(m);

py_SlicedTube_Interval
Expand Down
21 changes: 21 additions & 0 deletions python/src/core/functions/analytic/codac2_py_AnalyticExprWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ inline void export_VectorExpr(py::module& m)

;

if constexpr(!FOR_MATLAB)
{
exported
.def("__rmatmul__", [](const VectorExpr& e1, const MatrixExpr& e2) { return e2*e1; }, py::is_operator())
;
}

py::implicitly_convertible<Vector,VectorExpr>();
py::implicitly_convertible<IntervalVector,VectorExpr>();
py::implicitly_convertible<VectorVar,VectorExpr>();
Expand Down Expand Up @@ -181,6 +188,20 @@ inline void export_MatrixExpr(py::module& m)

;

if constexpr(!FOR_MATLAB)
{
exported
.def("__matmul__", [](const MatrixExpr& e1, const MatrixExpr& e2) { return e1*e2; }, py::is_operator())
.def("__matmul__", [](const MatrixExpr& e1, const IntervalMatrix& e2) { return e1*e2; }, py::is_operator())
.def("__matmul__", [](const MatrixExpr& e1, const MatrixVar& e2) { return e1*e2; }, py::is_operator())
.def("__rmatmul__", [](const MatrixExpr& e1, const IntervalMatrix& e2) { return e2*e1; }, py::is_operator())
.def("__rmatmul__", [](const MatrixExpr& e1, const MatrixVar& e2) { return e2*e1; }, py::is_operator())
.def("__matmul__", [](const MatrixExpr& e1, const VectorVar& e2) { return e1*e2; }, py::is_operator())
.def("__matmul__", [](const MatrixExpr& e1, const IntervalVector& e2) { return e1*e2; }, py::is_operator())
.def("__matmul__", [](const MatrixExpr& e1, const VectorExpr& e2) { return e1*e2; }, py::is_operator())
;
}

py::implicitly_convertible<Matrix,MatrixExpr>();
py::implicitly_convertible<IntervalMatrix,MatrixExpr>();
py::implicitly_convertible<MatrixVar,MatrixExpr>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ void export_VectorVar(py::module& m)
.def("__truediv__", [](const VectorVar& e1, const ScalarExpr& e2) { return e1 / e2; }, py::is_operator())
.def("__truediv__", [](const VectorVar& e1, const Interval& e2) { return e1 / e2; }, py::is_operator())
;

if constexpr(!FOR_MATLAB)
{
exported
.def("__rmatmul__", [](const VectorVar& e1, const IntervalMatrix& e2) { return e2 * e1; }, py::is_operator())
.def("__rmatmul__", [](const VectorVar& e1, const MatrixExpr& e2) { return e2 * e1; }, py::is_operator())
;
}

py::implicitly_convertible<VectorVar,VectorExpr>();
}
Expand Down Expand Up @@ -227,6 +235,20 @@ void export_MatrixVar(py::module& m)
.def("__truediv__", [](const MatrixVar& e1, const ScalarExpr& e2) { return e1 / e2; }, py::is_operator())
.def("__truediv__", [](const MatrixVar& e1, const Interval& e2) { return e1 / e2; }, py::is_operator())
;

if constexpr(!FOR_MATLAB)
{
exported
.def("__matmul__", [](const MatrixVar& e1, const VectorVar& e2) { return e1 * e2; }, py::is_operator())
.def("__matmul__", [](const MatrixVar& e1, const VectorExpr& e2) { return e1 * e2; }, py::is_operator())
.def("__matmul__", [](const MatrixVar& e1, const IntervalVector& e2) { return e1 * e2; }, py::is_operator())
.def("__matmul__", [](const MatrixVar& e1, const MatrixVar& e2) { return e1 * e2; }, py::is_operator())
.def("__matmul__", [](const MatrixVar& e1, const MatrixExpr& e2) { return e1 * e2; }, py::is_operator())
.def("__matmul__", [](const MatrixVar& e1, const IntervalMatrix& e2) { return e1 * e2; }, py::is_operator())
.def("__rmatmul__", [](const MatrixVar& e1, const IntervalMatrix& e2) { return e2 * e1; }, py::is_operator())
.def("__rmatmul__", [](const MatrixVar& e1, const MatrixExpr& e2) { return e2 * e1; }, py::is_operator())
;
}

py::implicitly_convertible<MatrixVar,MatrixExpr>();
}
46 changes: 46 additions & 0 deletions python/src/core/matrices/codac2_py_arithmetic_mul.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <codac2_Matrix.h>
#include <codac2_IntervalVector.h>
#include <codac2_IntervalMatrix.h>
#include "codac2_py_matlab.h"

using namespace std;
using namespace codac2;
Expand Down Expand Up @@ -153,4 +154,49 @@ void export_arithmetic_mul(
py_IM.def("__imul__", [](IntervalMatrix& x1, const IntervalMatrix& x2) { return x1*=x2; }, py::is_operator());
py_IM.def("__imul__", [](IntervalMatrix& x1, const IB& x2) { return x1*=x2; }, py::is_operator());

// ====== Matrix products with the @ operator (not available in Matlab)

if constexpr(!FOR_MATLAB)
{
//Vector operator*(const M& x1, const Vector& x2)
py_M.def("__matmul__", [](const Matrix& x1, const Vector& x2) -> Vector { return x1*x2; }, py::is_operator());
py_B.def("__matmul__", [](const B& x1, const Vector& x2) -> Vector { return x1*x2; }, py::is_operator());

//Matrix operator*(const M& x1, const M_& x2)
py_M.def("__matmul__", [](const Matrix& x1, const Matrix& x2) -> Matrix { return x1*x2; }, py::is_operator());
py_M.def("__matmul__", [](const Matrix& x1, const B& x2) -> Matrix { return x1*x2; }, py::is_operator());
py_B.def("__matmul__", [](const B& x1, const Matrix& x2) -> Matrix { return x1*x2; }, py::is_operator());
py_B.def("__matmul__", [](const B& x1, const B& x2) -> Matrix { return x1*x2; }, py::is_operator());

//IntervalVector operator*(const M& x1, const IntervalVector& x2)
py_M.def("__matmul__", [](const Matrix& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator());
py_B.def("__matmul__", [](const B& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator());

//IntervalMatrix operator*(const M& x1, const IM& x2)
py_M.def("__matmul__", [](const Matrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast<Interval>()*x2; }, py::is_operator());
py_M.def("__matmul__", [](const Matrix& x1, const IB& x2) -> IntervalMatrix { return x1.template cast<Interval>()*x2; }, py::is_operator());
py_B.def("__matmul__", [](const B& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1.template cast<Interval>()*x2; }, py::is_operator());
py_B.def("__matmul__", [](const B& x1, const IB& x2) -> IntervalMatrix { return x1.template cast<Interval>()*x2; }, py::is_operator());

//IntervalVector operator*(const IM& x1, const Vector& x2)
py_IM.def("__matmul__", [](const IntervalMatrix& x1, const Vector& x2) -> IntervalVector { return x1*x2.template cast<Interval>(); }, py::is_operator());
py_IB.def("__matmul__", [](const IB& x1, const Vector& x2) -> IntervalVector { return x1*x2.template cast<Interval>(); }, py::is_operator());

//IntervalMatrix operator*(const IM& x1, const M& x2)
py_IM.def("__matmul__", [](const IntervalMatrix& x1, const Matrix& x2) -> IntervalMatrix { return x1*x2.template cast<Interval>(); }, py::is_operator());
py_IM.def("__matmul__", [](const IntervalMatrix& x1, const B& x2) -> IntervalMatrix { return x1*x2.template cast<Interval>(); }, py::is_operator());
py_IB.def("__matmul__", [](const IB& x1, const Matrix& x2) -> IntervalMatrix { return x1*x2.template cast<Interval>(); }, py::is_operator());
py_IB.def("__matmul__", [](const IB& x1, const B& x2) -> IntervalMatrix { return x1*x2.template cast<Interval>(); }, py::is_operator());

//IntervalVector operator*(const IM& x1, const IntervalVector& x2)
py_IM.def("__matmul__", [](const IntervalMatrix& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator());
py_IB.def("__matmul__", [](const IB& x1, const IntervalVector& x2) -> IntervalVector { return x1*x2; }, py::is_operator());

//IntervalMatrix operator*(const IM& x1, const IM_& x2)
py_IM.def("__matmul__", [](const IntervalMatrix& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator());
py_IM.def("__matmul__", [](const IntervalMatrix& x1, const IB& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator());
py_IB.def("__matmul__", [](const IB& x1, const IntervalMatrix& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator());
py_IB.def("__matmul__", [](const IB& x1, const IB& x2) -> IntervalMatrix { return x1*x2; }, py::is_operator());
}

}
16 changes: 16 additions & 0 deletions python/src/core/tools/codac2_py_transformations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <codac2_transformations.h>
#include "codac2_py_transformations_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py):
#include "codac2_py_doc.h"
#include "codac2_py_matlab.h"

using namespace std;
using namespace codac2;
Expand All @@ -41,6 +42,21 @@ void export_transformations(py::module& m)
py::is_operator())

;

if constexpr(!FOR_MATLAB)
{
exported_affine2d

.def("__matmul__", [](const Eigen::Affine2d& x1, const Vector& x2)
{
assert_release(x2.size() == 2);
return Vector(x1*Eigen::Vector2d(x2));
},
DOC_TO_BE_DEFINED,
py::is_operator())

;
}

m

Expand Down
25 changes: 24 additions & 1 deletion python/src/core/trajectory/codac2_py_SampledTraj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,12 @@ void add_traj_operators(py::class_<SampledTraj<T>>& pyclass)
.def("__rmul__", [](const SampledTraj<T>& x2, double x1) { return x1*x2; },
SAMPLEDTRAJ_T_OPERATORMUL_DOUBLE_CONST_SAMPLEDTRAJ_T_REF,
py::is_operator())

.def("__mul__", [](const SampledTraj<T>& x1, const T& x2) { return x1*x2; },
SAMPLEDTRAJ_T_OPERATORMUL_CONST_SAMPLEDTRAJ_T_REF_CONST_Q_REF,
py::is_operator())

.def("__mul__", [](const T& x1, const SampledTraj<T>& x2) { return x1*x2; },
.def("__rmul__", [](const SampledTraj<T>& x2, const T& x1) { return x1*x2; },
SAMPLEDTRAJ_T_OPERATORMUL_CONST_Q_REF_CONST_SAMPLEDTRAJ_T_REF,
py::is_operator())

Expand Down Expand Up @@ -288,6 +292,25 @@ void export_SampledTraj(py::module& m)

;

if constexpr(!FOR_MATLAB)
{
py_SampledTraj_Matrix

.def("__matmul__", [](const SampledTraj<Matrix>& x1, const SampledTraj<Vector>& x2) { return x1*x2; },
SAMPLEDTRAJ_VECTOR_OPERATORMUL_CONST_SAMPLEDTRAJ_MATRIX_REF_CONST_SAMPLEDTRAJ_VECTOR_REF,
py::is_operator())

.def("__matmul__", [](const SampledTraj<Matrix>& x1, const SampledTraj<Matrix>& x2) { return x1*x2; },
SAMPLEDTRAJ_T_OPERATORMUL_CONST_SAMPLEDTRAJ_T_REF_CONST_SAMPLEDTRAJ_T_REF,
py::is_operator())

.def("__rmatmul__", [](const SampledTraj<Matrix>& x2, const Matrix& x1) { return x1*x2; },
SAMPLEDTRAJ_T_OPERATORMUL_CONST_Q_REF_CONST_SAMPLEDTRAJ_T_REF,
py::is_operator())

;
}

m

.def("sqr", (SampledTraj<double> (*)(const SampledTraj<double>&)) &codac2::sqr,
Expand Down
18 changes: 18 additions & 0 deletions tests/core/domains/tube/codac2_tests_SlicedTube.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,24 @@ def test_inversion_vector_tube(self):
inv = x.invert(inv_val, restricted)
self.assertTrue(inv == Interval(15.2,38))

@unittest.skipIf(FOR_MATLAB, "the @ operator is not available in Matlab")
def test_matrix_tube_matmul_operator(self):

tdomain = create_tdomain(Interval(0,1), 0.5, False)
M,N = IntervalMatrix([[1,2],[3,4]]),IntervalMatrix([[0,1],[1,0]])
A = SlicedTube(tdomain, M)
B = SlicedTube(tdomain, N)
x = SlicedTube(tdomain, IntervalVector([5,6]))

self.assertTrue((A@B).codomain() == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue((A@N).codomain() == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue((M@B).codomain() == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue((Matrix([[1,2],[3,4]])@B).codomain() == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue((A@x).codomain() == IntervalVector([17,39]))
self.assertTrue((A@x).codomain() == (A*x).codomain())
with self.assertRaises(TypeError):
x@x


if __name__ == '__main__':
unittest.main()
47 changes: 47 additions & 0 deletions tests/core/functions/analytic/codac2_tests_AnalyticFunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,53 @@ def test_eval(i,f,*args):
self.assertTrue(f.eval(Interval(0.0,4.0))==Interval(-4.0,4.0))
self.assertTrue(f.eval(Interval(0.0))==Interval(0.0))

@unittest.skipIf(FOR_MATLAB, "the @ operator is not available in Matlab")
def test_AnalyticFunction_matmul_operator(self):

A,B = MatrixVar(2,2),MatrixVar(2,2)
x = VectorVar(2)
M,N = Matrix([[1,2],[3,4]]),Matrix([[0,1],[1,0]])
v = Vector([5,6])

# eval() takes arguments of a single type: the matrix argument is set by composition
eval_Mv = lambda e: AnalyticFunction([x], AnalyticFunction([A,x], e)(M,x)).eval(v)

# MatrixVar @ ...
self.assertTrue(AnalyticFunction([A,B], A@B).eval(M,N) == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue(AnalyticFunction([A,B], A@(2*B)).eval(M,N) == IntervalMatrix([[4,2],[8,6]]))
self.assertTrue(AnalyticFunction([A], A@IntervalMatrix(N)).eval(M) == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue(eval_Mv(A@x) == IntervalVector([17,39]))
self.assertTrue(eval_Mv(A@(2*x)) == IntervalVector([34,78]))
self.assertTrue(AnalyticFunction([A], A@IntervalVector(v)).eval(M) == IntervalVector([17,39]))
self.assertTrue(AnalyticFunction([B], IntervalMatrix(M)@B).eval(N) == IntervalMatrix([[2,1],[4,3]]))
self.assertTrue(AnalyticFunction([B], M@B).eval(N) == IntervalMatrix([[2,1],[4,3]]))

# MatrixExpr @ ...
self.assertTrue(AnalyticFunction([A,B], (2*A)@(2*B)).eval(M,N) == IntervalMatrix([[8,4],[16,12]]))
self.assertTrue(AnalyticFunction([A,B], (2*A)@B).eval(M,N) == IntervalMatrix([[4,2],[8,6]]))
self.assertTrue(AnalyticFunction([A], (2*A)@IntervalMatrix(N)).eval(M) == IntervalMatrix([[4,2],[8,6]]))
self.assertTrue(eval_Mv((2*A)@x) == IntervalVector([34,78]))
self.assertTrue(eval_Mv((2*A)@(2*x)) == IntervalVector([68,156]))
self.assertTrue(AnalyticFunction([A], (2*A)@IntervalVector(v)).eval(M) == IntervalVector([34,78]))
self.assertTrue(AnalyticFunction([B], IntervalMatrix(M)@(2*B)).eval(N) == IntervalMatrix([[4,2],[8,6]]))

# ... @ VectorVar, ... @ VectorExpr
self.assertTrue(AnalyticFunction([x], IntervalMatrix(M)@x).eval(v) == IntervalVector([17,39]))
self.assertTrue(AnalyticFunction([x], M@x).eval(v) == IntervalVector([17,39]))
self.assertTrue(AnalyticFunction([x], IntervalMatrix(M)@(2*x)).eval(v) == IntervalVector([34,78]))

# Same results as with the * operator
h = AnalyticFunction([A], A@A)
f = AnalyticFunction([x,A], h(A)@x)
g = AnalyticFunction([x], f(x,Matrix([[0,2],[-1,0]])))
self.assertTrue(g.eval(IntervalVector([[-1,1],[2,3]])) == IntervalVector([[-2,2],[-6,-4]]))

# Matrix product only: no @ with scalar expressions
with self.assertRaises(TypeError):
A@ScalarVar()
with self.assertRaises(TypeError):
x@x


if __name__ == '__main__':
unittest.main()
Loading
Loading