1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file valarray.hpp |
3 | /// |
4 | // Copyright 2005 Eric Niebler. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #ifndef BOOST_NUMERIC_FUNCTIONAL_VALARRAY_HPP_EAN_12_12_2005 |
9 | #define BOOST_NUMERIC_FUNCTIONAL_VALARRAY_HPP_EAN_12_12_2005 |
10 | |
11 | #ifdef BOOST_NUMERIC_FUNCTIONAL_HPP_INCLUDED |
12 | # error Include this file before boost/accumulators/numeric/functional.hpp |
13 | #endif |
14 | |
15 | #include <valarray> |
16 | #include <functional> |
17 | #include <boost/assert.hpp> |
18 | #include <boost/mpl/and.hpp> |
19 | #include <boost/mpl/not.hpp> |
20 | #include <boost/mpl/assert.hpp> |
21 | #include <boost/utility/enable_if.hpp> |
22 | #include <boost/type_traits/is_same.hpp> |
23 | #include <boost/type_traits/is_scalar.hpp> |
24 | #include <boost/type_traits/remove_const.hpp> |
25 | #include <boost/typeof/std/valarray.hpp> |
26 | #include <boost/accumulators/numeric/functional_fwd.hpp> |
27 | |
28 | namespace boost { namespace numeric |
29 | { |
30 | namespace operators |
31 | { |
32 | namespace acc_detail |
33 | { |
34 | template<typename Fun> |
35 | struct make_valarray |
36 | { |
37 | typedef std::valarray<typename Fun::result_type> type; |
38 | }; |
39 | } |
40 | |
41 | /////////////////////////////////////////////////////////////////////////////// |
42 | // Handle valarray<Left> / Right where Right is a scalar and Right != Left. |
43 | template<typename Left, typename Right> |
44 | typename lazy_enable_if< |
45 | mpl::and_<is_scalar<Right>, mpl::not_<is_same<Left, Right> > > |
46 | , acc_detail::make_valarray<functional::divides<Left, Right> > |
47 | >::type |
48 | operator /(std::valarray<Left> const &left, Right const &right) |
49 | { |
50 | typedef typename functional::divides<Left, Right>::result_type value_type; |
51 | std::valarray<value_type> result(left.size()); |
52 | for(std::size_t i = 0, size = result.size(); i != size; ++i) |
53 | { |
54 | result[i] = numeric::divides(left[i], right); |
55 | } |
56 | return result; |
57 | } |
58 | |
59 | /////////////////////////////////////////////////////////////////////////////// |
60 | // Handle valarray<Left> * Right where Right is a scalar and Right != Left. |
61 | template<typename Left, typename Right> |
62 | typename lazy_enable_if< |
63 | mpl::and_<is_scalar<Right>, mpl::not_<is_same<Left, Right> > > |
64 | , acc_detail::make_valarray<functional::multiplies<Left, Right> > |
65 | >::type |
66 | operator *(std::valarray<Left> const &left, Right const &right) |
67 | { |
68 | typedef typename functional::multiplies<Left, Right>::result_type value_type; |
69 | std::valarray<value_type> result(left.size()); |
70 | for(std::size_t i = 0, size = result.size(); i != size; ++i) |
71 | { |
72 | result[i] = numeric::multiplies(left[i], right); |
73 | } |
74 | return result; |
75 | } |
76 | |
77 | /////////////////////////////////////////////////////////////////////////////// |
78 | // Handle valarray<Left> + valarray<Right> where Right != Left. |
79 | template<typename Left, typename Right> |
80 | typename lazy_disable_if< |
81 | is_same<Left, Right> |
82 | , acc_detail::make_valarray<functional::plus<Left, Right> > |
83 | >::type |
84 | operator +(std::valarray<Left> const &left, std::valarray<Right> const &right) |
85 | { |
86 | typedef typename functional::plus<Left, Right>::result_type value_type; |
87 | std::valarray<value_type> result(left.size()); |
88 | for(std::size_t i = 0, size = result.size(); i != size; ++i) |
89 | { |
90 | result[i] = numeric::plus(left[i], right[i]); |
91 | } |
92 | return result; |
93 | } |
94 | } |
95 | |
96 | namespace functional |
97 | { |
98 | struct std_valarray_tag; |
99 | |
100 | template<typename T> |
101 | struct tag<std::valarray<T> > |
102 | { |
103 | typedef std_valarray_tag type; |
104 | }; |
105 | |
106 | #ifdef __GLIBCXX__ |
107 | template<typename T, typename U> |
108 | struct tag<std::_Expr<T, U> > |
109 | { |
110 | typedef std_valarray_tag type; |
111 | }; |
112 | #endif |
113 | |
114 | /// INTERNAL ONLY |
115 | /// |
116 | // This is necessary because the GCC stdlib uses expression templates, and |
117 | // typeof(som-valarray-expression) is not an instance of std::valarray |
118 | #define BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(Name, Op) \ |
119 | template<typename Left, typename Right> \ |
120 | struct Name<Left, Right, std_valarray_tag, std_valarray_tag> \ |
121 | : std::binary_function< \ |
122 | Left \ |
123 | , Right \ |
124 | , std::valarray< \ |
125 | typename Name< \ |
126 | typename Left::value_type \ |
127 | , typename Right::value_type \ |
128 | >::result_type \ |
129 | > \ |
130 | > \ |
131 | { \ |
132 | typedef typename Left::value_type left_value_type; \ |
133 | typedef typename Right::value_type right_value_type; \ |
134 | typedef \ |
135 | std::valarray< \ |
136 | typename Name<left_value_type, right_value_type>::result_type \ |
137 | > \ |
138 | result_type; \ |
139 | result_type \ |
140 | operator ()(Left &left, Right &right) const \ |
141 | { \ |
142 | return numeric::promote<std::valarray<left_value_type> >(left) \ |
143 | Op numeric::promote<std::valarray<right_value_type> >(right); \ |
144 | } \ |
145 | }; \ |
146 | template<typename Left, typename Right> \ |
147 | struct Name<Left, Right, std_valarray_tag, void> \ |
148 | : std::binary_function< \ |
149 | Left \ |
150 | , Right \ |
151 | , std::valarray< \ |
152 | typename Name<typename Left::value_type, Right>::result_type \ |
153 | > \ |
154 | > \ |
155 | { \ |
156 | typedef typename Left::value_type left_value_type; \ |
157 | typedef \ |
158 | std::valarray< \ |
159 | typename Name<left_value_type, Right>::result_type \ |
160 | > \ |
161 | result_type; \ |
162 | result_type \ |
163 | operator ()(Left &left, Right &right) const \ |
164 | { \ |
165 | return numeric::promote<std::valarray<left_value_type> >(left) Op right;\ |
166 | } \ |
167 | }; \ |
168 | template<typename Left, typename Right> \ |
169 | struct Name<Left, Right, void, std_valarray_tag> \ |
170 | : std::binary_function< \ |
171 | Left \ |
172 | , Right \ |
173 | , std::valarray< \ |
174 | typename Name<Left, typename Right::value_type>::result_type \ |
175 | > \ |
176 | > \ |
177 | { \ |
178 | typedef typename Right::value_type right_value_type; \ |
179 | typedef \ |
180 | std::valarray< \ |
181 | typename Name<Left, right_value_type>::result_type \ |
182 | > \ |
183 | result_type; \ |
184 | result_type \ |
185 | operator ()(Left &left, Right &right) const \ |
186 | { \ |
187 | return left Op numeric::promote<std::valarray<right_value_type> >(right);\ |
188 | } \ |
189 | }; |
190 | |
191 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(plus, +) |
192 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(minus, -) |
193 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(multiplies, *) |
194 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(divides, /) |
195 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(modulus, %) |
196 | |
197 | #undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP |
198 | |
199 | /////////////////////////////////////////////////////////////////////////////// |
200 | // element-wise min of std::valarray |
201 | template<typename Left, typename Right> |
202 | struct min_assign<Left, Right, std_valarray_tag, std_valarray_tag> |
203 | : std::binary_function<Left, Right, void> |
204 | { |
205 | void operator ()(Left &left, Right &right) const |
206 | { |
207 | BOOST_ASSERT(left.size() == right.size()); |
208 | for(std::size_t i = 0, size = left.size(); i != size; ++i) |
209 | { |
210 | if(numeric::less(right[i], left[i])) |
211 | { |
212 | left[i] = right[i]; |
213 | } |
214 | } |
215 | } |
216 | }; |
217 | |
218 | /////////////////////////////////////////////////////////////////////////////// |
219 | // element-wise max of std::valarray |
220 | template<typename Left, typename Right> |
221 | struct max_assign<Left, Right, std_valarray_tag, std_valarray_tag> |
222 | : std::binary_function<Left, Right, void> |
223 | { |
224 | void operator ()(Left &left, Right &right) const |
225 | { |
226 | BOOST_ASSERT(left.size() == right.size()); |
227 | for(std::size_t i = 0, size = left.size(); i != size; ++i) |
228 | { |
229 | if(numeric::greater(right[i], left[i])) |
230 | { |
231 | left[i] = right[i]; |
232 | } |
233 | } |
234 | } |
235 | }; |
236 | |
237 | // partial specialization of numeric::fdiv<> for std::valarray. |
238 | template<typename Left, typename Right, typename RightTag> |
239 | struct fdiv<Left, Right, std_valarray_tag, RightTag> |
240 | : mpl::if_< |
241 | are_integral<typename Left::value_type, Right> |
242 | , divides<Left, double const> |
243 | , divides<Left, Right> |
244 | >::type |
245 | {}; |
246 | |
247 | // promote |
248 | template<typename To, typename From> |
249 | struct promote<To, From, std_valarray_tag, std_valarray_tag> |
250 | : std::unary_function<From, To> |
251 | { |
252 | To operator ()(From &arr) const |
253 | { |
254 | typename remove_const<To>::type res(arr.size()); |
255 | for(std::size_t i = 0, size = arr.size(); i != size; ++i) |
256 | { |
257 | res[i] = numeric::promote<typename To::value_type>(arr[i]); |
258 | } |
259 | return res; |
260 | } |
261 | }; |
262 | |
263 | template<typename ToFrom> |
264 | struct promote<ToFrom, ToFrom, std_valarray_tag, std_valarray_tag> |
265 | : std::unary_function<ToFrom, ToFrom> |
266 | { |
267 | ToFrom &operator ()(ToFrom &tofrom) const |
268 | { |
269 | return tofrom; |
270 | } |
271 | }; |
272 | |
273 | // for "promoting" a std::valarray<bool> to a bool, useful for |
274 | // comparing 2 valarrays for equality: |
275 | // if(numeric::promote<bool>(a == b)) |
276 | template<typename From> |
277 | struct promote<bool, From, void, std_valarray_tag> |
278 | : std::unary_function<From, bool> |
279 | { |
280 | bool operator ()(From &arr) const |
281 | { |
282 | BOOST_MPL_ASSERT((is_same<bool, typename From::value_type>)); |
283 | for(std::size_t i = 0, size = arr.size(); i != size; ++i) |
284 | { |
285 | if(!arr[i]) |
286 | { |
287 | return false; |
288 | } |
289 | } |
290 | return true; |
291 | } |
292 | }; |
293 | |
294 | template<typename From> |
295 | struct promote<bool const, From, void, std_valarray_tag> |
296 | : promote<bool, From, void, std_valarray_tag> |
297 | {}; |
298 | |
299 | /////////////////////////////////////////////////////////////////////////////// |
300 | // functional::as_min |
301 | template<typename T> |
302 | struct as_min<T, std_valarray_tag> |
303 | : std::unary_function<T, typename remove_const<T>::type> |
304 | { |
305 | typename remove_const<T>::type operator ()(T &arr) const |
306 | { |
307 | return 0 == arr.size() |
308 | ? T() |
309 | : T(numeric::as_min(arr[0]), arr.size()); |
310 | } |
311 | }; |
312 | |
313 | /////////////////////////////////////////////////////////////////////////////// |
314 | // functional::as_max |
315 | template<typename T> |
316 | struct as_max<T, std_valarray_tag> |
317 | : std::unary_function<T, typename remove_const<T>::type> |
318 | { |
319 | typename remove_const<T>::type operator ()(T &arr) const |
320 | { |
321 | return 0 == arr.size() |
322 | ? T() |
323 | : T(numeric::as_max(arr[0]), arr.size()); |
324 | } |
325 | }; |
326 | |
327 | /////////////////////////////////////////////////////////////////////////////// |
328 | // functional::as_zero |
329 | template<typename T> |
330 | struct as_zero<T, std_valarray_tag> |
331 | : std::unary_function<T, typename remove_const<T>::type> |
332 | { |
333 | typename remove_const<T>::type operator ()(T &arr) const |
334 | { |
335 | return 0 == arr.size() |
336 | ? T() |
337 | : T(numeric::as_zero(arr[0]), arr.size()); |
338 | } |
339 | }; |
340 | |
341 | /////////////////////////////////////////////////////////////////////////////// |
342 | // functional::as_one |
343 | template<typename T> |
344 | struct as_one<T, std_valarray_tag> |
345 | : std::unary_function<T, typename remove_const<T>::type> |
346 | { |
347 | typename remove_const<T>::type operator ()(T &arr) const |
348 | { |
349 | return 0 == arr.size() |
350 | ? T() |
351 | : T(numeric::as_one(arr[0]), arr.size()); |
352 | } |
353 | }; |
354 | |
355 | } // namespace functional |
356 | |
357 | }} // namespace boost::numeric |
358 | |
359 | #endif |
360 | |
361 | |