1//
2// Copyright 2013 Francisco Jerez
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20// OTHER DEALINGS IN THE SOFTWARE.
21//
22
23#ifndef CLOVER_UTIL_ALGEBRA_HPP
24#define CLOVER_UTIL_ALGEBRA_HPP
25
26#include <type_traits>
27
28#include "util/range.hpp"
29#include "util/functional.hpp"
30
31namespace clover {
32   ///
33   /// Class that identifies vectors (in the linear-algebraic sense).
34   ///
35   /// There should be a definition of this class for each type that
36   /// makes sense as vector arithmetic operand.
37   ///
38   template<typename V, typename = void>
39   struct vector_traits;
40
41   ///
42   /// References of vectors are vectors.
43   ///
44   template<typename T>
45   struct vector_traits<T &, typename vector_traits<T>::enable> {
46      typedef void enable;
47   };
48
49   ///
50   /// Constant vectors are vectors.
51   ///
52   template<typename T>
53   struct vector_traits<const T, typename vector_traits<T>::enable> {
54      typedef void enable;
55   };
56
57   ///
58   /// Arrays of arithmetic types are vectors.
59   ///
60   template<typename T, std::size_t N>
61   struct vector_traits<std::array<T, N>,
62                        typename std::enable_if<
63                           std::is_arithmetic<T>::value>::type> {
64      typedef void enable;
65   };
66
67   namespace detail {
68      template<typename... Ts>
69      struct are_defined {
70         typedef void enable;
71      };
72   }
73
74   ///
75   /// The result of mapping a vector is a vector.
76   ///
77   template<typename F, typename... Vs>
78   struct vector_traits<adaptor_range<F, Vs...>,
79                        typename detail::are_defined<
80                           typename vector_traits<Vs>::enable...>::enable> {
81      typedef void enable;
82   };
83
84   ///
85   /// Vector sum.
86   ///
87   template<typename U, typename V,
88            typename = typename vector_traits<U>::enable,
89            typename = typename vector_traits<V>::enable>
90   adaptor_range<plus, U, V>
91   operator+(U &&u, V &&v) {
92      return map(plus(), std::forward<U>(u), std::forward<V>(v));
93   }
94
95   ///
96   /// Vector difference.
97   ///
98   template<typename U, typename V,
99            typename = typename vector_traits<U>::enable,
100            typename = typename vector_traits<V>::enable>
101   adaptor_range<minus, U, V>
102   operator-(U &&u, V &&v) {
103      return map(minus(), std::forward<U>(u), std::forward<V>(v));
104   }
105
106   ///
107   /// Scalar multiplication.
108   ///
109   template<typename U, typename T,
110            typename = typename vector_traits<U>::enable>
111   adaptor_range<multiplies_by_t<T>, U>
112   operator*(U &&u, T &&a) {
113      return map(multiplies_by<T>(std::forward<T>(a)), std::forward<U>(u));
114   }
115
116   ///
117   /// Scalar multiplication.
118   ///
119   template<typename U, typename T,
120            typename = typename vector_traits<U>::enable>
121   adaptor_range<multiplies_by_t<T>, U>
122   operator*(T &&a, U &&u) {
123      return map(multiplies_by<T>(std::forward<T>(a)), std::forward<U>(u));
124   }
125
126   ///
127   /// Additive inverse.
128   ///
129   template<typename U,
130            typename = typename vector_traits<U>::enable>
131   adaptor_range<negate, U>
132   operator-(U &&u) {
133      return map(negate(), std::forward<U>(u));
134   }
135
136   namespace detail {
137      template<typename U, typename V>
138      using dot_type = typename std::common_type<
139           typename std::remove_reference<U>::type::value_type,
140           typename std::remove_reference<V>::type::value_type
141         >::type;
142   }
143
144   ///
145   /// Dot product of two vectors.
146   ///
147   /// It can also do matrix multiplication if \a u or \a v is a
148   /// vector of vectors.
149   ///
150   template<typename U, typename V,
151            typename = typename vector_traits<U>::enable,
152            typename = typename vector_traits<V>::enable>
153   detail::dot_type<U, V>
154   dot(U &&u, V &&v) {
155      return fold(plus(), detail::dot_type<U, V>(),
156                  map(multiplies(), u, v));
157   }
158}
159
160#endif
161