]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright 2018 John Maddock. Distributed under the Boost | |
3 | // Software License, Version 1.0. (See accompanying file | |
4 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | #ifndef BOOST_MP_EIGEN_HPP | |
7 | #define BOOST_MP_EIGEN_HPP | |
8 | ||
9 | #include <boost/multiprecision/number.hpp> | |
10 | #include <Eigen/Core> | |
11 | ||
12 | // | |
13 | // Generic Eigen support code: | |
14 | // | |
15 | namespace Eigen { | |
1e59de90 TL |
16 | |
17 | template <class B1, class B2> | |
18 | struct NumTraitsImp; | |
19 | ||
20 | template <class B1> | |
21 | struct NumTraitsImp<B1, B1> | |
92f5a8d4 | 22 | { |
1e59de90 TL |
23 | using self_type = B1; |
24 | using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type; | |
25 | using NonInteger = self_type; // Not correct but we can't do much better?? | |
26 | using Literal = double; | |
27 | using Nested = self_type; | |
92f5a8d4 TL |
28 | enum |
29 | { | |
30 | IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex, | |
31 | IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer, | |
32 | ReadCost = 1, | |
33 | AddCost = 4, | |
34 | MulCost = 8, | |
35 | IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true, | |
36 | RequireInitialization = 1, | |
37 | }; | |
38 | static Real epsilon() | |
39 | { | |
1e59de90 | 40 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); |
92f5a8d4 TL |
41 | return std::numeric_limits<Real>::epsilon(); |
42 | } | |
43 | static Real dummy_precision() | |
44 | { | |
45 | return 1000 * epsilon(); | |
46 | } | |
47 | static Real highest() | |
48 | { | |
1e59de90 | 49 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); |
92f5a8d4 TL |
50 | return (std::numeric_limits<Real>::max)(); |
51 | } | |
52 | static Real lowest() | |
53 | { | |
1e59de90 | 54 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); |
92f5a8d4 TL |
55 | return (std::numeric_limits<Real>::min)(); |
56 | } | |
1e59de90 | 57 | static int digits10_imp(const std::integral_constant<bool, true>&) |
92f5a8d4 | 58 | { |
1e59de90 | 59 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); |
92f5a8d4 TL |
60 | return std::numeric_limits<Real>::digits10; |
61 | } | |
62 | template <bool B> | |
1e59de90 TL |
63 | static int digits10_imp(const std::integral_constant<bool, B>&) |
64 | { | |
65 | return Real::thread_default_precision(); | |
66 | } | |
67 | static int digits10() | |
68 | { | |
69 | return digits10_imp(std::integral_constant < bool, std::numeric_limits<Real>::digits10 && (std::numeric_limits<Real>::digits10 != INT_MAX) ? true : false > ()); | |
70 | } | |
71 | static int digits() | |
72 | { | |
73 | // return the number of digits in the component type in case Real is complex | |
74 | // and we have no numeric_limits specialization. | |
75 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); | |
76 | return std::numeric_limits<Real>::digits; | |
77 | } | |
78 | static int min_exponent() | |
79 | { | |
80 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); | |
81 | return std::numeric_limits<Real>::min_exponent; | |
82 | } | |
83 | static int max_exponent() | |
84 | { | |
85 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); | |
86 | return std::numeric_limits<Real>::max_exponent; | |
87 | } | |
88 | static Real infinity() | |
89 | { | |
90 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); | |
91 | return std::numeric_limits<Real>::infinity(); | |
92 | } | |
93 | static Real quiet_NaN() | |
94 | { | |
95 | static_assert(std::numeric_limits<Real>::is_specialized, "Eigen's NumTraits instantiated on a type with no numeric_limits support. Are you using a variable precision type?"); | |
96 | return std::numeric_limits<Real>::quiet_NaN(); | |
97 | } | |
98 | }; | |
99 | ||
100 | template <class B1, class B2> | |
101 | struct NumTraitsImp : public NumTraitsImp<B2, B2> | |
102 | { | |
103 | // | |
104 | // This version is instantiated when B1 and B2 are different types, this happens for rational/complex/interval | |
105 | // types, in which case many methods defer to those of the "component type" B2. | |
106 | // | |
107 | using self_type = B1; | |
108 | using Real = typename boost::multiprecision::scalar_result_from_possible_complex<self_type>::type; | |
109 | using NonInteger = self_type; // Not correct but we can't do much better?? | |
110 | using Literal = double; | |
111 | using Nested = self_type; | |
112 | enum | |
113 | { | |
114 | IsComplex = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_complex, | |
115 | IsInteger = boost::multiprecision::number_category<self_type>::value == boost::multiprecision::number_kind_integer, | |
116 | ReadCost = 1, | |
117 | AddCost = 4, | |
118 | MulCost = 8, | |
119 | IsSigned = std::numeric_limits<self_type>::is_specialized ? std::numeric_limits<self_type>::is_signed : true, | |
120 | RequireInitialization = 1, | |
121 | }; | |
122 | static B2 epsilon() | |
92f5a8d4 | 123 | { |
1e59de90 TL |
124 | return NumTraitsImp<B2, B2>::epsilon(); |
125 | } | |
126 | static B2 dummy_precision() | |
127 | { | |
128 | return 1000 * epsilon(); | |
129 | } | |
130 | static B2 highest() | |
131 | { | |
132 | return NumTraitsImp<B2, B2>::highest(); | |
133 | } | |
134 | static B2 lowest() | |
135 | { | |
136 | return NumTraitsImp<B2, B2>::lowest(); | |
92f5a8d4 TL |
137 | } |
138 | static int digits10() | |
139 | { | |
1e59de90 TL |
140 | return NumTraitsImp<B2, B2>::digits10(); |
141 | } | |
142 | static int digits() | |
143 | { | |
144 | return NumTraitsImp<B2, B2>::digits(); | |
145 | } | |
146 | static int min_exponent() | |
147 | { | |
148 | return NumTraitsImp<B2, B2>::min_exponent(); | |
149 | } | |
150 | static int max_exponent() | |
151 | { | |
152 | return NumTraitsImp<B2, B2>::max_exponent(); | |
153 | } | |
154 | static B2 infinity() | |
155 | { | |
156 | return NumTraitsImp<B2, B2>::infinity(); | |
157 | } | |
158 | static B2 quiet_NaN() | |
159 | { | |
160 | return NumTraitsImp<B2, B2>::quiet_NaN(); | |
92f5a8d4 TL |
161 | } |
162 | }; | |
1e59de90 TL |
163 | |
164 | template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates> | |
165 | struct NumTraits<boost::multiprecision::number<Backend, ExpressionTemplates> > : public NumTraitsImp<boost::multiprecision::number<Backend, ExpressionTemplates>, typename boost::multiprecision::number<Backend, ExpressionTemplates>::value_type> | |
166 | {}; | |
92f5a8d4 TL |
167 | template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> |
168 | struct NumTraits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > : public NumTraits<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type> | |
1e59de90 | 169 | {}; |
92f5a8d4 TL |
170 | |
171 | #define BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(A) \ | |
172 | template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> \ | |
173 | struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, A, BinaryOp> \ | |
174 | { \ | |
175 | /*static_assert(boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");*/ \ | |
1e59de90 | 176 | using ReturnType = boost::multiprecision::number<Backend, ExpressionTemplates>; \ |
92f5a8d4 TL |
177 | }; \ |
178 | template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> \ | |
179 | struct ScalarBinaryOpTraits<A, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp> \ | |
180 | { \ | |
181 | /*static_assert(boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, "Interoperability with this arithmetic type is not supported.");*/ \ | |
1e59de90 | 182 | using ReturnType = boost::multiprecision::number<Backend, ExpressionTemplates>; \ |
92f5a8d4 TL |
183 | }; |
184 | ||
185 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(float) | |
186 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(double) | |
187 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(long double) | |
188 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(char) | |
189 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned char) | |
190 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(signed char) | |
191 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(short) | |
192 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned short) | |
193 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(int) | |
194 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned int) | |
195 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(long) | |
196 | BOOST_MP_EIGEN_SCALAR_TRAITS_DECL(unsigned long) | |
197 | ||
198 | #if 0 | |
199 | template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Backend2, boost::multiprecision::expression_template_option ExpressionTemplates2, typename BinaryOp> | |
200 | struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2>, BinaryOp> | |
201 | { | |
202 | static_assert( | |
203 | boost::multiprecision::is_compatible_arithmetic_type<boost::multiprecision::number<Backend2, ExpressionTemplates2>, boost::multiprecision::number<Backend, ExpressionTemplates> >::value | |
204 | || 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."); | |
1e59de90 TL |
205 | using ReturnType = typename std::conditional<std::is_convertible<boost::multiprecision::number<Backend2, ExpressionTemplates2>, boost::multiprecision::number<Backend, ExpressionTemplates> >::value, |
206 | boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend2, ExpressionTemplates2> >::type; | |
92f5a8d4 TL |
207 | }; |
208 | ||
209 | template<unsigned D, typename BinaryOp> | |
210 | struct ScalarBinaryOpTraits<boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<D>, boost::multiprecision::et_on>, boost::multiprecision::mpfr_float, BinaryOp> | |
211 | { | |
1e59de90 | 212 | using ReturnType = boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<D>, boost::multiprecision::et_on>; |
92f5a8d4 TL |
213 | }; |
214 | ||
215 | template<typename BinaryOp> | |
216 | struct ScalarBinaryOpTraits<boost::multiprecision::mpfr_float, boost::multiprecision::mpc_complex, BinaryOp> | |
217 | { | |
1e59de90 | 218 | using ReturnType = boost::multiprecision::number<boost::multiprecision::backends::mpc_complex_backend<0>, boost::multiprecision::et_on>; |
92f5a8d4 TL |
219 | }; |
220 | ||
221 | template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> | |
222 | struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp> | |
223 | { | |
1e59de90 | 224 | using ReturnType = boost::multiprecision::number<Backend, ExpressionTemplates>; |
92f5a8d4 TL |
225 | }; |
226 | #endif | |
227 | ||
228 | template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class tag, class Arg1, class Arg2, class Arg3, class Arg4, typename BinaryOp> | |
229 | struct ScalarBinaryOpTraits<boost::multiprecision::number<Backend, ExpressionTemplates>, boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, BinaryOp> | |
230 | { | |
1e59de90 TL |
231 | static_assert(std::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."); |
232 | using ReturnType = boost::multiprecision::number<Backend, ExpressionTemplates>; | |
92f5a8d4 TL |
233 | }; |
234 | ||
235 | template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, typename BinaryOp> | |
236 | struct ScalarBinaryOpTraits<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, boost::multiprecision::number<Backend, ExpressionTemplates>, BinaryOp> | |
237 | { | |
1e59de90 TL |
238 | static_assert(std::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."); |
239 | using ReturnType = boost::multiprecision::number<Backend, ExpressionTemplates>; | |
92f5a8d4 TL |
240 | }; |
241 | ||
242 | namespace internal { | |
243 | template <typename Scalar> | |
244 | struct conj_retval; | |
245 | ||
246 | template <typename Scalar, bool IsComplex> | |
247 | struct conj_impl; | |
248 | ||
249 | template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> | |
250 | struct conj_retval<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4> > | |
251 | { | |
1e59de90 | 252 | using type = typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type; |
92f5a8d4 TL |
253 | }; |
254 | ||
255 | template <class tag, class Arg1, class Arg2, class Arg3, class Arg4> | |
256 | struct conj_impl<boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>, true> | |
257 | { | |
258 | EIGEN_DEVICE_FUNC | |
259 | static inline typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type run(const typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>& x) | |
260 | { | |
261 | return conj(x); | |
262 | } | |
263 | }; | |
264 | ||
265 | } // namespace internal | |
266 | ||
267 | } // namespace Eigen | |
268 | ||
269 | #endif |