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 451 additions and 60 deletions
#
# Copyright (c) 2014-2021 CNRS INRIA
# Copyright (c) 2014-2023 CNRS INRIA
#
# --- LIBRARY --- #
......@@ -9,14 +9,20 @@ set(PYWRAP
PARENT_SCOPE)
make_directory("${${PROJECT_NAME}_BINARY_DIR}/python/${PROJECT_NAME}")
include(${JRL_CMAKE_MODULES}/python-helpers.cmake)
include("${JRL_CMAKE_MODULES}/stubs.cmake")
add_custom_target(python)
set_target_properties(python PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD True)
add_custom_target(${PROJECT_NAME}_python)
set_target_properties(${PROJECT_NAME}_python
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD True)
add_library(${PYWRAP} SHARED main.cpp)
add_dependencies(python ${PYWRAP})
add_library(${PYWRAP} MODULE main.cpp)
add_dependencies(${PROJECT_NAME}_python ${PYWRAP})
target_link_libraries(${PYWRAP} PUBLIC ${PROJECT_NAME})
python_build_get_target(python_build_target)
add_dependencies(${PYWRAP} ${python_build_target})
# BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS spews conversion warnings from int to
# long unsigned int. Unfortunately, using literals does not work in a macro. As
# such, this turns them off for the entire wrapper:
......@@ -35,16 +41,18 @@ set_target_properties(
PROPERTIES PREFIX ""
SUFFIX ${PYTHON_EXT_SUFFIX}
LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}"
"${PROJECT_BINARY_DIR}/python/${PROJECT_NAME}"
LIBRARY_OUTPUT_DIRECTORY_<CONFIG>
"${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}"
"${PROJECT_BINARY_DIR}/python/${PROJECT_NAME}"
RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}"
"${PROJECT_BINARY_DIR}/python/${PROJECT_NAME}"
RUNTIME_OUTPUT_DIRECTORY_<CONFIG>
"${CMAKE_BINARY_DIR}/python/${PROJECT_NAME}")
"${PROJECT_BINARY_DIR}/python/${PROJECT_NAME}")
if(UNIX AND NOT APPLE)
set_target_properties(${PYWRAP} PROPERTIES INSTALL_RPATH "\$ORIGIN/../../..")
if(UNIX)
get_relative_rpath(${${PYWRAP}_INSTALL_DIR} ${PYWRAP}_INSTALL_RPATH)
set_target_properties(${PYWRAP} PROPERTIES INSTALL_RPATH
"${${PYWRAP}_INSTALL_RPATH}")
endif()
install(TARGETS ${PYWRAP} DESTINATION ${${PYWRAP}_INSTALL_DIR})
......@@ -53,12 +61,14 @@ install(TARGETS ${PYWRAP} DESTINATION ${${PYWRAP}_INSTALL_DIR})
if(GENERATE_PYTHON_STUBS)
load_stubgen()
# Set PYWRAP and PROJECT_NAME as stubs dependencies PROJECT_NAME is mandatory
# (even if it's a PYWRAP dependency) to find PROJECT_NAME name DLL on windows
generate_stubs(${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_NAME}
${ABSOLUTE_PYTHON_SITELIB})
${ABSOLUTE_PYTHON_SITELIB} ${PYWRAP} ${PROJECT_NAME})
endif(GENERATE_PYTHON_STUBS)
# --- INSTALL SCRIPTS
set(PYTHON_FILES __init__.py)
set(PYTHON_FILES __init__.py windows_dll_manager.py)
foreach(python ${PYTHON_FILES})
python_build(${PROJECT_NAME} ${python})
......
......@@ -2,5 +2,29 @@
# Copyright (c) 2017-2021 CNRS INRIA
#
from .eigenpy_pywrap import * # noqa
from .eigenpy_pywrap import __version__, __raw_version__ # noqa
# On Windows, if eigenpy.dll is not in the same directory than
# the .pyd, it will not be loaded.
# We first try to load eigenpy, then, if it fail and we are on Windows:
# 1. We add all paths inside eigenpy_WINDOWS_DLL_PATH to DllDirectory
# 2. If EIGENPY_WINDOWS_DLL_PATH we add the relative path from the
# package directory to the bin directory to DllDirectory
# This solution is inspired from:
# - https://github.com/PixarAnimationStudios/OpenUSD/pull/1511/files
# - https://stackoverflow.com/questions/65334494/python-c-extension-packaging-dll-along-with-pyd
# More resources on https://github.com/diffpy/pyobjcryst/issues/33
try:
from .eigenpy_pywrap import * # noqa
from .eigenpy_pywrap import __raw_version__, __version__
except ImportError:
import platform
if platform.system() == "Windows":
from .windows_dll_manager import build_directory_manager, get_dll_paths
with build_directory_manager() as dll_dir_manager:
for p in get_dll_paths():
dll_dir_manager.add_dll_directory(p)
from .eigenpy_pywrap import * # noqa
from .eigenpy_pywrap import __raw_version__, __version__ # noqa
else:
raise
import contextlib
import os
def get_dll_paths():
eigenpy_paths = os.getenv("EIGENPY_WINDOWS_DLL_PATH")
if eigenpy_paths is None:
# From https://peps.python.org/pep-0250/#implementation
# lib/python-version/site-packages/package
RELATIVE_DLL_PATH1 = "..\\..\\..\\..\\bin"
# lib/site-packages/package
RELATIVE_DLL_PATH2 = "..\\..\\..\\bin"
# For unit test
RELATIVE_DLL_PATH3 = "..\\..\\bin"
return [
os.path.join(os.path.dirname(__file__), RELATIVE_DLL_PATH1),
os.path.join(os.path.dirname(__file__), RELATIVE_DLL_PATH2),
os.path.join(os.path.dirname(__file__), RELATIVE_DLL_PATH3),
]
else:
return eigenpy_paths.split(os.pathsep)
class DllDirectoryManager(contextlib.AbstractContextManager):
"""Restore DllDirectory state after importing Python module"""
def add_dll_directory(self, dll_dir: str):
# add_dll_directory can fail on relative path and non
# existing path.
# Since we don't know all the fail criterion we just ignore
# thrown exception
try:
self.dll_dirs.append(os.add_dll_directory(dll_dir))
except OSError:
pass
def __enter__(self):
self.dll_dirs = []
return self
def __exit__(self, *exc_details):
for d in self.dll_dirs:
d.close()
def build_directory_manager():
return DllDirectoryManager()
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2022, INRIA
* Copyright 2018-2024, INRIA
*/
#include <boost/python/scope.hpp>
......@@ -17,11 +17,42 @@
using namespace eigenpy;
template <typename Scalar>
void exposeIsApprox() {
enum { Options = 0 };
EIGENPY_MAKE_TYPEDEFS(Scalar, Options, s, Eigen::Dynamic, X);
EIGENPY_UNUSED_TYPE(VectorXs);
EIGENPY_UNUSED_TYPE(RowVectorXs);
// typedef Eigen::SparseMatrix<Scalar, Options> SparseMatrixXs;
typedef typename MatrixXs::RealScalar RealScalar;
using namespace Eigen;
const RealScalar dummy_precision =
Eigen::NumTraits<RealScalar>::dummy_precision();
bp::def("is_approx",
(bool (*)(const Eigen::MatrixBase<MatrixXs> &,
const Eigen::MatrixBase<MatrixXs> &,
const RealScalar &))&is_approx,
(bp::arg("A"), bp::arg("B"), bp::arg("prec") = dummy_precision),
"Returns True if A is approximately equal to B, within the "
"precision determined by prec.");
// bp::def("is_approx",
// (bool (*)(const Eigen::SparseMatrixBase<SparseMatrixXs> &,
// const Eigen::SparseMatrixBase<SparseMatrixXs> &,
// const RealScalar &)) &
// is_approx,
// (bp::arg("A"), bp::arg("B"), bp::arg("prec") = dummy_precision),
// "Returns True if A is approximately equal to B, within the "
// "precision determined by prec.");
}
BOOST_PYTHON_MODULE(eigenpy_pywrap) {
namespace bp = boost::python;
enableEigenPy();
bp::scope().attr("__version__") = eigenpy::printVersion();
bp::scope().attr("__eigen_version__") = eigenpy::printEigenVersion();
bp::scope().attr("__raw_version__") = bp::str(EIGENPY_VERSION);
bp::def("checkVersionAtLeast", &eigenpy::checkVersionAtLeast,
bp::args("major_version", "minor_version", "patch_version"),
......@@ -46,17 +77,8 @@ BOOST_PYTHON_MODULE(eigenpy_pywrap) {
register_symbolic_link_to_registered_type<Eigen::ComputationInfo>();
}
{
using namespace Eigen;
bp::def("is_approx",
(bool (*)(const Eigen::MatrixBase<MatrixXd> &,
const Eigen::MatrixBase<MatrixXd> &, const double &)) &
is_approx<MatrixXd, MatrixXd>,
(bp::arg("A"), bp::arg("B"), bp::arg("prec") = 1e-12),
"Returns True if A is approximately equal to B, within the "
"precision determined by prec.");
}
exposeIsApprox<double>();
exposeIsApprox<std::complex<double> >();
exposeDecompositions();
}
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/fwd.hpp"
#include "eigenpy/decompositions/decompositions.hpp"
#include "eigenpy/decompositions/sparse/accelerate/accelerate.hpp"
namespace eigenpy {
void exposeAccelerate() {
using namespace Eigen;
typedef Eigen::SparseMatrix<double, Eigen::ColMajor> ColMajorSparseMatrix;
// typedef Eigen::SparseMatrix<double,Eigen::RowMajor> RowMajorSparseMatrix;
bp::enum_<SparseOrder_t>("SparseOrder")
.value("SparseOrderUser", SparseOrderUser)
.value("SparseOrderAMD", SparseOrderAMD)
.value("SparseOrderMetis", SparseOrderMetis)
.value("SparseOrderCOLAMD", SparseOrderCOLAMD);
#define EXPOSE_ACCELERATE_DECOMPOSITION(name, doc) \
AccelerateImplVisitor<name<ColMajorSparseMatrix> >::expose( \
EIGENPY_STRINGIZE(name), doc)
EXPOSE_ACCELERATE_DECOMPOSITION(
AccelerateLLT,
"A direct Cholesky (LLT) factorization and solver based on Accelerate.");
EXPOSE_ACCELERATE_DECOMPOSITION(AccelerateLDLT,
"The default Cholesky (LDLT) factorization "
"and solver based on Accelerate.");
EXPOSE_ACCELERATE_DECOMPOSITION(
AccelerateLDLTUnpivoted,
"A direct Cholesky-like LDL^T factorization and solver based on "
"Accelerate with only 1x1 pivots and no pivoting.");
EXPOSE_ACCELERATE_DECOMPOSITION(
AccelerateLDLTSBK,
"A direct Cholesky (LDLT) factorization and solver based on Accelerate "
"with Supernode Bunch-Kaufman and static pivoting.");
EXPOSE_ACCELERATE_DECOMPOSITION(
AccelerateLDLTTPP,
"A direct Cholesky (LDLT) factorization and solver based on Accelerate "
"with full threshold partial pivoting.");
EXPOSE_ACCELERATE_DECOMPOSITION(
AccelerateQR, "A QR factorization and solver based on Accelerate.");
EXPOSE_ACCELERATE_DECOMPOSITION(
AccelerateCholeskyAtA,
"A QR factorization and solver based on Accelerate without storing Q "
"(equivalent to A^TA = R^T R).");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/fwd.hpp"
#include "eigenpy/decompositions/decompositions.hpp"
#include "eigenpy/decompositions/sparse/cholmod/CholmodSimplicialLLT.hpp"
#include "eigenpy/decompositions/sparse/cholmod/CholmodSimplicialLDLT.hpp"
#include "eigenpy/decompositions/sparse/cholmod/CholmodSupernodalLLT.hpp"
namespace eigenpy {
void exposeCholmod() {
using namespace Eigen;
typedef Eigen::SparseMatrix<double, Eigen::ColMajor> ColMajorSparseMatrix;
// typedef Eigen::SparseMatrix<double,Eigen::RowMajor> RowMajorSparseMatrix;
bp::enum_<CholmodMode>("CholmodMode")
.value("CholmodAuto", CholmodAuto)
.value("CholmodSimplicialLLt", CholmodSimplicialLLt)
.value("CholmodSupernodalLLt", CholmodSupernodalLLt)
.value("CholmodLDLt", CholmodLDLt);
CholmodSimplicialLLTVisitor<ColMajorSparseMatrix>::expose(
"CholmodSimplicialLLT");
CholmodSimplicialLDLTVisitor<ColMajorSparseMatrix>::expose(
"CholmodSimplicialLDLT");
CholmodSupernodalLLTVisitor<ColMajorSparseMatrix>::expose(
"CholmodSupernodalLLT");
}
} // namespace eigenpy
/*
* Copyright 2020-2021 INRIA
* Copyright 2020-2024 INRIA
*/
#include "eigenpy/decompositions/decompositions.hpp"
#include "eigenpy/decompositions/EigenSolver.hpp"
#include "eigenpy/decompositions/LDLT.hpp"
#include "eigenpy/decompositions/LLT.hpp"
#include "eigenpy/decompositions/SelfAdjointEigenSolver.hpp"
#include "eigenpy/decompositions/minres.hpp"
#include "eigenpy/fwd.hpp"
namespace eigenpy {
void exposeEigenSolver();
void exposeSelfAdjointEigenSolver();
void exposeLLTSolver();
void exposeLDLTSolver();
void exposeQRSolvers();
void exposeMINRESSolver();
void exposeSimplicialLLTSolver();
void exposeSimplicialLDLTSolver();
void exposePermutationMatrix();
void exposeDecompositions() {
using namespace Eigen;
namespace bp = boost::python;
EigenSolverVisitor<MatrixXd>::expose("EigenSolver");
SelfAdjointEigenSolverVisitor<MatrixXd>::expose("SelfAdjointEigenSolver");
LLTSolverVisitor<MatrixXd>::expose("LLT");
LDLTSolverVisitor<MatrixXd>::expose("LDLT");
MINRESSolverVisitor<MatrixXd>::expose("MINRES");
exposeEigenSolver();
exposeSelfAdjointEigenSolver();
exposeLLTSolver();
exposeLDLTSolver();
exposeQRSolvers();
exposeMINRESSolver();
{
bp::enum_<DecompositionOptions>("DecompositionOptions")
......@@ -35,5 +40,19 @@ void exposeDecompositions() {
.value("ABx_lx", ABx_lx)
.value("BAx_lx", BAx_lx);
}
// Expose sparse decompositions
exposeSimplicialLLTSolver();
exposeSimplicialLDLTSolver();
exposePermutationMatrix();
#ifdef EIGENPY_WITH_CHOLMOD_SUPPORT
exposeCholmod();
#endif
#ifdef EIGENPY_WITH_ACCELERATE_SUPPORT
exposeAccelerate();
#endif
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/EigenSolver.hpp"
namespace eigenpy {
void exposeEigenSolver() {
using namespace Eigen;
EigenSolverVisitor<MatrixXd>::expose("EigenSolver");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/LDLT.hpp"
namespace eigenpy {
void exposeLDLTSolver() {
using namespace Eigen;
LDLTSolverVisitor<MatrixXd>::expose("LDLT");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/LLT.hpp"
namespace eigenpy {
void exposeLLTSolver() {
using namespace Eigen;
LLTSolverVisitor<MatrixXd>::expose("LLT");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/minres.hpp"
namespace eigenpy {
void exposeMINRESSolver() {
using namespace Eigen;
MINRESSolverVisitor<MatrixXd>::expose("MINRES");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/PermutationMatrix.hpp"
namespace eigenpy {
void exposePermutationMatrix() {
using namespace Eigen;
PermutationMatrixVisitor<Eigen::Dynamic>::expose("PermutationMatrix");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/QR.hpp"
namespace eigenpy {
void exposeQRSolvers() {
using namespace Eigen;
HouseholderQRSolverVisitor<MatrixXd>::expose("HouseholderQR");
FullPivHouseholderQRSolverVisitor<MatrixXd>::expose("FullPivHouseholderQR");
ColPivHouseholderQRSolverVisitor<MatrixXd>::expose("ColPivHouseholderQR");
CompleteOrthogonalDecompositionSolverVisitor<MatrixXd>::expose(
"CompleteOrthogonalDecomposition");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/EigenSolver.hpp"
namespace eigenpy {
void exposeEigenSolver() {
using namespace Eigen;
EigenSolverVisitor<MatrixXd>::expose("EigenSolver");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/SelfAdjointEigenSolver.hpp"
namespace eigenpy {
void exposeSelfAdjointEigenSolver() {
using namespace Eigen;
SelfAdjointEigenSolverVisitor<MatrixXd>::expose("SelfAdjointEigenSolver");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/sparse/LDLT.hpp"
namespace eigenpy {
void exposeSimplicialLDLTSolver() {
using namespace Eigen;
typedef SparseMatrix<double, ColMajor> ColMajorSparseMatrix;
SimplicialLDLTVisitor<ColMajorSparseMatrix>::expose("SimplicialLDLT");
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/decompositions/sparse/LLT.hpp"
namespace eigenpy {
void exposeSimplicialLLTSolver() {
using namespace Eigen;
typedef SparseMatrix<double, ColMajor> ColMajorSparseMatrix;
SimplicialLLTVisitor<ColMajorSparseMatrix>::expose("SimplicialLLT");
}
} // namespace eigenpy
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2021, INRIA
* Copyright 2018-2023, INRIA
*/
#include "eigenpy/eigenpy.hpp"
......@@ -12,8 +12,21 @@ namespace eigenpy {
void seed(unsigned int seed_value) { srand(seed_value); }
void exposeMatrixBool();
void exposeMatrixInt();
void exposeMatrixLong();
void exposeMatrixInt8();
void exposeMatrixChar();
void exposeMatrixUInt8();
void exposeMatrixInt16();
void exposeMatrixUInt16();
void exposeMatrixInt32();
void exposeMatrixUInt32();
void exposeMatrixWindowsLong();
void exposeMatrixWindowsULong();
void exposeMatrixMacLong();
void exposeMatrixMacULong();
void exposeMatrixInt64();
void exposeMatrixUInt64();
void exposeMatrixLinuxLongLong();
void exposeMatrixLinuxULongLong();
void exposeMatrixFloat();
void exposeMatrixDouble();
void exposeMatrixLongDouble();
......@@ -22,6 +35,9 @@ void exposeMatrixComplexFloat();
void exposeMatrixComplexDouble();
void exposeMatrixComplexLongDouble();
void exposeNoneType();
void exposeTypeInfo();
/* Enable Eigen-Numpy serialization for a set of standard MatrixBase instances.
*/
void enableEigenPy() {
......@@ -30,20 +46,6 @@ void enableEigenPy() {
Exception::registerException();
bp::def(
"setNumpyType", &NumpyType::setNumpyType, bp::arg("numpy_type"),
"Change the Numpy type returned by the converters from an Eigen object.");
bp::def(
"getNumpyType", &NumpyType::getNumpyType,
"Get the Numpy type returned by the converters from an Eigen object.");
bp::def("switchToNumpyArray", &NumpyType::switchToNumpyArray,
"Set the conversion from Eigen::Matrix to numpy.ndarray.");
bp::def("switchToNumpyMatrix", &NumpyType::switchToNumpyMatrix,
"Set the conversion from Eigen::Matrix to numpy.matrix.");
bp::def("sharedMemory", (void (*)(const bool))NumpyType::sharedMemory,
bp::arg("value"),
"Share the memory when converting from Eigen to Numpy.");
......@@ -59,8 +61,21 @@ void enableEigenPy() {
"seed_value.");
exposeMatrixBool();
exposeMatrixInt();
exposeMatrixLong();
exposeMatrixInt8();
exposeMatrixChar();
exposeMatrixUInt8();
exposeMatrixInt16();
exposeMatrixUInt16();
exposeMatrixInt32();
exposeMatrixUInt32();
exposeMatrixWindowsLong();
exposeMatrixWindowsULong();
exposeMatrixMacLong();
exposeMatrixMacULong();
exposeMatrixInt64();
exposeMatrixUInt64();
exposeMatrixLinuxLongLong();
exposeMatrixLinuxULongLong();
exposeMatrixFloat();
exposeMatrixDouble();
exposeMatrixLongDouble();
......@@ -68,6 +83,17 @@ void enableEigenPy() {
exposeMatrixComplexFloat();
exposeMatrixComplexDouble();
exposeMatrixComplexLongDouble();
exposeNoneType();
exposeTypeInfo();
}
bool withTensorSupport() {
#ifdef EIGENPY_WITH_TENSOR_SUPPORT
return true;
#else
return false;
#endif
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <cstdint>
namespace eigenpy {
void exposeMatrixChar() {
exposeType<char>();
exposeType<char, Eigen::RowMajor>();
}
} // namespace eigenpy
/*
* Copyright 2024 INRIA
*/
#include "eigenpy/eigenpy.hpp"
#include <cstdint>
namespace eigenpy {
void exposeMatrixInt16() {
exposeType<int16_t>();
exposeType<int16_t, Eigen::RowMajor>();
}
} // namespace eigenpy