os/ossrv/ossrv_pub/boost_apis/boost/numeric/ublas/operation.hpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
//
sl@0
     2
//  Copyright (c) 2000-2002
sl@0
     3
//  Joerg Walter, Mathias Koch
sl@0
     4
//
sl@0
     5
//  Permission to use, copy, modify, distribute and sell this software
sl@0
     6
//  and its documentation for any purpose is hereby granted without fee,
sl@0
     7
//  provided that the above copyright notice appear in all copies and
sl@0
     8
//  that both that copyright notice and this permission notice appear
sl@0
     9
//  in supporting documentation.  The authors make no representations
sl@0
    10
//  about the suitability of this software for any purpose.
sl@0
    11
//  It is provided "as is" without express or implied warranty.
sl@0
    12
//
sl@0
    13
//  The authors gratefully acknowledge the support of
sl@0
    14
//  GeNeSys mbH & Co. KG in producing this work.
sl@0
    15
//
sl@0
    16
sl@0
    17
#ifndef _BOOST_UBLAS_OPERATION_
sl@0
    18
#define _BOOST_UBLAS_OPERATION_
sl@0
    19
sl@0
    20
#include <boost/numeric/ublas/matrix_proxy.hpp>
sl@0
    21
sl@0
    22
/** \file operation.hpp
sl@0
    23
 *  \brief This file contains some specialized products.
sl@0
    24
 */
sl@0
    25
sl@0
    26
// axpy-based products
sl@0
    27
// Alexei Novakov had a lot of ideas to improve these. Thanks.
sl@0
    28
// Hendrik Kueck proposed some new kernel. Thanks again.
sl@0
    29
sl@0
    30
