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