28#ifndef REMORA_MATRIX_EXPRESSION_HPP 
   29#define REMORA_MATRIX_EXPRESSION_HPP 
   31#include "detail/expression_optimizers.hpp" 
   54template<
class VecV, 
class Device>
 
   55vector_repeater<VecV> repeat(vector_expression<VecV, Device> 
const& vector, std::size_t rows){
 
   56    return vector_repeater<VecV>(vector(),rows);
 
   66typename std::enable_if<std::is_arithmetic<T>::value, scalar_matrix<T,cpu_tag, row_major> >::type
 
   67repeat(T scalar, std::size_t rows, std::size_t columns){
 
   68    return scalar_matrix<T,cpu_tag, row_major>(rows, columns, scalar);
 
   75class identity_matrix: 
public diagonal_matrix<scalar_vector<T, cpu_tag> > {
 
   76    typedef diagonal_matrix<scalar_vector<T, cpu_tag> > base_type;
 
   79    identity_matrix(std::size_t size):base_type(scalar_vector<T, cpu_tag>(size,T(1))){}
 
   85template<
class MatA, 
class Device>
 
   86diagonal_matrix<MatA> to_diagonal(vector_expression<MatA, Device> 
const& v){
 
   87    return diagonal_matrix<MatA>(v());
 
   98template<
class MatA, 
class Device>
 
   99typename detail::matrix_scalar_multiply_optimizer<MatA>::type
 
  100operator-(matrix_expression<MatA, Device> 
const& A){
 
  101    return detail::matrix_scalar_multiply_optimizer<MatA>::create(A(), 
typename MatA::value_type(-1));
 
  104#define REMORA_UNARY_MATRIX_TRANSFORMATION(name, F)\ 
  105template<class MatA, class Device>\ 
  106typename detail::matrix_unary_optimizer<MatA,typename device_traits<Device>:: template F<typename MatA::value_type> >::type \ 
  107name(matrix_expression<MatA, Device> const& m){\ 
  108    typedef typename device_traits<Device>:: template F<typename MatA::value_type> functor_type;\ 
  109    return detail::matrix_unary_optimizer<MatA, functor_type >::create(m(), functor_type());\ 
 
  130#undef REMORA_UNARY_MATRIX_TRANSFORMATION 
  132#define REMORA_UNARY_VECTOR_SET_TRANSFORMATION(name)\ 
  133template<class S, class Device>\ 
  134auto name(vector_set_expression<S, Device> const& set)\ 
  135-> decltype(as_set(name( set().expression()), typename S::point_orientation())){\ 
  136    return as_set(name( set().expression()), typename S::point_orientation());\ 
 
  157#undef REMORA_UNARY_VECTOR_SET_TRANSFORMATION 
  167template<
class MatA, 
class T, 
class Device>
 
  168typename std::enable_if<
 
  169    std::is_convertible<T, typename MatA::value_type >::value,
 
  170    typename detail::matrix_scalar_multiply_optimizer<MatA>::type
 
  172operator* (matrix_expression<MatA, Device> 
const& A, T scalar){
 
  173    return detail::matrix_scalar_multiply_optimizer<MatA>::create(A(), 
typename MatA::value_type(scalar));
 
  179template<
class T, 
class MatA, 
class Device>
 
  180typename std::enable_if<
 
  181    std::is_convertible<T, typename MatA::value_type >::value,
 
  182        typename detail::matrix_scalar_multiply_optimizer<MatA>::type
 
  184operator* (T scalar, matrix_expression<MatA, Device> 
const& A){
 
  185    return detail::matrix_scalar_multiply_optimizer<MatA>::create(A(), 
typename MatA::value_type(scalar));
 
  190template<
class MatA, 
class T, 
class Device>
 
  191typename std::enable_if<
 
  192    std::is_convertible<T, typename MatA::value_type>::value, 
 
  193    matrix_addition<MatA, scalar_matrix<T,Device, typename MatA::orientation> >
 
  195    matrix_expression<MatA, Device> 
const& A,
 
  198    return A + scalar_matrix<T,Device, typename MatA::orientation>(A().size1(),A().size2(),t);
 
  202template<
class T, 
class MatA, 
class Device>
 
  203typename std::enable_if<
 
  204    std::is_convertible<T, typename MatA::value_type>::value,
 
  205    matrix_addition<MatA, scalar_matrix<T,Device, typename MatA::orientation> >
 
  208    matrix_expression<MatA, Device> 
const& A
 
  210    return A + scalar_matrix<T,Device, typename MatA::orientation>(A().size1(),A().size2(),t);
 
  214template<
class MatA, 
class T, 
class Device>
 
  215typename std::enable_if<
 
  216    std::is_convertible<T, typename MatA::value_type>::value ,
 
  217    decltype(std::declval<MatA const&>() + T())
 
  219    matrix_expression<MatA, Device> 
const& A,
 
  226template<
class MatA, 
class T, 
class Device>
 
  227typename std::enable_if<
 
  228    std::is_convertible<T, typename MatA::value_type>::value,
 
  229    decltype(T() + (-std::declval<MatA const&>()))
 
  232    matrix_expression<MatA, Device> 
const& A
 
  237#define REMORA_MATRIX_SCALAR_TRANSFORMATION(name, F)\ 
  238template<class T, class MatA, class Device> \ 
  239typename std::enable_if< \ 
  240    std::is_convertible<T, typename MatA::value_type >::value,\ 
  241        matrix_binary<MatA, scalar_matrix<typename MatA::value_type,Device, typename MatA::orientation>,typename device_traits<Device>:: template  F<typename MatA::value_type> > \ 
  243name (matrix_expression<MatA, Device> const& m, T t){ \ 
  244    typedef typename MatA::value_type type;\ 
  245    typedef typename device_traits<Device>:: template F<type> functor_type;\ 
  246    typedef scalar_matrix<type,Device, typename MatA::orientation> mat_type;\ 
  247    return matrix_binary<MatA, mat_type, functor_type >(m(), mat_type(m().size1(), m().size2(), t) ,functor_type()); \ 
 
  259#undef REMORA_MATRIX_SCALAR_TRANSFORMATION 
  262#define REMORA_MATRIX_SCALAR_TRANSFORMATION_2(name, F)\ 
  263template<class T, class MatA, class Device> \ 
  264typename std::enable_if< \ 
  265    std::is_convertible<T, typename MatA::value_type >::value,\ 
  266    matrix_binary<scalar_matrix< typename MatA::value_type,Device, typename MatA::orientation>, MatA, typename device_traits<Device>:: template F< typename MatA::value_type> > \ 
  268name (T t, matrix_expression<MatA, Device> const& m){ \ 
  269    typedef typename MatA::value_type type;\ 
  270    typedef typename device_traits<Device>:: template F<type> functor_type;\ 
  271    typedef scalar_matrix<type,Device, typename MatA::orientation> mat_type;\ 
  272    return  matrix_binary<mat_type, MatA, functor_type >(mat_type(m().size1(), m().size2(), t), m(), functor_type()); \ 
 
  276#undef REMORA_MATRIX_SCALAR_TRANSFORMATION_2 
  285template<
class MatA, 
class MatB, 
class Device>
 
  286matrix_addition<MatA, MatB > operator+ (
 
  287    matrix_expression<MatA, Device> 
const& A,
 
  288    matrix_expression<MatB, Device> 
const& B
 
  290    REMORA_SIZE_CHECK(A().size1() == B().size1());
 
  291    REMORA_SIZE_CHECK(A().size2() == B().size2());
 
  292    return matrix_addition<MatA, MatB>(A(),B());
 
  296template<
class MatA, 
class MatB, 
class Device>
 
  298    matrix_expression<MatA, Device> 
const& A,
 
  299    matrix_expression<MatB, Device> 
const& B
 
  300) -> 
decltype(A() + (-B)){
 
  301    REMORA_SIZE_CHECK(A().size1() == B().size1());
 
  302    REMORA_SIZE_CHECK(A().size2() == B().size2());
 
  306template<
class MatA, 
class MatB, 
class Device>
 
  307matrix_binary<MatA, MatB, 
 
  308    typename device_traits<Device>:: template  safe_divide<typename common_value_type<MatA,MatB>::type> 
 
  311    matrix_expression<MatA, Device> 
const& A, 
 
  312    matrix_expression<MatB, Device> 
const& B, 
 
  313    typename common_value_type<MatA,MatB>::type defaultValue
 
  315    REMORA_SIZE_CHECK(A().size1() == B().size1());
 
  316    REMORA_SIZE_CHECK(A().size2() == B().size2());
 
  317    typedef typename common_value_type<MatA,MatB>::type result_type;
 
  318    typedef typename device_traits<Device>:: template safe_divide<result_type> functor_type;
 
  319    return matrix_binary<MatA, MatB, functor_type>(A(),B(), functor_type(defaultValue));
 
  323#define REMORA_BINARY_MATRIX_EXPRESSION(name, F)\ 
  324template<class MatA, class MatB, class Device>\ 
  325matrix_binary<MatA, MatB, typename device_traits<Device>:: template F<typename common_value_type<MatA,MatB>::type> >\ 
  326name(matrix_expression<MatA, Device> const& m1, matrix_expression<MatB, Device> const& m2){\ 
  327    REMORA_SIZE_CHECK(m1().size1() == m2().size1());\ 
  328    REMORA_SIZE_CHECK(m1().size2() == m2().size2());\ 
  329    typedef typename common_value_type<MatA,MatB>::type type;\ 
  330    typedef typename device_traits<Device>:: template F<type> functor_type;\ 
  331    return matrix_binary<MatA, MatB, functor_type >(m1(),m2(), functor_type());\ 
 
  340#undef REMORA_BINARY_MATRIX_EXPRESSION 
  351template<
class VecA, 
class VecB, 
class Device>
 
  352outer_product<VecA, VecB >
 
  354    vector_expression<VecA, Device> 
const& v1,
 
  355        vector_expression<VecB, Device> 
const& v2
 
  357    return outer_product<VecA, VecB>(v1(), v2());
 
  366template<
class MatA, 
class VecV, 
class Device>
 
  367typename detail::matrix_vector_prod_optimizer<MatA,VecV>::type prod(
 
  368    matrix_expression<MatA, Device> 
const& A,vector_expression<VecV, Device> 
const& v
 
  370    REMORA_SIZE_CHECK(A().size2() == v().size());
 
  371    return detail::matrix_vector_prod_optimizer<MatA,VecV>::create(A(),v());
 
  381template<
class MatA, 
class VecV, 
class Device>
 
  382auto prod(vector_expression<VecV, Device> 
const& v,matrix_expression<MatA, Device> 
const& A) -> 
decltype(prod(trans(A),v)){
 
  383    REMORA_SIZE_CHECK(A().size1() == v().size());
 
  384    return prod(trans(A),v);
 
  390template<
class MatA, 
class VecV, 
class Device>
 
  391auto operator%(vector_expression<VecV, Device> 
const& v,matrix_expression<MatA, Device> 
const& A) -> 
decltype(prod(trans(A),v)){
 
  392    REMORA_SIZE_CHECK(A().size1() == v().size());
 
  393    return prod(trans(A),v);
 
  399template<
class MatA, 
class VecV, 
class Device>
 
  400auto operator%(matrix_expression<MatA, Device> 
const& A,vector_expression<VecV, Device> 
const& v) -> 
decltype(prod(A,v)){
 
  401    REMORA_SIZE_CHECK(A().size2() == v().size());
 
  412template<
class TriangularType, 
class MatA, 
class VecV, 
class Device>
 
  414    matrix_expression<MatA, Device> 
const& A,
 
  415    vector_expression<VecV, Device>& v
 
  416) -> 
decltype(prod(to_triangular(A, TriangularType()), v)){
 
  417    REMORA_SIZE_CHECK(A().size2() == v().size());
 
  418    return prod(to_triangular(A, TriangularType()), v);
 
  422template<
class MatA, 
class MatB, 
class Device>
 
  423typename detail::matrix_matrix_prod_optimizer<MatA,MatB>::type prod(
 
  424    matrix_expression<MatA, Device> 
const& A,
 
  425    matrix_expression<MatB, Device> 
const& B
 
  427    REMORA_SIZE_CHECK(A().size2() == B().size1());
 
  428    return detail::matrix_matrix_prod_optimizer<MatA,MatB>::create(A(),B());
 
  434template<
class MatA, 
class MatB, 
class Device>
 
  436    matrix_expression<MatA, Device> 
const& A,
 
  437    matrix_expression<MatB, Device> 
const& B
 
  438) -> 
decltype(prod(A,B)){
 
  439    REMORA_SIZE_CHECK(A().size2() == B().size1());
 
  451template<
class TriangularType, 
class MatA, 
class MatB, 
class Device>
 
  453    matrix_expression<MatA, Device> 
const& A,
 
  454    matrix_expression<MatB, Device> 
const& B
 
  455)  -> 
decltype(prod(to_triangular(A, TriangularType()), B)){
 
  456    REMORA_SIZE_CHECK(A().size2() == B().size1());
 
  457    return prod(to_triangular(A, TriangularType()), B);
 
  509template<
class S, 
class Device>
 
  510typename detail::fold_vector_set_optimizer<
 
  511    S, 
typename device_traits<Device>:: template add<typename S::value_type>
 
  512    , 
typename device_traits<Device>:: template identity<typename S::value_type>
 
  514sum(vector_set_expression<S, Device> 
const& set) {
 
  515    typedef typename device_traits<Device>:: template add<typename S::value_type> Add;
 
  516    typedef typename device_traits<Device>:: template identity<typename S::value_type> Identity;
 
  517    return detail::fold_vector_set_optimizer<S, Add, Identity>::create(set(), Add(), Identity());
 
  523template<
class S, 
class Device>
 
  524typename detail::fold_vector_set_optimizer<
 
  525    S, 
typename device_traits<Device>:: template max<typename S::value_type>
 
  526    , 
typename device_traits<Device>:: template identity<typename S::value_type>
 
  528max(vector_set_expression<S, Device> 
const& set) {
 
  529    typedef typename device_traits<Device>:: template max<typename S::value_type> Max;
 
  530    typedef typename device_traits<Device>:: template identity<typename S::value_type> Identity;
 
  531    return detail::fold_vector_set_optimizer<S, Max, Identity>::create(set(), Max(), Identity());
 
  537template<
class S, 
class Device>
 
  538typename detail::fold_vector_set_optimizer<
 
  539    S, 
typename device_traits<Device>:: template min<typename S::value_type>
 
  540    , 
typename device_traits<Device>:: template identity<typename S::value_type>
 
  542min(vector_set_expression<S, Device> 
const& set) {
 
  543    typedef typename device_traits<Device>:: template min<typename S::value_type> Min;
 
  544    typedef typename device_traits<Device>:: template identity<typename S::value_type> Identity;
 
  545    return detail::fold_vector_set_optimizer<S, Min, Identity>::create(set(), Min(), Identity());
 
  563template<
class S, 
class Device>
 
  564auto norm_1(vector_set_expression<S, Device> 
const& set) ->decltype(sum(abs(set))) {
 
  565    return sum(abs(set));
 
  571template<
class S, 
class Device>
 
  572auto norm_sqr(vector_set_expression<S, Device> 
const& set) ->decltype(sum(
sqr(set))){
 
  573    return sum(
sqr(set));
 
  579template<
class S, 
class Device>
 
  580auto norm_2(vector_set_expression<S, Device> 
const& set) ->decltype(sqrt(norm_sqr(set))){
 
  581    return sqrt(norm_sqr(set));
 
  587template<
class S, 
class Device>
 
  588auto norm_inf(vector_set_expression<S, Device> 
const& set) ->decltype(max(abs(set))){
 
  589    return max(abs(set));
 
  600template<
class MatA, 
class Device>
 
  601typename MatA::value_type sum(matrix_expression<MatA, Device> 
const& A){
 
  602    typedef typename MatA::value_type value_type;
 
  603    typedef typename device_traits<Device>:: template add<value_type> functor_type;
 
  604    auto const& elem_result = eval_block(A);
 
  605    value_type result = 0;
 
  606    kernels::matrix_fold<functor_type>(elem_result,result);
 
  615template<
class MatA, 
class Device>
 
  616typename MatA::value_type max(matrix_expression<MatA, Device> 
const& A){
 
  617    typedef typename MatA::value_type value_type;
 
  618    typedef typename device_traits<Device>:: template max<value_type> functor_type;
 
  619    auto const& elem_result = eval_block(A);
 
  620    value_type result = 0;
 
  621    kernels::matrix_fold<functor_type>(elem_result,result);
 
  628template<
class MatA, 
class Device>
 
  629typename MatA::value_type min(matrix_expression<MatA, Device> 
const& A){
 
  630    typedef typename MatA::value_type value_type;
 
  631    typedef typename device_traits<Device>:: template min<value_type> functor_type;
 
  632    auto const& elem_result = eval_block(A);
 
  633    value_type result = 0;
 
  634    kernels::matrix_fold<functor_type>(elem_result,result);
 
  642template<
class MatA, 
class MatB, 
class Device>
 
  643decltype(
typename MatA::value_type() * 
typename MatB::value_type())
 
  645    matrix_expression<MatA, Device> 
const& A,
 
  646    matrix_expression<MatB, Device> 
const& B
 
  648    REMORA_SIZE_CHECK(A().size1() == B().size1());
 
  649    REMORA_SIZE_CHECK(A().size2() == B().size2());
 
  650    return sum(eval_block(A*B));
 
  656template<
class MatA, 
class Device>
 
  657typename real_traits<typename MatA::value_type>::type
 
  658norm_1(matrix_expression<MatA, Device> 
const& A) {
 
  659    return max(norm_1(as_columns(A)));
 
  665template<
class MatA, 
class Device>
 
  666typename real_traits<typename MatA::value_type>::type
 
  667norm_frobenius(matrix_expression<MatA, Device> 
const& A) {
 
  669    return sqrt(sum(
sqr(eval_block(A))));
 
  675template<
class MatA, 
class Device>
 
  676typename real_traits<typename MatA::value_type>::type
 
  677norm_inf(matrix_expression<MatA, Device> 
const& A) {
 
  678    return max(norm_1(as_rows(A)));
 
  688template < 
class MatA, 
class Device>
 
  689typename MatA::value_type trace(matrix_expression<MatA, Device> 
const& A){
 
  690    REMORA_SIZE_CHECK(A().size1() == A().size2());
 
  699template<
class MatA, 
class MatB, 
class Device>
 
  700matrix_concat<MatA, MatB, true> operator|(
 
  701    matrix_expression<MatA, Device> 
const& A,
 
  702    matrix_expression<MatB, Device> 
const& B
 
  704    return matrix_concat<MatA, MatB, true>(A(),B());
 
  708template<
class MatA, 
class VecV, 
class Device>
 
  710    matrix_expression<MatA, Device> 
const& A,
 
  711    vector_expression<VecV, Device> 
const& v
 
  712) -> 
decltype(A | trans(repeat(v,1))){
 
  713    return A | trans(repeat(v,1));
 
  717template<
class MatA, 
class VecV, 
class Device>
 
  719    vector_expression<VecV, Device> 
const& v,
 
  720    matrix_expression<MatA, Device> 
const& A
 
  721) -> 
decltype(trans(repeat(v,1)) | A){
 
  722    return trans(repeat(v,1)) | A;
 
  728template<
class MatA, 
class T, 
class Device>
 
  729typename std::enable_if<
 
  730    std::is_convertible<T, typename MatA::value_type>::value, 
 
  731    matrix_concat<MatA, scalar_matrix<T, Device, row_major>, 
true > 
 
  733    matrix_expression<MatA, Device> 
const& A,
 
  736    return A | repeat(t,A().size1(), 1);
 
  742template<
class MatA, 
class T, 
class Device>
 
  743typename std::enable_if<
 
  744    std::is_convertible<T, typename MatA::value_type>::value, 
 
  745    matrix_concat<scalar_matrix<T, Device, row_major>, MatA, 
true > 
 
  748    matrix_expression<MatA, Device> 
const& A
 
  750    return repeat(t,A().size1(), 1) | A;
 
  754template<
class MatA, 
class MatB, 
class Device>
 
  755matrix_concat<MatA, MatB, false> operator&(
 
  756    matrix_expression<MatA, Device> 
const& A,
 
  757    matrix_expression<MatB, Device> 
const& B
 
  759    return matrix_concat<MatA, MatB, false>(A(),B());
 
  763template<
class MatA, 
class VecV, 
class Device>
 
  765    matrix_expression<MatA, Device> 
const& A,
 
  766    vector_expression<VecV, Device> 
const& v
 
  767) -> 
decltype(A & repeat(v,1)){
 
  768    return A & repeat(v,1);
 
  772template<
class MatA, 
class VecV, 
class Device>
 
  774    vector_expression<VecV, Device> 
const& v,
 
  775    matrix_expression<MatA, Device> 
const& A
 
  776) -> 
decltype(repeat(v,1) & A){
 
  777    return repeat(v,1) & A;
 
  783template<
class MatA, 
class T, 
class Device>
 
  784typename std::enable_if<
 
  785    std::is_convertible<T, typename MatA::value_type>::value, 
 
  786    matrix_concat<MatA, scalar_matrix<T, Device, row_major>, 
false > 
 
  788    matrix_expression<MatA, Device> 
const& A,
 
  791    return A & repeat(t, 1, A().size2());
 
  797template<
class MatA, 
class T, 
class Device>
 
  798typename std::enable_if<
 
  799    std::is_convertible<T, typename MatA::value_type>::value, 
 
  800    matrix_concat<scalar_matrix<T, Device, row_major>, MatA, 
false > 
 
  803    matrix_expression<MatA, Device> 
const& A
 
  805    return repeat(t,1, A().size2()) & A;