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 | { \ |
122 | typedef Left first_argument_type; \ |
123 | typedef Right second_argument_type; \ |
124 | typedef typename Left::value_type left_value_type; \ |
125 | typedef typename Right::value_type right_value_type; \ |
126 | typedef \ |
127 | std::valarray< \ |
128 | typename Name<left_value_type, right_value_type>::result_type \ |
129 | > \ |
130 | result_type; \ |
131 | result_type \ |
132 | operator ()(Left &left, Right &right) const \ |
133 | { \ |
134 | return numeric::promote<std::valarray<left_value_type> >(left) \ |
135 | Op numeric::promote<std::valarray<right_value_type> >(right); \ |
136 | } \ |
137 | }; \ |
138 | template<typename Left, typename Right> \ |
139 | struct Name<Left, Right, std_valarray_tag, void> \ |
140 | { \ |
141 | typedef Left first_argument_type; \ |
142 | typedef Right second_argument_type; \ |
143 | typedef typename Left::value_type left_value_type; \ |
144 | typedef \ |
145 | std::valarray< \ |
146 | typename Name<left_value_type, Right>::result_type \ |
147 | > \ |
148 | result_type; \ |
149 | result_type \ |
150 | operator ()(Left &left, Right &right) const \ |
151 | { \ |
152 | return numeric::promote<std::valarray<left_value_type> >(left) Op right;\ |
153 | } \ |
154 | }; \ |
155 | template<typename Left, typename Right> \ |
156 | struct Name<Left, Right, void, std_valarray_tag> \ |
157 | { \ |
158 | typedef Left first_argument_type; \ |
159 | typedef Right second_argument_type; \ |
160 | typedef typename Right::value_type right_value_type; \ |
161 | typedef \ |
162 | std::valarray< \ |
163 | typename Name<Left, right_value_type>::result_type \ |
164 | > \ |
165 | result_type; \ |
166 | result_type \ |
167 | operator ()(Left &left, Right &right) const \ |
168 | { \ |
169 | return left Op numeric::promote<std::valarray<right_value_type> >(right);\ |
170 | } \ |
171 | }; |
172 | |
173 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(plus, +) |
174 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(minus, -) |
175 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(multiplies, *) |
176 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(divides, /) |
177 | BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP(modulus, %) |
178 | |
179 | #undef BOOST_NUMERIC_FUNCTIONAL_DEFINE_VALARRAY_BIN_OP |
180 | |
181 | /////////////////////////////////////////////////////////////////////////////// |
182 | // element-wise min of std::valarray |
183 | template<typename Left, typename Right> |
184 | struct min_assign<Left, Right, std_valarray_tag, std_valarray_tag> |
185 | { |
186 | typedef Left first_argument_type; |
187 | typedef Right second_argument_type; |
188 | typedef void result_type; |
189 | |
190 | void operator ()(Left &left, Right &right) const |
191 | { |
192 | BOOST_ASSERT(left.size() == right.size()); |
193 | for(std::size_t i = 0, size = left.size(); i != size; ++i) |
194 | { |
195 | if(numeric::less(right[i], left[i])) |
196 | { |
197 | left[i] = right[i]; |
198 | } |
199 | } |
200 | } |
201 | }; |
202 | |
203 | /////////////////////////////////////////////////////////////////////////////// |
204 | // element-wise max of std::valarray |
205 | template<typename Left, typename Right> |
206 | struct max_assign<Left, Right, std_valarray_tag, std_valarray_tag> |
207 | { |
208 | typedef Left first_argument_type; |
209 | typedef Right second_argument_type; |
210 | typedef void result_type; |
211 | |
212 | void operator ()(Left &left, Right &right) const |
213 | { |
214 | BOOST_ASSERT(left.size() == right.size()); |
215 | for(std::size_t i = 0, size = left.size(); i != size; ++i) |
216 | { |
217 | if(numeric::greater(right[i], left[i])) |
218 | { |
219 | left[i] = right[i]; |
220 | } |
221 | } |
222 | } |
223 | }; |
224 | |
225 | // partial specialization of numeric::fdiv<> for std::valarray. |
226 | template<typename Left, typename Right, typename RightTag> |
227 | struct fdiv<Left, Right, std_valarray_tag, RightTag> |
228 | : mpl::if_< |
229 | are_integral<typename Left::value_type, Right> |
230 | , divides<Left, double const> |
231 | , divides<Left, Right> |
232 | >::type |
233 | {}; |
234 | |
235 | // promote |
236 | template<typename To, typename From> |
237 | struct promote<To, From, std_valarray_tag, std_valarray_tag> |
238 | { |
239 | typedef From argument_type; |
240 | typedef To result_type; |
241 | |
242 | To operator ()(From &arr) const |
243 | { |
244 | typename remove_const<To>::type res(arr.size()); |
245 | for(std::size_t i = 0, size = arr.size(); i != size; ++i) |
246 | { |
247 | res[i] = numeric::promote<typename To::value_type>(arr[i]); |
248 | } |
249 | return res; |
250 | } |
251 | }; |
252 | |
253 | template<typename ToFrom> |
254 | struct promote<ToFrom, ToFrom, std_valarray_tag, std_valarray_tag> |
255 | { |
256 | typedef ToFrom argument_type; |
257 | typedef ToFrom result_type; |
258 | |
259 | ToFrom &operator ()(ToFrom &tofrom) const |
260 | { |
261 | return tofrom; |
262 | } |
263 | }; |
264 | |
265 | // for "promoting" a std::valarray<bool> to a bool, useful for |
266 | // comparing 2 valarrays for equality: |
267 | // if(numeric::promote<bool>(a == b)) |
268 | template<typename From> |
269 | struct promote<bool, From, void, std_valarray_tag> |
270 | { |
271 | typedef From argument_type; |
272 | typedef bool result_type; |
273 | |
274 | bool operator ()(From &arr) const |
275 | { |
276 | BOOST_MPL_ASSERT((is_same<bool, typename From::value_type>)); |
277 | for(std::size_t i = 0, size = arr.size(); i != size; ++i) |
278 | { |
279 | if(!arr[i]) |
280 | { |
281 | return false; |
282 | } |
283 | } |
284 | return true; |
285 | } |
286 | }; |
287 | |
288 | template<typename From> |
289 | struct promote<bool const, From, void, std_valarray_tag> |
290 | : promote<bool, From, void, std_valarray_tag> |
291 | {}; |
292 | |
293 | /////////////////////////////////////////////////////////////////////////////// |
294 | // functional::as_min |
295 | template<typename T> |
296 | struct as_min<T, std_valarray_tag> |
297 | { |
298 | typedef T argument_type; |
299 | typedef typename remove_const<T>::type result_type; |
300 | |
301 | typename remove_const<T>::type operator ()(T &arr) const |
302 | { |
303 | return 0 == arr.size() |
304 | ? T() |
305 | : T(numeric::as_min(arr[0]), arr.size()); |
306 | } |
307 | }; |
308 | |
309 | /////////////////////////////////////////////////////////////////////////////// |
310 | // functional::as_max |
311 | template<typename T> |
312 | struct as_max<T, std_valarray_tag> |
313 | { |
314 | typedef T argument_type; |
315 | typedef typename remove_const<T>::type result_type; |
316 | |
317 | typename remove_const<T>::type operator ()(T &arr) const |
318 | { |
319 | return 0 == arr.size() |
320 | ? T() |
321 | : T(numeric::as_max(arr[0]), arr.size()); |
322 | } |
323 | }; |
324 | |
325 | /////////////////////////////////////////////////////////////////////////////// |
326 | // functional::as_zero |
327 | template<typename T> |
328 | struct as_zero<T, std_valarray_tag> |
329 | { |
330 | typedef T argument_type; |
331 | typedef typename remove_const<T>::type result_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 | { |
346 | typedef T argument_type; |
347 | typedef typename remove_const<T>::type result_type; |
348 | |
349 | typename remove_const<T>::type operator ()(T &arr) const |
350 | { |
351 | return 0 == arr.size() |
352 | ? T() |
353 | : T(numeric::as_one(arr[0]), arr.size()); |
354 | } |
355 | }; |
356 | |
357 | } // namespace functional |
358 | |
359 | }} // namespace boost::numeric |
360 | |
361 | #endif |
362 | |
363 | |