namespace boost { namespace numeric { namespace ublas {
sl@0
    31
sl@0
    32
    template<class V, class T1, class IA1, class TA1, class E2>
sl@0
    33
    BOOST_UBLAS_INLINE
sl@0
    34
    V &
sl@0
    35
    axpy_prod (const compressed_matrix<T1, row_major, 0, IA1, TA1> &e1,
sl@0
    36
               const vector_expression<E2> &e2,
sl@0
    37
               V &v, row_major_tag) {
sl@0
    38
        typedef typename V::size_type size_type;
sl@0
    39
        typedef typename V::value_type value_type;
sl@0
    40
sl@0
    41
        for (size_type i = 0; i < e1.filled1 () -1; ++ i) {
sl@0
    42
            size_type begin = e1.index1_data () [i];
sl@0
    43
            size_type end = e1.index1_data () [i + 1];
sl@0
    44
            value_type t (v (i));
sl@0
    45
            for (size_type j = begin; j < end; ++ j)
sl@0
    46
                t += e1.value_data () [j] * e2 () (e1.index2_data () [j]);
sl@0
    47
            v (i) = t;
sl@0
    48
        }
sl@0
    49
        return v;
sl@0
    50
    }
sl@0
    51
sl@0
    52
    template<class V, class T1, class IA1, class TA1, class E2>
sl@0
    53
    BOOST_UBLAS_INLINE
sl@0
    54
    V &
sl@0
    55
    axpy_prod (const compressed_matrix<T1, column_major, 0, IA1, TA1> &e1,
sl@0
    56
               const vector_expression<E2> &e2,
sl@0
    57
               V &v, column_major_tag) {
sl@0
    58
        typedef typename V::size_type size_type;
sl@0
    59
sl@0
    60
        for (size_type j = 0; j < e1.filled1 () -1; ++ j) {
sl@0
    61
            size_type begin = e1.index1_data () [j];
sl@0
    62
            size_type end = e1.index1_data () [j + 1];
sl@0
    63
            for (size_type i = begin; i < end; ++ i)
sl@0
    64
                v (e1.index2_data () [i]) += e1.value_data () [i] * e2 () (j);
sl@0
    65
        }
sl@0
    66
        return v;
sl@0
    67
    }
sl@0
    68
sl@0
    69
    // Dispatcher
sl@0
    70
    template<class V, class T1, class L1, class IA1, class TA1, class E2>
sl@0
    71
    BOOST_UBLAS_INLINE
sl@0
    72
    V &
sl@0
    73
    axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
sl@0
    74
               const vector_expression<E2> &e2,
sl@0
    75
               V &v, bool init = true) {
sl@0
    76
        typedef typename V::value_type value_type;
sl@0
    77
        typedef typename L1::orientation_category orientation_category;
sl@0
    78
sl@0
    79
        if (init)
sl@0
    80
            v.assign (zero_vector<value_type> (e1.size1 ()));
sl@0
    81
#if BOOST_UBLAS_TYPE_CHECK
sl@0
    82
        vector<value_type> cv (v);
sl@0
    83
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
    84
        real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
sl@0
    85
        indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
sl@0
    86
#endif
sl@0
    87
        axpy_prod (e1, e2, v, orientation_category ());
sl@0
    88
#if BOOST_UBLAS_TYPE_CHECK
sl@0
    89
        BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
sl@0
    90
#endif
sl@0
    91
        return v;
sl@0
    92
    }
sl@0
    93
    template<class V, class T1, class L1, class IA1, class TA1, class E2>
sl@0
    94
    BOOST_UBLAS_INLINE
sl@0
    95
    V
sl@0
    96
    axpy_prod (const compressed_matrix<T1, L1, 0, IA1, TA1> &e1,
sl@0
    97
               const vector_expression<E2> &e2) {
sl@0
    98
        typedef V vector_type;
sl@0
    99
sl@0
   100
        vector_type v (e1.size1 ());
sl@0
   101
        return axpy_prod (e1, e2, v, true);
sl@0
   102
    }
sl@0
   103
sl@0
   104
    template<class V, class T1, class L1, class IA1, class TA1, class E2>
sl@0
   105
    BOOST_UBLAS_INLINE
sl@0
   106
    V &
sl@0
   107
    axpy_prod (const coordinate_matrix<T1, L1, 0, IA1, TA1> &e1,
sl@0
   108
               const vector_expression<E2> &e2,
sl@0
   109
               V &v, bool init = true) {
sl@0
   110
        typedef typename V::size_type size_type;
sl@0
   111
        typedef typename V::value_type value_type;
sl@0
   112
        typedef L1 layout_type;
sl@0
   113
sl@0
   114
        size_type size1 = e1.size1();
sl@0
   115
        size_type size2 = e1.size2();
sl@0
   116
sl@0
   117
        if (init) {
sl@0
   118
            noalias(v) = zero_vector<value_type>(size1);
sl@0
   119
        }
sl@0
   120
sl@0
   121
        for (size_type i = 0; i < e1.nnz(); ++i) {
sl@0
   122
            size_type row_index = layout_type::element1( e1.index1_data () [i], size1, e1.index2_data () [i], size2 );
sl@0
   123
            size_type col_index = layout_type::element2( e1.index1_data () [i], size1, e1.index2_data () [i], size2 );
sl@0
   124
            v( row_index ) += e1.value_data () [i] * e2 () (col_index);
sl@0
   125
        }
sl@0
   126
        return v;
sl@0
   127
    }
sl@0
   128
sl@0
   129
    template<class V, class E1, class E2>
sl@0
   130
    BOOST_UBLAS_INLINE
sl@0
   131
    V &
sl@0
   132
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   133
               const vector_expression<E2> &e2,
sl@0
   134
               V &v, packed_random_access_iterator_tag, row_major_tag) {
sl@0
   135
        typedef const E1 expression1_type;
sl@0
   136
        typedef const E2 expression2_type;
sl@0
   137
        typedef typename V::size_type size_type;
sl@0
   138
sl@0
   139
        typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
sl@0
   140
        typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
sl@0
   141
        while (it1 != it1_end) {
sl@0
   142
            size_type index1 (it1.index1 ());
sl@0
   143
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
sl@0
   144
            typename expression1_type::const_iterator2 it2 (it1.begin ());
sl@0
   145
            typename expression1_type::const_iterator2 it2_end (it1.end ());
sl@0
   146
#else
sl@0
   147
            typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
sl@0
   148
            typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
sl@0
   149
#endif
sl@0
   150
            while (it2 != it2_end) {
sl@0
   151
                v (index1) += *it2 * e2 () (it2.index2 ());
sl@0
   152
                ++ it2;
sl@0
   153
            }
sl@0
   154
            ++ it1;
sl@0
   155
        }
sl@0
   156
        return v;
sl@0
   157
    }
sl@0
   158
sl@0
   159
    template<class V, class E1, class E2>
sl@0
   160
    BOOST_UBLAS_INLINE
sl@0
   161
    V &
sl@0
   162
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   163
               const vector_expression<E2> &e2,
sl@0
   164
               V &v, packed_random_access_iterator_tag, column_major_tag) {
sl@0
   165
        typedef const E1 expression1_type;
sl@0
   166
        typedef const E2 expression2_type;
sl@0
   167
        typedef typename V::size_type size_type;
sl@0
   168
sl@0
   169
        typename expression1_type::const_iterator2 it2 (e1 ().begin2 ());
sl@0
   170
        typename expression1_type::const_iterator2 it2_end (e1 ().end2 ());
sl@0
   171
        while (it2 != it2_end) {
sl@0
   172
            size_type index2 (it2.index2 ());
sl@0
   173
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
sl@0
   174
            typename expression1_type::const_iterator1 it1 (it2.begin ());
sl@0
   175
            typename expression1_type::const_iterator1 it1_end (it2.end ());
sl@0
   176
#else
sl@0
   177
            typename expression1_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
sl@0
   178
            typename expression1_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
sl@0
   179
#endif
sl@0
   180
            while (it1 != it1_end) {
sl@0
   181
                v (it1.index1 ()) += *it1 * e2 () (index2);
sl@0
   182
                ++ it1;
sl@0
   183
            }
sl@0
   184
            ++ it2;
sl@0
   185
        }
sl@0
   186
        return v;
sl@0
   187
    }
sl@0
   188
sl@0
   189
    template<class V, class E1, class E2>
sl@0
   190
    BOOST_UBLAS_INLINE
sl@0
   191
    V &
sl@0
   192
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   193
               const vector_expression<E2> &e2,
sl@0
   194
               V &v, sparse_bidirectional_iterator_tag) {
sl@0
   195
        typedef const E1 expression1_type;
sl@0
   196
        typedef const E2 expression2_type;
sl@0
   197
        typedef typename V::size_type size_type;
sl@0
   198
sl@0
   199
        typename expression2_type::const_iterator it (e2 ().begin ());
sl@0
   200
        typename expression2_type::const_iterator it_end (e2 ().end ());
sl@0
   201
        while (it != it_end) {
sl@0
   202
            v.plus_assign (column (e1 (), it.index ()) * *it);
sl@0
   203
            ++ it;
sl@0
   204
        }
sl@0
   205
        return v;
sl@0
   206
    }
