|
| 1 | + |
| 2 | + |
| 3 | +#pragma once |
| 4 | + |
| 5 | +#ifndef EXAMPLE_CUSTOM_NUMERIC_TYPE |
| 6 | +#define EXAMPLE_CUSTOM_NUMERIC_TYPE |
| 7 | + |
| 8 | +#include <eigenpy/eigenpy.hpp> |
| 9 | +#include <eigenpy/user-type.hpp> |
| 10 | +#include <eigenpy/ufunc.hpp> |
| 11 | + |
| 12 | +#include <boost/multiprecision/mpc.hpp> |
| 13 | + |
| 14 | + |
| 15 | +namespace bmp = boost::multiprecision; |
| 16 | +using bmp::backends::mpc_complex_backend; |
| 17 | +using mpfr_complex = bmp::number<mpc_complex_backend<0>, bmp::et_on >; // T is a variable-precision complex number with expression templates turned on. |
| 18 | + |
| 19 | + |
| 20 | + |
| 21 | +void Expose(); |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | + |
| 28 | +// this code derived from |
| 29 | +// https://github.com/stack-of-tasks/eigenpy/issues/365 |
| 30 | +// where I asked about using custom types, and @jcarpent responded with a discussion |
| 31 | +// of an application of this in Pinnochio, a library for rigid body dynamics. |
| 32 | +namespace eigenpy |
| 33 | +{ |
| 34 | + namespace internal |
| 35 | + { |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | +// a template specialization for complex numbers |
| 40 | + // derived directly from the example for Pinnochio |
| 41 | +template <> |
| 42 | +struct getitem<mpfr_complex> |
| 43 | +{ |
| 44 | + static PyObject* run(void* data, void* /* arr */) { |
| 45 | + mpfr_complex & mpfr_scalar = *static_cast<mpfr_complex*>(data); |
| 46 | + auto & backend = mpfr_scalar.backend(); |
| 47 | + |
| 48 | + if(backend.data()[0].re->_mpfr_d == 0) // If the mpfr_scalar is not initialized, we have to init it. |
| 49 | + { |
| 50 | + mpfr_scalar = mpfr_complex(0); |
| 51 | + } |
| 52 | + boost::python::object m(boost::ref(mpfr_scalar)); |
| 53 | + Py_INCREF(m.ptr()); |
| 54 | + return m.ptr(); |
| 55 | + } |
| 56 | +}; |
| 57 | + |
| 58 | + |
| 59 | +} // namespace internal |
| 60 | + |
| 61 | + |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +// i lifted this from EigenPy and adapted it, basically removing the calls for the comparitors. |
| 67 | +template <typename Scalar> |
| 68 | +void registerUfunct_without_comparitors(){ |
| 69 | + const int type_code = Register::getTypeCode<Scalar>(); |
| 70 | + |
| 71 | + PyObject *numpy_str; |
| 72 | + #if PY_MAJOR_VERSION >= 3 |
| 73 | + numpy_str = PyUnicode_FromString("numpy"); |
| 74 | + #else |
| 75 | + numpy_str = PyString_FromString("numpy"); |
| 76 | + #endif |
| 77 | + PyObject *numpy; |
| 78 | + numpy = PyImport_Import(numpy_str); |
| 79 | + Py_DECREF(numpy_str); |
| 80 | + |
| 81 | + import_ufunc(); |
| 82 | + |
| 83 | + // Matrix multiply |
| 84 | + { |
| 85 | + int types[3] = {type_code, type_code, type_code}; |
| 86 | + |
| 87 | + std::stringstream ss; |
| 88 | + ss << "return result of multiplying two matrices of "; |
| 89 | + ss << bp::type_info(typeid(Scalar)).name(); |
| 90 | + PyUFuncObject *ufunc = |
| 91 | + (PyUFuncObject *)PyObject_GetAttrString(numpy, "matmul"); |
| 92 | + if (!ufunc) { |
| 93 | + std::stringstream ss; |
| 94 | + ss << "Impossible to define matrix_multiply for given type " |
| 95 | + << bp::type_info(typeid(Scalar)).name() << std::endl; |
| 96 | + eigenpy::Exception(ss.str()); |
| 97 | + } |
| 98 | + if (PyUFunc_RegisterLoopForType((PyUFuncObject *)ufunc, type_code, |
| 99 | + &internal::gufunc_matrix_multiply<Scalar>, |
| 100 | + types, 0) < 0) { |
| 101 | + std::stringstream ss; |
| 102 | + ss << "Impossible to register matrix_multiply for given type " |
| 103 | + << bp::type_info(typeid(Scalar)).name() << std::endl; |
| 104 | + eigenpy::Exception(ss.str()); |
| 105 | + } |
| 106 | + |
| 107 | + Py_DECREF(ufunc); |
| 108 | + } |
| 109 | + |
| 110 | + // Binary operators |
| 111 | + EIGENPY_REGISTER_BINARY_UFUNC(add, type_code, Scalar, Scalar, Scalar); |
| 112 | + EIGENPY_REGISTER_BINARY_UFUNC(subtract, type_code, Scalar, Scalar, Scalar); |
| 113 | + EIGENPY_REGISTER_BINARY_UFUNC(multiply, type_code, Scalar, Scalar, Scalar); |
| 114 | + EIGENPY_REGISTER_BINARY_UFUNC(divide, type_code, Scalar, Scalar, Scalar); |
| 115 | + |
| 116 | + // Comparison operators |
| 117 | + EIGENPY_REGISTER_BINARY_UFUNC(equal, type_code, Scalar, Scalar, bool); |
| 118 | + EIGENPY_REGISTER_BINARY_UFUNC(not_equal, type_code, Scalar, Scalar, bool); |
| 119 | + |
| 120 | + //these are commented out because the comparisons are NOT defined for complex types!! |
| 121 | + // EIGENPY_REGISTER_BINARY_UFUNC(greater, type_code, Scalar, Scalar, bool); |
| 122 | + // EIGENPY_REGISTER_BINARY_UFUNC(less, type_code, Scalar, Scalar, bool); |
| 123 | + // EIGENPY_REGISTER_BINARY_UFUNC(greater_equal, type_code, Scalar, Scalar, bool); |
| 124 | + // EIGENPY_REGISTER_BINARY_UFUNC(less_equal, type_code, Scalar, Scalar, bool); |
| 125 | + |
| 126 | + // Unary operators |
| 127 | + EIGENPY_REGISTER_UNARY_UFUNC(negative, type_code, Scalar, Scalar); |
| 128 | + |
| 129 | + Py_DECREF(numpy); |
| 130 | +} |
| 131 | + |
| 132 | +} // namespace eigenpy |
| 133 | + |
| 134 | + |
| 135 | + |
| 136 | +namespace bp = boost::python; |
| 137 | + |
| 138 | +// this derived directly from the code at https://github.com/stack-of-tasks/eigenpy/issues/365, in which this example was requested |
| 139 | +template<typename BoostNumber> |
| 140 | +struct BoostNumberPythonVisitor |
| 141 | +: public boost::python::def_visitor< BoostNumberPythonVisitor<BoostNumber> > |
| 142 | +{ |
| 143 | + |
| 144 | +public: |
| 145 | + |
| 146 | + template<class PyClass> |
| 147 | + void visit(PyClass& cl) const |
| 148 | + { |
| 149 | + cl |
| 150 | + .def(bp::init<>("Default constructor.",bp::arg("self"))) |
| 151 | + .def(bp::init<BoostNumber>("Copy constructor.",bp::args("self","value"))) |
| 152 | + .def(bp::init<std::string>("Constructor from a string.",bp::args("self","str_value"))) |
| 153 | + .def(bp::init<std::string, std::string>("Constructor from a pair of strings.",bp::args("self","real","imag"))) |
| 154 | + |
| 155 | + |
| 156 | + .def(bp::self + bp::self) |
| 157 | + .def(bp::self += bp::self) |
| 158 | + .def(bp::self - bp::self) |
| 159 | + .def(bp::self -= bp::self) |
| 160 | + .def(bp::self * bp::self) |
| 161 | + .def(bp::self *= bp::self) |
| 162 | + .def(bp::self / bp::self) |
| 163 | + .def(bp::self /= bp::self) |
| 164 | + |
| 165 | + .def(bp::self == bp::self) |
| 166 | + .def(bp::self != bp::self) |
| 167 | + .def(bp::self_ns::pow(bp::self_ns::self,long())) |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | + .def("str",&BoostNumber::str,bp::args("self","precision","scientific")) |
| 172 | + |
| 173 | + .def("default_precision", |
| 174 | + static_cast<unsigned (*)()>(BoostNumber::default_precision), |
| 175 | + "Get the default precision of the class.") |
| 176 | + .def("default_precision", |
| 177 | + static_cast<void (*)(unsigned)>(BoostNumber::default_precision),bp::arg("digits10"), |
| 178 | + "Set the default precision of the class.") |
| 179 | + .staticmethod("default_precision") |
| 180 | + |
| 181 | + .def("precision", |
| 182 | + static_cast<unsigned (BoostNumber::*)() const>(&BoostNumber::precision), |
| 183 | + bp::arg("self"), |
| 184 | + "Get the precision of this.") |
| 185 | + .def("precision", |
| 186 | + static_cast<void (BoostNumber::*)(unsigned)>(&BoostNumber::precision), |
| 187 | + bp::args("self","digits10"), |
| 188 | + "Set the precision of this.") |
| 189 | + |
| 190 | + |
| 191 | + .def("__str__",&print,bp::arg("self")) |
| 192 | + .def("__repr__",&print,bp::arg("self")) |
| 193 | + |
| 194 | + .def("set_display_precision",&set_display_precision,bp::arg("digit"), |
| 195 | + "Set the precision when printing values.") |
| 196 | + .staticmethod("set_display_precision") |
| 197 | + |
| 198 | + .def("get_display_precision",&get_display_precision, |
| 199 | + "Get the precision when printing values.", |
| 200 | + bp::return_value_policy<bp::copy_non_const_reference>()) |
| 201 | + .staticmethod("get_display_precision") |
| 202 | + |
| 203 | + ; |
| 204 | + |
| 205 | + } |
| 206 | + |
| 207 | + static std::string print(const BoostNumber & self) |
| 208 | + { |
| 209 | + return self.str(get_display_precision(), std::ios_base::dec); |
| 210 | + } |
| 211 | + |
| 212 | + static void set_display_precision(const int digit) |
| 213 | + { |
| 214 | + get_display_precision() = digit; |
| 215 | + } |
| 216 | + |
| 217 | + static int & get_display_precision() |
| 218 | + { |
| 219 | + static int precision = BoostNumber::default_precision(); |
| 220 | + return precision; |
| 221 | + } |
| 222 | +}; |
| 223 | + |
| 224 | + |
| 225 | + |
| 226 | + |
| 227 | +#endif |
| 228 | + |
| 229 | + |
0 commit comments