traits.hpp
Go to the documentation of this file.
1//===========================================================================
2/*!
3 *
4 *
5 * \brief Traits of matrix expressions
6 *
7 * \author O. Krause
8 * \date 2013
9 *
10 *
11 * \par Copyright 1995-2015 Shark Development Team
12 *
13 * <BR><HR>
14 * This file is part of Shark.
15 * <http://image.diku.dk/shark/>
16 *
17 * Shark is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU Lesser General Public License as published
19 * by the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * Shark is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public License
28 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
29 *
30 */
31//===========================================================================
32
33#ifndef REMORA_CPU_TRAITS_HPP
34#define REMORA_CPU_TRAITS_HPP
35
36#include "../expression_types.hpp"
37#include "iterator.hpp"
38#include <cmath>
39
40
41
42namespace remora{
43//pure block expressions do not have an iterator but the interface still requires one.
44// this is our cheap way out.
45struct no_iterator{};
46//some devices do not need a queue but the interface still expects one.
47struct no_queue{};
48
49template<class Device>
50struct device_traits;
51
52template<>
53struct device_traits<cpu_tag>{
54 //queue (not used on cpu)
55 typedef no_queue queue_type;
56
57 static queue_type& default_queue(){
58 static queue_type queue;
59 return queue;
60 }
61
62 //adding of indices
63 static std::size_t index_add(std::size_t i, std::size_t j){
64 return i+j;
65 }
66
67 template<class E>
68 static typename E::reference linearized_matrix_element(matrix_expression<E, cpu_tag> const& e, std::size_t i){
69 std::size_t leading_dimension = E::orientation::index_m(e().size1(), e().size2());
70 std::size_t i1 = i / leading_dimension;
71 std::size_t i2 = i % leading_dimension;
72 return e()(E::orientation::index_M(i1,i2), E::orientation::index_m(i1,i2));
73 }
74
75 template <class Iterator, class Functor>
76 struct transform_iterator{
77 typedef iterators::transform_iterator<Iterator, Functor> type;
78 };
79
80 template <class Iterator1, class Iterator2, class Functor>
81 struct binary_transform_iterator{
82 typedef iterators::binary_transform_iterator<Iterator1,Iterator2, Functor> type;
83 };
84
85 template<class T>
86 struct constant_iterator{
87 typedef iterators::constant_iterator<T> type;
88 };
89
90 template<class T>
91 struct one_hot_iterator{
92 typedef iterators::one_hot_iterator<T> type;
93 };
94
95 template<class Closure>
96 struct indexed_iterator{
97 typedef iterators::indexed_iterator<Closure> type;
98 };
99
100 //functors
101
102 template<class T>
103 struct constant{
104 typedef T result_type;
105 constant(T const& value): m_value(value){}
106
107 template<class Arg>
108 T operator()(Arg const&) const{
109 return m_value;
110 }
111 template<class Arg1, class Arg2>
112 T operator()(Arg1 const&, Arg2 const&) const{
113 return {m_value};
114 }
115
116 T m_value;
117 };
118
119 template<class T>
120 struct add {
121 static const bool left_zero_remains = false;
122 static const bool right_zero_remains = false;
123 static const bool right_zero_identity = true;
124 static const bool left_zero_identity = false;
125 typedef T result_type;
126 T operator()(T x, T y)const{
127 return x+y;
128 }
129 };
130 template<class T>
131 struct subtract {
132 static const bool left_zero_remains = false;
133 static const bool right_zero_remains = false;
134 static const bool right_zero_identity = true;
135 static const bool left_zero_identity = false;
136 typedef T result_type;
137 T operator()(T x, T y)const{
138 return x-y;
139 }
140 };
141
142 template<class T>
143 struct multiply {
144 static const bool left_zero_remains = true;
145 static const bool right_zero_remains = true;
146 static const bool right_zero_identity = false;
147 static const bool left_zero_identity = true;
148 typedef T result_type;
149 T operator()(T x, T y)const{
150 return x*y;
151 }
152 };
153
154 template<class T>
155 struct divide {
156 static const bool left_zero_remains = true;
157 static const bool right_zero_remains = false;
158 static const bool right_zero_identity = false;
159 static const bool left_zero_identity = true;
160 typedef T result_type;
161 T operator()(T x, T y)const{
162 return x/y;
163 }
164 };
165
166 template<class T>
167 struct multiply_and_add{
168 static const bool left_zero_remains = false;
169 static const bool right_zero_remains = false;
170 static const bool right_zero_identity = true;
171 static const bool left_zero_identity = false;
172 typedef T result_type;
173 multiply_and_add(T scalar):scalar(scalar){}
174 T operator()(T x, T y)const{
175 return x+scalar * y;
176 }
177 private:
178 T scalar;
179 };
180 template<class T>
181 struct multiply_assign{
182 static const bool left_zero_remains = false;
183 static const bool right_zero_remains = false;
184 static const bool right_zero_identity = true;
185 static const bool left_zero_identity = false;
186 typedef T result_type;
187 multiply_assign(T scalar):scalar(scalar){}
188 T operator()(T, T y)const{
189 return scalar * y;
190 }
191 private:
192 T scalar;
193 };
194 template<class T>
195 struct pow {
196 static const bool left_zero_remains = false;
197 static const bool right_zero_remains = false;
198 typedef T result_type;
199 T operator()(T x, T y)const {
200 using std::pow;
201 return pow(x,y);
202 }
203 };
204 template<class T>
205 struct multiply_scalar{
206 static const bool zero_identity = true;
207 typedef T result_type;
208 multiply_scalar(T scalar):m_scalar(scalar){}
209 T operator()(T x) const{
210 return x * m_scalar;
211 }
212 private:
213 T m_scalar;
214 };
215
216 template<class T>
217 struct add_scalar{
218 static const bool zero_identity = false;
219 typedef T result_type;
220 add_scalar(T scalar):m_scalar(scalar){}
221 T operator()(T x) const{
222 return x + m_scalar;
223 }
224 private:
225 T m_scalar;
226 };
227
228 template<class T>
229 struct divide_scalar{
230 static const bool zero_identity = true;
231 typedef T result_type;
232 divide_scalar(T scalar):m_scalar(scalar){}
233 T operator()(T x) const{
234 return x / m_scalar;
235 }
236 private:
237 T m_scalar;
238 };
239
240 template<class T>
241 struct modulo_scalar{
242 static const bool zero_identity = true;
243 typedef T result_type;
244 modulo_scalar(T scalar):m_scalar(scalar){}
245 T operator()(T x) const{
246 return x % m_scalar;
247 }
248 private:
249 T m_scalar;
250 };
251
252
253
254 template<class T>
255 struct safe_divide {
256 static const bool left_zero_remains = true;
257 static const bool right_zero_remains = false;
258 safe_divide(T defaultValue):m_defaultValue(defaultValue) {}
259 typedef T result_type;
260 T operator()(T x, T y)const{
261 return y == T()? m_defaultValue : x/y;
262 }
263 private:
264 T m_defaultValue;
265 };
266
267 template<class T>
268 struct identity{
269 typedef T result_type;
270
271 T operator()(T arg) const{
272 return arg;
273 }
274 };
275
276 template<class T>
277 struct left_arg{
278 typedef T result_type;
279 static const bool left_zero_remains = true;
280 static const bool right_zero_remains = false;
281 T operator()(T arg1, T) const{
282 return arg1;
283 }
284 };
285 template<class T>
286 struct right_arg{
287 typedef T result_type;
288 static const bool left_zero_remains = false;
289 static const bool right_zero_remains = true;
290 T operator()(T, T arg2) const{
291 return arg2;
292 }
293 };
294
295 //math unary functions
296 #define REMORA_STD_UNARY_FUNCTION(func, id)\
297 template<class T>\
298 struct func{\
299 static const bool zero_identity = id;\
300 typedef T result_type;\
301 T operator()(T x)const {\
302 return std::func(x);\
303 }\
304 };
305
307 REMORA_STD_UNARY_FUNCTION(sqrt, true)
308 REMORA_STD_UNARY_FUNCTION(cbrt, true)
309
310 REMORA_STD_UNARY_FUNCTION(exp, false)
311 REMORA_STD_UNARY_FUNCTION(log, false)
312
313 //trigonometric functions
314 REMORA_STD_UNARY_FUNCTION(cos, false)
317
318 REMORA_STD_UNARY_FUNCTION(acos, false)
319 REMORA_STD_UNARY_FUNCTION(asin, true)
320 REMORA_STD_UNARY_FUNCTION(atan, true)
321
322 //sigmoid type functions
323 REMORA_STD_UNARY_FUNCTION(tanh, true)
324
325 //special functions
326 REMORA_STD_UNARY_FUNCTION(erf, false)
327 REMORA_STD_UNARY_FUNCTION(erfc, false)
328#undef REMORA_STD_UNARY_FUNCTION
329
330 template<class T>
331 struct sigmoid {
332 static const bool zero_identity = false;
333 typedef T result_type;
334 T operator()(T x)const {
335 using std::tanh;
336 return (tanh(x/T(2)) + T(1))/T(2);
337 }
338 };
339 template<class T>
340 struct soft_plus {
341 static const bool zero_identity = false;
342 typedef T result_type;
343 T operator()(T x)const {
344 if(x > 100){
345 return x;
346 }
347 if(x < -100){
348 return 0;
349 }
350 return std::log(1+std::exp(x));
351 }
352 };
353
354 template<class T>
355 struct inv {
356 static const bool zero_identity = false;
357 typedef T result_type;
358 T operator()(T x)const {
359 return T(1)/x;
360 }
361 };
362 template<class T>
363 struct sqr{
364 static const bool zero_identity = true;
365 typedef T result_type;
366 T operator()(T x)const {
367 return x*x;
368 }
369 };
370
371
372 //min/max
373 template<class T>
374 struct min{
375 static const bool left_zero_remains = false;
376 static const bool right_zero_remains = false;
377 typedef T result_type;
378 T operator()(T x, T y)const{
379 return std::min(x,y);
380 }
381 };
382
383 template<class T>
384 struct max{
385 static const bool left_zero_remains = false;
386 static const bool right_zero_remains = false;
387 typedef T result_type;
388 T operator()(T x, T y)const{
389 return std::max(x,y);
390 }
391 };
392
393
394 //comparison
395 template<class T>
396 struct less{
397 static const bool left_zero_remains = false;
398 static const bool right_zero_remains = false;
399 typedef int result_type;
400 int operator()(T x1, T x2)const {
401 return x1 < x2;
402 }
403 };
404 template<class T>
405 struct less_equal{
406 static const bool left_zero_remains = false;
407 static const bool right_zero_remains = false;
408 typedef int result_type;
409 int operator()(T x1, T x2)const {
410 return x1 <= x2;
411 }
412 };
413
414 template<class T>
415 struct greater{
416 static const bool left_zero_remains = false;
417 static const bool right_zero_remains = false;
418 typedef int result_type;
419 int operator()(T x1, T x2)const {
420 return x1 > x2;
421 }
422 };
423
424 template<class T>
425 struct greater_equal{
426 static const bool left_zero_remains = false;
427 static const bool right_zero_remains = false;
428 typedef int result_type;
429 int operator()(T x1, T x2)const {
430 return x1 >= x2;
431 }
432 };
433
434 template<class T>
435 struct equal{
436 static const bool left_zero_remains = false;
437 static const bool right_zero_remains = false;
438 typedef int result_type;
439 int operator()(T x1, T x2)const {
440 return x1 == x2;
441 }
442 };
443
444 template<class T>
445 struct not_equal{
446 static const bool left_zero_remains = false;
447 static const bool right_zero_remains = false;
448 typedef int result_type;
449 int operator()(T x1, T x2)const {
450 return x1 != x2;
451 }
452 };
453
454 //functional
455 template<class F, class G>
456 struct compose{
457 typedef typename G::result_type result_type;
458 compose(F const& f, G const& g): m_f(f), m_g(g){ }
459
460 template<class Arg1>
461 result_type operator()(Arg1 const& x) const{
462 return m_g(m_f(x));
463 }
464
465 template<class Arg1, class Arg2>
466 result_type operator()(Arg1 const& x, Arg2 const& y) const{
467 return m_g(m_f(x,y));
468 }
469
470 F m_f;
471 G m_g;
472 };
473
474 //G(F1(args),F2(args))
475 template<class F1, class F2, class G>
476 struct compose_binary{
477 typedef typename G::result_type result_type;
478 compose_binary(F1 const& f1, F2 const& f2, G const& g): m_f1(f1), m_f2(f2), m_g(g){ }
479
480 template<class Arg1>
481 result_type operator()( Arg1 const& x) const{
482 return m_g(m_f1(x), m_f2(x));
483 }
484 template<class Arg1, class Arg2>
485 result_type operator()( Arg1 const& x, Arg2 const& y) const{
486 return m_g(m_f1(x,y), m_f2(x,y));
487 }
488
489 F1 m_f1;
490 F2 m_f2;
491 G m_g;
492 };
493
494 //G(F1(arg1),F2(arg2))
495 template<class F1, class F2, class G>
496 struct transform_arguments{
497 typedef typename G::result_type result_type;
498 transform_arguments(F1 const& f1, F2 const& f2, G const& g): m_f1(f1), m_f2(f2), m_g(g){ }
499
500 template<class Arg1, class Arg2>
501 result_type operator()( Arg1 const& x, Arg2 const& y) const{
502 return m_g(m_f1(x),m_f2(y));
503 }
504
505 F1 m_f1;
506 F2 m_f2;
507 G m_g;
508 };
509
510 template<class F, class Arg2>
511 struct bind_second{
512 typedef typename F::result_type result_type;
513 bind_second(F const& f, Arg2 const& arg2) : m_function(f), m_arg2(arg2){ }
514
515 template<class Arg1>
516 result_type operator()(Arg1 const& arg1) const{
517 return m_function(arg1, m_arg2);
518 }
519
520 F m_function;
521 Arg2 m_arg2;
522
523 };
524
525 //helper functions
526 template<class F, class G>
527 static compose<F,G> make_compose(F const& f, G const&g){
528 return compose<F,G>(f,g);
529 }
530
531 template<class F1, class F2, class G>
532 static compose_binary<F1, F2, G> make_compose_binary(F1 const& f1, F2 const& f2, G const&g){
533 return compose_binary<F1, F2, G>(f1, f2, g);
534 }
535
536 template<class F1, class F2, class G>
537 static transform_arguments<F1, F2, G> make_transform_arguments(F1 const& f1, F2 const& f2, G const& g){
538 return transform_arguments<F1, F2, G>(f1, f2, g);
539 }
540
541 template<class F, class Arg2>
542 static bind_second<F,Arg2> make_bind_second(F const& f, Arg2 const& arg2){
543 return bind_second<F,Arg2>(f,arg2);
544 }
545
546};
547
548}
549
550#endif