sl@0
   207
sl@0
   208
    // Dispatcher
sl@0
   209
    template<class V, class E1, class E2>
sl@0
   210
    BOOST_UBLAS_INLINE
sl@0
   211
    V &
sl@0
   212
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   213
               const vector_expression<E2> &e2,
sl@0
   214
               V &v, packed_random_access_iterator_tag) {
sl@0
   215
        typedef typename E1::orientation_category orientation_category;
sl@0
   216
        return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
sl@0
   217
    }
sl@0
   218
sl@0
   219
sl@0
   220
  /** \brief computes <tt>v += A x</tt> or <tt>v = A x</tt> in an
sl@0
   221
          optimized fashion.
sl@0
   222
sl@0
   223
          \param e1 the matrix expression \c A
sl@0
   224
          \param e2 the vector expression \c x
sl@0
   225
          \param v  the result vector \c v
sl@0
   226
          \param init a boolean parameter
sl@0
   227
sl@0
   228
          <tt>axpy_prod(A, x, v, init)</tt> implements the well known
sl@0
   229
          axpy-product.  Setting \a init to \c true is equivalent to call
sl@0
   230
          <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
sl@0
   231
          defaults to \c true, but this may change in the future.
sl@0
   232
sl@0
   233
          Up to now there are some specialisation for compressed
sl@0
   234
          matrices that give a large speed up compared to prod.
sl@0
   235
          
sl@0
   236
          \ingroup blas2
sl@0
   237
sl@0
   238
          \internal
sl@0
   239
          
sl@0
   240
          template parameters:
sl@0
   241
          \param V type of the result vector \c v
sl@0
   242
          \param E1 type of a matrix expression \c A
sl@0
   243
          \param E2 type of a vector expression \c x
sl@0
   244
  */
sl@0
   245
    template<class V, class E1, class E2>
sl@0
   246
    BOOST_UBLAS_INLINE
sl@0
   247
    V &
sl@0
   248
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   249
               const vector_expression<E2> &e2,
sl@0
   250
               V &v, bool init = true) {
sl@0
   251
        typedef typename V::value_type value_type;
sl@0
   252
        typedef typename E2::const_iterator::iterator_category iterator_category;
sl@0
   253
sl@0
   254
        if (init)
sl@0
   255
            v.assign (zero_vector<value_type> (e1 ().size1 ()));
sl@0
   256
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   257
        vector<value_type> cv (v);
sl@0
   258
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   259
        real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
sl@0
   260
        indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
sl@0
   261
#endif
sl@0
   262
        axpy_prod (e1, e2, v, iterator_category ());
sl@0
   263
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   264
        BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
sl@0
   265
#endif
sl@0
   266
        return v;
sl@0
   267
    }
sl@0
   268
    template<class V, class E1, class E2>
sl@0
   269
    BOOST_UBLAS_INLINE
sl@0
   270
    V
sl@0
   271
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   272
               const vector_expression<E2> &e2) {
sl@0
   273
        typedef V vector_type;
sl@0
   274
sl@0
   275
        vector_type v (e1 ().size1 ());
sl@0
   276
        return axpy_prod (e1, e2, v, true);
sl@0
   277
    }
sl@0
   278
sl@0
   279
    template<class V, class E1, class T2, class IA2, class TA2>
sl@0
   280
    BOOST_UBLAS_INLINE
sl@0
   281
    V &
sl@0
   282
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   283
               const compressed_matrix<T2, column_major, 0, IA2, TA2> &e2,
sl@0
   284
               V &v, column_major_tag) {
sl@0
   285
        typedef typename V::size_type size_type;
sl@0
   286
        typedef typename V::value_type value_type;
sl@0
   287
sl@0
   288
        for (size_type j = 0; j < e2.filled1 () -1; ++ j) {
sl@0
   289
            size_type begin = e2.index1_data () [j];
sl@0
   290
            size_type end = e2.index1_data () [j + 1];
sl@0
   291
            value_type t (v (j));
sl@0
   292
            for (size_type i = begin; i < end; ++ i)
sl@0
   293
                t += e2.value_data () [i] * e1 () (e2.index2_data () [i]);
sl@0
   294
            v (j) = t;
sl@0
   295
        }
sl@0
   296
        return v;
sl@0
   297
    }
sl@0
   298
sl@0
   299
    template<class V, class E1, class T2, class IA2, class TA2>
sl@0
   300
    BOOST_UBLAS_INLINE
sl@0
   301
    V &
sl@0
   302
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   303
               const compressed_matrix<T2, row_major, 0, IA2, TA2> &e2,
sl@0
   304
               V &v, row_major_tag) {
sl@0
   305
        typedef typename V::size_type size_type;
sl@0
   306
sl@0
   307
        for (size_type i = 0; i < e2.filled1 () -1; ++ i) {
sl@0
   308
            size_type begin = e2.index1_data () [i];
sl@0
   309
            size_type end = e2.index1_data () [i + 1];
sl@0
   310
            for (size_type j = begin; j < end; ++ j)
sl@0
   311
                v (e2.index2_data () [j]) += e2.value_data () [j] * e1 () (i);
sl@0
   312
        }
sl@0
   313
        return v;
sl@0
   314
    }
sl@0
   315
sl@0
   316
    // Dispatcher
sl@0
   317
    template<class V, class E1, class T2, class L2, class IA2, class TA2>
sl@0
   318
    BOOST_UBLAS_INLINE
sl@0
   319
    V &
