carl  24.04
Computer ARithmetic Library
typetraits.h
Go to the documentation of this file.
1 /**
2  * @file numbers/typetraits.h
3  * @ingroup typetraits
4  * @author Gereon Kremer <gereon.kremer@cs.rwth-aachen.de>
5  * @author Sebastian Junges
6  *
7  * @addtogroup typetraits Type Traits
8  * We define custom type traits for number types we use.
9  * We use the notation conventions of the STL, being lower cases with underscores.
10  *
11  * We define the following type traits:
12  * - `is_field_type`: Types that represent elements from a field.
13  * - `is_finite_type`: Types that represent only a finite domain.
14  * - `is_float_type`: Types that represent real numbers using a floating point representation.
15  * - `is_integer_type`: Types that represent the set of integral numbers.
16  * - `is_subset_of_integers_type`: Types that may represent some integral numbers.
17  * - `is_number_type`: Types that represent numbers.
18  * - `is_rational_type`: Types that may represent any rational number.
19  * - `is_subset_of_rationals_type`: Types that may represent some rational numbers.
20  *
21  * A more exact definition for each of these type traits can be found in their own documentation.
22  *
23  * Additionally, we define related types in a type traits like manner:
24  * - `IntegralType`: Integral type, that the given type is based on. For fractions, this would be the type of the numerator and denominator.
25  * - `UnderlyingNumberType`: Number type that is used within a more complex type. For polynomials, this would be the number type of the coefficients.
26  *
27  * Note that we keep away from similar type traits defined in the standard @cite C++Standard (20.9) (like `std::is_integral` or `std::is_floating_point`, as they are not meant to be specialized for custom types.
28  */
29 
30 #pragma once
31 
32 #ifndef INCLUDED_FROM_NUMBERS_H
33 static_assert(false, "This file may only be included indirectly by numbers.h");
34 #endif
35 
37 #include <carl-common/config.h>
38 #include <limits>
39 #include <type_traits>
40 
41 #include "../interval/typetraits.h" // TODO remove
42 
43 
44 namespace carl {
45 
46 template<typename T, typename U =
47  typename std::remove_cv<
48  typename std::remove_pointer<
49  typename std::remove_reference<
50  typename std::remove_extent<
51  T
52  >::type
53  >::type
54  >::type
55  >::type
56 > struct remove_all : remove_all<U> {};
57 template<typename T> struct remove_all<T, T> { using type = T; };
58 
59 /**
60  * This template is designed to provide types that are related to other types.
61  * It works very much like std::integral_constant, except that it provides a type instead of a constant.
62  * We use it as an extension to type traits, meaning that types may have traits that are boolean or other types.
63  *
64  * The class can be used as follows.
65  * Assume that you have a class `A` with an associated type `B`.
66  * @code
67  * template<T> struct Associated {};
68  * template<> struct Associated<A>: has_subtype<B> {};
69  * @endcode
70  * Now you can obtain the associated type with `Associated<A>::type`.
71  *
72  * @ingroup typetraits
73  */
74 template<typename T>
75 struct has_subtype {
76  /// A type associated with the type
77  using type = T;
78 };
79 
80 }
81 
82 #define TRAIT_TRUE(name,type,groups) \
83 /** States that type has the trait name. @ingroup typetraits_ ## name groups */ \
84 template<> struct name<type>: std::true_type {};
85 
86 #define TRAIT_FALSE(name,type,groups) \
87 /** States that type does not have the trait name. @ingroup typetraits_ ## name groups */ \
88 template<> struct name<type>: std::false_type {};
89 
90 #define TRAIT_TYPE(name,_type,value,groups) \
91 /** States that name of _type is value. @ingroup typetraits_ ## name groups */ \
92 template<> struct name<_type>: carl::has_subtype<value> {};
93 
94 namespace carl {
95 
96 //
97 // Forward declarations
98 //
99 template<typename IntegerT>
100 class GFNumber;
101 
102 template<typename C>
103 class UnivariatePolynomial;
104 
105 template<typename C, typename O, typename P>
106 class MultivariatePolynomial;
107 
108 template<typename T> struct is_rational_type;
109 template<typename T> struct is_subset_of_rationals_type;
110 
111 /**
112  * @addtogroup typetraits_is_field_type
113  * All types that represent a field are marked with `is_field_type`.
114  *
115  * To be a field, the type must satisfy the common axioms for fields (and their technical interpretation):
116  * - It represents some (not empty) set of numbers.
117  * - It defines the basic operators \f$+,-,\cdot,/\f$, implemented as `operator+()`, `operator-()`, `operator*()`, `operator/()`. The result of these operators is of the same type, i.e. the type is closed under the given operations.
118  * - It's operations are *associative* and *commutative*. Multiplication and addition are *distributive*.
119  * - There are *identity elements* for addition and multiplication.
120  * - For every element of the type, there are *inverse elements* for addition and multiplication.
121  *
122  * All types that are marked with `is_rational_type` represent a field.
123  */
124 
125 /**
126  * States if a type is a field.
127  * Default is true for rationals, false otherwise.
128  * @ingroup typetraits_is_field_type
129  * @see UnivariatePolynomial - CauchyBound for example.
130  */
131 template<typename T>
132 struct is_field_type: std::integral_constant<bool, is_rational_type<T>::value> {};
133 /**
134  * States that a Gallois field is a field.
135  * @ingroup typetraits_is_field_type
136  */
137 template<typename C>
138 struct is_field_type<GFNumber<C>>: std::true_type {};
139 
140 
141 /**
142  * @addtogroup typetraits_is_finite_type is_finite_type
143  * All types that can represent only numbers from a finite domain are marked with `is_finite_type`.
144  *
145  * All fundamental types are also finite.
146  */
147 /**
148  * States if a type represents only a finite domain.
149  * Default is true for fundamental types, false otherwise.
150  * @ingroup typetraits_is_finite_type
151  */
152 template<typename T>
153 struct is_finite_type: std::integral_constant<bool, std::is_fundamental<T>::value> {};
154 
155 /**
156  * Type trait is_finite_type_domain.
157  * Default is false.
158  * @ingroup typetraits_is_finite_type
159  */
160 template<typename C>
161 struct is_finite_type<GFNumber<C>>: std::false_type {};
162 
163 /**
164  * @addtogroup typetraits_is_float_type is_float_type
165  * All types that represent floating point numbers are marked with `is_float_type`.
166  *
167  * A floating point type is used to approximate real number and in general behaves like a field.
168  * However, it does not guarantee exact computation and may be subject to rounding errors or overflows.
169  */
170 /**
171  * States if a type is a floating point type.
172  *
173  * Default is true if `std::is_floating_point` is true for this type.
174  * @ingroup typetraits_is_float_type
175  */
176 template<typename T>
177 struct is_float_type: std::integral_constant<bool, std::is_floating_point<T>::value> {};
178 
179 /**
180  * @addtogroup typetraits_is_integer_type is_integer_type
181  * All integral types that can (in theory) represent all integers are marked with `is_integer_type`.
182  *
183  * To be an integer type, the type must satisfy the following conditions:
184  * - It represents exactly all integer numbers.
185  * - It defines the basic operators \f$+, -, \cdot\f$ by implementing `operator+()`, `operator-()` and `operator*()` which are closed.
186  * - It's operations are *associative* and *commutative*. Multiplication and addition are *distributive*.
187  * - There are *identity elements* for addition and multiplication.
188  * - For every element of the type, there is an *inverse element* for addition.
189  * - Additionally, it defines the following operations:
190  * - `div()`: Performs an integer division, asserting that the remainder is zero.
191  * - `quotient()`: Calculates the quotient of an integer division.
192  * - `remainder()`: Calculates the remainder of an integer division.
193  * - `mod()`: Calculated the modulus of an integer.
194  * - `operator/()` shall be an alias for `quotient()`.
195  */
196 /**
197  * States if a type is an integer type.
198  *
199  * Default is false.
200  * @ingroup typetraits_is_integer_type
201  */
202 template<typename T>
203 struct is_integer_type: std::false_type {};
204 
205 /**
206  * @addtogroup typetraits_is_subset_of_integers_type is_subset_of_integers_type
207  * All integral types are marked with `is_subset_of_integers_type`.
208  *
209  * They must satisfy the same conditions as for `is_integer_type`, except that they may represent only a subset of all integer numbers.
210  * If this is the case, `std::numeric_limits` must be specialized.
211  * If the limits are exceeded, the type may behave arbitrarily and the type is not obliged to check for this.
212  */
213 /**
214  * States if a type represents a subset of all integers.
215  * Default is true for integer types, false otherwise.
216  * @ingroup typetraits_is_subset_of_integers_type
217  */
218 template<typename Type>
219 struct is_subset_of_integers_type: std::integral_constant<bool, is_integer_type<Type>::value> {};
220 
221 /**
222  * @addtogroup typetraits_is_number_type
223  * All types that represent any kind of number are marked with `is_number_type`.
224  *
225  * All number types are required to implement the following methods:
226  * - `abs()`: Returns the absolute value.
227  * - `floor()`: Returns the nearest integer below.
228  * - `ceil()`: Returns the nearest integer above.
229  * - `pow()`: Returns the power.
230  */
231 /**
232  * States if a type is a number type.
233  * Default is true for rationals, integers and floats, false otherwise.
234  * @ingroup typetraits_is_number_type
235  */
236 template<typename T>
238  /// Default value of this trait.
240 };
241 template<typename T>
242 constexpr bool is_number_type<T>::value;
243 
244 /**
245  * @ingroup typetraits_is_number_type
246  * @see GFNumber
247  */
248 template<typename C>
249 struct is_number_type<GFNumber<C>>: std::true_type {};
250 
251 /**
252  * @addtogroup typetraits_is_rational_type is_rational_type
253  * All integral types that can (in theory) represent all rationals are marked with `is_rational_type`.
254  *
255  * It is assumed that a fractional representation is used.
256  * A type that is rational must satisfy all requirements of `is_field_type`.
257  * Additionally, it must implement the following methods:
258  * - `get_num()`: Returns the numerator of a fraction.
259  * - `get_denom()`: Return the denominator of a fraction.
260  * - `rationalize()`: Converts a native floating point number to the rational type.
261  */
262 /**
263  * States if a type is a rational type.
264  *
265  * We consider a type to be rational, if it can (in theory) represent any rational number.
266  * Default is false.
267  */
268 template<typename T>
269 struct is_rational_type: std::false_type {};
270 
271 /**
272  * @addtogroup typetraits_is_subset_of_rationals_type is_subset_of_rationals_type
273  * All rational types that can represent a subset of all rationals are marked with `is_subset_of_rationals_type`.
274  *
275  * It is assumed that a fractional representation is used and the restriction to a subset of all rationals is due to the type of the numerator and the denominator.
276  */
277 /**
278  * States if a type represents a subset of all rationals and the representation is similar to a rational.
279  * Default is true for rationals, false otherwise.
280  * @ingroup typetraits_is_subset_of_rationals_type
281  */
282 template<typename T>
284  /// Default value of this trait.
285  static constexpr bool value = is_rational_type<T>::value;
286 };
287 
288 
289 /**
290  * Type trait for the characteristic of the given field (template argument).
291  * @see UnivariatePolynomial - squareFreeFactorization for example.
292  */
293 template<typename type>
294 struct characteristic: std::integral_constant<uint, 0> {};
295 
296 
297 /**
298  * @addtogroup typetraits_IntegralType
299  * The associated integral type of any type can be defined with IntegralType.
300  *
301  * Any function that operates on the type and naturally returns an integer, regardless whether the input was actually integral, uses the associated integral type as result type.
302  * Simple examples for this are get_num() and get_denom() which return the numerator and denominator respectively of a fraction.
303  */
304 /**
305  * Gives the corresponding integral type.
306  * Default is int.
307  * @ingroup typetraits_IntegralType
308  */
309 template<typename RationalType>
310 struct IntegralType {
311  /// @todo Should *any* type have an integral type?
312  using type = sint;
313 };
314 
315 template<typename C>
316 struct IntegralType<GFNumber<C>> {
317  using type = C;
318 };
319 
320 template<typename C>
321 using IntegralTypeIfDifferent = typename std::enable_if<!std::is_same<C, typename IntegralType<C>::type>::value, typename IntegralType<C>::type>::type;
322 
323 /**
324  * @addtogroup typetraits_UnderlyingNumberType
325  * The number type that some type is built upon can be defined with UnderlyingNumberType.
326  *
327  * Any function that operates on the (more complex) type and returns a number can use this trait.
328  * The function can thereby easily retrieve the exact number type that is used within the complex type.
329  */
330 /**
331  * Gives the underlying number type of a complex object.
332  * Default is the type itself.
333  * @ingroup typetraits_UnderlyingNumberType
334  */
335 template<typename T>
337 
338 }
339 
340 namespace carl
341 {
342 
343 template<typename T>
345 {
346  private:
348  public:
349  explicit PreventConversion( const T& _other ) : mContent( _other ) {}
350 // template<typename O>
351 // PreventConversion( const O& _other ) = delete;
352  operator const T&() const { return mContent; }
353 };
354 
355 template<typename T, typename T2>
356 bool fits_within(const T2& t) {
357  return std::numeric_limits<T>::min() <= t && t <= std::numeric_limits<T>::max();
358 }
359 
360 }
States if a type is a field.
Definition: typetraits.h:132
States if a type represents only a finite domain.
Definition: typetraits.h:153
States if a type is a floating point type.
Definition: typetraits.h:177
States if a type is an integer type.
Definition: typetraits.h:203
States if a type represents a subset of all integers.
Definition: typetraits.h:219
Gives the underlying number type of a complex object.
Definition: typetraits.h:336
carl is the main namespace for the library.
bool fits_within(const T2 &t)
Definition: typetraits.h:356
typename std::enable_if<!std::is_same< C, typename IntegralType< C >::type >::value, typename IntegralType< C >::type >::type IntegralTypeIfDifferent
Definition: typetraits.h:321
std::int64_t sint
Definition: numbers.h:17
Galois Field numbers, i.e.
Definition: GFNumber.h:21
This template is designed to provide types that are related to other types.
Definition: typetraits.h:75
T type
A type associated with the type.
Definition: typetraits.h:77
States if a type is a rational type.
Definition: typetraits.h:269
States if a type represents a subset of all rationals and the representation is similar to a rational...
Definition: typetraits.h:283
static constexpr bool value
Default value of this trait.
Definition: typetraits.h:285
States if a type is a number type.
Definition: typetraits.h:237
static const bool value
Default value of this trait.
Definition: typetraits.h:239
Type trait for the characteristic of the given field (template argument).
Definition: typetraits.h:294
Gives the corresponding integral type.
Definition: typetraits.h:310
PreventConversion(const T &_other)
Definition: typetraits.h:349