28#ifndef REMORA_VECTOR_EXPRESSION_HPP
29#define REMORA_VECTOR_EXPRESSION_HPP
31#include "detail/expression_optimizers.hpp"
38template<
class T,
class VecV,
class Device>
39typename std::enable_if<
40 std::is_convertible<T, typename VecV::value_type >::value,
41 typename detail::vector_scalar_multiply_optimizer<VecV>::type
43operator* (vector_expression<VecV, Device>
const& v, T scalar){
44 typedef typename VecV::value_type value_type;
45 return detail::vector_scalar_multiply_optimizer<VecV>::create(v(),value_type(scalar));
47template<
class T,
class VecV,
class Device>
48typename std::enable_if<
49 std::is_convertible<T, typename VecV::value_type >::value,
50 typename detail::vector_scalar_multiply_optimizer<VecV>::type
52operator* (T scalar, vector_expression<VecV, Device>
const& v){
53 typedef typename VecV::value_type value_type;
54 return detail::vector_scalar_multiply_optimizer<VecV>::create(v(),value_type(scalar));
57template<
class VecV,
class Device>
58typename detail::vector_scalar_multiply_optimizer<VecV>::type
59operator-(vector_expression<VecV, Device>
const& v){
60 typedef typename VecV::value_type value_type;
61 return detail::vector_scalar_multiply_optimizer<VecV>::create(v(),value_type(-1));
69typename std::enable_if<std::is_arithmetic<T>::value, scalar_vector<T, cpu_tag> >::type
70repeat(T scalar, std::size_t elements){
71 return scalar_vector<T, cpu_tag>(elements,scalar);
75#define REMORA_UNARY_VECTOR_TRANSFORMATION(name, F)\
76template<class VecV, class Device>\
77typename detail::vector_unary_optimizer<VecV,typename device_traits<Device>:: template F<typename VecV::value_type> >::type \
78name(vector_expression<VecV, Device> const& v){\
79 typedef typename device_traits<Device>:: template F<typename VecV::value_type> functor_type;\
80 return detail::vector_unary_optimizer<VecV, functor_type >::create(v(), functor_type());\
100#undef REMORA_UNARY_VECTOR_TRANSFORMATION
103template<
class VecV1,
class VecV2,
class Device>
104vector_addition<VecV1, VecV2 > operator+ (
105 vector_expression<VecV1, Device>
const& v1,
106 vector_expression<VecV2, Device>
const& v2
108 REMORA_SIZE_CHECK(v1().size() == v2().size());
109 return vector_addition<VecV1, VecV2>(v1(),v2());
112template<
class VecV1,
class VecV2,
class Device>
114 vector_expression<VecV1, Device>
const& v1,
115 vector_expression<VecV2, Device>
const& v2
116) ->
decltype (v1 + (-v2)){
117 REMORA_SIZE_CHECK(v1().size() == v2().size());
122template<
class VecV,
class T,
class Device>
123typename std::enable_if<
124 std::is_convertible<T, typename VecV::value_type>::value,
125 vector_addition<VecV, scalar_vector<T, Device> >
127 vector_expression<VecV, Device>
const& v,
130 return v + scalar_vector<T, Device>(v().size(),t);
134template<
class T,
class VecV,
class Device>
135typename std::enable_if<
136 std::is_convertible<T, typename VecV::value_type>::value,
137 vector_addition<VecV, scalar_vector<T, Device> >
140 vector_expression<VecV, Device>
const& v
142 return v + scalar_vector<T, Device>(v().size(),t);
146template<
class VecV,
class T,
class Device>
147typename std::enable_if<
148 std::is_convertible<T, typename VecV::value_type>::value ,
149 decltype(std::declval<VecV const&>() + T())
151 vector_expression<VecV, Device>
const& v,
158template<
class VecV,
class T,
class Device>
159typename std::enable_if<
160 std::is_convertible<T, typename VecV::value_type>::value,
161 decltype(T() + (-std::declval<VecV const&>()))
164 vector_expression<VecV, Device>
const& v
169#define REMORA_BINARY_VECTOR_EXPRESSION(name, F)\
170template<class VecV1, class VecV2, class Device>\
171vector_binary<VecV1, VecV2, typename device_traits<Device>:: template F<typename common_value_type<VecV1,VecV2>::type> >\
172name(vector_expression<VecV1, Device> const& v1, vector_expression<VecV2, Device> const& v2){\
173 REMORA_SIZE_CHECK(v1().size() == v2().size());\
174 typedef typename common_value_type<VecV1,VecV2>::type type;\
175 typedef typename device_traits<Device>:: template F<type> functor_type;\
176 return vector_binary<VecV1, VecV2, functor_type >(v1(),v2(), functor_type());\
185#undef REMORA_BINARY_VECTOR_EXPRESSION
189#define REMORA_VECTOR_SCALAR_TRANSFORMATION(name, F)\
190template<class T, class VecV, class Device> \
191typename std::enable_if< \
192 std::is_convertible<T, typename VecV::value_type >::value,\
193 vector_binary<VecV, scalar_vector<typename VecV::value_type, Device>, \
194 typename device_traits<Device>:: template F<typename VecV::value_type> > \
196name (vector_expression<VecV, Device> const& v, T t){ \
197 typedef typename VecV::value_type type;\
198 typedef typename device_traits<Device>:: template F<type> functor_type;\
199 return vector_binary<VecV, scalar_vector<type, Device>, functor_type >(v(), scalar_vector<type, Device>(v().size(),(type)t), functor_type()); \
211#undef REMORA_VECTOR_SCALAR_TRANSFORMATION
214#define REMORA_VECTOR_SCALAR_TRANSFORMATION_2(name, F)\
215template<class T, class VecV, class Device> \
216typename std::enable_if< \
217 std::is_convertible<T, typename VecV::value_type >::value,\
218 vector_binary<scalar_vector<typename VecV::value_type, Device>, VecV, typename device_traits<Device>:: template F<typename VecV::value_type> > \
220name (T t, vector_expression<VecV, Device> const& v){ \
221 typedef typename VecV::value_type type;\
222 typedef typename device_traits<Device>:: template F<type> functor_type;\
223 return vector_binary<scalar_vector<T, Device>, VecV, functor_type >(scalar_vector<T, Device>(v().size(),t), v() ,functor_type()); \
227#undef REMORA_VECTOR_SCALAR_TRANSFORMATION_2
229template<
class VecV1,
class VecV2,
class Device>
230vector_binary<VecV1, VecV2,
231 typename device_traits<Device>:: template safe_divide<typename common_value_type<VecV1,VecV2>::type >
234 vector_expression<VecV1, Device>
const& v1,
235 vector_expression<VecV2, Device>
const& v2,
236 typename common_value_type<VecV1,VecV2>::type defaultValue
238 REMORA_SIZE_CHECK(v1().size() == v2().size());
239 typedef typename common_value_type<VecV1,VecV2>::type result_type;
241 typedef typename device_traits<Device>:: template safe_divide<result_type> functor_type;
242 return vector_binary<VecV1, VecV2, functor_type>(v1(),v2(), functor_type(defaultValue));
248template<
class VecV,
class Device>
249typename VecV::value_type
250sum(vector_expression<VecV, Device>
const& v) {
251 typedef typename VecV::value_type value_type;
252 typedef typename device_traits<Device>:: template add<value_type> functor_type;
253 auto const& elem_result = eval_block(v);
254 value_type result = 0;
255 kernels::vector_fold<functor_type>(elem_result,result);
260template<
class VecV,
class Device>
261typename VecV::value_type
262max(vector_expression<VecV, Device>
const& v) {
263 typedef typename VecV::value_type value_type;
264 typedef typename device_traits<Device>:: template max<value_type> functor_type;
265 auto const& elem_result = eval_block(v);
266 value_type result = std::numeric_limits<value_type>::lowest();
267 kernels::vector_fold<functor_type>(elem_result,result);
272template<
class VecV,
class Device>
273typename VecV::value_type
274min(vector_expression<VecV, Device>
const& v) {
275 typedef typename VecV::value_type value_type;
276 typedef typename device_traits<Device>:: template min<value_type> functor_type;
277 auto const& elem_result = eval_block(v);
278 value_type result = std::numeric_limits<value_type>::max();
279 kernels::vector_fold<functor_type>(elem_result,result);
284template<
class VecV,
class Device>
285std::size_t arg_max(vector_expression<VecV, Device>
const& v) {
286 REMORA_SIZE_CHECK(v().size() > 0);
287 auto const& elem_result = eval_block(v);
288 return kernels::vector_max(elem_result);
292template<
class VecV,
class Device>
293std::size_t arg_min(vector_expression<VecV, Device>
const& v) {
294 REMORA_SIZE_CHECK(v().size() > 0);
305template<
class VecV,
class Device>
306typename VecV::value_type
307soft_max(vector_expression<VecV, Device>
const& v) {
308 typename VecV::value_type maximum = max(v);
310 return log(sum(exp(v - maximum))) + maximum;
317template<
class VecV,
class Device>
318typename real_traits<typename VecV::value_type >::type
319norm_1(vector_expression<VecV, Device>
const& v) {
320 return sum(abs(eval_block(v)));
324template<
class VecV,
class Device>
325typename real_traits<typename VecV::value_type >::type
326norm_sqr(vector_expression<VecV, Device>
const& v) {
327 return sum(
sqr(eval_block(v)));
331template<
class VecV,
class Device>
332typename real_traits<typename VecV::value_type >::type
333norm_2(vector_expression<VecV, Device>
const& v) {
335 return sqrt(norm_sqr(v));
339template<
class VecV,
class Device>
340typename real_traits<typename VecV::value_type >::type
341norm_inf(vector_expression<VecV, Device>
const& v){
342 return max(abs(eval_block(v)));
346template<
class VecV,
class Device>
347std::size_t index_norm_inf(vector_expression<VecV, Device>
const& v){
348 return arg_max(abs(eval_block(v)));
352template<
class VecV1,
class VecV2,
class Device>
354 typename VecV1::value_type() *
typename VecV2::value_type()
357 vector_expression<VecV1, Device>
const& v1,
358 vector_expression<VecV2, Device>
const& v2
360 REMORA_SIZE_CHECK(v1().size() == v2().size());
362 typename VecV1::value_type() *
typename VecV2::value_type()
364 value_type result = value_type();
365 kernels::dot(eval_block(v1),eval_block(v2),result);
376template<
class VecV1,
class VecV2,
class Device>
377vector_concat<VecV1,VecV2> operator|(
378 vector_expression<VecV1, Device>
const& v1,
379 vector_expression<VecV2, Device>
const& v2
381 return vector_concat<VecV1,VecV2>(v1(),v2());
387template<
class VecV,
class T,
class Device>
388typename std::enable_if<
389 std::is_convertible<T, typename VecV::value_type>::value,
390 vector_concat<VecV, scalar_vector<T, Device> >
392 vector_expression<VecV, Device>
const& v,
395 return v | scalar_vector<T, Device>(1,t);
401template<
class T,
class VecV,
class Device>
402typename std::enable_if<
403 std::is_convertible<T, typename VecV::value_type>::value,
404 vector_concat<scalar_vector<T, Device>,VecV >
407 vector_expression<VecV, Device>
const& v
409 return scalar_vector<T, Device>(1,t) | v;