forked from stack-of-tasks/eigenpy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added a bunch more exercises to the custom type, + pytest
much of the functions I added were me trying to get Python to crash in a specific way. I failed, which is a good thing, because it means that EigenPy doesn't have the bug I thought it does. BUT. EigenPy *does* have two issues exercised in the unit tests for the custom type, issues stack-of-tasks#519 and stack-of-tasks#520 . Additionally, this code exercises issue stack-of-tasks#521 , where I try to compute vector norms in two different ways and fail. Additionally, I bumped the C++ standard to C++14, since Boost 1.87 didn't work correctly with only C++11, and 1.87 is now distributed by homebrew (I develop on a Mac)
- Loading branch information
1 parent
c6048d3
commit cb58069
Showing
8 changed files
with
457 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,173 @@ | ||
# some code that exercises C++-exposed code using custom numeric type via EigenPy. | ||
|
||
import sys | ||
|
||
sys.path.append('./') | ||
|
||
import numpy as np | ||
import eigenpy_example_custom_numeric_type as example | ||
|
||
|
||
def make_empty_with_conversion(num_type): | ||
return np.array( np.empty( (3)).astype(np.int64),dtype=num_type) | ||
|
||
|
||
def make_zeros_with_conversion(num_type): | ||
return np.array( np.zeros( (3)).astype(np.int32),dtype=num_type) # make an array of the custom numeric type | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
def make_in_numpy_then_modify_in_cpp(num_type): | ||
A = make_zeros_with_conversion(num_type) | ||
example.set_to_ones(A) | ||
|
||
assert(A[0] == num_type(1)) | ||
|
||
def make_in_cpp_then_modify_in_cpp_once(num_type): | ||
|
||
A = example.make_a_vector_in_cpp(4,num_type(1)) # the second argument is used only for type dispatch | ||
example.set_to_ones(A) | ||
|
||
for a in A: | ||
assert(a == num_type(1)) | ||
|
||
|
||
def make_in_cpp_then_modify_in_cpp_list(num_type): | ||
|
||
my_list = [] | ||
|
||
for ii in range(10): | ||
A = example.make_a_vector_in_cpp(4,num_type(1)) # the second argument is used only for type dispatch | ||
my_list.append( A ) | ||
|
||
for A in my_list: | ||
example.set_to_ones(A) | ||
for a in A: | ||
assert(a == num_type(1)) | ||
|
||
example.set_to_ones(A) | ||
|
||
|
||
def make_then_call_function_taking_scalar_and_vector(num_type): | ||
A = make_zeros_with_conversion(num_type) | ||
s = num_type(3) | ||
|
||
result = example.a_function_taking_both_a_scalar_and_a_vector(s, A) | ||
|
||
|
||
|
||
def set_entire_array_to_one_value(num_type): | ||
A = example.make_a_vector_in_cpp(10, num_type(0)) # again, type dispatch on the second | ||
|
||
cst = num_type("13") / num_type("7") # 13/7 seems like a good number. why not. | ||
|
||
example.set_all_entries_to_constant(A,cst) # all entries should become the constant, in this case 13 | ||
|
||
|
||
|
||
|
||
def class_function_with_both_arguments(): | ||
num_type = example.MpfrFloat | ||
|
||
c = example.JustSomeClass(); | ||
|
||
A = example.make_a_vector_in_cpp(10, num_type(0)) # again, type dispatch on the second | ||
|
||
cst = num_type("13") / num_type("7") # 13/7 seems like a good number. why not. | ||
|
||
c.foo(cst,A) # all entries should become the constant, in this case 13 | ||
example.qwfp(cst,A) | ||
|
||
|
||
|
||
def numpy_norm(num_type): | ||
A = make_zeros_with_conversion(num_type) | ||
example.set_to_ones(A) | ||
|
||
# assert np.abs(np.linalg.norm(A) - np.sqrt(3)) < 1e-10 | ||
|
||
|
||
def numpy_manual_norm(num_type): | ||
A = make_zeros_with_conversion(num_type) | ||
example.set_to_ones(A) | ||
assert np.sqrt(np.sum((A)**2)) < 1e-10 | ||
print('arst') | ||
|
||
|
||
|
||
def expected_to_succeed(num_type): | ||
|
||
print(f'testing {num_type} at precision {num_type.default_precision()}') | ||
|
||
make_empty_with_conversion(num_type) | ||
make_zeros_with_conversion(num_type) | ||
|
||
make_in_numpy_then_modify_in_cpp(num_type) | ||
make_in_cpp_then_modify_in_cpp_once(num_type) | ||
make_in_cpp_then_modify_in_cpp_list(num_type) | ||
|
||
set_entire_array_to_one_value(num_type) | ||
|
||
make_then_call_function_taking_scalar_and_vector(num_type) | ||
|
||
class_function_with_both_arguments() | ||
|
||
numpy_norm(num_type) | ||
numpy_manual_norm(num_type) | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
def make_empty_without_conversion(num_type): | ||
return np.empty( (3),dtype=num_type) | ||
|
||
def make_zeros_without_conversion(num_type): | ||
|
||
A = np.zeros( (3),dtype=num_type) # make an array of the custom numeric type | ||
assert(A[0] == num_type(0)) | ||
|
||
return A | ||
|
||
def try_things(num_type): | ||
|
||
print(f'testing {num_type}') | ||
def expected_to_crash(num_type): | ||
print("the following calls are expected to crash, not because they should, but because for whatever reason, eigenpy does not let us directly make numpy arrays WITHOUT converting") | ||
make_empty_without_conversion(num_type) | ||
make_zeros_without_conversion(num_type) | ||
|
||
x = num_type(2) # the number 2, in variable precision as a complex number | ||
|
||
import numpy as np | ||
|
||
print('making array from empty WITH conversion') | ||
A = np.array( np.empty( (3,4)).astype(np.int64),dtype=num_type) | ||
|
||
print(A) | ||
|
||
print('making array from zeros WITH conversion') | ||
M = np.array( np.zeros( (3,4)).astype(np.int64),dtype=num_type) # make an array of the custom numeric type | ||
|
||
print(M) | ||
|
||
assert(M[0,0] == num_type(0)) | ||
|
||
|
||
example.set_to_ones(M) | ||
|
||
|
||
assert(M[0,0] == num_type(1)) | ||
for prec in [20, 50, 100]: | ||
example.MpfrFloat.default_precision(prec) | ||
expected_to_succeed(example.MpfrFloat) | ||
|
||
example.MpfrComplex.default_precision(prec) | ||
expected_to_succeed(example.MpfrComplex) | ||
|
||
print(M) | ||
|
||
print('making zeros without conversion') | ||
B = np.zeros( (4,5), dtype=num_type) | ||
print(B) | ||
|
||
|
||
try_things(example.MpfrFloat) | ||
try_things(example.MpfrComplex) | ||
# these really shouldn't crash!!!! but they do, and it's a problem. 2024.12.18 | ||
expected_to_crash(example.MpfrFloat) | ||
expected_to_crash(example.MpfrComplex) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#pragma once | ||
|
||
#ifndef EXAMPLE_A_CLASS | ||
#define EXAMPLE_A_CLASS | ||
|
||
#include <eigenpy/eigenpy.hpp> | ||
#include <eigenpy/user-type.hpp> | ||
#include <eigenpy/ufunc.hpp> | ||
|
||
#include <boost/multiprecision/mpc.hpp> | ||
|
||
#include <boost/multiprecision/eigen.hpp> | ||
|
||
|
||
|
||
namespace bmp = boost::multiprecision; | ||
|
||
using mpfr_float = | ||
boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<0>, | ||
boost::multiprecision::et_off>; | ||
|
||
using bmp::backends::mpc_complex_backend; | ||
using mpfr_complex = | ||
bmp::number<mpc_complex_backend<0>, | ||
bmp::et_off>; // T is a variable-precision complex number with | ||
// expression templates turned on. | ||
|
||
|
||
class Whatevs : public boost::python::def_visitor<Whatevs>{ | ||
|
||
public: | ||
static | ||
void qwfp(mpfr_float const& c, Eigen::Matrix<mpfr_float,Eigen::Dynamic, Eigen::Dynamic> const& M){} | ||
}; | ||
|
||
class JustSomeClass | ||
{ | ||
public: | ||
JustSomeClass(){}; | ||
~JustSomeClass() = default; | ||
|
||
void foo(mpfr_float const& the_constant, Eigen::Matrix<mpfr_float, Eigen::Dynamic, Eigen::Dynamic> const& M){}; | ||
|
||
static int bar(JustSomeClass const& self, mpfr_float const& c, Eigen::Matrix<mpfr_float,Eigen::Dynamic, Eigen::Dynamic> const& M){return 42;} | ||
}; | ||
|
||
|
||
|
||
|
||
|
||
void ExposeAClass(); | ||
|
||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.