Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • jcarpent/eigenpy
  • gsaurel/eigenpy
  • stack-of-tasks/eigenpy
3 results
Show changes
Showing
with 628 additions and 37 deletions
/// Copyright 2023 LAAS-CNRS, INRIA
#include <eigenpy/eigenpy.hpp>
using std::shared_ptr;
namespace bp = boost::python;
// fwd declaration
struct MyVirtualData;
/// A virtual class with two pure virtual functions taking different signatures,
/// and a polymorphic factory function.
struct MyVirtualClass {
MyVirtualClass() {}
virtual ~MyVirtualClass() {}
// polymorphic fn taking arg by shared_ptr
virtual void doSomethingPtr(shared_ptr<MyVirtualData> const &data) const = 0;
// polymorphic fn taking arg by reference
virtual void doSomethingRef(MyVirtualData &data) const = 0;
virtual shared_ptr<MyVirtualData> createData() const {
return std::make_shared<MyVirtualData>(*this);
}
};
struct MyVirtualData {
MyVirtualData(MyVirtualClass const &) {}
virtual ~MyVirtualData() {} // virtual dtor to mark class as polymorphic
};
shared_ptr<MyVirtualData> callDoSomethingPtr(const MyVirtualClass &obj) {
auto d = obj.createData();
printf("Created MyVirtualData with address %p\n", (void *)d.get());
obj.doSomethingPtr(d);
return d;
}
shared_ptr<MyVirtualData> callDoSomethingRef(const MyVirtualClass &obj) {
auto d = obj.createData();
printf("Created MyVirtualData with address %p\n", (void *)d.get());
obj.doSomethingRef(*d);
return d;
}
void throw_virtual_not_implemented_error() {
throw std::runtime_error("Called C++ virtual function.");
}
/// Wrapper classes
struct VirtualClassWrapper : MyVirtualClass, bp::wrapper<MyVirtualClass> {
void doSomethingPtr(shared_ptr<MyVirtualData> const &data) const override {
if (bp::override fo = this->get_override("doSomethingPtr")) {
/// shared_ptr HAS to be passed by value.
/// Boost.Python's argument converter has the wrong behaviour for
/// reference_wrapper<shared_ptr<T>>, so boost::ref(data) does not work.
fo(data);
return;
}
throw_virtual_not_implemented_error();
}
/// The data object is passed by mutable reference to this function,
/// and wrapped in a @c boost::reference_wrapper when passed to the override.
/// Otherwise, Boost.Python's argument converter will convert to Python by
/// value and create a copy.
void doSomethingRef(MyVirtualData &data) const override {
if (bp::override fo = this->get_override("doSomethingRef")) {
fo(boost::ref(data));
return;
}
throw_virtual_not_implemented_error();
}
shared_ptr<MyVirtualData> createData() const override {
if (bp::override fo = this->get_override("createData")) {
bp::object result = fo().as<bp::object>();
return bp::extract<shared_ptr<MyVirtualData> >(result);
}
return default_createData();
}
shared_ptr<MyVirtualData> default_createData() const {
return MyVirtualClass::createData();
}
};
/// This "trampoline class" does nothing but is ABSOLUTELY required to ensure
/// downcasting works properly with non-smart ptr signatures. Otherwise,
/// there is no handle to the original Python object ( @c PyObject *).
/// Every single polymorphic type exposed to Python should be exposed through
/// such a trampoline. Users can also create their own wrapper classes by taking
/// inspiration from boost::python::wrapper<T>.
struct DataWrapper : MyVirtualData, bp::wrapper<MyVirtualData> {
/// we have to use-declare non-defaulted constructors
/// (see https://en.cppreference.com/w/cpp/language/default_constructor)
/// or define them manually.
using MyVirtualData::MyVirtualData;
};
/// Take and return a const reference
const MyVirtualData &iden_ref(const MyVirtualData &d) {
// try cast to holder
return d;
}
/// Take a shared_ptr (by const reference or value, doesn't matter), return by
/// const reference
const MyVirtualData &iden_shared(const shared_ptr<MyVirtualData> &d) {
// get boost.python's custom deleter
// boost.python hides the handle to the original object in there
// dter being nonzero indicates shared_ptr was wrapped by Boost.Python
auto *dter = std::get_deleter<bp::converter::shared_ptr_deleter>(d);
if (dter != 0) printf("> input shared_ptr has a deleter\n");
return *d;
}
/// Take and return a shared_ptr
shared_ptr<MyVirtualData> copy_shared(const shared_ptr<MyVirtualData> &d) {
auto *dter = std::get_deleter<bp::converter::shared_ptr_deleter>(d);
if (dter != 0) printf("> input shared_ptr has a deleter\n");
return d;
}
BOOST_PYTHON_MODULE(bind_virtual_factory) {
assert(std::is_polymorphic<MyVirtualClass>::value &&
"MyVirtualClass should be polymorphic!");
assert(std::is_polymorphic<MyVirtualData>::value &&
"MyVirtualData should be polymorphic!");
bp::class_<VirtualClassWrapper, boost::noncopyable>(
"MyVirtualClass", bp::init<>(bp::args("self")))
.def("doSomething", bp::pure_virtual(&MyVirtualClass::doSomethingPtr),
bp::args("self", "data"))
.def("doSomethingRef", bp::pure_virtual(&MyVirtualClass::doSomethingRef),
bp::args("self", "data"))
.def("createData", &MyVirtualClass::createData,
&VirtualClassWrapper::default_createData, bp::args("self"));
bp::register_ptr_to_python<shared_ptr<MyVirtualData> >();
/// Trampoline used as 1st argument
/// otherwise if passed as "HeldType", we need to define
/// the constructor and call initializer manually.
bp::class_<DataWrapper, boost::noncopyable>("MyVirtualData", bp::no_init)
.def(bp::init<MyVirtualClass const &>(bp::args("self", "model")));
bp::def("callDoSomethingPtr", callDoSomethingPtr, bp::args("obj"));
bp::def("callDoSomethingRef", callDoSomethingRef, bp::args("obj"));
bp::def("iden_ref", iden_ref, bp::return_internal_reference<>());
bp::def("iden_shared", iden_shared, bp::return_internal_reference<>());
bp::def("copy_shared", copy_shared);
}
......@@ -69,17 +69,19 @@ BOOST_PYTHON_MODULE(complex) {
bp::def("ascomplex",
ascomplex<long double, Eigen::Dynamic, Eigen::Dynamic, 0>);
bp::def("real", (MatrixXf(*)(const Eigen::MatrixBase<MatrixXcf> &)) &
real<MatrixXcf>);
bp::def("real", (MatrixXd(*)(const Eigen::MatrixBase<MatrixXcd> &)) &
real<MatrixXcd>);
bp::def("real", (MatrixXld(*)(const Eigen::MatrixBase<MatrixXcld> &)) &
real<MatrixXcld>);
bp::def("real",
(MatrixXf(*)(const Eigen::MatrixBase<MatrixXcf> &))&real<MatrixXcf>);
bp::def("real",
(MatrixXd(*)(const Eigen::MatrixBase<MatrixXcd> &))&real<MatrixXcd>);
bp::def(
"real",
(MatrixXld(*)(const Eigen::MatrixBase<MatrixXcld> &))&real<MatrixXcld>);
bp::def("imag", (MatrixXf(*)(const Eigen::MatrixBase<MatrixXcf> &)) &
imag<MatrixXcf>);
bp::def("imag", (MatrixXd(*)(const Eigen::MatrixBase<MatrixXcd> &)) &
imag<MatrixXcd>);
bp::def("imag", (MatrixXld(*)(const Eigen::MatrixBase<MatrixXcld> &)) &
imag<MatrixXcld>);
bp::def("imag",
(MatrixXf(*)(const Eigen::MatrixBase<MatrixXcf> &))&imag<MatrixXcf>);
bp::def("imag",
(MatrixXd(*)(const Eigen::MatrixBase<MatrixXcd> &))&imag<MatrixXcd>);
bp::def(
"imag",
(MatrixXld(*)(const Eigen::MatrixBase<MatrixXcld> &))&imag<MatrixXcld>);
}
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/deprecation-policy.hpp"
#include <iostream>
namespace bp = boost::python;
using eigenpy::DeprecationType;
void some_deprecated_function() {
std::cout << "Calling this should produce a warning" << std::endl;
}
void some_future_deprecated_function() {
std::cout
<< "Calling this should produce a warning about a future deprecation"
<< std::endl;
}
class X {
public:
void deprecated_member_function() {}
};
BOOST_PYTHON_MODULE(deprecation_policy) {
bp::def("some_deprecated_function", some_deprecated_function,
eigenpy::deprecated_function<DeprecationType::DEPRECATION>());
bp::def("some_future_deprecated_function", some_future_deprecated_function,
eigenpy::deprecated_function<DeprecationType::FUTURE>());
bp::class_<X>("X", bp::init<>(bp::args("self")))
.def("deprecated_member_function", &X::deprecated_member_function,
eigenpy::deprecated_member<>());
}
......@@ -132,6 +132,11 @@ ReturnMatrix copy(const Eigen::MatrixBase<Matrix>& mat) {
return mat;
}
template <typename Matrix>
Matrix copy_same(const Eigen::MatrixBase<Matrix>& mat) {
return mat;
}
BOOST_PYTHON_MODULE(matrix) {
using namespace Eigen;
namespace bp = boost::python;
......@@ -190,4 +195,39 @@ BOOST_PYTHON_MODULE(matrix) {
copy<RowMajorMatrixXd, RowMajorMatrixXd>);
bp::def("asRowMajorFromRowMajorVector",
copy<Eigen::RowVectorXd, Eigen::RowVectorXd>);
bp::def("copyBoolToBool", copy_same<Eigen::Matrix<bool, -1, -1> >);
bp::def("copyInt8ToInt8", copy_same<Eigen::Matrix<int8_t, -1, -1> >);
bp::def("copyCharToChar", copy_same<Eigen::Matrix<char, -1, -1> >);
bp::def("copyUCharToUChar", copy_same<Eigen::Matrix<unsigned char, -1, -1> >);
bp::def("copyInt16ToInt16", copy_same<Eigen::Matrix<int16_t, -1, -1> >);
bp::def("copyUInt16ToUInt16", copy_same<Eigen::Matrix<uint16_t, -1, -1> >);
bp::def("copyInt32ToInt32", copy_same<Eigen::Matrix<int32_t, -1, -1> >);
bp::def("copyUInt32ToUInt32", copy_same<Eigen::Matrix<uint32_t, -1, -1> >);
bp::def("copyInt64ToInt64", copy_same<Eigen::Matrix<int64_t, -1, -1> >);
bp::def("copyUInt64ToUInt64", copy_same<Eigen::Matrix<uint64_t, -1, -1> >);
bp::def("copyLongToLong", copy_same<Eigen::Matrix<long, -1, -1> >);
bp::def("copyULongToULong", copy_same<Eigen::Matrix<unsigned long, -1, -1> >);
bp::def("copyLongLongToLongLong",
copy_same<Eigen::Matrix<long long, -1, -1> >);
bp::def("copyULongLongToULongLong",
copy_same<Eigen::Matrix<unsigned long long, -1, -1> >);
bp::def("copyFloatToFloat", copy_same<Eigen::Matrix<float, -1, -1> >);
bp::def("copyDoubleToDouble", copy_same<Eigen::Matrix<double, -1, -1> >);
bp::def("copyLongDoubleToLongDouble",
copy_same<Eigen::Matrix<long double, -1, -1> >);
bp::def("copyCFloatToCFloat",
copy_same<Eigen::Matrix<std::complex<float>, -1, -1> >);
bp::def("copyCDoubleToCDouble",
copy_same<Eigen::Matrix<std::complex<double>, -1, -1> >);
bp::def("copyCLongDoubleToCLongDouble",
copy_same<Eigen::Matrix<std::complex<long double>, -1, -1> >);
}
#include "eigenpy/registration.hpp"
#include <cstdio>
namespace bp = boost::python;
class X {
public:
X() {}
void operator()() { printf("DOOT\n"); }
};
class X_wrapper : public X, bp::wrapper<X> {
public:
static void expose() {
if (!eigenpy::register_symbolic_link_to_registered_type<X>()) {
bp::class_<X>("X", bp::init<>()).def("__call__", &X::operator());
}
}
};
BOOST_PYTHON_MODULE(multiple_registration) {
X_wrapper::expose();
X_wrapper::expose();
X_wrapper::expose();
X_wrapper::expose();
X_wrapper::expose();
X_wrapper::expose();
}
import numpy as np
from scipy.sparse import csc_matrix
import eigenpy
dim = 100
rng = np.random.default_rng()
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
A = csc_matrix(A)
llt = eigenpy.CholmodSimplicialLDLT(A)
assert llt.info() == eigenpy.ComputationInfo.Success
X = rng.random((dim, 20))
B = A.dot(X)
X_est = llt.solve(B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
llt.analyzePattern(A)
llt.factorize(A)
import numpy as np
from scipy.sparse import csc_matrix
import eigenpy
dim = 100
rng = np.random.default_rng()
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
A = csc_matrix(A)
llt = eigenpy.CholmodSimplicialLLT(A)
assert llt.info() == eigenpy.ComputationInfo.Success
X = rng.random((dim, 20))
B = A.dot(X)
X_est = llt.solve(B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
llt.analyzePattern(A)
llt.factorize(A)
import numpy as np
from scipy.sparse import csc_matrix
import eigenpy
dim = 100
rng = np.random.default_rng()
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
A = csc_matrix(A)
llt = eigenpy.CholmodSupernodalLLT(A)
assert llt.info() == eigenpy.ComputationInfo.Success
X = rng.random((dim, 20))
B = A.dot(X)
X_est = llt.solve(B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
llt.analyzePattern(A)
llt.factorize(A)
import numpy as np
from scipy.sparse import csc_matrix
import eigenpy
rng = np.random.default_rng()
def test(SolverType: type):
dim = 100
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
A = csc_matrix(A)
llt = SolverType(A)
assert llt.info() == eigenpy.ComputationInfo.Success
X = rng.random((dim, 20))
B = A.dot(X)
X_est = llt.solve(B)
# import pdb; pdb.set_trace()
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
llt.analyzePattern(A)
llt.factorize(A)
test(eigenpy.AccelerateLLT)
test(eigenpy.AccelerateLDLT)
test(eigenpy.AccelerateLDLTUnpivoted)
test(eigenpy.AccelerateLDLTSBK)
test(eigenpy.AccelerateLDLTTPP)
test(eigenpy.AccelerateQR)
# test(eigenpy.AccelerateCholeskyAtA) # This test is not passing. Seems there is a bug in Eigen with the support of Accelerate.
import numpy as np
from scipy.sparse import csc_matrix
import eigenpy
dim = 100
rng = np.random.default_rng()
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
A = csc_matrix(A)
ldlt = eigenpy.SimplicialLDLT(A)
assert ldlt.info() == eigenpy.ComputationInfo.Success
L = ldlt.matrixL()
U = ldlt.matrixU()
D = csc_matrix(np.diag(ldlt.vectorD()))
LDU = L @ D @ U
assert eigenpy.is_approx(LDU.toarray(), A.toarray())
X = rng.random((dim, 20))
B = A.dot(X)
X_est = ldlt.solve(B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
ldlt.analyzePattern(A)
ldlt.factorize(A)
permutation = ldlt.permutationP()
import numpy as np
from scipy.sparse import csc_matrix
import eigenpy
dim = 100
rng = np.random.default_rng()
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
A = csc_matrix(A)
llt = eigenpy.SimplicialLLT(A)
assert llt.info() == eigenpy.ComputationInfo.Success
L = llt.matrixL()
U = llt.matrixU()
LU = L @ U
assert eigenpy.is_approx(LU.toarray(), A.toarray())
X = rng.random((dim, 20))
B = A.dot(X)
X_est = llt.solve(B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
llt.analyzePattern(A)
llt.factorize(A)
permutation = llt.permutationP()
import eigenpy
import numpy as np
import eigenpy
dim = 100
A = np.random.rand(dim, dim)
rng = np.random.default_rng()
A = (A + A.T) * 0.5 + np.diag(10.0 + np.random.rand(dim))
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
ldlt = eigenpy.LDLT(A)
......@@ -16,7 +18,7 @@ assert eigenpy.is_approx(
np.transpose(P).dot(L.dot(np.diag(D).dot(np.transpose(L).dot(P)))), A
)
X = np.random.rand(dim, 20)
X = rng.random((dim, 20))
B = A.dot(X)
X_est = ldlt.solve(B)
assert eigenpy.is_approx(X, X_est)
......
import eigenpy
import numpy as np
import eigenpy
dim = 100
A = np.random.rand(dim, dim)
rng = np.random.default_rng()
A = (A + A.T) * 0.5 + np.diag(10.0 + np.random.rand(dim))
A = rng.random((dim, dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + rng.random(dim))
llt = eigenpy.LLT(A)
L = llt.matrixL()
assert eigenpy.is_approx(L.dot(np.transpose(L)), A)
X = np.random.rand(dim, 20)
X = rng.random((dim, 20))
B = A.dot(X)
X_est = llt.solve(B)
assert eigenpy.is_approx(X, X_est)
......
import eigenpy
import numpy as np
import eigenpy
dim = 100
rng = np.random.default_rng()
A = np.eye(dim)
minres = eigenpy.MINRES(A)
X = np.random.rand(dim, 20)
X = rng.random((dim, 20))
B = A.dot(X)
X_est = minres.solve(B)
print("A.dot(X_est):", A.dot(X_est))
......
import numpy as np
import eigenpy
rows = 20
cols = 100
rng = np.random.default_rng()
A = rng.random((rows, cols))
# Test HouseholderQR decomposition
householder_qr = eigenpy.HouseholderQR()
householder_qr = eigenpy.HouseholderQR(rows, cols)
householder_qr = eigenpy.HouseholderQR(A)
householder_qr_eye = eigenpy.HouseholderQR(np.eye(rows, rows))
X = rng.random((rows, 20))
assert householder_qr_eye.absDeterminant() == 1.0
assert householder_qr_eye.logAbsDeterminant() == 0.0
Y = householder_qr_eye.solve(X)
assert (X == Y).all()
# Test FullPivHouseholderQR decomposition
fullpiv_householder_qr = eigenpy.FullPivHouseholderQR()
fullpiv_householder_qr = eigenpy.FullPivHouseholderQR(rows, cols)
fullpiv_householder_qr = eigenpy.FullPivHouseholderQR(A)
fullpiv_householder_qr = eigenpy.FullPivHouseholderQR(np.eye(rows, rows))
X = rng.random((rows, 20))
assert fullpiv_householder_qr.absDeterminant() == 1.0
assert fullpiv_householder_qr.logAbsDeterminant() == 0.0
Y = fullpiv_householder_qr.solve(X)
assert (X == Y).all()
assert fullpiv_householder_qr.rank() == rows
fullpiv_householder_qr.setThreshold(1e-8)
assert fullpiv_householder_qr.threshold() == 1e-8
assert eigenpy.is_approx(np.eye(rows, rows), fullpiv_householder_qr.inverse())
# Test ColPivHouseholderQR decomposition
colpiv_householder_qr = eigenpy.ColPivHouseholderQR()
colpiv_householder_qr = eigenpy.ColPivHouseholderQR(rows, cols)
colpiv_householder_qr = eigenpy.ColPivHouseholderQR(A)
colpiv_householder_qr = eigenpy.ColPivHouseholderQR(np.eye(rows, rows))
X = rng.random((rows, 20))
assert colpiv_householder_qr.absDeterminant() == 1.0
assert colpiv_householder_qr.logAbsDeterminant() == 0.0
Y = colpiv_householder_qr.solve(X)
assert (X == Y).all()
assert colpiv_householder_qr.rank() == rows
colpiv_householder_qr.setThreshold(1e-8)
assert colpiv_householder_qr.threshold() == 1e-8
assert eigenpy.is_approx(np.eye(rows, rows), colpiv_householder_qr.inverse())
# Test CompleteOrthogonalDecomposition
cod = eigenpy.CompleteOrthogonalDecomposition()
cod = eigenpy.CompleteOrthogonalDecomposition(rows, cols)
cod = eigenpy.CompleteOrthogonalDecomposition(A)
cod = eigenpy.CompleteOrthogonalDecomposition(np.eye(rows, rows))
X = rng.random((rows, 20))
assert cod.absDeterminant() == 1.0
assert cod.logAbsDeterminant() == 0.0
Y = cod.solve(X)
assert (X == Y).all()
assert cod.rank() == rows
cod.setThreshold(1e-8)
assert cod.threshold() == 1e-8
assert eigenpy.is_approx(np.eye(rows, rows), cod.pseudoInverse())
import bind_virtual_factory as bvf
class ImplClass(bvf.MyVirtualClass):
def __init__(self):
self.val = 42
bvf.MyVirtualClass.__init__(self)
def createData(self):
return ImplData(self)
# override MyVirtualClass::doSomethingPtr(shared_ptr data)
def doSomethingPtr(self, data):
print("Hello from doSomething!")
assert isinstance(data, ImplData)
print("Data value:", data.value)
data.value += 1
# override MyVirtualClass::doSomethingPtr(data&)
def doSomethingRef(self, data):
print("Hello from doSomethingRef!")
print(type(data))
assert isinstance(data, ImplData)
print("Data value:", data.value)
data.value += 1
class ImplData(bvf.MyVirtualData):
def __init__(self, c):
# parent virtual class requires arg
bvf.MyVirtualData.__init__(self, c)
self.value = c.val
def test_instantiate_child():
obj = ImplClass()
data = obj.createData()
print(data)
def test_call_do_something_ptr():
obj = ImplClass()
print("Calling doSomething (by ptr)")
d1 = bvf.callDoSomethingPtr(obj)
print("Output data.value:", d1.value)
def test_call_do_something_ref():
obj = ImplClass()
print("Ref variant:")
d2 = bvf.callDoSomethingRef(obj)
print(d2.value)
print("-----")
def test_iden_fns():
obj = ImplClass()
d = obj.createData()
print(d, type(d))
# take and return const T&
d1 = bvf.iden_ref(d)
print(d1, type(d1))
assert isinstance(d1, ImplData)
# take a shared_ptr, return const T&
d2 = bvf.iden_shared(d)
assert isinstance(d2, ImplData)
print(d2, type(d2))
print("copy shared ptr -> py -> cpp")
d3 = bvf.copy_shared(d)
assert isinstance(d3, ImplData)
print(d3, type(d3))
test_instantiate_child()
test_call_do_something_ptr()
test_call_do_something_ref()
test_iden_fns()
from __future__ import print_function
import numpy as np
from complex import switchToNumpyArray, real, imag, ascomplex
switchToNumpyArray()
from complex import ascomplex, imag, real
rows = 10
cols = 20
rng = np.random.default_rng()
def test(dtype):
Z = np.zeros((rows, cols), dtype=dtype)
Z.real = np.random.rand(rows, cols)
Z.imag = np.random.rand(rows, cols)
Z.real = rng.random((rows, cols))
Z.imag = rng.random((rows, cols))
Z_real = real(Z)
assert (Z_real == Z.real).all()
......
from deprecation_policy import (
X,
some_deprecated_function,
some_future_deprecated_function,
)
some_deprecated_function()
some_future_deprecated_function()
X().deprecated_member_function()
from __future__ import print_function
import eigenpy
quat = eigenpy.Quaternion()
# By default, we convert as numpy.matrix
eigenpy.switchToNumpyMatrix()
coeffs_vector = quat.coeffs()
assert len(coeffs_vector.shape) == 2
# Switch to numpy.array
eigenpy.switchToNumpyArray()
coeffs_vector = quat.coeffs()
assert len(coeffs_vector.shape) == 1