sl@0
   320
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   321
               const compressed_matrix<T2, L2, 0, IA2, TA2> &e2,
sl@0
   322
               V &v, bool init = true) {
sl@0
   323
        typedef typename V::value_type value_type;
sl@0
   324
        typedef typename L2::orientation_category orientation_category;
sl@0
   325
sl@0
   326
        if (init)
sl@0
   327
            v.assign (zero_vector<value_type> (e2.size2 ()));
sl@0
   328
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   329
        vector<value_type> cv (v);
sl@0
   330
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   331
        real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
sl@0
   332
        indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
sl@0
   333
#endif
sl@0
   334
        axpy_prod (e1, e2, v, orientation_category ());
sl@0
   335
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   336
        BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
sl@0
   337
#endif
sl@0
   338
        return v;
sl@0
   339
    }
sl@0
   340
    template<class V, class E1, class T2, class L2, class IA2, class TA2>
sl@0
   341
    BOOST_UBLAS_INLINE
sl@0
   342
    V
sl@0
   343
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   344
               const compressed_matrix<T2, L2, 0, IA2, TA2> &e2) {
sl@0
   345
        typedef V vector_type;
sl@0
   346
sl@0
   347
        vector_type v (e2.size2 ());
sl@0
   348
        return axpy_prod (e1, e2, v, true);
sl@0
   349
    }
sl@0
   350
sl@0
   351
    template<class V, class E1, class E2>
sl@0
   352
    BOOST_UBLAS_INLINE
sl@0
   353
    V &
sl@0
   354
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   355
               const matrix_expression<E2> &e2,
sl@0
   356
               V &v, packed_random_access_iterator_tag, column_major_tag) {
sl@0
   357
        typedef const E1 expression1_type;
sl@0
   358
        typedef const E2 expression2_type;
sl@0
   359
        typedef typename V::size_type size_type;
sl@0
   360
sl@0
   361
        typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
sl@0
   362
        typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
sl@0
   363
        while (it2 != it2_end) {
sl@0
   364
            size_type index2 (it2.index2 ());
sl@0
   365
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
sl@0
   366
            typename expression2_type::const_iterator1 it1 (it2.begin ());
sl@0
   367
            typename expression2_type::const_iterator1 it1_end (it2.end ());
sl@0
   368
#else
sl@0
   369
            typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
sl@0
   370
            typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
sl@0
   371
#endif
sl@0
   372
            while (it1 != it1_end) {
sl@0
   373
                v (index2) += *it1 * e1 () (it1.index1 ());
sl@0
   374
                ++ it1;
sl@0
   375
            }
sl@0
   376
            ++ it2;
sl@0
   377
        }
sl@0
   378
        return v;
sl@0
   379
    }
sl@0
   380
sl@0
   381
    template<class V, class E1, class E2>
sl@0
   382
    BOOST_UBLAS_INLINE
sl@0
   383
    V &
sl@0
   384
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   385
               const matrix_expression<E2> &e2,
sl@0
   386
               V &v, packed_random_access_iterator_tag, row_major_tag) {
sl@0
   387
        typedef const E1 expression1_type;
sl@0
   388
        typedef const E2 expression2_type;
sl@0
   389
        typedef typename V::size_type size_type;
sl@0
   390
sl@0
   391
        typename expression2_type::const_iterator1 it1 (e2 ().begin1 ());
sl@0
   392
        typename expression2_type::const_iterator1 it1_end (e2 ().end1 ());
sl@0
   393
        while (it1 != it1_end) {
sl@0
   394
            size_type index1 (it1.index1 ());
sl@0
   395
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
sl@0
   396
            typename expression2_type::const_iterator2 it2 (it1.begin ());
sl@0
   397
            typename expression2_type::const_iterator2 it2_end (it1.end ());
sl@0
   398
#else
sl@0
   399
            typename expression2_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
sl@0
   400
            typename expression2_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
sl@0
   401
#endif
sl@0
   402
            while (it2 != it2_end) {
sl@0
   403
                v (it2.index2 ()) += *it2 * e1 () (index1);
sl@0
   404
                ++ it2;
sl@0
   405
            }
sl@0
   406
            ++ it1;
sl@0
   407
        }
sl@0
   408
        return v;
sl@0
   409
    }
sl@0
   410
sl@0
   411
    template<class V, class E1, class E2>
sl@0
   412
    BOOST_UBLAS_INLINE
sl@0
   413
    V &
sl@0
   414
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   415
               const matrix_expression<E2> &e2,
sl@0
   416
               V &v, sparse_bidirectional_iterator_tag) {
sl@0
   417
        typedef const E1 expression1_type;
sl@0
   418
        typedef const E2 expression2_type;
sl@0
   419
        typedef typename V::size_type size_type;
sl@0
   420
sl@0
   421
        typename expression1_type::const_iterator it (e1 ().begin ());
sl@0
   422
        typename expression1_type::const_iterator it_end (e1 ().end ());
sl@0
   423
        while (it != it_end) {
sl@0
   424
            v.plus_assign (*it * row (e2 (), it.index ()));
sl@0
   425
            ++ it;
sl@0
   426
        }
sl@0
   427
        return v;
sl@0
   428
    }
sl@0
   429
sl@0
   430
    // Dispatcher
sl@0
   431
    template<class V, class E1, class E2>
sl@0
   432
    BOOST_UBLAS_INLINE
sl@0
   433
    V &
sl@0
   434
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   435
               const matrix_expression<E2> &e2,
