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 2287 additions and 522 deletions
/*
* Copyright 2024 INRIA
*/
#ifndef __eigenpy_scipy_type_hpp__
#define __eigenpy_scipy_type_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/register.hpp"
#include "eigenpy/scalar-conversion.hpp"
#include "eigenpy/numpy-type.hpp"
namespace eigenpy {
struct EIGENPY_DLLAPI ScipyType {
static ScipyType& getInstance();
static void sharedMemory(const bool value);
static bool sharedMemory();
static bp::object getScipyType();
static const PyTypeObject* getScipyCSRMatrixType();
static const PyTypeObject* getScipyCSCMatrixType();
template <typename SparseMatrix>
static bp::object get_pytype_object(
const Eigen::SparseMatrixBase<SparseMatrix>* ptr = nullptr) {
EIGENPY_UNUSED_VARIABLE(ptr);
return SparseMatrix::IsRowMajor ? getInstance().csr_matrix_obj
: getInstance().csc_matrix_obj;
}
template <typename SparseMatrix>
static PyTypeObject const* get_pytype(
const Eigen::SparseMatrixBase<SparseMatrix>* ptr = nullptr) {
EIGENPY_UNUSED_VARIABLE(ptr);
return SparseMatrix::IsRowMajor ? getInstance().csr_matrix_type
: getInstance().csc_matrix_type;
}
static int get_numpy_type_num(const bp::object& obj) {
const PyTypeObject* type = Py_TYPE(obj.ptr());
EIGENPY_USED_VARIABLE_ONLY_IN_DEBUG_MODE(type);
assert(type == getInstance().csr_matrix_type ||
type == getInstance().csc_matrix_type);
bp::object dtype = obj.attr("dtype");
const PyArray_Descr* npy_type =
reinterpret_cast<PyArray_Descr*>(dtype.ptr());
return npy_type->type_num;
}
protected:
ScipyType();
bp::object sparse_module;
// SciPy types
bp::object csr_matrix_obj, csc_matrix_obj;
PyTypeObject *csr_matrix_type, *csc_matrix_type;
bool shared_memory;
};
} // namespace eigenpy
#endif // ifndef __eigenpy_scipy_type_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
* Copyright 2024 Inria
*/
#ifndef __eigenpy_bfgs_preconditioners_hpp__
#define __eigenpy_bfgs_preconditioners_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/IterativeLinearSolvers>
#include "eigenpy/fwd.hpp"
#include "eigenpy/solvers/BasicPreconditioners.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename Preconditioner>
struct BFGSPreconditionerBaseVisitor
: public bp::def_visitor< BFGSPreconditionerBaseVisitor<Preconditioner> >
{
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(PreconditionerBaseVisitor<Preconditioner>())
.def("rows",&Preconditioner::rows,"Returns the number of rows in the preconditioner.")
.def("cols",&Preconditioner::cols,"Returns the number of cols in the preconditioner.")
.def("dim",&Preconditioner::dim,"Returns the dimension of the BFGS preconditioner")
.def("update",(const Preconditioner& (Preconditioner::*)(const VectorType &, const VectorType &) const)&Preconditioner::update,bp::args("s","y"),"Update the BFGS estimate of the matrix A.",bp::return_value_policy<bp::reference_existing_object>())
.def("reset",&Preconditioner::reset,"Reset the BFGS estimate.")
;
}
static void expose(const std::string & name)
{
bp::class_<Preconditioner>(name,
bp::no_init)
.def(BFGSPreconditionerBaseVisitor<Preconditioner>())
;
}
};
template<typename Preconditioner>
struct LimitedBFGSPreconditionerBaseVisitor
: public bp::def_visitor< LimitedBFGSPreconditionerBaseVisitor<Preconditioner> >
{
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(PreconditionerBaseVisitor<Preconditioner>())
.def(BFGSPreconditionerBaseVisitor<Preconditioner>())
.def("resize",&Preconditioner::resize,bp::arg("dim"),"Resizes the preconditionner with size dim.",bp::return_value_policy<bp::reference_existing_object>())
;
}
static void expose(const std::string & name)
{
bp::class_<Preconditioner>(name.c_str(),
bp::no_init)
.def(LimitedBFGSPreconditionerBaseVisitor<Preconditioner>())
;
}
};
} // namespace eigenpy
namespace eigenpy {
#endif // ifndef __eigenpy_bfgs_preconditioners_hpp__
template <typename Preconditioner>
struct BFGSPreconditionerBaseVisitor
: public bp::def_visitor<BFGSPreconditionerBaseVisitor<Preconditioner> > {
typedef Eigen::VectorXd VectorType;
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(PreconditionerBaseVisitor<Preconditioner>())
.def("rows", &Preconditioner::rows,
"Returns the number of rows in the preconditioner.")
.def("cols", &Preconditioner::cols,
"Returns the number of cols in the preconditioner.")
.def("dim", &Preconditioner::dim,
"Returns the dimension of the BFGS preconditioner")
.def("update",
(const Preconditioner& (Preconditioner::*)(const VectorType&,
const VectorType&)
const) &
Preconditioner::update,
bp::args("s", "y"), "Update the BFGS estimate of the matrix A.",
bp::return_value_policy<bp::reference_existing_object>())
.def("reset", &Preconditioner::reset, "Reset the BFGS estimate.");
}
static void expose(const std::string& name) {
bp::class_<Preconditioner>(name, bp::no_init)
.def(IdVisitor<Preconditioner>())
.def(BFGSPreconditionerBaseVisitor<Preconditioner>());
}
};
template <typename Preconditioner>
struct LimitedBFGSPreconditionerBaseVisitor
: public bp::def_visitor<
LimitedBFGSPreconditionerBaseVisitor<Preconditioner> > {
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(PreconditionerBaseVisitor<Preconditioner>())
.def(BFGSPreconditionerBaseVisitor<Preconditioner>())
.def("resize", &Preconditioner::resize, bp::arg("dim"),
"Resizes the preconditionner with size dim.",
bp::return_value_policy<bp::reference_existing_object>());
}
static void expose(const std::string& name) {
bp::class_<Preconditioner>(name.c_str(), bp::no_init)
.def(IdVisitor<Preconditioner>())
.def(LimitedBFGSPreconditionerBaseVisitor<Preconditioner>());
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_bfgs_preconditioners_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
* Copyright 2024 Inria
*/
#ifndef __eigenpy_basic_preconditioners_hpp__
#define __eigenpy_basic_preconditioners_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include <Eigen/IterativeLinearSolvers>
namespace eigenpy
{
namespace bp = boost::python;
template<typename Preconditioner>
struct PreconditionerBaseVisitor
: public bp::def_visitor< PreconditionerBaseVisitor<Preconditioner> >
{
typedef Eigen::MatrixXd MatrixType;
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::arg("A"),"Initialize the preconditioner with matrix A for further Az=b solving."))
#if EIGEN_VERSION_AT_LEAST(3,3,0)
.def("info",&Preconditioner::info,
"Returns success if the Preconditioner has been well initialized.")
#include "eigenpy/fwd.hpp"
namespace eigenpy {
template <typename Preconditioner>
struct PreconditionerBaseVisitor
: public bp::def_visitor<PreconditionerBaseVisitor<Preconditioner> > {
typedef Eigen::MatrixXd MatrixType;
typedef Eigen::VectorXd VectorType;
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::args("self", "A"),
"Initialize the preconditioner with matrix A "
"for further Az=b solving."))
#if EIGEN_VERSION_AT_LEAST(3, 3, 0)
.def("info", &Preconditioner::info,
"Returns success if the Preconditioner has been well initialized.")
#endif
.def("solve",&solve,bp::arg("b"),
"Returns the solution A * z = b where the preconditioner is an estimate of A^-1.")
.def("compute",&Preconditioner::template compute<MatrixType>,bp::arg("mat"),
"Initialize the preconditioner from the matrix value.",
bp::return_value_policy<bp::reference_existing_object>())
.def("factorize",&Preconditioner::template factorize<MatrixType>,bp::arg("mat"),
"Initialize the preconditioner from the matrix value, i.e factorize the mat given as input to approximate its inverse.",
bp::return_value_policy<bp::reference_existing_object>())
;
}
private:
static VectorType solve(Preconditioner & self, const VectorType & b)
{
return self.solve(b);
}
};
template<typename Scalar>
struct DiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar> >
{
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
typedef Eigen::DiagonalPreconditioner<Scalar> Preconditioner;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(PreconditionerBaseVisitor<Preconditioner>())
.def("rows",&Preconditioner::rows,"Returns the number of rows in the preconditioner.")
.def("cols",&Preconditioner::cols,"Returns the number of cols in the preconditioner.")
;
}
static void expose()
{
bp::class_<Preconditioner>("DiagonalPreconditioner",
"A preconditioner based on the digonal entrie.\n"
"This class allows to approximately solve for A.x = b problems assuming A is a diagonal matrix.",
bp::no_init)
;
}
};
#if EIGEN_VERSION_AT_LEAST(3,3,5)
template<typename Scalar>
struct LeastSquareDiagonalPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::LeastSquareDiagonalPreconditioner<Scalar> >
{
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> MatrixType;
typedef Eigen::LeastSquareDiagonalPreconditioner<Scalar> Preconditioner;
template<class PyClass>
void visit(PyClass&) const
{
}
static void expose()
{
bp::class_<Preconditioner>("LeastSquareDiagonalPreconditioner",
"Jacobi preconditioner for LeastSquaresConjugateGradient.\n"
"his class allows to approximately solve for A' A x = A' b problems assuming A' A is a diagonal matrix.",
bp::no_init)
.def(DiagonalPreconditionerVisitor<Scalar>())
;
}
};
.def("solve", &solve, bp::arg("b"),
"Returns the solution A * z = b where the preconditioner is an "
"estimate of A^-1.")
.def("compute", &Preconditioner::template compute<MatrixType>,
bp::arg("mat"),
"Initialize the preconditioner from the matrix value.",
bp::return_value_policy<bp::reference_existing_object>())
.def("factorize", &Preconditioner::template factorize<MatrixType>,
bp::arg("mat"),
"Initialize the preconditioner from the matrix value, i.e "
"factorize the mat given as input to approximate its inverse.",
bp::return_value_policy<bp::reference_existing_object>());
}
private:
static VectorType solve(Preconditioner& self, const VectorType& b) {
return self.solve(b);
}
};
template <typename Scalar>
struct DiagonalPreconditionerVisitor
: PreconditionerBaseVisitor<Eigen::DiagonalPreconditioner<Scalar> > {
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
typedef Eigen::DiagonalPreconditioner<Scalar> Preconditioner;
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(PreconditionerBaseVisitor<Preconditioner>())
.def("rows", &Preconditioner::rows,
"Returns the number of rows in the preconditioner.")
.def("cols", &Preconditioner::cols,
"Returns the number of cols in the preconditioner.");
}
static void expose() {
bp::class_<Preconditioner>(
"DiagonalPreconditioner",
"A preconditioner based on the digonal entrie.\n"
"This class allows to approximately solve for A.x = b problems "
"assuming A is a diagonal matrix.",
bp::no_init)
.def(IdVisitor<Preconditioner>());
}
};
#if EIGEN_VERSION_AT_LEAST(3, 3, 5)
template <typename Scalar>
struct LeastSquareDiagonalPreconditionerVisitor
: PreconditionerBaseVisitor<
Eigen::LeastSquareDiagonalPreconditioner<Scalar> > {
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> MatrixType;
typedef Eigen::LeastSquareDiagonalPreconditioner<Scalar> Preconditioner;
template <class PyClass>
void visit(PyClass&) const {}
static void expose() {
bp::class_<Preconditioner>(
"LeastSquareDiagonalPreconditioner",
"Jacobi preconditioner for LeastSquaresConjugateGradient.\n"
"his class allows to approximately solve for A' A x = A' b problems "
"assuming A' A is a diagonal matrix.",
bp::no_init)
.def(DiagonalPreconditionerVisitor<Scalar>())
.def(IdVisitor<Preconditioner>());
}
};
#endif
struct IdentityPreconditionerVisitor : PreconditionerBaseVisitor<Eigen::IdentityPreconditioner >
{
typedef Eigen::IdentityPreconditioner Preconditioner;
template<class PyClass>
void visit(PyClass&) const
{
}
static void expose()
{
bp::class_<Preconditioner>("IdentityPreconditioner",
bp::no_init)
.def(PreconditionerBaseVisitor<Preconditioner>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_basic_preconditioners_hpp__
struct IdentityPreconditionerVisitor
: PreconditionerBaseVisitor<Eigen::IdentityPreconditioner> {
typedef Eigen::IdentityPreconditioner Preconditioner;
template <class PyClass>
void visit(PyClass&) const {}
static void expose() {
bp::class_<Preconditioner>("IdentityPreconditioner", bp::no_init)
.def(PreconditionerBaseVisitor<Preconditioner>())
.def(IdVisitor<Preconditioner>());
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_basic_preconditioners_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_conjugate_gradient_hpp__
#define __eigenpy_conjugate_gradient_hpp__
#include <boost/python.hpp>
#include <Eigen/IterativeLinearSolvers>
#include "eigenpy/fwd.hpp"
#include "eigenpy/solvers/IterativeSolverBase.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename ConjugateGradient>
struct ConjugateGradientVisitor
: public boost::python::def_visitor< ConjugateGradientVisitor<ConjugateGradient> >
{
typedef typename ConjugateGradient::MatrixType MatrixType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(IterativeSolverVisitor<ConjugateGradient>())
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::arg("A"),"Initialize the solver with matrix A for further Ax=b solving.\n"
"This constructor is a shortcut for the default constructor followed by a call to compute()."))
;
}
static void expose(const std::string & name = "ConjugateGradient")
{
bp::class_<ConjugateGradient,boost::noncopyable>(name.c_str(),
bp::no_init)
.def(ConjugateGradientVisitor<ConjugateGradient>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_conjugate_gradient_hpp__
namespace eigenpy {
template <typename ConjugateGradient>
struct ConjugateGradientVisitor
: public boost::python::def_visitor<
ConjugateGradientVisitor<ConjugateGradient> > {
typedef typename ConjugateGradient::MatrixType MatrixType;
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(IterativeSolverVisitor<ConjugateGradient>())
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(
bp::arg("A"),
"Initialize the solver with matrix A for further Ax=b solving.\n"
"This constructor is a shortcut for the default constructor "
"followed by a call to compute()."));
}
static void expose(const std::string& name = "ConjugateGradient") {
bp::class_<ConjugateGradient, boost::noncopyable>(name.c_str(), bp::no_init)
.def(ConjugateGradientVisitor<ConjugateGradient>())
.def(IdVisitor<ConjugateGradient>());
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_conjugate_gradient_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_iterative_solver_base_hpp__
#define __eigenpy_iterative_solver_base_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
#include "eigenpy/fwd.hpp"
#include "eigenpy/solvers/SparseSolverBase.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename IterativeSolver>
struct IterativeSolverVisitor
: public boost::python::def_visitor< IterativeSolverVisitor<IterativeSolver> >
{
typedef typename IterativeSolver::MatrixType MatrixType;
typedef typename IterativeSolver::Preconditioner Preconditioner;
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
typedef IterativeSolver IS;
cl
.def(SparseSolverVisitor<IS>())
.def("error",&IS::error,"Returns the tolerance error reached during the last solve.\n"
"It is a close approximation of the true relative residual error |Ax-b|/|b|.")
.def("info",&IS::info,"Returns success if the iterations converged, and NoConvergence otherwise.")
.def("iterations",&IS::iterations,"Returns the number of iterations performed during the last solve.")
.def("maxIterations",&IS::maxIterations,"Returns the max number of iterations.\n"
"It is either the value setted by setMaxIterations or, by default, twice the number of columns of the matrix.")
.def("setMaxIterations",&IS::setMaxIterations,"Sets the max number of iterations.\n"
"Default is twice the number of columns of the matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("tolerance",&IS::tolerance,"Returns he tolerance threshold used by the stopping criteria.")
.def("setTolerance",&IS::setTolerance,"Sets the tolerance threshold used by the stopping criteria.\n"
"This value is used as an upper bound to the relative residual error: |Ax-b|/|b|. The default value is the machine precision.",
bp::return_value_policy<bp::reference_existing_object>())
.def("analyzePattern",&analyzePattern,bp::arg("A"),"Initializes the iterative solver for the sparsity pattern of the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls analyzePattern on the preconditioner.\n"
"In the future we might, for instance, implement column reordering for faster matrix vector products.",
bp::return_value_policy<bp::reference_existing_object>())
.def("factorize",&factorize,bp::arg("A"),"Initializes the iterative solver with the numerical values of the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls factorize on the preconditioner.",
bp::return_value_policy<bp::reference_existing_object>())
.def("compute",&compute,bp::arg("A"),"Initializes the iterative solver with the numerical values of the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls factorize on the preconditioner.\n"
"In the future we might, for instance, implement column reordering for faster matrix vector products.",
bp::return_value_policy<bp::reference_existing_object>())
.def("solveWithGuess",&solveWithGuess,bp::args("b","x0"),
"Returns the solution x of Ax = b using the current decomposition of A and x0 as an initial solution.")
.def("preconditioner",(Preconditioner & (IS::*)(void))&IS::preconditioner,"Returns a read-write reference to the preconditioner for custom configuration.",bp::return_internal_reference<>())
;
}
private:
static IterativeSolver & factorize(IterativeSolver & self, const MatrixType & m)
{
return self.factorize(m);
}
static IterativeSolver & compute(IterativeSolver & self, const MatrixType & m)
{
return self.compute(m);
}
static IterativeSolver & analyzePattern(IterativeSolver & self, const MatrixType & m)
{
return self.analyzePattern(m);
}
static VectorType solveWithGuess(IterativeSolver & self, const Eigen::VectorXd & b, const Eigen::VectorXd & x0)
{
return self.solveWithGuess(b,x0);
}
};
namespace eigenpy {
template <typename IterativeSolver>
struct IterativeSolverVisitor : public boost::python::def_visitor<
IterativeSolverVisitor<IterativeSolver> > {
typedef typename IterativeSolver::MatrixType MatrixType;
typedef typename IterativeSolver::Preconditioner Preconditioner;
typedef Eigen::VectorXd VectorType;
template <class PyClass>
void visit(PyClass& cl) const {
typedef IterativeSolver IS;
cl.def(SparseSolverVisitor<IS>())
.def("error", &IS::error,
"Returns the tolerance error reached during the last solve.\n"
"It is a close approximation of the true relative residual error "
"|Ax-b|/|b|.")
.def("info", &IS::info,
"Returns success if the iterations converged, and NoConvergence "
"otherwise.")
.def(
"iterations", &IS::iterations,
"Returns the number of iterations performed during the last solve.")
.def("maxIterations", &IS::maxIterations,
"Returns the max number of iterations.\n"
"It is either the value setted by setMaxIterations or, by "
"default, twice the number of columns of the matrix.")
.def("setMaxIterations", &IS::setMaxIterations,
"Sets the max number of iterations.\n"
"Default is twice the number of columns of the matrix.",
bp::return_value_policy<bp::reference_existing_object>())
.def("tolerance", &IS::tolerance,
"Returns he tolerance threshold used by the stopping criteria.")
.def("setTolerance", &IS::setTolerance,
"Sets the tolerance threshold used by the stopping criteria.\n"
"This value is used as an upper bound to the relative residual "
"error: |Ax-b|/|b|. The default value is the machine precision.",
bp::return_value_policy<bp::reference_existing_object>())
.def("analyzePattern", &analyzePattern, bp::arg("A"),
"Initializes the iterative solver for the sparsity pattern of the "
"matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls analyzePattern on the "
"preconditioner.\n"
"In the future we might, for instance, implement column "
"reordering for faster matrix vector products.",
bp::return_value_policy<bp::reference_existing_object>())
.def("factorize", &factorize, bp::arg("A"),
"Initializes the iterative solver with the numerical values of "
"the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls factorize on the "
"preconditioner.",
bp::return_value_policy<bp::reference_existing_object>())
.def("compute", &compute, bp::arg("A"),
"Initializes the iterative solver with the numerical values of "
"the matrix A for further solving Ax=b problems.\n"
"Currently, this function mostly calls factorize on the "
"preconditioner.\n"
"In the future we might, for instance, implement column "
"reordering for faster matrix vector products.",
bp::return_value_policy<bp::reference_existing_object>())
.def("solveWithGuess", &solveWithGuess, bp::args("b", "x0"),
"Returns the solution x of Ax = b using the current decomposition "
"of A and x0 as an initial solution.")
.def("preconditioner",
(Preconditioner & (IS::*)(void)) & IS::preconditioner,
"Returns a read-write reference to the preconditioner for custom "
"configuration.",
bp::return_internal_reference<>());
}
private:
static IterativeSolver& factorize(IterativeSolver& self,
const MatrixType& m) {
return self.factorize(m);
}
static IterativeSolver& compute(IterativeSolver& self, const MatrixType& m) {
return self.compute(m);
}
static IterativeSolver& analyzePattern(IterativeSolver& self,
const MatrixType& m) {
return self.analyzePattern(m);
}
static VectorType solveWithGuess(IterativeSolver& self,
const Eigen::VectorXd& b,
const Eigen::VectorXd& x0) {
return self.solveWithGuess(b, x0);
}
};
} // namespace eigenpy
} // namespace eigenpy
#endif // ifndef __eigenpy_iterative_solver_base_hpp__
#endif // ifndef __eigenpy_iterative_solver_base_hpp__
/*
* Copyright 2017-2018, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017-2018 CNRS
*/
#ifndef __eigenpy_least_square_conjugate_gradient_hpp__
#define __eigenpy_least_square_conjugate_gradient_hpp__
#include <boost/python.hpp>
#include <Eigen/IterativeLinearSolvers>
#include "eigenpy/fwd.hpp"
#include "eigenpy/solvers/IterativeSolverBase.hpp"
namespace eigenpy
{
namespace bp = boost::python;
template<typename LeastSquaresConjugateGradient>
struct LeastSquaresConjugateGradientVisitor
: public boost::python::def_visitor< LeastSquaresConjugateGradientVisitor<LeastSquaresConjugateGradient> >
{
typedef Eigen::MatrixXd MatrixType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(bp::arg("A"),"Initialize the solver with matrix A for further || Ax - b || solving.\n"
"This constructor is a shortcut for the default constructor followed by a call to compute()."))
;
}
static void expose()
{
bp::class_<LeastSquaresConjugateGradient,boost::noncopyable>("LeastSquaresConjugateGradient",
bp::no_init)
.def(IterativeSolverVisitor<LeastSquaresConjugateGradient>())
.def(LeastSquaresConjugateGradientVisitor<LeastSquaresConjugateGradient>())
;
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_least_square_conjugate_gradient_hpp__
namespace eigenpy {
template <typename LeastSquaresConjugateGradient>
struct LeastSquaresConjugateGradientVisitor
: public boost::python::def_visitor<LeastSquaresConjugateGradientVisitor<
LeastSquaresConjugateGradient> > {
typedef Eigen::MatrixXd MatrixType;
template <class PyClass>
void visit(PyClass& cl) const {
cl.def(bp::init<>("Default constructor"))
.def(bp::init<MatrixType>(
bp::arg("A"),
"Initialize the solver with matrix A for further || Ax - b || "
"solving.\n"
"This constructor is a shortcut for the default constructor "
"followed by a call to compute()."));
}
static void expose() {
bp::class_<LeastSquaresConjugateGradient, boost::noncopyable>(
"LeastSquaresConjugateGradient", bp::no_init)
.def(IterativeSolverVisitor<LeastSquaresConjugateGradient>())
.def(LeastSquaresConjugateGradientVisitor<
LeastSquaresConjugateGradient>())
.def(IdVisitor<LeastSquaresConjugateGradient>());
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_least_square_conjugate_gradient_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_sparse_solver_base_hpp__
#define __eigenpy_sparse_solver_base_hpp__
#include <boost/python.hpp>
#include <Eigen/Core>
namespace eigenpy
{
namespace bp = boost::python;
template<typename SparseSolver>
struct SparseSolverVisitor
: public bp::def_visitor< SparseSolverVisitor<SparseSolver> >
{
typedef Eigen::VectorXd VectorType;
template<class PyClass>
void visit(PyClass& cl) const
{
cl
.def("solve",&solve,bp::arg("b"),
"Returns the solution x of Ax = b using the current decomposition of A.")
;
}
private:
static VectorType solve(SparseSolver & self, const VectorType & b)
{
return self.solve(b);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_sparse_solver_base_hpp__
#include "eigenpy/fwd.hpp"
namespace eigenpy {
template <typename SparseSolver>
struct SparseSolverVisitor
: public bp::def_visitor<SparseSolverVisitor<SparseSolver> > {
typedef Eigen::VectorXd VectorType;
template <class PyClass>
void visit(PyClass& cl) const {
cl.def("solve", &solve, bp::arg("b"),
"Returns the solution x of Ax = b using the current decomposition "
"of A.");
}
private:
static VectorType solve(SparseSolver& self, const VectorType& b) {
return self.solve(b);
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_sparse_solver_base_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017 CNRS
*/
#ifndef __eigenpy_preconditioners_hpp__
#define __eigenpy_preconditioners_hpp__
#include "eigenpy/eigenpy_export.h"
#include "eigenpy/config.hpp"
namespace eigenpy
{
void EIGENPY_EXPORT exposePreconditioners();
} // namespace eigenpy
namespace eigenpy {
#endif // define __eigenpy_preconditioners_hpp__
void EIGENPY_DLLAPI exposePreconditioners();
} // namespace eigenpy
#endif // define __eigenpy_preconditioners_hpp__
/*
* Copyright 2017, Justin Carpentier, LAAS-CNRS
*
* This file is part of eigenpy.
* eigenpy is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* eigenpy is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with eigenpy. If not, see <http://www.gnu.org/licenses/>.
* Copyright 2017-2020 CNRS INRIA
*/
#ifndef __eigenpy_solvers_hpp__
#define __eigenpy_solvers_hpp__
#include "eigenpy/eigenpy_export.h"
#include "eigenpy/config.hpp"
namespace eigenpy
{
struct SolversScope {};
void EIGENPY_EXPORT exposeSolvers();
} // namespace eigenpy
namespace eigenpy {
struct SolversScope {};
#endif // define __eigenpy_solvers_hpp__
void EIGENPY_DLLAPI exposeSolvers();
} // namespace eigenpy
#endif // define __eigenpy_solvers_hpp__
//
// Copyright (c) 2024 INRIA
//
#ifndef __eigenpy_sparse_eigen_from_python_hpp__
#define __eigenpy_sparse_eigen_from_python_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-allocator.hpp"
#include "eigenpy/scipy-type.hpp"
#include "eigenpy/scalar-conversion.hpp"
namespace eigenpy {
template <typename SparseMatrixType>
struct expected_pytype_for_arg<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType> > {
static PyTypeObject const *get_pytype() {
PyTypeObject const *py_type = ScipyType::get_pytype<SparseMatrixType>();
return py_type;
}
};
} // namespace eigenpy
namespace boost {
namespace python {
namespace converter {
template <typename Scalar, int Options, typename StorageIndex>
struct expected_pytype_for_arg<
Eigen::SparseMatrix<Scalar, Options, StorageIndex> >
: eigenpy::expected_pytype_for_arg<
Eigen::SparseMatrix<Scalar, Options, StorageIndex> > {};
template <typename Scalar, int Options, typename StorageIndex>
struct rvalue_from_python_data<
Eigen::SparseMatrix<Scalar, Options, StorageIndex> const &>
: ::eigenpy::rvalue_from_python_data<
Eigen::SparseMatrix<Scalar, Options, StorageIndex> const &> {
typedef Eigen::SparseMatrix<Scalar, Options, StorageIndex> T;
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(T const &)
};
template <typename Derived>
struct rvalue_from_python_data<Eigen::SparseMatrixBase<Derived> const &>
: ::eigenpy::rvalue_from_python_data<Derived const &> {
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
};
} // namespace converter
} // namespace python
} // namespace boost
namespace boost {
namespace python {
namespace detail {
// template <typename TensorType>
// struct referent_storage<Eigen::TensorRef<TensorType> &> {
// typedef Eigen::TensorRef<TensorType> RefType;
// typedef ::eigenpy::details::referent_storage_eigen_ref<RefType>
// StorageType; typedef typename ::eigenpy::aligned_storage<
// referent_size<StorageType &>::value>::type type;
// };
// template <typename TensorType>
// struct referent_storage<const Eigen::TensorRef<const TensorType> &> {
// typedef Eigen::TensorRef<const TensorType> RefType;
// typedef ::eigenpy::details::referent_storage_eigen_ref<RefType>
// StorageType; typedef typename ::eigenpy::aligned_storage<
// referent_size<StorageType &>::value>::type type;
// };
} // namespace detail
} // namespace python
} // namespace boost
namespace eigenpy {
template <typename SparseMatrixType>
struct eigen_from_py_impl<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType> > {
typedef typename SparseMatrixType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void *convertible(PyObject *pyObj);
/// \brief Allocate memory and copy pyObj in the new storage
static void construct(PyObject *pyObj,
bp::converter::rvalue_from_python_stage1_data *memory);
static void registration();
};
template <typename SparseMatrixType>
void *eigen_from_py_impl<
SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType> >::convertible(PyObject *pyObj) {
const PyTypeObject *type = Py_TYPE(pyObj);
const PyTypeObject *sparse_matrix_py_type =
ScipyType::get_pytype<SparseMatrixType>();
typedef typename SparseMatrixType::Scalar Scalar;
if (type != sparse_matrix_py_type) return 0;
bp::object obj(bp::handle<>(bp::borrowed(pyObj)));
const int type_num = ScipyType::get_numpy_type_num(obj);
if (!np_type_is_convertible_into_scalar<Scalar>(type_num)) return 0;
return pyObj;
}
template <typename MatOrRefType>
void eigen_sparse_matrix_from_py_construct(
PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory) {
typedef typename MatOrRefType::Scalar Scalar;
typedef typename MatOrRefType::StorageIndex StorageIndex;
typedef Eigen::Map<MatOrRefType> MapMatOrRefType;
bp::converter::rvalue_from_python_storage<MatOrRefType> *storage =
reinterpret_cast<
bp::converter::rvalue_from_python_storage<MatOrRefType> *>(
reinterpret_cast<void *>(memory));
void *raw_ptr = storage->storage.bytes;
bp::object obj(bp::handle<>(bp::borrowed(pyObj)));
const int type_num_python_sparse_matrix = ScipyType::get_numpy_type_num(obj);
const int type_num_eigen_sparse_matrix = Register::getTypeCode<Scalar>();
if (type_num_eigen_sparse_matrix == type_num_python_sparse_matrix) {
typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> DataVector;
// typedef const Eigen::Ref<const DataVector> RefDataVector;
DataVector data = bp::extract<DataVector>(obj.attr("data"));
bp::tuple shape = bp::extract<bp::tuple>(obj.attr("shape"));
typedef Eigen::Matrix<StorageIndex, Eigen::Dynamic, 1> StorageIndexVector;
// typedef const Eigen::Ref<const StorageIndexVector>
// RefStorageIndexVector;
StorageIndexVector indices =
bp::extract<StorageIndexVector>(obj.attr("indices"));
StorageIndexVector indptr =
bp::extract<StorageIndexVector>(obj.attr("indptr"));
const Eigen::Index m = bp::extract<Eigen::Index>(shape[0]),
n = bp::extract<Eigen::Index>(shape[1]),
nnz = bp::extract<Eigen::Index>(obj.attr("nnz"));
// Handle the specific case of the null matrix
Scalar *data_ptr = nullptr;
StorageIndex *indices_ptr = nullptr;
if (nnz > 0) {
data_ptr = data.data();
indices_ptr = indices.data();
}
MapMatOrRefType sparse_map(m, n, nnz, indptr.data(), indices_ptr, data_ptr);
new (raw_ptr) MatOrRefType(sparse_map);
}
memory->convertible = storage->storage.bytes;
}
template <typename SparseMatrixType>
void eigen_from_py_impl<SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType> >::
construct(PyObject *pyObj,
bp::converter::rvalue_from_python_stage1_data *memory) {
eigen_sparse_matrix_from_py_construct<SparseMatrixType>(pyObj, memory);
}
template <typename SparseMatrixType>
void eigen_from_py_impl<
SparseMatrixType,
Eigen::SparseMatrixBase<SparseMatrixType> >::registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&eigen_from_py_impl::convertible),
&eigen_from_py_impl::construct, bp::type_id<SparseMatrixType>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<SparseMatrixType>::get_pytype
#endif
);
}
template <typename SparseMatrixType>
struct eigen_from_py_converter_impl<
SparseMatrixType, Eigen::SparseMatrixBase<SparseMatrixType> > {
static void registration() {
EigenFromPy<SparseMatrixType>::registration();
// Add conversion to Eigen::SparseMatrixBase<SparseMatrixType>
typedef Eigen::SparseMatrixBase<SparseMatrixType> SparseMatrixBase;
EigenFromPy<SparseMatrixBase>::registration();
// // Add conversion to Eigen::Ref<SparseMatrixType>
// typedef Eigen::Ref<SparseMatrixType> RefType;
// EigenFromPy<SparseMatrixType>::registration();
//
// // Add conversion to Eigen::Ref<const SparseMatrixType>
// typedef const Eigen::Ref<const SparseMatrixType> ConstRefType;
// EigenFromPy<ConstRefType>::registration();
}
};
template <typename SparseMatrixType>
struct EigenFromPy<Eigen::SparseMatrixBase<SparseMatrixType> >
: EigenFromPy<SparseMatrixType> {
typedef EigenFromPy<SparseMatrixType> EigenFromPyDerived;
typedef Eigen::SparseMatrixBase<SparseMatrixType> Base;
static void registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&EigenFromPy::construct, bp::type_id<Base>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<SparseMatrixType>::get_pytype
#endif
);
}
};
//
// template <typename TensorType>
// struct EigenFromPy<Eigen::TensorRef<TensorType> > {
// typedef Eigen::TensorRef<TensorType> RefType;
// typedef typename TensorType::Scalar Scalar;
//
// /// \brief Determine if pyObj can be converted into a MatType object
// static void *convertible(PyObject *pyObj) {
// if (!call_PyArray_Check(pyObj)) return 0;
// PyArrayObject *pyArray = reinterpret_cast<PyArrayObject *>(pyObj);
// if (!PyArray_ISWRITEABLE(pyArray)) return 0;
// return EigenFromPy<TensorType>::convertible(pyObj);
// }
//
// static void registration() {
// bp::converter::registry::push_back(
// reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
// &eigen_from_py_construct<RefType>, bp::type_id<RefType>()
// #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
// ,
// &eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
// #endif
// );
// }
//};
// template <typename TensorType>
// struct EigenFromPy<const Eigen::TensorRef<const TensorType> > {
// typedef const Eigen::TensorRef<const TensorType> ConstRefType;
// typedef typename TensorType::Scalar Scalar;
//
// /// \brief Determine if pyObj can be converted into a MatType object
// static void *convertible(PyObject *pyObj) {
// return EigenFromPy<TensorType>::convertible(pyObj);
// }
//
// static void registration() {
// bp::converter::registry::push_back(
// reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
// &eigen_from_py_construct<ConstRefType>, bp::type_id<ConstRefType>()
// #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
// ,
// &eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
// #endif
// );
// }
// };
} // namespace eigenpy
#endif // __eigenpy_sparse_eigen_from_python_hpp__
///
/// Copyright (c) 2023-2024 CNRS INRIA
///
#ifndef __eigenpy_utils_std_array_hpp__
#define __eigenpy_utils_std_array_hpp__
#include <boost/python/suite/indexing/indexing_suite.hpp>
#include "eigenpy/std-vector.hpp"
#include <array>
namespace eigenpy {
template <typename Container, bool NoProxy, class SliceAllocator,
class DerivedPolicies>
class array_indexing_suite;
namespace details {
template <typename Container, bool NoProxy, class SliceAllocator>
class final_array_derived_policies
: public array_indexing_suite<
Container, NoProxy, SliceAllocator,
final_array_derived_policies<Container, NoProxy, SliceAllocator> > {};
} // namespace details
template <typename Container, bool NoProxy = false,
class SliceAllocator = std::allocator<typename Container::value_type>,
class DerivedPolicies = details::final_array_derived_policies<
Container, NoProxy, SliceAllocator> >
class array_indexing_suite
: public bp::vector_indexing_suite<Container, NoProxy, DerivedPolicies> {
public:
typedef typename Container::value_type data_type;
typedef typename Container::value_type key_type;
typedef typename Container::size_type index_type;
typedef typename Container::size_type size_type;
typedef typename Container::difference_type difference_type;
typedef std::vector<data_type, SliceAllocator> slice_vector_type;
static constexpr std::size_t Size = std::tuple_size<Container>{};
template <class Class>
static void extension_def(Class &) {}
// throws exception
static void delete_item(Container &, index_type) {
PyErr_SetString(PyExc_NotImplementedError,
"Cannot delete item from std::array type.");
bp::throw_error_already_set();
}
// throws exception
static void delete_slice(Container &, index_type, index_type) {
PyErr_SetString(PyExc_NotImplementedError,
"Cannot delete slice from std::array type.");
bp::throw_error_already_set();
}
static void set_slice(Container &container, index_type from, index_type to,
data_type const &v) {
if (from >= to) {
PyErr_SetString(PyExc_NotImplementedError,
"Setting this slice would insert into an std::array, "
"which is not supported.");
bp::throw_error_already_set();
} else {
std::fill(container.begin() + from, container.begin() + to, v);
}
}
template <class Iter>
static void set_slice(Container &container, index_type from, index_type to,
Iter first, Iter last) {
if (from >= to) {
PyErr_SetString(PyExc_NotImplementedError,
"Setting this slice would insert into an std::array, "
"which is not supported.");
bp::throw_error_already_set();
} else {
if (long(to - from) == std::distance(first, last)) {
std::copy(first, last, container.begin() + from);
} else {
PyErr_SetString(PyExc_NotImplementedError,
"Size of std::array slice and size of right-hand side "
"iterator are incompatible.");
bp::throw_error_already_set();
}
}
}
static bp::object get_slice(Container &container, index_type from,
index_type to) {
if (from > to) return bp::object(slice_vector_type());
slice_vector_type out;
for (size_t i = from; i < to; i++) {
out.push_back(container[i]);
}
return bp::object(std::move(out));
}
};
/// \brief Expose an std::array (a C++11 fixed-size array) from a given type
/// \tparam array_type std::array type to expose
/// \tparam NoProxy When set to false, the elements will be copied when
/// returned to Python.
/// \tparam SliceAllocator Allocator type to use for slices of std::array type
/// accessed using e.g. __getitem__[0:4] in Python. These slices are returned as
/// std::vector (dynamic size).
template <typename array_type, bool NoProxy = false,
class SliceAllocator =
std::allocator<typename array_type::value_type> >
struct StdArrayPythonVisitor {
typedef typename array_type::value_type value_type;
static ::boost::python::list tolist(array_type &self, const bool deep_copy) {
return details::build_list<array_type, NoProxy>::run(self, deep_copy);
}
static void expose(const std::string &class_name,
const std::string &doc_string = "") {
expose(class_name, doc_string, EmptyPythonVisitor());
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const bp::def_visitor<DerivedVisitor> &visitor) {
expose(class_name, "", visitor);
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const std::string &doc_string,
const bp::def_visitor<DerivedVisitor> &visitor) {
if (!register_symbolic_link_to_registered_type<array_type>()) {
bp::class_<array_type> cl(class_name.c_str(), doc_string.c_str());
cl.def(bp::init<const array_type &>(bp::args("self", "other"),
"Copy constructor"));
cl.def(IdVisitor<array_type>());
array_indexing_suite<array_type, NoProxy, SliceAllocator> indexing_suite;
cl.def(indexing_suite)
.def(visitor)
.def("tolist", tolist,
(bp::arg("self"), bp::arg("deep_copy") = false),
"Returns the std::array as a Python list.");
}
}
};
/// Exposes std::array<MatrixType, Size>
template <typename MatrixType, std::size_t Size>
void exposeStdArrayEigenSpecificType(const char *name) {
std::ostringstream oss;
oss << "StdArr";
oss << Size << "_" << name;
typedef std::array<MatrixType, Size> array_type;
StdArrayPythonVisitor<array_type, false,
Eigen::aligned_allocator<MatrixType> >::
expose(oss.str(),
details::overload_base_get_item_for_std_vector<array_type>());
}
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_std_array_hpp__
/// Copyright (c) 2024, INRIA
///
#ifndef __eigenpy_std_map_hpp__
#define __eigenpy_std_map_hpp__
#include "eigenpy/map.hpp"
#include "eigenpy/deprecated.hpp"
#include <map>
namespace eigenpy {
template <typename Container>
using overload_base_get_item_for_std_map EIGENPY_DEPRECATED_MESSAGE(
"Use overload_base_get_item_for_map<> instead.") =
overload_base_get_item_for_map<Container>;
namespace details {
using ::eigenpy::overload_base_get_item_for_std_map;
} // namespace details
/**
* @brief Expose an std::map from a type given as template argument.
*
* @param[in] T Type to expose as std::map<T>.
* @param[in] Compare Type for the Compare in std::map<T,Compare,Allocator>.
* @param[in] Allocator Type for the Allocator in
* std::map<T,Compare,Allocator>.
* @param[in] NoProxy When set to false, the elements will be copied when
* returned to Python.
*/
template <class Key, class T, class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >,
bool NoProxy = false>
struct StdMapPythonVisitor
: GenericMapVisitor<std::map<Key, T, Compare, Allocator>, NoProxy> {};
namespace python {
// fix previous mistake
using ::eigenpy::StdMapPythonVisitor;
} // namespace python
} // namespace eigenpy
#endif // ifndef __eigenpy_std_map_hpp__
//
// Copyright (c) 2023 INRIA
//
#ifndef __eigenpy_utils_std_pair_hpp__
#define __eigenpy_utils_std_pair_hpp__
#include <boost/python.hpp>
#include <utility>
namespace eigenpy {
template <typename pair_type>
struct StdPairConverter {
typedef typename pair_type::first_type T1;
typedef typename pair_type::second_type T2;
static PyObject* convert(const pair_type& pair) {
return boost::python::incref(
boost::python::make_tuple(pair.first, pair.second).ptr());
}
static void* convertible(PyObject* obj) {
if (!PyTuple_CheckExact(obj)) return 0;
if (PyTuple_Size(obj) != 2) return 0;
{
boost::python::tuple tuple(boost::python::borrowed(obj));
boost::python::extract<T1> elt1(tuple[0]);
if (!elt1.check()) return 0;
boost::python::extract<T2> elt2(tuple[1]);
if (!elt2.check()) return 0;
}
return obj;
}
static void construct(
PyObject* obj,
boost::python::converter::rvalue_from_python_stage1_data* memory) {
boost::python::tuple tuple(boost::python::borrowed(obj));
void* storage =
reinterpret_cast<
boost::python::converter::rvalue_from_python_storage<pair_type>*>(
reinterpret_cast<void*>(memory))
->storage.bytes;
new (storage) pair_type(boost::python::extract<T1>(tuple[0]),
boost::python::extract<T2>(tuple[1]));
memory->convertible = storage;
}
static PyTypeObject const* get_pytype() {
PyTypeObject const* py_type = &PyTuple_Type;
return py_type;
}
static void registration() {
boost::python::converter::registry::push_back(
&convertible, &construct, boost::python::type_id<pair_type>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
get_pytype
#endif
);
boost::python::to_python_converter<pair_type, StdPairConverter, true>();
}
};
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_std_pair_hpp__
//
// Copyright (c) 2024 INRIA
//
#ifndef __eigenpy_utils_std_unique_ptr_hpp__
#define __eigenpy_utils_std_unique_ptr_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/utils/traits.hpp"
#include "eigenpy/utils/python-compat.hpp"
#include <boost/python.hpp>
#include <memory>
#include <type_traits>
namespace eigenpy {
namespace details {
/// Transfer std::unique_ptr ownership to an owning holder
template <typename T>
typename std::enable_if<!is_python_primitive_type<T>::value, PyObject*>::type
unique_ptr_to_python(std::unique_ptr<T>&& x) {
typedef bp::objects::pointer_holder<std::unique_ptr<T>, T> holder_t;
if (!x) {
return bp::detail::none();
} else {
return bp::objects::make_ptr_instance<T, holder_t>::execute(x);
}
}
/// Convert and copy the primitive value to python
template <typename T>
typename std::enable_if<is_python_primitive_type<T>::value, PyObject*>::type
unique_ptr_to_python(std::unique_ptr<T>&& x) {
if (!x) {
return bp::detail::none();
} else {
return bp::to_python_value<const T&>()(*x);
}
}
/// std::unique_ptr keep the ownership but a reference to the std::unique_ptr
/// value is created
template <typename T>
typename std::enable_if<!is_python_primitive_type<T>::value, PyObject*>::type
internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
if (!x) {
return bp::detail::none();
} else {
return bp::detail::make_reference_holder::execute(x.get());
}
}
/// Convert and copy the primitive value to python
template <typename T>
typename std::enable_if<is_python_primitive_type<T>::value, PyObject*>::type
internal_unique_ptr_to_python(std::unique_ptr<T>& x) {
if (!x) {
return bp::detail::none();
} else {
return bp::to_python_value<const T&>()(*x);
}
}
/// result_converter of StdUniquePtrCallPolicies
struct StdUniquePtrResultConverter {
template <typename T>
struct apply {
struct type {
typedef typename T::element_type element_type;
PyObject* operator()(T&& x) const {
return unique_ptr_to_python(std::forward<T>(x));
}
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
PyTypeObject const* get_pytype() const {
return bp::to_python_value<const element_type&>().get_pytype();
}
#endif
};
};
};
/// result_converter of ReturnInternalStdUniquePtr
struct InternalStdUniquePtrConverter {
template <typename T>
struct apply {
struct type {
typedef typename remove_cvref<T>::type::element_type element_type;
PyObject* operator()(T x) const {
return internal_unique_ptr_to_python(x);
}
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
PyTypeObject const* get_pytype() const {
return bp::to_python_value<const element_type&>().get_pytype();
}
#endif
};
};
};
} // namespace details
/// CallPolicies to get std::unique_ptr value from a function
/// that return an std::unique_ptr.
/// If the object inside the std::unique_ptr is a class or an union
/// it will be moved. In other case, it will be copied.
struct StdUniquePtrCallPolicies : bp::default_call_policies {
typedef details::StdUniquePtrResultConverter result_converter;
};
/// Variant of \see bp::return_internal_reference that extract std::unique_ptr
/// content reference before converting it into a PyObject
struct ReturnInternalStdUniquePtr : bp::return_internal_reference<> {
typedef details::InternalStdUniquePtrConverter result_converter;
template <class ArgumentPackage>
static PyObject* postcall(ArgumentPackage const& args_, PyObject* result) {
// Don't run return_internal_reference postcall on primitive type
if (PyInt_Check(result) || PyBool_Check(result) || PyFloat_Check(result) ||
PyStr_Check(result) || PyComplex_Check(result)) {
return result;
}
return bp::return_internal_reference<>::postcall(args_, result);
}
};
} // namespace eigenpy
namespace boost {
namespace python {
/// Specialize to_python_value for std::unique_ptr
template <typename T>
struct to_python_value<const std::unique_ptr<T>&>
: eigenpy::details::StdUniquePtrResultConverter::apply<
std::unique_ptr<T> >::type {};
} // namespace python
} // namespace boost
#endif // ifndef __eigenpy_utils_std_unique_ptr_hpp__
///
/// Copyright (c) 2016-2024 CNRS INRIA
/// This file was taken from Pinocchio (header
/// <pinocchio/bindings/python/utils/std-vector.hpp>)
///
#ifndef __eigenpy_utils_std_vector_hpp__
#define __eigenpy_utils_std_vector_hpp__
#include <boost/mpl/if.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <iterator>
#include <string>
#include <vector>
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/config.hpp"
#include "eigenpy/copyable.hpp"
#include "eigenpy/eigen-to-python.hpp"
#include "eigenpy/pickle-vector.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/utils/empty-visitor.hpp"
namespace eigenpy {
// Forward declaration
template <typename vector_type, bool NoProxy = false>
struct StdContainerFromPythonList;
namespace details {
/// \brief Check if a PyObject can be converted to an std::vector<T>.
template <typename T>
bool from_python_list(PyObject *obj_ptr, T *) {
// Check if it is a list
if (!PyList_Check(obj_ptr)) return false;
// Retrieve the underlying list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
bp::ssize_t list_size = bp::len(bp_list);
// Check if all the elements contained in the current vector is of type T
for (bp::ssize_t k = 0; k < list_size; ++k) {
bp::extract<T> elt(bp_list[k]);
if (!elt.check()) return false;
}
return true;
}
template <typename vector_type, bool NoProxy>
struct build_list {
static ::boost::python::list run(vector_type &vec, const bool deep_copy) {
if (deep_copy) return build_list<vector_type, true>::run(vec, true);
bp::list bp_list;
for (size_t k = 0; k < vec.size(); ++k) {
bp_list.append(boost::ref(vec[k]));
}
return bp_list;
}
};
template <typename vector_type>
struct build_list<vector_type, true> {
static ::boost::python::list run(vector_type &vec, const bool) {
typedef bp::iterator<vector_type> iterator;
return bp::list(iterator()(vec));
}
};
/// \brief Change the behavior of indexing (method __getitem__ in Python).
/// This is suitable for container of Eigen matrix objects if you want to mutate
/// them.
template <typename Container>
struct overload_base_get_item_for_std_vector
: public boost::python::def_visitor<
overload_base_get_item_for_std_vector<Container> > {
typedef typename Container::value_type value_type;
typedef typename Container::value_type data_type;
typedef size_t index_type;
template <class Class>
void visit(Class &cl) const {
cl.def("__getitem__", &base_get_item);
}
private:
static boost::python::object base_get_item(
boost::python::back_reference<Container &> container, PyObject *i_) {
index_type idx = convert_index(container.get(), i_);
typename Container::iterator i = container.get().begin();
std::advance(i, idx);
if (i == container.get().end()) {
PyErr_SetString(PyExc_KeyError, "Invalid index");
bp::throw_error_already_set();
}
typename bp::to_python_indirect<data_type &,
bp::detail::make_reference_holder>
convert;
return bp::object(bp::handle<>(convert(*i)));
}
static index_type convert_index(Container &container, PyObject *i_) {
bp::extract<long> i(i_);
if (i.check()) {
long index = i();
if (index < 0) index += (long)container.size();
if (index >= long(container.size()) || index < 0) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
bp::throw_error_already_set();
}
return (index_type)index;
}
PyErr_SetString(PyExc_TypeError, "Invalid index type");
bp::throw_error_already_set();
return index_type();
}
};
} // namespace details
} // namespace eigenpy
namespace boost {
namespace python {
template <typename MatrixType>
struct extract_to_eigen_ref
: converter::extract_rvalue<Eigen::Ref<MatrixType> > {
typedef Eigen::Ref<MatrixType> RefType;
protected:
typedef converter::extract_rvalue<RefType> base;
public:
typedef RefType result_type;
operator result_type() const { return (*this)(); }
extract_to_eigen_ref(PyObject *o) : base(o) {}
extract_to_eigen_ref(api::object const &o) : base(o.ptr()) {}
};
/// \brief Specialization of the boost::python::extract struct for references to
/// Eigen matrix objects.
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows,
int MaxCols>
struct extract<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &>
: extract_to_eigen_ref<
Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> > {
typedef Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>
MatrixType;
typedef extract_to_eigen_ref<MatrixType> base;
extract(PyObject *o) : base(o) {}
extract(api::object const &o) : base(o.ptr()) {}
};
template <typename Derived>
struct extract<Eigen::MatrixBase<Derived> &>
: extract_to_eigen_ref<Eigen::MatrixBase<Derived> > {
typedef Eigen::MatrixBase<Derived> MatrixType;
typedef extract_to_eigen_ref<MatrixType> base;
extract(PyObject *o) : base(o) {}
extract(api::object const &o) : base(o.ptr()) {}
};
template <typename Derived>
struct extract<Eigen::RefBase<Derived> &>
: extract_to_eigen_ref<Eigen::RefBase<Derived> > {
typedef Eigen::RefBase<Derived> MatrixType;
typedef extract_to_eigen_ref<MatrixType> base;
extract(PyObject *o) : base(o) {}
extract(api::object const &o) : base(o.ptr()) {}
};
namespace converter {
template <typename Type, class Allocator>
struct reference_arg_from_python<std::vector<Type, Allocator> &>
: arg_lvalue_from_python_base {
typedef std::vector<Type, Allocator> vector_type;
typedef vector_type &ref_vector_type;
typedef ref_vector_type result_type;
typedef extract<Type &> extract_type;
reference_arg_from_python(PyObject *py_obj)
: arg_lvalue_from_python_base(converter::get_lvalue_from_python(
py_obj, registered<vector_type>::converters)),
m_data(NULL),
m_source(py_obj),
vec_ptr(NULL) {
if (result() != 0) // we have found a lvalue converter
return;
// Check if py_obj is a py_list, which can then be converted to an
// std::vector
bool is_convertible =
::eigenpy::details::from_python_list(py_obj, (Type *)(0));
if (!is_convertible) return;
typedef ::eigenpy::StdContainerFromPythonList<vector_type> Constructor;
Constructor::construct(py_obj, &m_data.stage1);
void *&m_result = const_cast<void *&>(result());
m_result = m_data.stage1.convertible;
vec_ptr = reinterpret_cast<vector_type *>(m_data.storage.bytes);
}
result_type operator()() const {
return ::boost::python::detail::void_ptr_to_reference(result(),
(result_type(*)())0);
}
~reference_arg_from_python() {
if (m_data.stage1.convertible == m_data.storage.bytes) {
// Copy back the reference
const vector_type &vec = *vec_ptr;
list bp_list(handle<>(borrowed(m_source)));
for (size_t i = 0; i < vec.size(); ++i) {
typename extract_type::result_type elt = extract_type(bp_list[i]);
elt = vec[i];
}
}
}
private:
rvalue_from_python_data<ref_vector_type> m_data;
PyObject *m_source;
vector_type *vec_ptr;
};
} // namespace converter
} // namespace python
} // namespace boost
namespace eigenpy {
namespace details {
/// Defines traits for the container, used in \struct StdContainerFromPythonList
template <class Container>
struct container_traits {
// default behavior expects allocators
typedef typename Container::allocator_type Allocator;
};
template <typename _Tp, std::size_t Size>
struct container_traits<std::array<_Tp, Size> > {
typedef void Allocator;
};
}; // namespace details
///
/// \brief Register the conversion from a Python list to a std::vector
///
/// \tparam vector_type A std container (e.g. std::vector or std::list)
///
template <typename vector_type, bool NoProxy>
struct StdContainerFromPythonList {
typedef typename vector_type::value_type T;
typedef typename details::container_traits<vector_type>::Allocator Allocator;
/// \brief Check if obj_ptr can be converted
static void *convertible(PyObject *obj_ptr) {
namespace bp = boost::python;
// Check if it is a list
if (!PyList_Check(obj_ptr)) return 0;
// Retrieve the underlying list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
bp::ssize_t list_size = bp::len(bp_list);
// Check if all the elements contained in the current vector is of type T
for (bp::ssize_t k = 0; k < list_size; ++k) {
bp::extract<T> elt(bp_list[k]);
if (!elt.check()) return 0;
}
return obj_ptr;
}
/// \brief Allocate the std::vector and fill it with the element contained in
/// the list
static void construct(
PyObject *obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data *memory) {
// Extract the list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
void *storage =
reinterpret_cast<
bp::converter::rvalue_from_python_storage<vector_type> *>(
reinterpret_cast<void *>(memory))
->storage.bytes;
typedef bp::stl_input_iterator<T> iterator;
// Build the std::vector
new (storage) vector_type(iterator(bp_list), iterator());
// Validate the construction
memory->convertible = storage;
}
static void register_converter() {
::boost::python::converter::registry::push_back(
&convertible, &construct, ::boost::python::type_id<vector_type>());
}
static ::boost::python::list tolist(vector_type &self,
const bool deep_copy = false) {
return details::build_list<vector_type, NoProxy>::run(self, deep_copy);
}
};
namespace internal {
template <typename T,
bool has_operator_equal_value =
std::is_base_of<std::true_type, has_operator_equal<T> >::value>
struct contains_algo;
template <typename T>
struct contains_algo<T, true> {
template <class Container, typename key_type>
static bool run(const Container &container, key_type const &key) {
return std::find(container.begin(), container.end(), key) !=
container.end();
}
};
template <typename T>
struct contains_algo<T, false> {
template <class Container, typename key_type>
static bool run(const Container &container, key_type const &key) {
for (size_t k = 0; k < container.size(); ++k) {
if (&container[k] == &key) return true;
}
return false;
}
};
template <class Container, bool NoProxy>
struct contains_vector_derived_policies
: public ::boost::python::vector_indexing_suite<
Container, NoProxy,
contains_vector_derived_policies<Container, NoProxy> > {
typedef typename Container::value_type key_type;
static bool contains(Container &container, key_type const &key) {
return contains_algo<key_type>::run(container, key);
}
};
///
/// \brief Add standard method to a std::vector.
/// \tparam NoProxy When set to false, the elements will be copied when
/// returned to Python.
///
template <typename Container, bool NoProxy, typename CoVisitor>
struct ExposeStdMethodToStdVector
: public boost::python::def_visitor<
ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor> > {
typedef StdContainerFromPythonList<Container, NoProxy>
FromPythonListConverter;
ExposeStdMethodToStdVector(const CoVisitor &co_visitor)
: m_co_visitor(co_visitor) {}
template <class Class>
void visit(Class &cl) const {
cl.def(m_co_visitor)
.def("tolist", &FromPythonListConverter::tolist,
(bp::arg("self"), bp::arg("deep_copy") = false),
"Returns the std::vector as a Python list.")
.def("reserve", &Container::reserve,
(bp::arg("self"), bp::arg("new_cap")),
"Increase the capacity of the vector to a value that's greater "
"or equal to new_cap.")
.def(CopyableVisitor<Container>());
}
const CoVisitor &m_co_visitor;
};
/// Helper to ease ExposeStdMethodToStdVector construction
template <typename Container, bool NoProxy, typename CoVisitor>
static ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>
createExposeStdMethodToStdVector(const CoVisitor &co_visitor) {
return ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>(co_visitor);
}
} // namespace internal
namespace internal {
template <typename vector_type, bool T_picklable = false>
struct def_pickle_std_vector {
static void run(bp::class_<vector_type> &) {}
};
template <typename vector_type>
struct def_pickle_std_vector<vector_type, true> {
static void run(bp::class_<vector_type> &cl) {
cl.def_pickle(PickleVector<vector_type>());
}
};
} // namespace internal
///
/// \brief Expose an std::vector from a type given as template argument.
/// \tparam vector_type std::vector type to expose
/// \tparam NoProxy When set to false, the elements will be copied when
/// returned to Python.
/// \tparam EnableFromPythonListConverter Enables the
/// conversion from a Python list to a std::vector<T,Allocator>
///
template <class vector_type, bool NoProxy = false,
bool EnableFromPythonListConverter = true, bool pickable = true>
struct StdVectorPythonVisitor {
typedef typename vector_type::value_type value_type;
typedef StdContainerFromPythonList<vector_type, NoProxy>
FromPythonListConverter;
static void expose(const std::string &class_name,
const std::string &doc_string = "") {
expose(class_name, doc_string, EmptyPythonVisitor());
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const bp::def_visitor<DerivedVisitor> &visitor) {
expose(class_name, "", visitor);
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const std::string &doc_string,
const bp::def_visitor<DerivedVisitor> &visitor) {
// Apply visitor on already registered type or if type is not already
// registered, we define and apply the visitor on it
auto add_std_visitor =
internal::createExposeStdMethodToStdVector<vector_type, NoProxy>(
visitor);
if (!register_symbolic_link_to_registered_type<vector_type>(
add_std_visitor)) {
bp::class_<vector_type> cl(class_name.c_str(), doc_string.c_str());
cl.def(IdVisitor<vector_type>());
// Standard vector indexing definition
boost::python::vector_indexing_suite<
vector_type, NoProxy,
internal::contains_vector_derived_policies<vector_type, NoProxy> >
vector_indexing;
cl.def(bp::init<size_t, const value_type &>(
bp::args("self", "size", "value"),
"Constructor from a given size and a given value."))
.def(bp::init<const vector_type &>(bp::args("self", "other"),
"Copy constructor"))
.def(vector_indexing)
.def(add_std_visitor);
internal::def_pickle_std_vector<vector_type, pickable>::run(cl);
}
if (EnableFromPythonListConverter) {
// Register conversion
FromPythonListConverter::register_converter();
}
}
};
/**
* Expose std::vector for given matrix or vector sizes.
*/
void EIGENPY_DLLAPI exposeStdVector();
template <typename MatType, typename Alloc = Eigen::aligned_allocator<MatType> >
void exposeStdVectorEigenSpecificType(const char *name) {
typedef std::vector<MatType, Alloc> VecMatType;
std::string full_name = "StdVec_";
full_name += name;
StdVectorPythonVisitor<VecMatType>::expose(
full_name.c_str(),
details::overload_base_get_item_for_std_vector<VecMatType>());
}
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_std_vector_hpp__
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2019, INRIA
* Copyright 2018-2023, INRIA
*/
#ifndef __eigenpy_stride_hpp__
#define __eigenpy_stride_hpp__
#include <Eigen/Core>
namespace eigenpy
{
template<typename MatType, bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
struct StrideType
{
typedef Eigen::Stride<Eigen::Dynamic,Eigen::Dynamic> type;
};
template<typename MatType>
struct StrideType<MatType,true>
{
typedef Eigen::InnerStride<Eigen::Dynamic> type;
};
}
#endif // ifndef __eigenpy_stride_hpp__
#include <eigenpy/fwd.hpp>
namespace eigenpy {
template <typename MatType, int InnerStride, int OuterStride,
bool IsVectorAtCompileTime = MatType::IsVectorAtCompileTime>
struct stride_type_matrix {
typedef Eigen::Stride<OuterStride, InnerStride> type;
};
template <typename MatType, int InnerStride, int OuterStride>
struct stride_type_matrix<MatType, InnerStride, OuterStride, true> {
typedef Eigen::InnerStride<InnerStride> type;
};
template <typename EigenType, int InnerStride, int OuterStride,
typename BaseType = typename get_eigen_base_type<EigenType>::type>
struct stride_type;
template <typename MatrixType, int InnerStride, int OuterStride>
struct stride_type<MatrixType, InnerStride, OuterStride,
Eigen::MatrixBase<MatrixType> > {
typedef
typename stride_type_matrix<MatrixType, InnerStride, OuterStride>::type
type;
};
template <typename MatrixType, int InnerStride, int OuterStride>
struct stride_type<const MatrixType, InnerStride, OuterStride,
const Eigen::MatrixBase<MatrixType> > {
typedef typename stride_type_matrix<const MatrixType, InnerStride,
OuterStride>::type type;
};
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
template <typename TensorType, int InnerStride, int OuterStride>
struct stride_type<TensorType, InnerStride, OuterStride,
Eigen::TensorBase<TensorType> > {
typedef Eigen::Stride<OuterStride, InnerStride> type;
};
template <typename TensorType, int InnerStride, int OuterStride>
struct stride_type<const TensorType, InnerStride, OuterStride,
const Eigen::TensorBase<TensorType> > {
typedef Eigen::Stride<OuterStride, InnerStride> type;
};
#endif
template <typename EigenType, int InnerStride = Eigen::Dynamic,
int OuterStride = Eigen::Dynamic>
struct StrideType {
typedef typename stride_type<EigenType, InnerStride, OuterStride>::type type;
};
} // namespace eigenpy
#endif // ifndef __eigenpy_stride_hpp__
//
// Copyright (c) 2020 INRIA
//
#ifndef __eigenpy_swig_hpp__
#define __eigenpy_swig_hpp__
#include "eigenpy/fwd.hpp"
namespace eigenpy {
struct PySwigObject {
PyObject_HEAD void* ptr;
const char* desc;
};
inline PySwigObject* get_PySwigObject(PyObject* pyObj) {
if (!PyObject_HasAttrString(pyObj, "this")) return NULL;
PyObject* this_ptr = PyObject_GetAttrString(pyObj, "this");
if (this_ptr == NULL) return NULL;
PySwigObject* swig_obj = reinterpret_cast<PySwigObject*>(this_ptr);
return swig_obj;
}
} // namespace eigenpy
#endif // ifndef __eigenpy_swig_hpp__
//
// Copyright (c) 2023 INRIA
//
#ifndef __eigenpy_tensor_eigen_from_python_hpp__
#define __eigenpy_tensor_eigen_from_python_hpp__
#include "eigenpy/fwd.hpp"
#include "eigenpy/eigen-allocator.hpp"
#include "eigenpy/numpy-type.hpp"
#include "eigenpy/scalar-conversion.hpp"
namespace eigenpy {
template <typename TensorType>
struct expected_pytype_for_arg<TensorType, Eigen::TensorBase<TensorType> > {
static PyTypeObject const *get_pytype() {
PyTypeObject const *py_type = eigenpy::getPyArrayType();
return py_type;
}
};
} // namespace eigenpy
namespace boost {
namespace python {
namespace converter {
template <typename Scalar, int Rank, int Options, typename IndexType>
struct expected_pytype_for_arg<Eigen::Tensor<Scalar, Rank, Options, IndexType> >
: eigenpy::expected_pytype_for_arg<
Eigen::Tensor<Scalar, Rank, Options, IndexType> > {};
template <typename Scalar, int Rank, int Options, typename IndexType>
struct rvalue_from_python_data<
Eigen::Tensor<Scalar, Rank, Options, IndexType> const &>
: ::eigenpy::rvalue_from_python_data<
Eigen::Tensor<Scalar, Rank, Options, IndexType> const &> {
typedef Eigen::Tensor<Scalar, Rank, Options, IndexType> T;
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(T const &)
};
template <typename Derived>
struct rvalue_from_python_data<Eigen::TensorBase<Derived> const &>
: ::eigenpy::rvalue_from_python_data<Derived const &> {
EIGENPY_RVALUE_FROM_PYTHON_DATA_INIT(Derived const &)
};
} // namespace converter
} // namespace python
} // namespace boost
namespace boost {
namespace python {
namespace detail {
template <typename TensorType>
struct referent_storage<Eigen::TensorRef<TensorType> &> {
typedef Eigen::TensorRef<TensorType> RefType;
typedef ::eigenpy::details::referent_storage_eigen_ref<RefType> StorageType;
typedef typename ::eigenpy::aligned_storage<
referent_size<StorageType &>::value>::type type;
};
template <typename TensorType>
struct referent_storage<const Eigen::TensorRef<const TensorType> &> {
typedef Eigen::TensorRef<const TensorType> RefType;
typedef ::eigenpy::details::referent_storage_eigen_ref<RefType> StorageType;
typedef typename ::eigenpy::aligned_storage<
referent_size<StorageType &>::value>::type type;
};
} // namespace detail
} // namespace python
} // namespace boost
namespace eigenpy {
template <typename TensorType>
struct eigen_from_py_impl<TensorType, Eigen::TensorBase<TensorType> > {
typedef typename TensorType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void *convertible(PyObject *pyObj);
/// \brief Allocate memory and copy pyObj in the new storage
static void construct(PyObject *pyObj,
bp::converter::rvalue_from_python_stage1_data *memory);
static void registration();
};
template <typename TensorType>
void *
eigen_from_py_impl<TensorType, Eigen::TensorBase<TensorType> >::convertible(
PyObject *pyObj) {
if (!call_PyArray_Check(reinterpret_cast<PyObject *>(pyObj))) return 0;
typedef typename Eigen::internal::traits<TensorType>::Index Index;
static const Index NumIndices = TensorType::NumIndices;
PyArrayObject *pyArray = reinterpret_cast<PyArrayObject *>(pyObj);
if (!np_type_is_convertible_into_scalar<Scalar>(
EIGENPY_GET_PY_ARRAY_TYPE(pyArray)))
return 0;
if (!(PyArray_NDIM(pyArray) == NumIndices || NumIndices == Eigen::Dynamic))
return 0;
#ifdef NPY_1_8_API_VERSION
if (!(PyArray_FLAGS(pyArray)))
#else
if (!(PyArray_FLAGS(pyArray) & NPY_ALIGNED))
#endif
{
return 0;
}
return pyArray;
}
template <typename TensorType>
void eigen_from_py_impl<TensorType, Eigen::TensorBase<TensorType> >::construct(
PyObject *pyObj, bp::converter::rvalue_from_python_stage1_data *memory) {
eigen_from_py_construct<TensorType>(pyObj, memory);
}
template <typename TensorType>
void eigen_from_py_impl<TensorType,
Eigen::TensorBase<TensorType> >::registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&eigen_from_py_impl::convertible),
&eigen_from_py_impl::construct, bp::type_id<TensorType>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
#endif
);
}
template <typename TensorType>
struct eigen_from_py_converter_impl<TensorType,
Eigen::TensorBase<TensorType> > {
static void registration() {
EigenFromPy<TensorType>::registration();
// Add conversion to Eigen::TensorBase<TensorType>
typedef Eigen::TensorBase<TensorType> TensorBase;
EigenFromPy<TensorBase>::registration();
// Add conversion to Eigen::TensorRef<TensorType>
typedef Eigen::TensorRef<TensorType> RefType;
EigenFromPy<RefType>::registration();
// Add conversion to Eigen::TensorRef<const TensorType>
typedef const Eigen::TensorRef<const TensorType> ConstRefType;
EigenFromPy<ConstRefType>::registration();
}
};
template <typename TensorType>
struct EigenFromPy<Eigen::TensorBase<TensorType> > : EigenFromPy<TensorType> {
typedef EigenFromPy<TensorType> EigenFromPyDerived;
typedef Eigen::TensorBase<TensorType> Base;
static void registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&EigenFromPy::construct, bp::type_id<Base>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
#endif
);
}
};
template <typename TensorType>
struct EigenFromPy<Eigen::TensorRef<TensorType> > {
typedef Eigen::TensorRef<TensorType> RefType;
typedef typename TensorType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void *convertible(PyObject *pyObj) {
if (!call_PyArray_Check(pyObj)) return 0;
PyArrayObject *pyArray = reinterpret_cast<PyArrayObject *>(pyObj);
if (!PyArray_ISWRITEABLE(pyArray)) return 0;
return EigenFromPy<TensorType>::convertible(pyObj);
}
static void registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&eigen_from_py_construct<RefType>, bp::type_id<RefType>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
#endif
);
}
};
template <typename TensorType>
struct EigenFromPy<const Eigen::TensorRef<const TensorType> > {
typedef const Eigen::TensorRef<const TensorType> ConstRefType;
typedef typename TensorType::Scalar Scalar;
/// \brief Determine if pyObj can be converted into a MatType object
static void *convertible(PyObject *pyObj) {
return EigenFromPy<TensorType>::convertible(pyObj);
}
static void registration() {
bp::converter::registry::push_back(
reinterpret_cast<void *(*)(_object *)>(&EigenFromPy::convertible),
&eigen_from_py_construct<ConstRefType>, bp::type_id<ConstRefType>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
,
&eigenpy::expected_pytype_for_arg<TensorType>::get_pytype
#endif
);
}
};
} // namespace eigenpy
#endif // __eigenpy_tensor_eigen_from_python_hpp__
///
/// Copyright (c) 2024 INRIA
///
#ifndef __eigenpy_type_info_hpp__
#define __eigenpy_type_info_hpp__
#include "eigenpy/fwd.hpp"
#include <boost/type_index.hpp>
#include <typeinfo>
#include <typeindex>
namespace eigenpy {
template <typename T>
boost::typeindex::type_index type_info(const T& value) {
return boost::typeindex::type_id_runtime(value);
}
template <typename T>
void expose_boost_type_info() {
boost::python::def(
"type_info",
+[](const T& value) -> boost::typeindex::type_index {
return boost::typeindex::type_id_runtime(value);
},
bp::arg("value"),
"Returns information of the type of value as a "
"boost::typeindex::type_index (can work without RTTI).");
boost::python::def(
"boost_type_info",
+[](const T& value) -> boost::typeindex::type_index {
return boost::typeindex::type_id_runtime(value);
},
bp::arg("value"),
"Returns information of the type of value as a "
"boost::typeindex::type_index (can work without RTTI).");
}
template <typename T>
void expose_std_type_info() {
boost::python::def(
"std_type_info",
+[](const T& value) -> std::type_index { return typeid(value); },
bp::arg("value"),
"Returns information of the type of value as a std::type_index.");
}
///
/// \brief Add the Python method type_info to query information of a type.
///
template <class C>
struct TypeInfoVisitor : public bp::def_visitor<TypeInfoVisitor<C> > {
template <class PyClass>
void visit(PyClass& cl) const {
cl.def("type_info", &boost_type_info, bp::arg("self"),
"Queries information of the type of *this as a "
"boost::typeindex::type_index (can work without RTTI).");
cl.def("boost_type_info", &boost_type_info, bp::arg("self"),
"Queries information of the type of *this as a "
"boost::typeindex::type_index (can work without RTTI).");
cl.def("std_type_info", &std_type_info, bp::arg("self"),
"Queries information of the type of *this as a std::type_index.");
}
private:
static boost::typeindex::type_index boost_type_info(const C& self) {
return boost::typeindex::type_id_runtime(self);
}
static std::type_index std_type_info(const C& self) { return typeid(self); }
};
} // namespace eigenpy
#endif // __eigenpy_type_info_hpp__
//
// Copyright (c) 2020-2025 INRIA
// code aptapted from
// https://github.com/numpy/numpy/blob/41977b24ae011a51f64faa75cb524c7350fdedd9/numpy/core/src/umath/_rational_tests.c.src
//
#ifndef __eigenpy_ufunc_hpp__
#define __eigenpy_ufunc_hpp__
#include "eigenpy/register.hpp"
#include "eigenpy/user-type.hpp"
#include "eigenpy/utils/python-compat.hpp"
namespace eigenpy {
namespace internal {
#ifdef NPY_1_19_API_VERSION
#define EIGENPY_NPY_CONST_UFUNC_ARG const
#else
#define EIGENPY_NPY_CONST_UFUNC_ARG
#endif
template <typename T>
void matrix_multiply(char **args, npy_intp const *dimensions,
npy_intp const *steps) {
/* pointers to data for input and output arrays */
char *ip1 = args[0];
char *ip2 = args[1];
char *op = args[2];
/* lengths of core dimensions */
npy_intp dm = dimensions[0];
npy_intp dn = dimensions[1];
npy_intp dp = dimensions[2];
/* striding over core dimensions */
npy_intp is1_m = steps[0];
npy_intp is1_n = steps[1];
npy_intp is2_n = steps[2];
npy_intp is2_p = steps[3];
npy_intp os_m = steps[4];
npy_intp os_p = steps[5];
/* core dimensions counters */
npy_intp m, p;
/* calculate dot product for each row/column vector pair */
for (m = 0; m < dm; m++) {
for (p = 0; p < dp; p++) {
SpecialMethods<T>::dotfunc(ip1, is1_n, ip2, is2_n, op, dn, NULL);
/* advance to next column of 2nd input array and output array */
ip2 += is2_p;
op += os_p;
}
/* reset to first column of 2nd input array and output array */
ip2 -= is2_p * p;
op -= os_p * p;
/* advance to next row of 1st input array and output array */
ip1 += is1_m;
op += os_m;
}
}
template <typename T>
void gufunc_matrix_multiply(char **args,
npy_intp EIGENPY_NPY_CONST_UFUNC_ARG *dimensions,
npy_intp EIGENPY_NPY_CONST_UFUNC_ARG *steps,
void *NPY_UNUSED(func)) {
/* outer dimensions counter */
npy_intp N_;
/* length of flattened outer dimensions */
npy_intp dN = dimensions[0];
/* striding over flattened outer dimensions for input and output arrays */
npy_intp s0 = steps[0];
npy_intp s1 = steps[1];
npy_intp s2 = steps[2];
/*
* loop through outer dimensions, performing matrix multiply on
* core dimensions for each loop
*/
for (N_ = 0; N_ < dN; N_++, args[0] += s0, args[1] += s1, args[2] += s2) {
matrix_multiply<T>(args, dimensions + 1, steps + 3);
}
}
#define EIGENPY_REGISTER_BINARY_OPERATOR(name, op) \
template <typename T1, typename T2, typename R> \
void binary_op_##name( \
char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \
EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void * /*data*/) { \
npy_intp is0 = steps[0], is1 = steps[1], os = steps[2], n = *dimensions; \
char *i0 = args[0], *i1 = args[1], *o = args[2]; \
int k; \
for (k = 0; k < n; k++) { \
T1 &x = *static_cast<T1 *>(static_cast<void *>(i0)); \
T2 &y = *static_cast<T2 *>(static_cast<void *>(i1)); \
R &res = *static_cast<R *>(static_cast<void *>(o)); \
res = x op y; \
i0 += is0; \
i1 += is1; \
o += os; \
} \
} \
\
template <typename T> \
void binary_op_##name( \
char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \
EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void *data) { \
binary_op_##name<T, T, T>(args, dimensions, steps, data); \
}
EIGENPY_REGISTER_BINARY_OPERATOR(add, +)
EIGENPY_REGISTER_BINARY_OPERATOR(subtract, -)
EIGENPY_REGISTER_BINARY_OPERATOR(multiply, *)
EIGENPY_REGISTER_BINARY_OPERATOR(divide, /)
EIGENPY_REGISTER_BINARY_OPERATOR(equal, ==)
EIGENPY_REGISTER_BINARY_OPERATOR(not_equal, !=)
EIGENPY_REGISTER_BINARY_OPERATOR(less, <)
EIGENPY_REGISTER_BINARY_OPERATOR(greater, >)
EIGENPY_REGISTER_BINARY_OPERATOR(less_equal, <=)
EIGENPY_REGISTER_BINARY_OPERATOR(greater_equal, >=)
#define EIGENPY_REGISTER_UNARY_OPERATOR(name, op) \
template <typename T, typename R> \
void unary_op_##name( \
char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \
EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void * /*data*/) { \
npy_intp is = steps[0], os = steps[1], n = *dimensions; \
char *i = args[0], *o = args[1]; \
int k; \
for (k = 0; k < n; k++) { \
T &x = *static_cast<T *>(static_cast<void *>(i)); \
R &res = *static_cast<R *>(static_cast<void *>(o)); \
res = op x; \
i += is; \
o += os; \
} \
} \
\
template <typename T> \
void unary_op_##name( \
char **args, EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *dimensions, \
EIGENPY_NPY_CONST_UFUNC_ARG npy_intp *steps, void *data) { \
unary_op_##name<T, T>(args, dimensions, steps, data); \
}
EIGENPY_REGISTER_UNARY_OPERATOR(negative, -)
EIGENPY_REGISTER_UNARY_OPERATOR(square, x *)
} // namespace internal
#define EIGENPY_REGISTER_BINARY_UFUNC(name, code, T1, T2, R) \
{ \
PyUFuncObject *ufunc = \
(PyUFuncObject *)PyObject_GetAttrString(numpy, #name); \
int _types[3] = {Register::getTypeCode<T1>(), Register::getTypeCode<T2>(), \
Register::getTypeCode<R>()}; \
if (!ufunc) { \
/*goto fail; \*/ \
} \
if (sizeof(_types) / sizeof(int) != ufunc->nargs) { \
PyErr_Format(PyExc_AssertionError, \
"ufunc %s takes %d arguments, our loop takes %lu", #name, \
ufunc->nargs, \
(unsigned long)(sizeof(_types) / sizeof(int))); \
Py_DECREF(ufunc); \
} \
if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, code, \
internal::binary_op_##name<T1, T2, R>, \
_types, 0) < 0) { \
/*Py_DECREF(ufunc);*/ \
/*goto fail; \*/ \
} \
Py_DECREF(ufunc); \
}
#define EIGENPY_REGISTER_UNARY_UFUNC(name, code, T, R) \
{ \
PyUFuncObject *ufunc = \
(PyUFuncObject *)PyObject_GetAttrString(numpy, #name); \
int _types[2] = {Register::getTypeCode<T>(), Register::getTypeCode<R>()}; \
if (!ufunc) { \
/*goto fail; \*/ \
} \
if (sizeof(_types) / sizeof(int) != ufunc->nargs) { \
PyErr_Format(PyExc_AssertionError, \
"ufunc %s takes %d arguments, our loop takes %lu", #name, \
ufunc->nargs, \
(unsigned long)(sizeof(_types) / sizeof(int))); \
Py_DECREF(ufunc); \
} \
if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, code, \
internal::unary_op_##name<T, R>, _types, \
0) < 0) { \
/*Py_DECREF(ufunc);*/ \
/*goto fail; \*/ \
} \
Py_DECREF(ufunc); \
}
template <typename Scalar>
void registerCommonUfunc() {
const int type_code = Register::getTypeCode<Scalar>();
PyObject *numpy_str;
numpy_str = PyStr_FromString("numpy");
PyObject *numpy;
numpy = PyImport_Import(numpy_str);
Py_DECREF(numpy_str);
import_ufunc();
// Matrix multiply
{
int types[3] = {type_code, type_code, type_code};
std::stringstream ss;
ss << "return result of multiplying two matrices of ";
ss << bp::type_info(typeid(Scalar)).name();
PyUFuncObject *ufunc =
(PyUFuncObject *)PyObject_GetAttrString(numpy, "matmul");
if (!ufunc) {
std::stringstream ss;
ss << "Impossible to define matrix_multiply for given type "
<< bp::type_info(typeid(Scalar)).name() << std::endl;
eigenpy::Exception(ss.str());
}
if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, type_code,
&internal::gufunc_matrix_multiply<Scalar>,
types, 0) < 0) {
std::stringstream ss;
ss << "Impossible to register matrix_multiply for given type "
<< bp::type_info(typeid(Scalar)).name() << std::endl;
eigenpy::Exception(ss.str());
}
Py_DECREF(ufunc);
}
// Binary operators
EIGENPY_REGISTER_BINARY_UFUNC(add, type_code, Scalar, Scalar, Scalar);
EIGENPY_REGISTER_BINARY_UFUNC(subtract, type_code, Scalar, Scalar, Scalar);
EIGENPY_REGISTER_BINARY_UFUNC(multiply, type_code, Scalar, Scalar, Scalar);
EIGENPY_REGISTER_BINARY_UFUNC(divide, type_code, Scalar, Scalar, Scalar);
// Comparison operators
EIGENPY_REGISTER_BINARY_UFUNC(equal, type_code, Scalar, Scalar, bool);
EIGENPY_REGISTER_BINARY_UFUNC(not_equal, type_code, Scalar, Scalar, bool);
EIGENPY_REGISTER_BINARY_UFUNC(greater, type_code, Scalar, Scalar, bool);
EIGENPY_REGISTER_BINARY_UFUNC(less, type_code, Scalar, Scalar, bool);
EIGENPY_REGISTER_BINARY_UFUNC(greater_equal, type_code, Scalar, Scalar, bool);
EIGENPY_REGISTER_BINARY_UFUNC(less_equal, type_code, Scalar, Scalar, bool);
// Unary operators
EIGENPY_REGISTER_UNARY_UFUNC(negative, type_code, Scalar, Scalar);
EIGENPY_REGISTER_UNARY_UFUNC(square, type_code, Scalar, Scalar);
Py_DECREF(numpy);
}
} // namespace eigenpy
#endif // __eigenpy_ufunc_hpp__