1 // Copyright 2012 John Maddock. Distributed under the Boost
2 // Software License, Version 1.0. (See accompanying file
3 // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5 #include <boost/multiprecision/cpp_int.hpp>
6 #include <boost/multiprecision/cpp_dec_float.hpp>
7 #include <boost/multiprecision/cpp_bin_float.hpp>
11 #include <boost/multiprecision/mpfr.hpp>
12 #include <boost/multiprecision/logged_adaptor.hpp>
13 #include <boost/multiprecision/gmp.hpp>
14 #include <boost/multiprecision/mpc.hpp>
18 using namespace Eigen;
21 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
22 struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> >
24 typedef boost::multiprecision::number<Backend, ExpressionTemplates> self_type;
25 typedef typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type Real;
26 typedef self_type NonInteger; // Not correct but we can't do much better??
27 typedef double Literal;
28 typedef self_type Nested;
31 IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex,
32 IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer,
36 IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true,
37 RequireInitialization = 1,
41 return std::numeric_limits<Real>::epsilon();
43 static Real dummy_precision()
45 return sqrt(epsilon());
49 return (std::numeric_limits<Real>::max)();
53 return (std::numeric_limits<Real>::min)();
55 static int digits10_imp(const boost::mpl::true_&)
57 return std::numeric_limits<Real>::digits10;
60 static int digits10_imp(const boost::mpl::bool_<B>&)
62 return Real::default_precision();
66 return digits10_imp(boost::mpl::bool_ < std::numeric_limits<Real>::digits10 && (std::numeric_limits<Real>::digits10 != INT_MAX) ? true : false > ());
70 #define BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(A) \
71 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> \
72 struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, A, BinaryOp> \
74 static_assert(boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported."); \
75 typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType; \
77 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> \
78 struct ScalarBinaryOpTraits<A, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp> \
80 static_assert(boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported."); \
81 typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType; \
84 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(float)
85 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(double)
86 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(long double)
87 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(char)
88 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned char)
89 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(signed char)
90 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(short)
91 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned short)
92 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(int)
93 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned int)
94 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(long)
95 BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned long)
97 template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Backend2, boost::multiprecision::expression_template_option ExpressionTemplates2, typename BinaryOp>
98 struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2>, BinaryOp>
101 boost::multiprecision::is_compatible_arithmetic_type<boost::multiprecision::number<Backend2, ExpressionTemplates2>, boost::multiprecision::number<Backend, ExpressionTemplates> >::value
102 || boost::multiprecision::is_compatible_arithmetic_type<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >::value, "Interoperability with this arithmetic type is not supported.");
103 typedef typename boost::mpl::if_c<boost::is_convertible<boost::multiprecision::number<Backend2, ExpressionTemplates2>, boost::multiprecision::number<Backend, ExpressionTemplates> >::value,
104 boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >::type ReturnType;
107 template<unsigned D, typename BinaryOp>
108 struct ScalarBinaryOpTraits<boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<D>, boost::multiprecision::et_on>, boost::multiprecision::mpfr_float, BinaryOp>
110 typedef boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<D>, boost::multiprecision::et_on> ReturnType;
113 template<typename BinaryOp>
114 struct ScalarBinaryOpTraits<boost::multiprecision::mpfr_float, boost::multiprecision::mpc_complex, BinaryOp>
116 typedef boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>, boost::multiprecision::et_on> ReturnType;
119 template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp>
120 struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp>
122 typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;
125 template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4, typename BinaryOp>
126 struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, BinaryOp>
128 static_assert(boost::is_convertible<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");
129 typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;
132 template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp>
133 struct ScalarBinaryOpTraits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp>
135 static_assert(boost::is_convertible<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");
136 typedef boost::multiprecision::number<Backend, ExpressionTemplates> ReturnType;
142 struct related_number
148 struct related_number<boost::multiprecision::cpp_bin_float_50>
150 typedef boost::multiprecision::cpp_bin_float_quad type;
153 struct related_number<boost::multiprecision::cpp_dec_float_100>
155 typedef boost::multiprecision::cpp_dec_float_50 type;
161 // expected results first:
162 Matrix<Num, 2, 2> r1, r2;
165 Matrix<Num, 3, 1> r3;
170 Matrix<Num, Dynamic, Dynamic> b(2, 2);
172 std::cout << "a + b =\n"
173 << a + b << std::endl;
174 BOOST_CHECK_EQUAL(a + b, r1);
175 std::cout << "a - b =\n"
176 << a - b << std::endl;
177 BOOST_CHECK_EQUAL(a - b, r2);
178 std::cout << "Doing a += b;" << std::endl;
180 std::cout << "Now a =\n"
182 Matrix<Num, 3, 1> v(1, 2, 3);
183 Matrix<Num, 3, 1> w(1, 0, 0);
184 std::cout << "-v + w - v =\n"
185 << -v + w - v << std::endl;
186 BOOST_CHECK_EQUAL(-v + w - v, r3);
194 Matrix<Num, 3, 1> v(1, 2, 3);
195 std::cout << "a * 2.5 =\n"
196 << a * 2.5 << std::endl;
197 std::cout << "0.1 * v =\n"
198 << 0.1 * v << std::endl;
199 std::cout << "Doing v *= 2;" << std::endl;
201 std::cout << "Now v =\n"
204 std::cout << "Doing v *= Num;" << std::endl;
206 std::cout << "Now v =\n"
208 typedef typename related_number<Num>::type related_type;
210 std::cout << "Doing v *= RelatedType;" << std::endl;
212 std::cout << "Now v =\n"
214 std::cout << "RelatedType * v =\n"
215 << r * v << std::endl;
216 std::cout << "Doing v *= RelatedType^2;" << std::endl;
218 std::cout << "Now v =\n"
220 std::cout << "RelatedType^2 * v =\n"
221 << r * r * v << std::endl;
223 static_assert(boost::is_same<typename Eigen::ScalarBinaryOpTraits<Num, related_type, Eigen::internal::scalar_product_op<Num, related_type> >::ReturnType, Num>::value, "Incorrect type.");
230 Matrix<Num, Dynamic, Dynamic> a = Matrix<Num, Dynamic, Dynamic>::Random(2, 2);
231 cout << "Here is the matrix a\n"
233 cout << "Here is the matrix a^T\n"
234 << a.transpose() << endl;
235 cout << "Here is the conjugate of a\n"
236 << a.conjugate() << endl;
237 cout << "Here is the matrix a^*\n"
238 << a.adjoint() << endl;
244 Matrix<Num, 2, 2> mat;
247 Matrix<Num, 2, 1> u(-1, 1), v(2, 0);
248 std::cout << "Here is mat*mat:\n"
249 << mat * mat << std::endl;
250 std::cout << "Here is mat*u:\n"
251 << mat * u << std::endl;
252 std::cout << "Here is u^T*mat:\n"
253 << u.transpose() * mat << std::endl;
254 std::cout << "Here is u^T*v:\n"
255 << u.transpose() * v << std::endl;
256 std::cout << "Here is u*v^T:\n"
257 << u * v.transpose() << std::endl;
258 std::cout << "Let's multiply mat by itself" << std::endl;
260 std::cout << "Now mat is mat:\n"
268 Matrix<Num, 3, 1> v(1, 2, 3);
269 Matrix<Num, 3, 1> w(0, 1, 2);
270 cout << "Dot product: " << v.dot(w) << endl;
271 Num dp = v.adjoint() * w; // automatic conversion of the inner product to a scalar
272 cout << "Dot product via a matrix product: " << dp << endl;
273 cout << "Cross product:\n"
274 << v.cross(w) << endl;
281 Matrix<Num, 2, 2> mat;
284 cout << "Here is mat.sum(): " << mat.sum() << endl;
285 cout << "Here is mat.prod(): " << mat.prod() << endl;
286 cout << "Here is mat.mean(): " << mat.mean() << endl;
287 cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
288 cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
289 cout << "Here is mat.trace(): " << mat.trace() << endl;
297 Array<Num, Dynamic, Dynamic> m(2, 2);
299 // assign some values coefficient by coefficient
303 m(1, 1) = m(0, 1) + m(1, 0);
305 // print values to standard output
309 // using the comma-initializer is also allowed
313 // print values to standard output
321 Array<Num, Dynamic, Dynamic> a(3, 3);
322 Array<Num, Dynamic, Dynamic> b(3, 3);
331 cout << "a + b = " << endl
334 // Subtracting a scalar from an array
335 cout << "a - 2 = " << endl
343 Array<Num, Dynamic, Dynamic> a(2, 2);
344 Array<Num, Dynamic, Dynamic> b(2, 2);
349 cout << "a * b = " << endl
357 Array<Num, Dynamic, 1> a = Array<Num, Dynamic, 1>::Random(5);
359 cout << "a =" << endl
361 cout << "a.abs() =" << endl
363 cout << "a.abs().sqrt() =" << endl
364 << a.abs().sqrt() << endl;
365 cout << "a.min(a.abs().sqrt()) =" << endl
366 << a.std::min)(a.abs().sqrt()) << endl;
373 Matrix<Num, Dynamic, Dynamic> m(2, 2);
374 Matrix<Num, Dynamic, Dynamic> n(2, 2);
375 Matrix<Num, Dynamic, Dynamic> result(2, 2);
381 cout << "-- Matrix m*n: --" << endl
384 result = m.array() * n.array();
385 cout << "-- Array m*n: --" << endl
388 result = m.cwiseProduct(n);
389 cout << "-- With cwiseProduct: --" << endl
392 result = m.array() + 4;
393 cout << "-- Array m + 4: --" << endl
402 Matrix<Num, Dynamic, Dynamic> m(2, 2);
403 Matrix<Num, Dynamic, Dynamic> n(2, 2);
404 Matrix<Num, Dynamic, Dynamic> result(2, 2);
410 result = (m.array() + 4).matrix() * m;
411 cout << "-- Combination 1: --" << endl
414 result = (m.array() * n.array()).matrix() * m;
415 cout << "-- Combination 2: --" << endl
424 Matrix<Num, Dynamic, Dynamic> m(4, 4);
429 cout << "Block in the middle" << endl;
430 cout << m.template block<2, 2>(1, 1) << endl
432 for (int i = 1; i <= 3; ++i)
434 cout << "Block of size " << i << "x" << i << endl;
435 cout << m.block(0, 0, i, i) << endl
447 Array<Num, 4, 4> a = Array<Num, 4, 4>::Constant(0.6);
448 cout << "Here is the array a:" << endl
451 a.template block<2, 2>(1, 1) = m;
452 cout << "Here is now a with m copied into its central 2x2 block:" << endl
455 a.block(0, 0, 2, 3) = a.block(2, 1, 2, 3);
456 cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x2 block:" << endl
465 Eigen::Matrix<Num, Dynamic, Dynamic> m(3, 3);
469 cout << "Here is the matrix m:" << endl
471 cout << "2nd Row: " << m.row(1) << endl;
472 m.col(2) += 3 * m.col(0);
473 cout << "After adding 3 times the first column into the third column, the matrix m is:\n";
486 cout << "m.leftCols(2) =" << endl
487 << m.leftCols(2) << endl
489 cout << "m.bottomRows<2>() =" << endl
490 << m.template bottomRows<2>() << endl
492 m.topLeftCorner(1, 3) = m.bottomRightCorner(3, 1).transpose();
493 cout << "After assignment, m = " << endl
501 Array<Num, Dynamic, 1> v(6);
502 v << 1, 2, 3, 4, 5, 6;
503 cout << "v.head(3) =" << endl
506 cout << "v.tail<3>() = " << endl
507 << v.template tail<3>() << endl
509 v.segment(1, 4) *= 2;
510 cout << "after 'v.segment(1,4) *= 2', v =" << endl
518 Matrix<Num, 2, 2> mat;
521 cout << "Here is mat.sum(): " << mat.sum() << endl;
522 cout << "Here is mat.prod(): " << mat.prod() << endl;
523 cout << "Here is mat.mean(): " << mat.mean() << endl;
524 cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
525 cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
526 cout << "Here is mat.trace(): " << mat.trace() << endl;
528 BOOST_CHECK_EQUAL(mat.sum(), 10);
529 BOOST_CHECK_EQUAL(mat.prod(), 24);
530 BOOST_CHECK_EQUAL(mat.mean(), Num(5) / 2);
531 BOOST_CHECK_EQUAL(mat.minCoeff(), 1);
532 BOOST_CHECK_EQUAL(mat.maxCoeff(), 4);
533 BOOST_CHECK_EQUAL(mat.trace(), 5);
540 Matrix<Num, 2, 2> mat;
543 cout << "Here is mat.sum(): " << mat.sum() << endl;
544 cout << "Here is mat.prod(): " << mat.prod() << endl;
545 cout << "Here is mat.mean(): " << mat.mean() << endl;
546 //cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
547 //cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
548 cout << "Here is mat.trace(): " << mat.trace() << endl;
555 Matrix<Num, Dynamic, 1> v(2);
556 Matrix<Num, Dynamic, Dynamic> m(2, 2), n(2, 2);
563 cout << "v.squaredNorm() = " << v.squaredNorm() << endl;
564 cout << "v.norm() = " << v.norm() << endl;
565 cout << "v.lpNorm<1>() = " << v.template lpNorm<1>() << endl;
566 cout << "v.lpNorm<Infinity>() = " << v.template lpNorm<Infinity>() << endl;
568 cout << "m.squaredNorm() = " << m.squaredNorm() << endl;
569 cout << "m.norm() = " << m.norm() << endl;
570 cout << "m.lpNorm<1>() = " << m.template lpNorm<1>() << endl;
571 cout << "m.lpNorm<Infinity>() = " << m.template lpNorm<Infinity>() << endl;
580 A << 1, 2, 3, 4, 5, 6, 7, 8, 10;
582 cout << "Here is the matrix A:\n"
584 cout << "Here is the vector b:\n"
586 Matrix<Num, 3, 1> x = A.colPivHouseholderQr().solve(b);
587 cout << "The solution is:\n"
595 Matrix<Num, 2, 2> A, b;
598 cout << "Here is the matrix A:\n"
600 cout << "Here is the right hand side b:\n"
602 Matrix<Num, 2, 2> x = A.ldlt().solve(b);
603 cout << "The solution is:\n"
611 Matrix<Num, Dynamic, Dynamic> A = Matrix<Num, Dynamic, Dynamic>::Random(100, 100);
612 Matrix<Num, Dynamic, Dynamic> b = Matrix<Num, Dynamic, Dynamic>::Random(100, 50);
613 Matrix<Num, Dynamic, Dynamic> x = A.fullPivLu().solve(b);
614 Matrix<Num, Dynamic, Dynamic> axmb = A * x - b;
615 double relative_error = static_cast<double>(abs(axmb.norm() / b.norm())); // norm() is L2 norm
616 cout << "norm1 = " << axmb.norm() << endl;
617 cout << "norm2 = " << b.norm() << endl;
618 cout << "The relative error is:\n"
619 << relative_error << endl;
628 cout << "Here is the matrix A:\n"
630 SelfAdjointEigenSolver<Matrix<Num, 2, 2> > eigensolver(A);
631 if (eigensolver.info() != Success)
633 std::cout << "Eigenvalue solver failed!" << endl;
637 cout << "The eigenvalues of A are:\n"
638 << eigensolver.eigenvalues() << endl;
639 cout << "Here's a matrix whose columns are eigenvectors of A \n"
640 << "corresponding to these eigenvalues:\n"
641 << eigensolver.eigenvectors() << endl;
653 cout << "Here is the matrix A:\n"
655 cout << "The determinant of A is " << A.determinant() << endl;
656 cout << "The inverse of A is:\n"
657 << A.inverse() << endl;
661 void test_integer_type()
669 void test_float_type()
671 std::cout << "Epsilon = " << Eigen::NumTraits<Num>::epsilon() << std::endl;
672 std::cout << "Dummy Prec = " << Eigen::NumTraits<Num>::dummy_precision() << std::endl;
673 std::cout << "Highest = " << Eigen::NumTraits<Num>::highest() << std::endl;
674 std::cout << "Lowest = " << Eigen::NumTraits<Num>::lowest() << std::endl;
675 std::cout << "Digits10 = " << Eigen::NumTraits<Num>::digits10() << std::endl;
703 void test_complex_type()
705 std::cout << "Epsilon = " << Eigen::NumTraits<Num>::epsilon() << std::endl;
706 std::cout << "Dummy Prec = " << Eigen::NumTraits<Num>::dummy_precision() << std::endl;
707 std::cout << "Highest = " << Eigen::NumTraits<Num>::highest() << std::endl;
708 std::cout << "Lowest = " << Eigen::NumTraits<Num>::lowest() << std::endl;
709 std::cout << "Digits10 = " << Eigen::NumTraits<Num>::digits10() << std::endl;
731 // example23<Num>(); //requires comparisons.
736 namespace multiprecision {
738 template <unsigned D>
739 inline void log_postfix_event(const mpc_complex_backend<D>& val, const char* event_description)
741 if (mpfr_nan_p(mpc_realref(val.data())))
743 std::cout << "Found a NaN! " << event_description << std::endl;
748 } // namespace boost::multiprecision
752 using namespace boost::multiprecision;
753 test_complex_type<mpc_complex>();
755 test_integer_type<int>();
757 test_float_type<double>();
758 test_complex_type<std::complex<double> >();
760 test_float_type<boost::multiprecision::cpp_dec_float_100>();
761 test_float_type<boost::multiprecision::cpp_bin_float_50>();
762 test_float_type<boost::multiprecision::mpfr_float>();
764 test_integer_type<boost::multiprecision::int256_t>();
765 test_integer_type<boost::multiprecision::cpp_int>();
766 test_integer_type<boost::multiprecision::cpp_rational>();
767 test_integer_type<boost::multiprecision::mpz_int>();
768 test_integer_type<boost::multiprecision::mpq_rational>();