sl@0
   436
               V &v, packed_random_access_iterator_tag) {
sl@0
   437
        typedef typename E2::orientation_category orientation_category;
sl@0
   438
        return axpy_prod (e1, e2, v, packed_random_access_iterator_tag (), orientation_category ());
sl@0
   439
    }
sl@0
   440
sl@0
   441
sl@0
   442
  /** \brief computes <tt>v += A<sup>T</sup> x</tt> or <tt>v = A<sup>T</sup> x</tt> in an
sl@0
   443
          optimized fashion.
sl@0
   444
sl@0
   445
          \param e1 the vector expression \c x
sl@0
   446
          \param e2 the matrix expression \c A
sl@0
   447
          \param v  the result vector \c v
sl@0
   448
          \param init a boolean parameter
sl@0
   449
sl@0
   450
          <tt>axpy_prod(x, A, v, init)</tt> implements the well known
sl@0
   451
          axpy-product.  Setting \a init to \c true is equivalent to call
sl@0
   452
          <tt>v.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
sl@0
   453
          defaults to \c true, but this may change in the future.
sl@0
   454
sl@0
   455
          Up to now there are some specialisation for compressed
sl@0
   456
          matrices that give a large speed up compared to prod.
sl@0
   457
          
sl@0
   458
          \ingroup blas2
sl@0
   459
sl@0
   460
          \internal
sl@0
   461
          
sl@0
   462
          template parameters:
sl@0
   463
          \param V type of the result vector \c v
sl@0
   464
          \param E1 type of a vector expression \c x
sl@0
   465
          \param E2 type of a matrix expression \c A
sl@0
   466
  */
sl@0
   467
    template<class V, class E1, class E2>
sl@0
   468
    BOOST_UBLAS_INLINE
sl@0
   469
    V &
sl@0
   470
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   471
               const matrix_expression<E2> &e2,
sl@0
   472
               V &v, bool init = true) {
sl@0
   473
        typedef typename V::value_type value_type;
sl@0
   474
        typedef typename E1::const_iterator::iterator_category iterator_category;
sl@0
   475
sl@0
   476
        if (init)
sl@0
   477
            v.assign (zero_vector<value_type> (e2 ().size2 ()));
sl@0
   478
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   479
        vector<value_type> cv (v);
sl@0
   480
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   481
        real_type verrorbound (norm_1 (v) + norm_1 (e1) * norm_1 (e2));
sl@0
   482
        indexing_vector_assign<scalar_plus_assign> (cv, prod (e1, e2));
sl@0
   483
#endif
sl@0
   484
        axpy_prod (e1, e2, v, iterator_category ());
sl@0
   485
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   486
        BOOST_UBLAS_CHECK (norm_1 (v - cv) <= 2 * std::numeric_limits<real_type>::epsilon () * verrorbound, internal_logic ());
sl@0
   487
#endif
sl@0
   488
        return v;
sl@0
   489
    }
sl@0
   490
    template<class V, class E1, class E2>
sl@0
   491
    BOOST_UBLAS_INLINE
sl@0
   492
    V
sl@0
   493
    axpy_prod (const vector_expression<E1> &e1,
sl@0
   494
               const matrix_expression<E2> &e2) {
sl@0
   495
        typedef V vector_type;
sl@0
   496
sl@0
   497
        vector_type v (e2 ().size2 ());
sl@0
   498
        return axpy_prod (e1, e2, v, true);
sl@0
   499
    }
sl@0
   500
sl@0
   501
    template<class M, class E1, class E2, class TRI>
sl@0
   502
    BOOST_UBLAS_INLINE
sl@0
   503
    M &
sl@0
   504
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   505
               const matrix_expression<E2> &e2,
sl@0
   506
               M &m, TRI,
sl@0
   507
               dense_proxy_tag, row_major_tag) {
sl@0
   508
        typedef M matrix_type;
sl@0
   509
        typedef const E1 expression1_type;
sl@0
   510
        typedef const E2 expression2_type;
sl@0
   511
        typedef typename M::size_type size_type;
sl@0
   512
        typedef typename M::value_type value_type;
sl@0
   513
sl@0
   514
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   515
        matrix<value_type, row_major> cm (m);
sl@0
   516
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   517
        real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
sl@0
   518
        indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
sl@0
   519
#endif
sl@0
   520
        size_type size1 (e1 ().size1 ());
sl@0
   521
        size_type size2 (e1 ().size2 ());
sl@0
   522
        for (size_type i = 0; i < size1; ++ i)
sl@0
   523
            for (size_type j = 0; j < size2; ++ j)
sl@0
   524
                row (m, i).plus_assign (e1 () (i, j) * row (e2 (), j));
sl@0
   525
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   526
        BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
sl@0
   527
#endif
sl@0
   528
        return m;
sl@0
   529
    }
sl@0
   530
    template<class M, class E1, class E2, class TRI>
sl@0
   531
    BOOST_UBLAS_INLINE
sl@0
   532
    M &
sl@0
   533
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   534
               const matrix_expression<E2> &e2,
sl@0
   535
               M &m, TRI,
