All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SMatDMatMultExpr.h
Go to the documentation of this file.
1 //=================================================================================================
20 //=================================================================================================
21 
22 #ifndef _BLAZE_MATH_EXPRESSIONS_SMATDMATMULTEXPR_H_
23 #define _BLAZE_MATH_EXPRESSIONS_SMATDMATMULTEXPR_H_
24 
25 
26 //*************************************************************************************************
27 // Includes
28 //*************************************************************************************************
29 
30 #include <stdexcept>
31 #include <boost/type_traits/remove_reference.hpp>
39 #include <blaze/math/shims/Reset.h>
61 #include <blaze/util/Assert.h>
62 #include <blaze/util/DisableIf.h>
63 #include <blaze/util/EnableIf.h>
64 #include <blaze/util/InvalidType.h>
66 #include <blaze/util/SelectType.h>
67 #include <blaze/util/Types.h>
68 
69 
70 namespace blaze {
71 
72 //=================================================================================================
73 //
74 // CLASS SMATDMATMULTEXPR
75 //
76 //=================================================================================================
77 
78 //*************************************************************************************************
85 template< typename MT1 // Type of the left-hand side sparse matrix
86  , typename MT2 > // Type of the right-hand side dense matrix
87 class SMatDMatMultExpr : public DenseMatrix< SMatDMatMultExpr<MT1,MT2>, false >
88  , private Expression
89  , private Computation
90 {
91  private:
92  //**Type definitions****************************************************************************
93  typedef typename MT1::ResultType RT1;
94  typedef typename MT2::ResultType RT2;
95  typedef typename MT1::ElementType ET1;
96  typedef typename MT2::ElementType ET2;
97  typedef typename MT1::CompositeType CT1;
98  typedef typename MT2::CompositeType CT2;
99  //**********************************************************************************************
100 
101  public:
102  //**Type definitions****************************************************************************
105  typedef typename ResultType::OppositeType OppositeType;
106  typedef typename ResultType::TransposeType TransposeType;
107  typedef typename ResultType::ElementType ElementType;
108  typedef const ElementType ReturnType;
109  typedef const ResultType CompositeType;
110 
112  typedef typename SelectType< IsExpression<MT1>::value, const MT1, const MT1& >::Type LeftOperand;
113 
115  typedef typename SelectType< IsExpression<MT2>::value, const MT2, const MT2& >::Type RightOperand;
116 
118  typedef typename SelectType< IsComputation<MT1>::value, const RT1, CT1 >::Type LT;
119 
121  typedef typename SelectType< IsComputation<MT2>::value, const RT2, CT2 >::Type RT;
122  //**********************************************************************************************
123 
124  //**Compilation flags***************************************************************************
126  enum { vectorizable = 0 };
127  //**********************************************************************************************
128 
129  //**Constructor*********************************************************************************
135  explicit inline SMatDMatMultExpr( const MT1& lhs, const MT2& rhs )
136  : lhs_( lhs ) // Left-hand side sparse matrix of the multiplication expression
137  , rhs_( rhs ) // Right-hand side dense matrix of the multiplication expression
138  {
139  BLAZE_INTERNAL_ASSERT( lhs.columns() == rhs.rows(), "Invalid matrix sizes" );
140  }
141  //**********************************************************************************************
142 
143  //**Access operator*****************************************************************************
150  inline ReturnType operator()( size_t i, size_t j ) const {
151  BLAZE_INTERNAL_ASSERT( i < lhs_.rows() , "Invalid row access index" );
152  BLAZE_INTERNAL_ASSERT( j < rhs_.columns(), "Invalid column access index" );
153 
154  typedef typename boost::remove_reference<CT1>::type::ConstIterator ConstIterator;
155 
156  ElementType tmp = ElementType();
157 
158  // Early exit
159  if( lhs_.columns() == 0 )
160  return tmp;
161 
162  // Fast computation in case the left-hand side sparse matrix directly provides iterators
164  {
165  CT1 A( lhs_ ); // Evaluation of the left-hand side sparse matrix operand
166 
167  const ConstIterator end( A.end(i) );
168  ConstIterator element( A.begin(i) );
169 
170  // Early exit in case row i is empty
171  if( element == end )
172  return tmp;
173 
174  // Calculating element (i,j)
175  tmp = element->value() * rhs_(element->index(),j);
176  ++element;
177  for( ; element!=end; ++element )
178  tmp += element->value() * rhs_(element->index(),j);
179  }
180 
181  // Default computation in case the left-hand side sparse matrix doesn't provide iterators
182  else {
183  tmp = lhs_(i,0) * rhs_(0,j);
184  for( size_t k=1; k<lhs_.columns(); ++k ) {
185  tmp += lhs_(i,k) * rhs_(k,j);
186  }
187  }
188 
189  return tmp;
190  }
191  //**********************************************************************************************
192 
193  //**Rows function*******************************************************************************
198  inline size_t rows() const {
199  return lhs_.rows();
200  }
201  //**********************************************************************************************
202 
203  //**Columns function****************************************************************************
208  inline size_t columns() const {
209  return rhs_.columns();
210  }
211  //**********************************************************************************************
212 
213  //**Left operand access*************************************************************************
218  inline LeftOperand leftOperand() const {
219  return lhs_;
220  }
221  //**********************************************************************************************
222 
223  //**Right operand access************************************************************************
228  inline RightOperand rightOperand() const {
229  return rhs_;
230  }
231  //**********************************************************************************************
232 
233  //**********************************************************************************************
239  template< typename T >
240  inline bool canAlias( const T* alias ) const {
241  return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
242  }
243  //**********************************************************************************************
244 
245  //**********************************************************************************************
251  template< typename T >
252  inline bool isAliased( const T* alias ) const {
253  return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
254  }
255  //**********************************************************************************************
256 
257  private:
258  //**Member variables****************************************************************************
261  //**********************************************************************************************
262 
263  //**Default assignment to dense matrices********************************************************
276  template< typename MT // Type of the target dense matrix
277  , bool SO > // Storage order of the target dense matrix
278  friend inline typename EnableIf< IsResizable<typename MT::ElementType> >::Type
279  assign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
280  {
282 
283  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
284  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
285 
286  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
287 
288  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
289  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
290 
291  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
292  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
293  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
294  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
295  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
296  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
297 
298  for( size_t i=0; i<A.rows(); ++i )
299  {
300  const ConstIterator end( A.end(i) );
301 
302  for( size_t j=0; j<B.columns(); ++j )
303  {
304  ConstIterator element( A.begin(i) );
305 
306  if( element != end ) {
307  (~lhs)(i,j) = element->value() * B(element->index(),j);
308  ++element;
309  for( ; element!=end; ++element ) {
310  (~lhs)(i,j) += element->value() * B(element->index(),j);
311  }
312  }
313  else {
314  reset( (~lhs)(i,j) );
315  }
316  }
317  }
318  }
320  //**********************************************************************************************
321 
322  //**Optimized assignment to dense matrices******************************************************
335  template< typename MT // Type of the target dense matrix
336  , bool SO > // Storage order of the target dense matrix
337  friend inline typename DisableIf< IsResizable<typename MT::ElementType> >::Type
338  assign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
339  {
341 
342  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
343  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
344 
345  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
346 
347  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
348  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
349 
350  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
351  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
352  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
353  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
354  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
355  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
356 
357  reset( ~lhs );
358 
359  BLAZE_INTERNAL_ASSERT( ( B.columns() - ( B.columns() % 4UL ) ) == ( B.columns() & size_t(-4) ), "Invalid end calculation" );
360  const size_t jend( B.columns() & size_t(-4) );
361 
362  for( size_t i=0UL; i<A.rows(); ++i ) {
363  const ConstIterator end( A.end(i) );
364  ConstIterator element( A.begin(i) );
365 
366  const size_t nonzeros( A.nonZeros(i) );
367  const size_t kend( nonzeros & size_t(-4) );
368 
369  for( size_t k=0UL; k<kend; k+=4UL ) {
370  const size_t i1( element->index() );
371  const ET1 v1( element->value() );
372  ++element;
373  const size_t i2( element->index() );
374  const ET1 v2( element->value() );
375  ++element;
376  const size_t i3( element->index() );
377  const ET1 v3( element->value() );
378  ++element;
379  const size_t i4( element->index() );
380  const ET1 v4( element->value() );
381  ++element;
382 
383  for( size_t j=0UL; j<jend; j+=4UL ) {
384  (~lhs)(i,j ) += v1 * B(i1,j ) + v2 * B(i2,j ) + v3 * B(i3,j ) + v4 * B(i4,j );
385  (~lhs)(i,j+1UL) += v1 * B(i1,j+1UL) + v2 * B(i2,j+1UL) + v3 * B(i3,j+1UL) + v4 * B(i4,j+1UL);
386  (~lhs)(i,j+2UL) += v1 * B(i1,j+2UL) + v2 * B(i2,j+2UL) + v3 * B(i3,j+2UL) + v4 * B(i4,j+2UL);
387  (~lhs)(i,j+3UL) += v1 * B(i1,j+3UL) + v2 * B(i2,j+3UL) + v3 * B(i3,j+3UL) + v4 * B(i4,j+3UL);
388  }
389  for( size_t j=jend; j<B.columns(); ++j ) {
390  (~lhs)(i,j) += v1 * B(i1,j) + v2 * B(i2,j) + v3 * B(i3,j) + v4 * B(i4,j);
391  }
392  }
393 
394  for( ; element!=end; ++element ) {
395  for( size_t j=0UL; j<jend; j+=4UL ) {
396  (~lhs)(i,j ) += element->value() * B(element->index(),j );
397  (~lhs)(i,j+1UL) += element->value() * B(element->index(),j+1UL);
398  (~lhs)(i,j+2UL) += element->value() * B(element->index(),j+2UL);
399  (~lhs)(i,j+3UL) += element->value() * B(element->index(),j+3UL);
400  }
401  for( size_t j=jend; j<B.columns(); ++j ) {
402  (~lhs)(i,j) += element->value() * B(element->index(),j);
403  }
404  }
405  }
406  }
408  //**********************************************************************************************
409 
410  //**Assignment to sparse matrices***************************************************************
422  template< typename MT // Type of the target sparse matrix
423  , bool SO > // Storage order of the target sparse matrix
424  friend inline void assign( SparseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
425  {
427 
428  typedef typename SelectType< SO, OppositeType, ResultType >::Type TmpType;
429 
435  BLAZE_CONSTRAINT_MUST_BE_REFERENCE_TYPE( typename TmpType::CompositeType );
436 
437  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
438  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
439 
440  const TmpType tmp( rhs );
441  assign( ~lhs, tmp );
442  }
444  //**********************************************************************************************
445 
446  //**Addition assignment to dense matrices*******************************************************
458  template< typename MT // Type of the target dense matrix
459  , bool SO > // Storage order of the target dense matrix
460  friend inline void addAssign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
461  {
463 
464  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
465  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
466 
467  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
468 
469  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
470  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
471 
472  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
473  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
474  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
475  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
476  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
477  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
478 
479  BLAZE_INTERNAL_ASSERT( ( B.columns() - ( B.columns() % 4UL ) ) == ( B.columns() & size_t(-4) ), "Invalid end calculation" );
480  const size_t kend( B.columns() & size_t(-4) );
481 
482  for( size_t i=0UL; i<A.rows(); ++i ) {
483  const ConstIterator end( A.end(i) );
484  ConstIterator element( A.begin(i) );
485  for( ; element!=end; ++element ) {
486  for( size_t k=0UL; k<kend; k+=4UL ) {
487  (~lhs)(i,k ) += element->value() * B(element->index(),k );
488  (~lhs)(i,k+1UL) += element->value() * B(element->index(),k+1UL);
489  (~lhs)(i,k+2UL) += element->value() * B(element->index(),k+2UL);
490  (~lhs)(i,k+3UL) += element->value() * B(element->index(),k+3UL);
491  }
492  for( size_t k=kend; k<B.columns(); ++k ) {
493  (~lhs)(i,k) += element->value() * B(element->index(),k);
494  }
495  }
496  }
497  }
499  //**********************************************************************************************
500 
501  //**Addition assignment to sparse matrices******************************************************
502  // No special implementation for the addition assignment to sparse matrices.
503  //**********************************************************************************************
504 
505  //**Subtraction assignment to dense matrices****************************************************
517  template< typename MT // Type of the target dense matrix
518  , bool SO > // Storage order of the target dense matrix
519  friend inline void subAssign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
520  {
522 
523  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
524  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
525 
526  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
527 
528  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
529  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
530 
531  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
532  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
533  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
534  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
535  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
536  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
537 
538  BLAZE_INTERNAL_ASSERT( ( B.columns() - ( B.columns() % 4UL ) ) == ( B.columns() & size_t(-4) ), "Invalid end calculation" );
539  const size_t kend( B.columns() & size_t(-4) );
540 
541  for( size_t i=0UL; i<A.rows(); ++i ) {
542  const ConstIterator end( A.end(i) );
543  ConstIterator element( A.begin(i) );
544  for( ; element!=end; ++element ) {
545  for( size_t k=0UL; k<kend; k+=4UL ) {
546  (~lhs)(i,k ) -= element->value() * B(element->index(),k );
547  (~lhs)(i,k+1UL) -= element->value() * B(element->index(),k+1UL);
548  (~lhs)(i,k+2UL) -= element->value() * B(element->index(),k+2UL);
549  (~lhs)(i,k+3UL) -= element->value() * B(element->index(),k+3UL);
550  }
551  for( size_t k=kend; k<B.columns(); ++k ) {
552  (~lhs)(i,k) -= element->value() * B(element->index(),k);
553  }
554  }
555  }
556  }
558  //**********************************************************************************************
559 
560  //**Subtraction assignment to sparse matrices***************************************************
561  // No special implementation for the subtraction assignment to sparse matrices.
562  //**********************************************************************************************
563 
564  //**Multiplication assignment to dense matrices*************************************************
565  // No special implementation for the multiplication assignment to dense matrices.
566  //**********************************************************************************************
567 
568  //**Multiplication assignment to sparse matrices************************************************
569  // No special implementation for the multiplication assignment to sparse matrices.
570  //**********************************************************************************************
571 
572  //**Compile time checks*************************************************************************
579  //**********************************************************************************************
580 };
581 //*************************************************************************************************
582 
583 
584 
585 
586 //=================================================================================================
587 //
588 // GLOBAL BINARY ARITHMETIC OPERATORS
589 //
590 //=================================================================================================
591 
592 //*************************************************************************************************
621 template< typename T1 // Type of the left-hand side sparse matrix
622  , typename T2 > // Type of the right-hand side dense matrix
623 inline const SMatDMatMultExpr<T1,T2>
625 {
627 
628  if( (~lhs).columns() != (~rhs).rows() )
629  throw std::invalid_argument( "Matrix sizes do not match" );
630 
631  return SMatDMatMultExpr<T1,T2>( ~lhs, ~rhs );
632 }
633 //*************************************************************************************************
634 
635 
636 
637 
638 //=================================================================================================
639 //
640 // GLOBAL OPERATORS
641 //
642 //=================================================================================================
643 
644 //*************************************************************************************************
656 template< typename MT1 // Type of the left-hand side sparse matrix
657  , typename MT2 > // Type of the right-hand side dense matrix
658 inline typename RowExprTrait< SMatDMatMultExpr<MT1,MT2> >::Type
659  row( const SMatDMatMultExpr<MT1,MT2>& dm, size_t index )
660 {
662 
663  return row( dm.leftOperand(), index ) * dm.rightOperand();
664 }
666 //*************************************************************************************************
667 
668 
669 //*************************************************************************************************
681 template< typename MT1 // Type of the left-hand side sparse matrix
682  , typename MT2 > // Type of the right-hand side dense matrix
683 inline typename ColumnExprTrait< SMatDMatMultExpr<MT1,MT2> >::Type
684  column( const SMatDMatMultExpr<MT1,MT2>& dm, size_t index )
685 {
687 
688  return dm.leftOperand() * column( dm.rightOperand(), index );
689 }
691 //*************************************************************************************************
692 
693 
694 
695 
696 //=================================================================================================
697 //
698 // EXPRESSION TRAIT SPECIALIZATIONS
699 //
700 //=================================================================================================
701 
702 //*************************************************************************************************
704 template< typename MT1, typename MT2, typename VT >
705 struct DMatDVecMultExprTrait< SMatDMatMultExpr<MT1,MT2>, VT >
706 {
707  public:
708  //**********************************************************************************************
709  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
710  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value &&
711  IsDenseVector<VT>::value && !IsTransposeVector<VT>::value
712  , typename SMatDVecMultExprTrait< MT1, typename DMatDVecMultExprTrait<MT2,VT>::Type >::Type
713  , INVALID_TYPE >::Type Type;
714  //**********************************************************************************************
715 };
717 //*************************************************************************************************
718 
719 
720 //*************************************************************************************************
722 template< typename MT1, typename MT2, typename VT >
723 struct DMatSVecMultExprTrait< SMatDMatMultExpr<MT1,MT2>, VT >
724 {
725  public:
726  //**********************************************************************************************
727  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
728  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value &&
729  IsSparseVector<VT>::value && !IsTransposeVector<VT>::value
730  , typename SMatDVecMultExprTrait< MT1, typename DMatSVecMultExprTrait<MT2,VT>::Type >::Type
731  , INVALID_TYPE >::Type Type;
732  //**********************************************************************************************
733 };
735 //*************************************************************************************************
736 
737 
738 //*************************************************************************************************
740 template< typename VT, typename MT1, typename MT2 >
741 struct TDVecDMatMultExprTrait< VT, SMatDMatMultExpr<MT1,MT2> >
742 {
743  public:
744  //**********************************************************************************************
745  typedef typename SelectType< IsDenseVector<VT>::value && IsTransposeVector<VT>::value &&
746  IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
747  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value
748  , typename TDVecDMatMultExprTrait< typename TDVecSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
749  , INVALID_TYPE >::Type Type;
750  //**********************************************************************************************
751 };
753 //*************************************************************************************************
754 
755 
756 //*************************************************************************************************
758 template< typename VT, typename MT1, typename MT2 >
759 struct TSVecDMatMultExprTrait< VT, SMatDMatMultExpr<MT1,MT2> >
760 {
761  public:
762  //**********************************************************************************************
763  typedef typename SelectType< IsSparseVector<VT>::value && IsTransposeVector<VT>::value &&
764  IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
765  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value
766  , typename TSVecDMatMultExprTrait< typename TSVecSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
767  , INVALID_TYPE >::Type Type;
768  //**********************************************************************************************
769 };
771 //*************************************************************************************************
772 
773 
774 //*************************************************************************************************
776 template< typename MT1, typename MT2 >
777 struct RowExprTrait< SMatDMatMultExpr<MT1,MT2> >
778 {
779  public:
780  //**********************************************************************************************
781  typedef typename MultExprTrait< typename RowExprTrait<const MT1>::Type, MT2 >::Type Type;
782  //**********************************************************************************************
783 };
785 //*************************************************************************************************
786 
787 
788 //*************************************************************************************************
790 template< typename MT1, typename MT2 >
791 struct ColumnExprTrait< SMatDMatMultExpr<MT1,MT2> >
792 {
793  public:
794  //**********************************************************************************************
795  typedef typename MultExprTrait< MT1, typename ColumnExprTrait<const MT2>::Type >::Type Type;
796  //**********************************************************************************************
797 };
799 //*************************************************************************************************
800 
801 } // namespace blaze
802 
803 #endif