28 #ifndef REMORA_MATRIX_EXPRESSION_HPP 29 #define REMORA_MATRIX_EXPRESSION_HPP 31 #include "detail/expression_optimizers.hpp" 44 template<
class VecA,
class VecB,
class Device>
45 outer_product<VecA, VecB >
47 vector_expression<VecA, Device>
const& v1,
48 vector_expression<VecB, Device>
const& v2
50 return outer_product<VecA, VecB>(v1(), v2());
64 template<
class VecV,
class Device>
65 vector_repeater<VecV> repeat(vector_expression<VecV, Device>
const& vector, std::size_t rows){
66 return vector_repeater<VecV>(vector(),rows);
76 typename std::enable_if<std::is_arithmetic<T>::value, scalar_matrix<T,cpu_tag> >::type
77 repeat(T scalar, std::size_t rows, std::size_t columns){
78 return scalar_matrix<T,cpu_tag>(rows, columns, scalar);
85 template<
class MatA,
class T,
class Device>
86 typename std::enable_if<
87 std::is_convertible<T, typename MatA::value_type >::value,
88 matrix_scalar_multiply<MatA>
90 operator* (matrix_expression<MatA, Device>
const& A, T scalar){
91 return matrix_scalar_multiply<MatA>(A(),
typename MatA::value_type(scalar));
97 template<
class T,
class MatA,
class Device>
98 typename std::enable_if<
99 std::is_convertible<T, typename MatA::value_type >::value,
100 matrix_scalar_multiply<MatA>
102 operator* (T scalar, matrix_expression<MatA, Device>
const& A){
103 return matrix_scalar_multiply<MatA>(A(),
typename MatA::value_type(scalar));
109 template<
class MatA,
class Device>
110 matrix_scalar_multiply<MatA> operator-(matrix_expression<MatA, Device>
const& A){
111 return matrix_scalar_multiply<MatA>(A(),
typename MatA::value_type(-1));
114 #define REMORA_UNARY_MATRIX_TRANSFORMATION(name, F)\ 115 template<class MatA, class Device>\ 116 matrix_unary<MatA,typename device_traits<Device>:: template F<typename MatA::value_type> >\ 117 name(matrix_expression<MatA, Device> const& v){\ 118 typedef typename device_traits<Device>:: template F<typename MatA::value_type> functor_type;\ 119 return matrix_unary<MatA, functor_type >(v(), functor_type());\ 139 #undef REMORA_UNARY_MATRIX_TRANSFORMATION 142 template<
class MatA,
class MatB,
class Device>
143 matrix_addition<MatA, MatB > operator+ (
144 matrix_expression<MatA, Device>
const& A,
145 matrix_expression<MatB, Device>
const& B
147 REMORA_SIZE_CHECK(A().size1() == B().size1());
148 REMORA_SIZE_CHECK(A().size2() == B().size2());
149 return matrix_addition<MatA, MatB>(A(),B());
153 template<
class MatA,
class MatB,
class Device>
154 matrix_addition<MatA, matrix_scalar_multiply<MatB> > operator- (
155 matrix_expression<MatA, Device>
const& A,
156 matrix_expression<MatB, Device>
const& B
158 REMORA_SIZE_CHECK(A().size1() == B().size1());
159 REMORA_SIZE_CHECK(A().size2() == B().size2());
160 return matrix_addition<MatA, matrix_scalar_multiply<MatB> >(A(),-B());
164 template<
class MatA,
class T,
class Device>
165 typename std::enable_if<
166 std::is_convertible<T, typename MatA::value_type>::value,
167 matrix_addition<MatA, scalar_matrix<T,Device> >
169 matrix_expression<MatA, Device>
const& A,
172 return A + scalar_matrix<T,Device>(A().size1(),A().size2(),t);
176 template<
class T,
class MatA,
class Device>
177 typename std::enable_if<
178 std::is_convertible<T, typename MatA::value_type>::value,
179 matrix_addition<MatA, scalar_matrix<T,Device> >
182 matrix_expression<MatA, Device>
const& A
184 return A + scalar_matrix<T,Device>(A().size1(),A().size2(),t);
188 template<
class MatA,
class T,
class Device>
189 typename std::enable_if<
190 std::is_convertible<T, typename MatA::value_type>::value ,
191 matrix_addition<MatA, matrix_scalar_multiply<scalar_matrix<T,Device> > >
193 matrix_expression<MatA, Device>
const& A,
196 return A - scalar_matrix<T,Device>(A().size1(),A().size2(),t);
200 template<
class MatA,
class T,
class Device>
201 typename std::enable_if<
202 std::is_convertible<T, typename MatA::value_type>::value,
203 matrix_addition<scalar_matrix<T,Device>, matrix_scalar_multiply<MatA> >
206 matrix_expression<MatA, Device>
const& A
208 return scalar_matrix<T,Device>(A().size1(),A().size2(),t) - A;
211 #define REMORA_BINARY_MATRIX_EXPRESSION(name, F)\ 212 template<class MatA, class MatB, class Device>\ 213 matrix_binary<MatA, MatB, typename device_traits<Device>:: template F<typename common_value_type<MatA,MatB>::type> >\ 214 name(matrix_expression<MatA, Device> const& m1, matrix_expression<MatB, Device> const& m2){\ 215 REMORA_SIZE_CHECK(m1().size1() == m2().size1());\ 216 REMORA_SIZE_CHECK(m1().size2() == m2().size2());\ 217 typedef typename common_value_type<MatA,MatB>::type type;\ 218 typedef typename device_traits<Device>:: template F<type> functor_type;\ 219 return matrix_binary<MatA, MatB, functor_type >(m1(),m2(), functor_type());\ 228 #undef REMORA_BINARY_MATRIX_EXPRESSION 230 #define REMORA_MATRIX_SCALAR_TRANSFORMATION(name, F)\ 231 template<class T, class MatA, class Device> \ 232 typename std::enable_if< \ 233 std::is_convertible<T, typename MatA::value_type >::value,\ 234 matrix_binary<MatA, scalar_matrix<typename MatA::value_type,Device>,typename device_traits<Device>:: template F<typename MatA::value_type> > \ 236 name (matrix_expression<MatA, Device> const& m, T t){ \ 237 typedef typename MatA::value_type type;\ 238 typedef typename device_traits<Device>:: template F<type> functor_type;\ 239 return matrix_binary<MatA, scalar_matrix<type,Device>, functor_type >(m(), scalar_matrix<type,Device>(m().size1(), m().size2(), t) ,functor_type()); \ 251 #undef REMORA_MATRIX_SCALAR_TRANSFORMATION 254 #define REMORA_MATRIX_SCALAR_TRANSFORMATION_2(name, F)\ 255 template<class T, class MatA, class Device> \ 256 typename std::enable_if< \ 257 std::is_convertible<T, typename MatA::value_type >::value,\ 258 matrix_binary<scalar_matrix< typename MatA::value_type,Device>, MatA, typename device_traits<Device>:: template F< typename MatA::value_type> > \ 260 name (T t, matrix_expression<MatA, Device> const& m){ \ 261 typedef typename MatA::value_type type;\ 262 typedef typename device_traits<Device>:: template F<type> functor_type;\ 263 return matrix_binary<scalar_matrix<type,Device>, MatA, functor_type >(scalar_matrix<type,Device>(m().size1(), m().size2(), t), m(), functor_type()); \ 267 #undef REMORA_MATRIX_SCALAR_TRANSFORMATION_2 269 template<
class MatA,
class MatB,
class Device>
270 matrix_binary<MatA, MatB,
271 typename device_traits<Device>:: template safe_divide<typename common_value_type<MatA,MatB>::type>
274 matrix_expression<MatA, Device>
const& A,
275 matrix_expression<MatB, Device>
const& B,
276 typename common_value_type<MatA,MatB>::type defaultValue
278 REMORA_SIZE_CHECK(A().size1() == B().size1());
279 REMORA_SIZE_CHECK(A().size2() == B().size2());
280 typedef typename common_value_type<MatA,MatB>::type result_type;
281 typedef typename device_traits<Device>:: template safe_divide<result_type> functor_type;
282 return matrix_binary<MatA, MatB, functor_type>(A(),B(), functor_type(defaultValue));
291 template<
class MatA,
class VecV,
class Device>
292 typename detail::matrix_vector_prod_optimizer<MatA,VecV>::type prod(
293 matrix_expression<MatA, Device>
const& A,vector_expression<VecV, Device>
const& v
295 REMORA_SIZE_CHECK(A().size2() == v().size());
296 return detail::matrix_vector_prod_optimizer<MatA,VecV>::create(A(),v());
306 template<
class MatA,
class VecV,
class Device>
307 auto prod(vector_expression<VecV, Device>
const& v,matrix_expression<MatA, Device>
const& A) -> decltype(prod(trans(A),v)){
308 REMORA_SIZE_CHECK(A().size1() == v().size());
309 return prod(trans(A),v);
315 template<
class MatA,
class VecV,
class Device>
316 auto operator%(vector_expression<VecV, Device>
const& v,matrix_expression<MatA, Device>
const& A) -> decltype(prod(trans(A),v)){
317 REMORA_SIZE_CHECK(A().size1() == v().size());
318 return prod(trans(A),v);
324 template<
class MatA,
class VecV,
class Device>
325 auto operator%(matrix_expression<MatA, Device>
const& A,vector_expression<VecV, Device>
const& v) -> decltype(prod(A,v)){
326 REMORA_SIZE_CHECK(A().size2() == v().size());
337 template<
class TriangularType,
class MatA,
class VecV,
class Device>
338 matrix_vector_prod<detail::dense_triangular_proxy<typename const_expression<MatA>::type,TriangularType> ,VecV>
340 matrix_expression<MatA, Device>
const& A,
341 vector_expression<VecV, Device>& v
343 REMORA_SIZE_CHECK(A().size2() == v().size());
344 typedef detail::dense_triangular_proxy<typename const_expression<MatA>::type,TriangularType> Wrapper;
345 return matrix_vector_prod<Wrapper ,VecV>(Wrapper(A()), v());
349 template<
class MatA,
class MatB,
class Device>
350 typename detail::matrix_matrix_prod_optimizer<MatA,MatB>::type prod(
351 matrix_expression<MatA, Device>
const& A,
352 matrix_expression<MatB, Device>
const& B
354 REMORA_SIZE_CHECK(A().size2() == B().size1());
355 static_assert(std::is_base_of<linear_structure, typename MatA::orientation>::value,
"A must be linearly stored");
356 static_assert(std::is_base_of<linear_structure, typename MatB::orientation>::value,
"B must be linearly stored");
357 return detail::matrix_matrix_prod_optimizer<MatA,MatB>::create(A(),B());
363 template<
class MatA,
class MatB,
class Device>
365 matrix_expression<MatA, Device>
const& A,
366 matrix_expression<MatB, Device>
const& B
367 ) -> decltype(prod(A,B)){
368 REMORA_SIZE_CHECK(A().size2() == B().size1());
380 template<
class TriangularType,
class MatA,
class MatB,
class Device>
381 matrix_matrix_prod<detail::dense_triangular_proxy<typename const_expression<MatA>::type,TriangularType> ,MatB>
383 matrix_expression<MatA, Device>
const& A,
384 matrix_expression<MatB, Device>
const& B
386 REMORA_SIZE_CHECK(A().size2() == B().size1());
387 static_assert(std::is_base_of<linear_structure, typename MatA::orientation>::value,
"A must be linearly stored");
388 static_assert(std::is_base_of<linear_structure, typename MatB::orientation>::value,
"B must be linearly stored");
389 typedef detail::dense_triangular_proxy<typename const_expression<MatA>::type,TriangularType> Wrapper;
390 return matrix_matrix_prod<Wrapper ,MatB>(Wrapper(A()), B());
393 template<
class MatA,
class Device>
394 sum_matrix_rows<MatA>
395 sum_rows(matrix_expression<MatA, Device>
const& A){
396 return sum_matrix_rows<MatA>(A());
399 template<
class MatA,
class Device>
400 auto sum_columns(matrix_expression<MatA, Device>
const& A)->decltype(sum_rows(trans(A))){
401 return sum_rows(trans(A));
405 template<
class MatA,
class Device>
406 typename MatA::value_type sum(matrix_expression<MatA, Device>
const& A){
407 typedef typename MatA::value_type value_type;
408 typedef typename device_traits<Device>:: template add<value_type> functor_type;
409 auto const& elem_result = eval_block(A);
410 value_type result = 0;
411 kernels::matrix_fold<functor_type>(elem_result,result);
415 template<
class MatA,
class Device>
416 typename MatA::value_type max(matrix_expression<MatA, Device>
const& A){
417 typedef typename MatA::value_type value_type;
418 typedef typename device_traits<Device>:: template max<value_type> functor_type;
419 auto const& elem_result = eval_block(A);
420 value_type result = 0;
421 kernels::matrix_fold<functor_type>(elem_result,result);
425 template<
class MatA,
class Device>
426 typename MatA::value_type min(matrix_expression<MatA, Device>
const& A){
427 typedef typename MatA::value_type value_type;
428 typedef typename device_traits<Device>:: template min<value_type> functor_type;
429 auto const& elem_result = eval_block(A);
430 value_type result = 0;
431 kernels::matrix_fold<functor_type>(elem_result,result);
439 template<
class MatA,
class MatB,
class Device>
440 decltype(
typename MatA::value_type() *
typename MatB::value_type())
442 matrix_expression<MatA, Device>
const& A,
443 matrix_expression<MatB, Device>
const& B
445 REMORA_SIZE_CHECK(A().size1() == B().size1());
446 REMORA_SIZE_CHECK(A().size2() == B().size2());
447 return sum(eval_block(A*B));
453 template<
class MatA,
class Device>
454 typename real_traits<typename MatA::value_type>::type
455 norm_1(matrix_expression<MatA, Device>
const& A) {
456 return max(sum_rows(abs(A)));
462 template<
class MatA,
class Device>
463 typename real_traits<typename MatA::value_type>::type
464 norm_frobenius(matrix_expression<MatA, Device>
const& A) {
466 return sqrt(sum(
sqr(eval_block(A))));
472 template<
class MatA,
class Device>
473 typename real_traits<typename MatA::value_type>::type
474 norm_inf(matrix_expression<MatA, Device>
const& A) {
475 return max(sum_columns(abs(A)));
485 template <
class MatA,
class Device>
486 typename MatA::value_type trace(matrix_expression<MatA, Device>
const& A)
488 REMORA_SIZE_CHECK(A().size1() == A().size2());
497 class identity_matrix:
public diagonal_matrix<scalar_vector<T, cpu_tag> > {
498 typedef diagonal_matrix<scalar_vector<T, cpu_tag> > base_type;
501 identity_matrix(std::size_t size):base_type(scalar_vector<T, cpu_tag>(size,T(1))){}
505 template<
class MatA,
class Device>
506 diagonal_matrix<MatA> to_diagonal(vector_expression<MatA, Device>
const& A){
507 return diagonal_matrix<MatA>(A());
514 template<
class MatA,
class MatB,
class Device>
515 matrix_concat<MatA, MatB, true> operator|(
516 matrix_expression<MatA, Device>
const& A,
517 matrix_expression<MatB, Device>
const& B
519 return matrix_concat<MatA, MatB, true>(A(),B());
523 template<
class MatA,
class VecV,
class Device>
525 matrix_expression<MatA, Device>
const& A,
526 vector_expression<VecV, Device>
const& v
527 ) -> decltype(A | trans(repeat(v,1))){
528 return A | trans(repeat(v,1));
532 template<
class MatA,
class VecV,
class Device>
534 vector_expression<VecV, Device>
const& v,
535 matrix_expression<MatA, Device>
const& A
536 ) -> decltype(trans(repeat(v,1)) | A){
537 return trans(repeat(v,1)) | A;
543 template<
class MatA,
class T,
class Device>
544 typename std::enable_if<
545 std::is_convertible<T, typename MatA::value_type>::value,
546 matrix_concat<MatA, scalar_matrix<T, Device>,
true >
548 matrix_expression<MatA, Device>
const& A,
551 return A | repeat(t,A().size1(), 1);
557 template<
class MatA,
class T,
class Device>
558 typename std::enable_if<
559 std::is_convertible<T, typename MatA::value_type>::value,
560 matrix_concat<scalar_matrix<T, Device>, MatA,
true >
563 matrix_expression<MatA, Device>
const& A
565 return repeat(t,A().size1(), 1) | A;
569 template<
class MatA,
class MatB,
class Device>
570 matrix_concat<MatA, MatB, false> operator&(
571 matrix_expression<MatA, Device>
const& A,
572 matrix_expression<MatB, Device>
const& B
574 return matrix_concat<MatA, MatB, false>(A(),B());
578 template<
class MatA,
class VecV,
class Device>
580 matrix_expression<MatA, Device>
const& A,
581 vector_expression<VecV, Device>
const& v
582 ) -> decltype(A & repeat(v,1)){
583 return A & repeat(v,1);
587 template<
class MatA,
class VecV,
class Device>
589 vector_expression<VecV, Device>
const& v,
590 matrix_expression<MatA, Device>
const& A
591 ) -> decltype(repeat(v,1) & A){
592 return repeat(v,1) & A;
598 template<
class MatA,
class T,
class Device>
599 typename std::enable_if<
600 std::is_convertible<T, typename MatA::value_type>::value,
601 matrix_concat<MatA, scalar_matrix<T, Device>,
false >
603 matrix_expression<MatA, Device>
const& A,
606 return A & repeat(t, 1, A().size2());
612 template<
class MatA,
class T,
class Device>
613 typename std::enable_if<
614 std::is_convertible<T, typename MatA::value_type>::value,
615 matrix_concat<scalar_matrix<T, Device>, MatA,
false >
618 matrix_expression<MatA, Device>
const& A
620 return repeat(t,1, A().size2()) & A;
626 E
const& copy_to_cpu(matrix_expression<E, cpu_tag>
const& e){
632 #ifdef REMORA_USE_GPU