sl@0
   536
               sparse_proxy_tag, row_major_tag) {
sl@0
   537
        typedef M matrix_type;
sl@0
   538
        typedef TRI triangular_restriction;
sl@0
   539
        typedef const E1 expression1_type;
sl@0
   540
        typedef const E2 expression2_type;
sl@0
   541
        typedef typename M::size_type size_type;
sl@0
   542
        typedef typename M::value_type value_type;
sl@0
   543
sl@0
   544
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   545
        matrix<value_type, row_major> cm (m);
sl@0
   546
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   547
        real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
sl@0
   548
        indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
sl@0
   549
#endif
sl@0
   550
        typename expression1_type::const_iterator1 it1 (e1 ().begin1 ());
sl@0
   551
        typename expression1_type::const_iterator1 it1_end (e1 ().end1 ());
sl@0
   552
        while (it1 != it1_end) {
sl@0
   553
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
sl@0
   554
            typename expression1_type::const_iterator2 it2 (it1.begin ());
sl@0
   555
            typename expression1_type::const_iterator2 it2_end (it1.end ());
sl@0
   556
#else
sl@0
   557
            typename expression1_type::const_iterator2 it2 (boost::numeric::ublas::begin (it1, iterator1_tag ()));
sl@0
   558
            typename expression1_type::const_iterator2 it2_end (boost::numeric::ublas::end (it1, iterator1_tag ()));
sl@0
   559
#endif
sl@0
   560
            while (it2 != it2_end) {
sl@0
   561
                // row (m, it1.index1 ()).plus_assign (*it2 * row (e2 (), it2.index2 ()));
sl@0
   562
                matrix_row<expression2_type> mr (e2 (), it2.index2 ());
sl@0
   563
                typename matrix_row<expression2_type>::const_iterator itr (mr.begin ());
sl@0
   564
                typename matrix_row<expression2_type>::const_iterator itr_end (mr.end ());
sl@0
   565
                while (itr != itr_end) {
sl@0
   566
                    if (triangular_restriction::other (it1.index1 (), itr.index ()))
sl@0
   567
                        m (it1.index1 (), itr.index ()) += *it2 * *itr;
sl@0
   568
                    ++ itr;
sl@0
   569
                }
sl@0
   570
                ++ it2;
sl@0
   571
            }
sl@0
   572
            ++ it1;
sl@0
   573
        }
sl@0
   574
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   575
        BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
sl@0
   576
#endif
sl@0
   577
        return m;
sl@0
   578
    }
sl@0
   579
sl@0
   580
    template<class M, class E1, class E2, class TRI>
sl@0
   581
    BOOST_UBLAS_INLINE
sl@0
   582
    M &
sl@0
   583
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   584
               const matrix_expression<E2> &e2,
sl@0
   585
               M &m, TRI,
sl@0
   586
               dense_proxy_tag, column_major_tag) {
sl@0
   587
        typedef M matrix_type;
sl@0
   588
        typedef const E1 expression1_type;
sl@0
   589
        typedef const E2 expression2_type;
sl@0
   590
        typedef typename M::size_type size_type;
sl@0
   591
        typedef typename M::value_type value_type;
sl@0
   592
sl@0
   593
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   594
        matrix<value_type, column_major> cm (m);
sl@0
   595
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   596
        real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
sl@0
   597
        indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
sl@0
   598
#endif
sl@0
   599
        size_type size1 (e2 ().size1 ());
sl@0
   600
        size_type size2 (e2 ().size2 ());
sl@0
   601
        for (size_type j = 0; j < size2; ++ j)
sl@0
   602
            for (size_type i = 0; i < size1; ++ i)
sl@0
   603
                column (m, j).plus_assign (e2 () (i, j) * column (e1 (), i));
sl@0
   604
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   605
        BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
sl@0
   606
#endif
sl@0
   607
        return m;
sl@0
   608
    }
sl@0
   609
    template<class M, class E1, class E2, class TRI>
sl@0
   610
    BOOST_UBLAS_INLINE
sl@0
   611
    M &
sl@0
   612
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   613
               const matrix_expression<E2> &e2,
sl@0
   614
               M &m, TRI,
sl@0
   615
               sparse_proxy_tag, column_major_tag) {
sl@0
   616
        typedef M matrix_type;
sl@0
   617
        typedef TRI triangular_restriction;
sl@0
   618
        typedef const E1 expression1_type;
sl@0
   619
        typedef const E2 expression2_type;
sl@0
   620
        typedef typename M::size_type size_type;
sl@0
   621
        typedef typename M::value_type value_type;
sl@0
   622
sl@0
   623
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   624
        matrix<value_type, column_major> cm (m);
sl@0
   625
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   626
        real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
sl@0
   627
        indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
sl@0
   628
#endif
sl@0
   629
        typename expression2_type::const_iterator2 it2 (e2 ().begin2 ());
sl@0
   630
        typename expression2_type::const_iterator2 it2_end (e2 ().end2 ());
sl@0
   631
        while (it2 != it2_end) {
sl@0
   632
#ifndef BOOST_UBLAS_NO_NESTED_CLASS_RELATION
sl@0
   633
            typename expression2_type::const_iterator1 it1 (it2.begin ());
sl@0
   634
            typename expression2_type::const_iterator1 it1_end (it2.end ());
sl@0
   635
#else
sl@0
   636
            typename expression2_type::const_iterator1 it1 (boost::numeric::ublas::begin (it2, iterator2_tag ()));
sl@0
   637
            typename expression2_type::const_iterator1 it1_end (boost::numeric::ublas::end (it2, iterator2_tag ()));
sl@0
   638
#endif
sl@0
   639
            while (it1 != it1_end) {
sl@0
   640
                // column (m, it2.index2 ()).plus_assign (*it1 * column (e1 (), it1.index1 ()));
sl@0
   641
                matrix_column<expression1_type> mc (e1 (), it1.index1 ());
sl@0
   642
                typename matrix_column<expression1_type>::const_iterator itc (mc.begin ());
sl@0
   643
                typename matrix_column<expression1_type>::const_iterator itc_end (mc.end ());
sl@0
   644
                while (itc != itc_end) {
sl@0
   645
                    if (triangular_restriction::functor_type ().other (itc.index (), it2.index2 ()))
sl@0
   646
                        m (itc.index (), it2.index2 ()) += *it1 * *itc;
sl@0
   647
                    ++ itc;
sl@0
   648
                }
sl@0
   649
                ++ it1;
sl@0
   650
            }
sl@0
   651
            ++ it2;
sl@0
   652
        }
sl@0
   653
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   654
        BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
sl@0
   655
#endif
sl@0
   656
        return m;
sl@0
   657
    }
