• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
operator /(std::valarray<Left> const & left,Right const & right)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
operator *(std::valarray<Left> const & left,Right const & right)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
operator +(std::valarray<Left> const & left,std::valarray<Right> const & right)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 
operator ()boost::numeric::functional::min_assign190             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 
operator ()boost::numeric::functional::max_assign212             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 
operator ()boost::numeric::functional::promote242             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 
operator ()boost::numeric::functional::promote259             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 
operator ()boost::numeric::functional::promote274             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 
operator ()boost::numeric::functional::as_min301             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 
operator ()boost::numeric::functional::as_max317             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 
operator ()boost::numeric::functional::as_zero333             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 
operator ()boost::numeric::functional::as_one349             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