Unverified Commit c2aba985 authored by Justin Carpentier's avatar Justin Carpentier Committed by GitHub
Browse files

Merge pull request #275 from jcarpent/devel

Expose const Eigen::Ref<const ... + update pre-commit + correctly export the project version
parents 80b1fd72 e3685069
Pipeline #18213 passed with stage
in 8 minutes and 47 seconds
......@@ -3,8 +3,12 @@ repos:
rev: v13.0.1
hooks:
- id: clang-format
args: [-i, --style=Google]
args: ['-i', '--style={BasedOnStyle: Google, SortIncludes: false}']
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0
hooks:
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
#
# Copyright (c) 2014-2019 CNRS
# Copyright (c) 2018-2021 INRIA
# Copyright (c) 2018-2022 INRIA
#
CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
......@@ -11,6 +11,7 @@ SET(PROJECT_URL "http://github.com/stack-of-tasks/eigenpy")
SET(PROJECT_USE_CMAKE_EXPORT TRUE)
SET(PROJECT_USE_KEYWORD_LINK_LIBRARIES TRUE)
SET(PROJECT_CUSTOM_HEADER_EXTENSION "hpp")
SET(PROJECT_COMPATIBILITY_VERSION AnyNewerVersion)
# Check if the submodule cmake have been initialized
set(JRL_CMAKE_MODULES "${CMAKE_CURRENT_LIST_DIR}/cmake")
......
......@@ -7,10 +7,11 @@ import time
import timeit
from IPython import get_ipython
ipython = get_ipython()
quat = eigenpy.Quaternion()
a = [0., 0., 0.]
a = [0.0, 0.0, 0.0]
cmd1 = "timeit np.array(a)"
print("\n")
......@@ -50,7 +51,7 @@ print(cmd5)
ipython.magic(cmd5)
print("\n")
a_matrix = np.matrix(a);
a_matrix = np.matrix(a)
cmd6 = "timeit np.asarray(a_matrix)"
print(cmd6)
ipython.magic(cmd6)
......
Subproject commit 332976cc4d5305256c79a479e55ad7ab2ecc42f1
Subproject commit e77c9c32b1d69b21e447cf64f1ad1590aab61159
......@@ -68,6 +68,7 @@ void enableEigenPySpecific() {
EigenToPyConverter<MatType>::registration();
#if EIGEN_VERSION_AT_LEAST(3, 2, 0)
EigenToPyConverter<Eigen::Ref<MatType> >::registration();
EigenToPyConverter<const Eigen::Ref<const MatType> >::registration();
#endif
// from-python
......
/*
* Copyright 2020 INRIA
* Copyright 2020-2022 INRIA
*/
#ifndef __eigenpy_numpy_allocator_hpp__
......@@ -116,13 +116,11 @@ template <typename MatType, int Options, typename Stride>
struct NumpyAllocator<const Eigen::Ref<const MatType, Options, Stride> > {
typedef const Eigen::Ref<const MatType, Options, Stride> RefType;
template <typename SimilarMatrixType>
static PyArrayObject *allocate(RefType &mat, npy_intp nd, npy_intp *shape) {
typedef typename SimilarMatrixType::Scalar Scalar;
typedef typename RefType::Scalar Scalar;
enum {
NPY_ARRAY_MEMORY_CONTIGUOUS_RO = SimilarMatrixType::IsRowMajor
? NPY_ARRAY_CARRAY_RO
: NPY_ARRAY_FARRAY_RO
NPY_ARRAY_MEMORY_CONTIGUOUS_RO =
RefType::IsRowMajor ? NPY_ARRAY_CARRAY_RO : NPY_ARRAY_FARRAY_RO
};
if (NumpyType::sharedMemory()) {
......
/*
* Copyright 2014-2019, CNRS
* Copyright 2018-2020, INRIA
* Copyright 2018-2022, INRIA
*/
#include <iostream>
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/eigen-from-python.hpp"
using namespace Eigen;
using namespace eigenpy;
......@@ -41,6 +42,16 @@ Eigen::Ref<MatType> asRef(const int rows, const int cols) {
return mat;
}
template <typename MatType>
Eigen::Ref<MatType> asRef(Eigen::Ref<MatType> mat) {
return Eigen::Ref<MatType>(mat);
}
template <typename MatType>
const Eigen::Ref<const MatType> asConstRef(Eigen::Ref<MatType> mat) {
return Eigen::Ref<const MatType>(mat);
}
BOOST_PYTHON_MODULE(eigen_ref) {
namespace bp = boost::python;
eigenpy::enableEigenPy();
......@@ -60,5 +71,10 @@ BOOST_PYTHON_MODULE(eigen_ref) {
bp::def("fillVec", fill<VectorXd>);
bp::def("fill", fill<MatrixXd>);
bp::def("asRef", asRef<MatrixXd>);
bp::def("asRef",
(Eigen::Ref<MatrixXd>(*)(const int, const int))asRef<MatrixXd>);
bp::def("asRef",
(Eigen::Ref<MatrixXd>(*)(Eigen::Ref<MatrixXd>))asRef<MatrixXd>);
bp::def("asConstRef", (const Eigen::Ref<const MatrixXd> (*)(
Eigen::Ref<MatrixXd>))asConstRef<MatrixXd>);
}
......@@ -4,9 +4,9 @@ import numpy as np
import numpy.linalg as la
dim = 100
A = np.random.rand(dim,dim)
A = np.random.rand(dim, dim)
A = (A + A.T)*0.5 + np.diag(10. + np.random.rand(dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + np.random.rand(dim))
ldlt = eigenpy.LDLT(A)
......@@ -14,10 +14,12 @@ L = ldlt.matrixL()
D = ldlt.vectorD()
P = ldlt.transpositionsP()
assert eigenpy.is_approx(np.transpose(P).dot(L.dot(np.diag(D).dot(np.transpose(L).dot(P)))),A)
assert eigenpy.is_approx(
np.transpose(P).dot(L.dot(np.diag(D).dot(np.transpose(L).dot(P)))), A
)
X = np.random.rand(dim,20)
X = np.random.rand(dim, 20)
B = A.dot(X)
X_est = ldlt.solve(B)
assert eigenpy.is_approx(X,X_est)
assert eigenpy.is_approx(A.dot(X_est),B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
......@@ -4,17 +4,17 @@ import numpy as np
import numpy.linalg as la
dim = 100
A = np.random.rand(dim,dim)
A = np.random.rand(dim, dim)
A = (A + A.T)*0.5 + np.diag(10. + np.random.rand(dim))
A = (A + A.T) * 0.5 + np.diag(10.0 + np.random.rand(dim))
llt = eigenpy.LLT(A)
L = llt.matrixL()
assert eigenpy.is_approx(L.dot(np.transpose(L)),A)
assert eigenpy.is_approx(L.dot(np.transpose(L)), A)
X = np.random.rand(dim,20)
X = np.random.rand(dim, 20)
B = A.dot(X)
X_est = llt.solve(B)
assert eigenpy.is_approx(X,X_est)
assert eigenpy.is_approx(A.dot(X_est),B)
assert eigenpy.is_approx(X, X_est)
assert eigenpy.is_approx(A.dot(X_est), B)
......@@ -8,9 +8,9 @@ A = np.eye(dim)
minres = eigenpy.MINRES(A)
X = np.random.rand(dim,20)
X = np.random.rand(dim, 20)
B = A.dot(X)
X_est = minres.solve(B)
print("A.dot(X_est):",A.dot(X_est))
print("B:",B)
assert eigenpy.is_approx(A.dot(X_est),B,1e-6)
print("A.dot(X_est):", A.dot(X_est))
print("B:", B)
assert eigenpy.is_approx(A.dot(X_est), B, 1e-6)
......@@ -8,20 +8,22 @@ switchToNumpyArray()
rows = 10
cols = 20
def test(dtype):
Z = np.zeros((rows,cols),dtype=dtype)
Z.real = np.random.rand(rows,cols)
Z.imag = np.random.rand(rows,cols)
Z_real = real(Z)
assert (Z_real == Z.real).all()
Z_imag = imag(Z)
assert (Z_imag == Z.imag).all()
Y = np.ones((rows,cols))
Y_complex = ascomplex(Y)
assert (Y_complex.real == Y).all()
assert (Y_complex.imag == np.zeros((rows,cols))).all()
Z = np.zeros((rows, cols), dtype=dtype)
Z.real = np.random.rand(rows, cols)
Z.imag = np.random.rand(rows, cols)
Z_real = real(Z)
assert (Z_real == Z.real).all()
Z_imag = imag(Z)
assert (Z_imag == Z.imag).all()
Y = np.ones((rows, cols))
Y_complex = ascomplex(Y)
assert (Y_complex.real == Y).all()
assert (Y_complex.imag == np.zeros((rows, cols))).all()
# Float
test(np.csingle)
......
import numpy as np
from eigen_ref import *
def test(mat):
printMatrix(mat)
fill(mat,1.)
printMatrix(mat)
assert np.array_equal(mat,np.full(mat.shape,1.))
printMatrix(mat)
fill(mat, 1.0)
printMatrix(mat)
assert np.array_equal(mat, np.full(mat.shape, 1.0))
A_ref = asRef(mat.shape[0], mat.shape[1])
A_ref.fill(1.0)
A_ref2 = asRef(mat.shape[0], mat.shape[1])
assert np.array_equal(A_ref, A_ref2)
A_ref = asRef(mat.shape[0],mat.shape[1])
A_ref.fill(1.)
A_ref2 = asRef(mat.shape[0],mat.shape[1])
A_ref2.fill(0)
assert np.array_equal(A_ref, A_ref2)
assert np.array_equal(A_ref,A_ref2)
ref = asRef(mat)
assert np.all(ref == mat)
A_ref2.fill(0)
assert np.array_equal(A_ref,A_ref2)
const_ref = asConstRef(mat)
assert np.all(const_ref == mat)
rows = 10
cols = 30
mat = np.array(np.zeros((rows,cols)))
mat = np.ones((rows, cols), order="F")
test(mat)
import eigenpy
eigenpy.switchToNumpyArray()
import numpy as np
import numpy.linalg as la
dim = 100
A = np.random.rand(dim,dim)
A = np.random.rand(dim, dim)
es = eigenpy.EigenSolver(A)
V = es.eigenvectors()
D = es.eigenvalues()
assert eigenpy.is_approx(A.dot(V).real,V.dot(np.diag(D)).real)
assert eigenpy.is_approx(A.dot(V).imag,V.dot(np.diag(D)).imag)
assert eigenpy.is_approx(A.dot(V).real, V.dot(np.diag(D)).real)
assert eigenpy.is_approx(A.dot(V).imag, V.dot(np.diag(D)).imag)
......@@ -2,83 +2,87 @@ from __future__ import print_function
from geometry import *
import numpy as np
from numpy import cos,sin
from numpy import cos, sin
verbose = True
def isapprox(a,b,epsilon=1e-6):
if issubclass(a.__class__,np.ndarray) and issubclass(b.__class__,np.ndarray):
return np.allclose(a,b,epsilon)
def isapprox(a, b, epsilon=1e-6):
if issubclass(a.__class__, np.ndarray) and issubclass(b.__class__, np.ndarray):
return np.allclose(a, b, epsilon)
else:
return abs(a-b)<epsilon
return abs(a - b) < epsilon
# --- Quaternion ---------------------------------------------------------------
# Coefficient initialisation
verbose and print("[Quaternion] Coefficient initialisation")
q = Quaternion(1,2,3,4)
q = Quaternion(1, 2, 3, 4)
q.normalize()
assert(isapprox(np.linalg.norm(q.coeffs()),q.norm()))
assert(isapprox(np.linalg.norm(q.coeffs()),1))
assert isapprox(np.linalg.norm(q.coeffs()), q.norm())
assert isapprox(np.linalg.norm(q.coeffs()), 1)
# Coefficient-vector initialisation
verbose and print("[Quaternion] Coefficient-vector initialisation")
v = np.array([0.5,-0.5,0.5,0.5])
v = np.array([0.5, -0.5, 0.5, 0.5])
qv = Quaternion(v)
assert(isapprox(qv.coeffs(), v))
assert isapprox(qv.coeffs(), v)
# Angle axis initialisation
verbose and print("[Quaternion] AngleAxis initialisation")
r = AngleAxis(q)
q2 = Quaternion(r)
assert(q==q)
assert(isapprox(q.coeffs(),q2.coeffs()))
assert(q2.isApprox(q2))
assert(q2.isApprox(q2,1e-2))
assert q == q
assert isapprox(q.coeffs(), q2.coeffs())
assert q2.isApprox(q2)
assert q2.isApprox(q2, 1e-2)
Rq = q.matrix()
Rr = r.matrix()
assert(isapprox(Rq.dot(Rq.T),np.eye(3)))
assert(isapprox(Rr,Rq))
assert isapprox(Rq.dot(Rq.T), np.eye(3))
assert isapprox(Rr, Rq)
# Rotation matrix initialisation
verbose and print("[Quaternion] Rotation Matrix initialisation")
qR = Quaternion(Rr)
assert(q.isApprox(qR))
assert(isapprox(q.coeffs(),qR.coeffs()))
assert q.isApprox(qR)
assert isapprox(q.coeffs(), qR.coeffs())
assert(isapprox(qR[3],1./np.sqrt(30)))
assert isapprox(qR[3], 1.0 / np.sqrt(30))
try:
qR[5]
print("Error, this message should not appear.")
qR[5]
print("Error, this message should not appear.")
except RuntimeError as e:
if verbose: print("As expected, caught exception: ", e)
if verbose:
print("As expected, caught exception: ", e)
# --- Angle Vector ------------------------------------------------
r = AngleAxis(.1,np.array([1,0,0],np.double))
if verbose: print("Rx(.1) = \n\n",r.matrix(),"\n")
assert( isapprox(r.matrix()[2,2],cos(r.angle)))
assert( isapprox(r.axis,np.array([1.,0,0])) )
assert( isapprox(r.angle,0.1) )
assert(r.isApprox(r))
assert(r.isApprox(r,1e-2))
r = AngleAxis(0.1, np.array([1, 0, 0], np.double))
if verbose:
print("Rx(.1) = \n\n", r.matrix(), "\n")
assert isapprox(r.matrix()[2, 2], cos(r.angle))
assert isapprox(r.axis, np.array([1.0, 0, 0]))
assert isapprox(r.angle, 0.1)
assert r.isApprox(r)
assert r.isApprox(r, 1e-2)
r.axis = np.array([0,1,0],np.double).T
assert( isapprox(r.matrix()[0,0],cos(r.angle)))
r.axis = np.array([0, 1, 0], np.double).T
assert isapprox(r.matrix()[0, 0], cos(r.angle))
ri = r.inverse()
assert( isapprox(ri.angle,-.1) )
assert isapprox(ri.angle, -0.1)
R = r.matrix()
r2 = AngleAxis(np.dot(R,R))
assert( isapprox(r2.angle,r.angle*2) )
r2 = AngleAxis(np.dot(R, R))
assert isapprox(r2.angle, r.angle * 2)
# --- USER FUNCTIONS -----------------------------------------------------------
ro = testOutAngleAxis()
assert(ro.__class__ == AngleAxis)
assert ro.__class__ == AngleAxis
res = testInAngleAxis(r)
assert( res==r.angle )
assert res == r.angle
qo = testOutQuaternion()
assert(qo.__class__ == Quaternion)
assert qo.__class__ == Quaternion
res = testInQuaternion(q)
assert(q.norm() == res)
assert q.norm() == res
......@@ -5,144 +5,176 @@ import matrix as eigenpy
verbose = True
if verbose: print("===> From empty MatrixXd to Py")
if verbose:
print("===> From empty MatrixXd to Py")
M = eigenpy.emptyMatrix()
assert M.shape == (0,0)
assert M.shape == (0, 0)
if verbose: print("===> From empty VectorXd to Py")
if verbose:
print("===> From empty VectorXd to Py")
v = eigenpy.emptyVector()
assert v.shape == (0,)
if verbose: print("===> From MatrixXd to Py")
M = eigenpy.naturals(3,3,verbose)
Mcheck = np.reshape(np.array(range(9),np.double),[3,3])
assert np.array_equal(Mcheck,M)
if verbose: print("===> From Matrix3d to Py")
M33= eigenpy.naturals33(verbose)
assert np.array_equal(Mcheck,M33)
if verbose: print("===> From VectorXd to Py")
v = eigenpy.naturalsX(3,verbose)
vcheck = np.array(range(3),np.double).T
assert np.array_equal(vcheck ,v)
if verbose: print("===> From Py to Eigen::MatrixXd")
if verbose: print("===> From Py to Eigen::MatrixXd")
if verbose: print("===> From Py to Eigen::MatrixXd")
Mref = np.reshape(np.array(range(64),np.double),[8,8])
if verbose:
print("===> From MatrixXd to Py")
M = eigenpy.naturals(3, 3, verbose)
Mcheck = np.reshape(np.array(range(9), np.double), [3, 3])
assert np.array_equal(Mcheck, M)
if verbose:
print("===> From Matrix3d to Py")
M33 = eigenpy.naturals33(verbose)
assert np.array_equal(Mcheck, M33)
if verbose:
print("===> From VectorXd to Py")
v = eigenpy.naturalsX(3, verbose)
vcheck = np.array(range(3), np.double).T
assert np.array_equal(vcheck, v)
if verbose:
print("===> From Py to Eigen::MatrixXd")
if verbose:
print("===> From Py to Eigen::MatrixXd")
if verbose:
print("===> From Py to Eigen::MatrixXd")
Mref = np.reshape(np.array(range(64), np.double), [8, 8])
# Test base function
Mref_from_base = eigenpy.base(Mref)
assert( np.array_equal(Mref,Mref_from_base) );
assert np.array_equal(Mref, Mref_from_base)
# Test plain function
Mref_from_plain = eigenpy.plain(Mref)
assert( np.array_equal(Mref,Mref_from_plain) );
assert np.array_equal(Mref, Mref_from_plain)
if verbose: print("===> Matrix 8x8")
if verbose:
print("===> Matrix 8x8")
M = Mref
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block 0:3x0:3")
M = Mref[0:3,0:3]
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block 1:3x1:3")
M = Mref[1:3,1:3]
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block 1:5:2x1:5:2")
M = Mref[1:5:2,1:5:2]
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block 1:8:3x1:5")
M = Mref[1:8:3,1:5]
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block transpose 1:8:3x1:6:2")
M = Mref[1:8:3,0:6:2].T
assert( np.array_equal(M,eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 1x0:6:2")
M = Mref[1:2,0:6:2]
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 1x0:6:2 tanspose")
M = Mref[1:2,0:6:2].T
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 0:6:2x1")
M = Mref[0:6:2,1:2]
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> Block Vector 0:6:2x1 tanspose")
M = Mref[0:6:2,1:2].T
assert( np.array_equal(M.squeeze(),eigenpy.reflex(M,verbose)) );
if verbose: print("===> From Py to Eigen::VectorXd")
if verbose: print("===> From Py to Eigen::VectorXd")
if verbose: print("===> From Py to Eigen::VectorXd")
if verbose: print("===> Block Vector 0:6:2x1 1 dim")
M = Mref[0:6:2,1].T
assert np.array_equal(M, eigenpy.reflex(M, verbose))
if verbose:
print("===> Block 0:3x0:3")
M = Mref[0:3, 0:3]
assert np.array_equal(M, eigenpy.reflex(M, verbose))
if verbose:
print("===> Block 1:3x1:3")
M = Mref[1:3, 1:3]
assert np.array_equal(M, eigenpy.reflex(M, verbose))
if verbose:
print("===> Block 1:5:2x1:5:2")
M = Mref[1:5:2, 1:5:2]
assert np.array_equal(M, eigenpy.reflex(M, verbose))
if verbose:
print("===> Block 1:8:3x1:5")
M = Mref[1:8:3, 1:5]
assert np.array_equal(M, eigenpy.reflex(M, verbose))
if verbose:
print("===> Block transpose 1:8:3x1:6:2")
M = Mref[1:8:3, 0:6:2].T
assert np.array_equal(M, eigenpy.reflex(M, verbose))
if verbose:
print("===> Block Vector 1x0:6:2")
M = Mref[1:2, 0:6:2]
assert np.array_equal(M.squeeze(), eigenpy.reflex(M, verbose))
if verbose:
print("===> Block Vector 1x0:6:2 tanspose")
M = Mref[