sl@0
   658
sl@0
   659
    // Dispatcher
sl@0
   660
    template<class M, class E1, class E2, class TRI>
sl@0
   661
    BOOST_UBLAS_INLINE
sl@0
   662
    M &
sl@0
   663
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   664
               const matrix_expression<E2> &e2,
sl@0
   665
               M &m, TRI, bool init = true) {
sl@0
   666
        typedef typename M::value_type value_type;
sl@0
   667
        typedef typename M::storage_category storage_category;
sl@0
   668
        typedef typename M::orientation_category orientation_category;
sl@0
   669
        typedef TRI triangular_restriction;
sl@0
   670
sl@0
   671
        if (init)
sl@0
   672
            m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
sl@0
   673
        return axpy_prod (e1, e2, m, triangular_restriction (), storage_category (), orientation_category ());
sl@0
   674
    }
sl@0
   675
    template<class M, class E1, class E2, class TRI>
sl@0
   676
    BOOST_UBLAS_INLINE
sl@0
   677
    M
sl@0
   678
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   679
               const matrix_expression<E2> &e2,
sl@0
   680
               TRI) {
sl@0
   681
        typedef M matrix_type;
sl@0
   682
        typedef TRI triangular_restriction;
sl@0
   683
sl@0
   684
        matrix_type m (e1 ().size1 (), e2 ().size2 ());
sl@0
   685
        return axpy_prod (e1, e2, m, triangular_restriction (), true);
sl@0
   686
    }
sl@0
   687
sl@0
   688
  /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
sl@0
   689
          optimized fashion.
sl@0
   690
sl@0
   691
          \param e1 the matrix expression \c A
sl@0
   692
          \param e2 the matrix expression \c X
sl@0
   693
          \param m  the result matrix \c M
sl@0
   694
          \param init a boolean parameter
sl@0
   695
sl@0
   696
          <tt>axpy_prod(A, X, M, init)</tt> implements the well known
sl@0
   697
          axpy-product.  Setting \a init to \c true is equivalent to call
sl@0
   698
          <tt>M.clear()</tt> before <tt>axpy_prod</tt>. Currently \a init
sl@0
   699
          defaults to \c true, but this may change in the future.
sl@0
   700
sl@0
   701
          Up to now there are no specialisations.
sl@0
   702
          
sl@0
   703
          \ingroup blas3
sl@0
   704
sl@0
   705
          \internal
sl@0
   706
          
sl@0
   707
          template parameters:
sl@0
   708
          \param M type of the result matrix \c M
sl@0
   709
          \param E1 type of a matrix expression \c A
sl@0
   710
          \param E2 type of a matrix expression \c X
sl@0
   711
  */
sl@0
   712
    template<class M, class E1, class E2>
sl@0
   713
    BOOST_UBLAS_INLINE
sl@0
   714
    M &
sl@0
   715
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   716
               const matrix_expression<E2> &e2,
sl@0
   717
               M &m, bool init = true) {
sl@0
   718
        typedef typename M::value_type value_type;
sl@0
   719
        typedef typename M::storage_category storage_category;
sl@0
   720
        typedef typename M::orientation_category orientation_category;
sl@0
   721
sl@0
   722
        if (init)
sl@0
   723
            m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
sl@0
   724
        return axpy_prod (e1, e2, m, full (), storage_category (), orientation_category ());
sl@0
   725
    }
sl@0
   726
    template<class M, class E1, class E2>
sl@0
   727
    BOOST_UBLAS_INLINE
sl@0
   728
    M
sl@0
   729
    axpy_prod (const matrix_expression<E1> &e1,
sl@0
   730
               const matrix_expression<E2> &e2) {
sl@0
   731
        typedef M matrix_type;
sl@0
   732
sl@0
   733
        matrix_type m (e1 ().size1 (), e2 ().size2 ());
sl@0
   734
        return axpy_prod (e1, e2, m, full (), true);
sl@0
   735
    }
sl@0
   736
sl@0
   737
sl@0
   738
    template<class M, class E1, class E2>
sl@0
   739
    BOOST_UBLAS_INLINE
sl@0
   740
    M &
sl@0
   741
    opb_prod (const matrix_expression<E1> &e1,
sl@0
   742
              const matrix_expression<E2> &e2,
sl@0
   743
              M &m,
sl@0
   744
              dense_proxy_tag, row_major_tag) {
sl@0
   745
        typedef M matrix_type;
sl@0
   746
        typedef const E1 expression1_type;
sl@0
   747
        typedef const E2 expression2_type;
sl@0
   748
        typedef typename M::size_type size_type;
sl@0
   749
        typedef typename M::value_type value_type;
sl@0
   750
sl@0
   751
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   752
        matrix<value_type, row_major> cm (m);
sl@0
   753
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   754
        real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
sl@0
   755
        indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), row_major_tag ());
sl@0
   756
#endif
sl@0
   757
        size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
sl@0
   758
        for (size_type k = 0; k < size; ++ k) {
sl@0
   759
            vector<value_type> ce1 (column (e1 (), k));
sl@0
   760
            vector<value_type> re2 (row (e2 (), k));
sl@0
   761
            m.plus_assign (outer_prod (ce1, re2));
sl@0
   762
        }
sl@0
   763
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   764
        BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
sl@0
   765
#endif
sl@0
   766
        return m;
sl@0
   767
    }
sl@0
   768
sl@0
   769
    template<class M, class E1, class E2>
sl@0
   770
    BOOST_UBLAS_INLINE
sl@0
   771
    M &
sl@0
   772
    opb_prod (const matrix_expression<E1> &e1,
sl@0
   773
              const matrix_expression<E2> &e2,
sl@0
   774
              M &m,
sl@0
   775
              dense_proxy_tag, column_major_tag) {
sl@0
   776
        typedef M matrix_type;
sl@0
   777
        typedef const E1 expression1_type;
sl@0
   778
        typedef const E2 expression2_type;
sl@0
   779
        typedef typename M::size_type size_type;
sl@0
   780
        typedef typename M::value_type value_type;
sl@0
   781
sl@0
   782
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   783
        matrix<value_type, column_major> cm (m);
sl@0
   784
        typedef typename type_traits<value_type>::real_type real_type;
sl@0
   785
        real_type merrorbound (norm_1 (m) + norm_1 (e1) * norm_1 (e2));
sl@0
   786
        indexing_matrix_assign<scalar_plus_assign> (cm, prod (e1, e2), column_major_tag ());
sl@0
   787
#endif
sl@0
   788
        size_type size (BOOST_UBLAS_SAME (e1 ().size2 (), e2 ().size1 ()));
sl@0
   789
        for (size_type k = 0; k < size; ++ k) {
sl@0
   790
            vector<value_type> ce1 (column (e1 (), k));
sl@0
   791
            vector<value_type> re2 (row (e2 (), k));
sl@0
   792
            m.plus_assign (outer_prod (ce1, re2));
sl@0
   793
        }
sl@0
   794
#if BOOST_UBLAS_TYPE_CHECK
sl@0
   795
        BOOST_UBLAS_CHECK (norm_1 (m - cm) <= 2 * std::numeric_limits<real_type>::epsilon () * merrorbound, internal_logic ());
sl@0
   796
#endif
sl@0
   797
        return m;
sl@0
   798
    }
sl@0
   799
sl@0
   800
    // Dispatcher
sl@0
   801
sl@0
   802
  /** \brief computes <tt>M += A X</tt> or <tt>M = A X</tt> in an
sl@0
   803
          optimized fashion.
sl@0
   804
sl@0
   805
          \param e1 the matrix expression \c A
sl@0
   806
          \param e2 the matrix expression \c X
sl@0
   807
          \param m  the result matrix \c M
sl@0
   808
          \param init a boolean parameter
sl@0
   809
sl@0
   810
          <tt>opb_prod(A, X, M, init)</tt> implements the well known
sl@0
   811
          axpy-product. Setting \a init to \c true is equivalent to call
sl@0
   812
          <tt>M.clear()</tt> before <tt>opb_prod</tt>. Currently \a init
sl@0
   813
          defaults to \c true, but this may change in the future.
sl@0
   814
sl@0
   815
          This function may give a speedup if \c A has less columns than
sl@0
   816
          rows, because the product is computed as a sum of outer
sl@0
   817
          products.
sl@0
   818
          
sl@0
   819
          \ingroup blas3
sl@0
   820
sl@0
   821
          \internal
sl@0
   822
          
sl@0
   823
          template parameters:
sl@0
   824
          \param M type of the result matrix \c M
sl@0
   825
          \param E1 type of a matrix expression \c A
sl@0
   826
          \param E2 type of a matrix expression \c X
sl@0
   827
  */
sl@0
   828
    template<class M, class E1, class E2>
sl@0
   829
    BOOST_UBLAS_INLINE
sl@0
   830
    M &
sl@0
   831
    opb_prod (const matrix_expression<E1> &e1,
sl@0
   832
              const matrix_expression<E2> &e2,
sl@0
   833
              M &m, bool init = true) {
sl@0
   834
        typedef typename M::value_type value_type;
sl@0
   835
        typedef typename M::storage_category storage_category;
sl@0
   836
        typedef typename M::orientation_category orientation_category;
sl@0
   837
sl@0
   838
        if (init)
sl@0
   839
            m.assign (zero_matrix<value_type> (e1 ().size1 (), e2 ().size2 ()));
sl@0
   840
        return opb_prod (e1, e2, m, storage_category (), orientation_category ());
sl@0
   841
    }
sl@0
   842
    template<class M, class E1, class E2>
sl@0
   843
    BOOST_UBLAS_INLINE
sl@0
   844
    M
sl@0
   845
    opb_prod (const matrix_expression<E1> &e1,
sl@0
   846
              const matrix_expression<E2> &e2) {
sl@0
   847
        typedef M matrix_type;
sl@0
   848
sl@0
   849
        matrix_type m (e1 ().size1 (), e2 ().size2 ());
sl@0
   850
        return opb_prod (e1, e2, m, true);
sl@0
   851
    }
sl@0
   852
sl@0
   853
}}}
sl@0
   854
sl@0
   855
#endif