All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TSMatTSMatMultExpr.h
Go to the documentation of this file.
1 //=================================================================================================
20 //=================================================================================================
21 
22 #ifndef _BLAZE_MATH_EXPRESSIONS_TSMATTSMATMULTEXPR_H_
23 #define _BLAZE_MATH_EXPRESSIONS_TSMATTSMATMULTEXPR_H_
24 
25 
26 //*************************************************************************************************
27 // Includes
28 //*************************************************************************************************
29 
30 #include <algorithm>
31 #include <stdexcept>
32 #include <vector>
42 #include <blaze/math/Infinity.h>
44 #include <blaze/math/shims/Reset.h>
62 #include <blaze/util/Assert.h>
63 #include <blaze/util/Byte.h>
64 #include <blaze/util/DisableIf.h>
65 #include <blaze/util/EnableIf.h>
66 #include <blaze/util/InvalidType.h>
68 #include <blaze/util/SelectType.h>
69 #include <blaze/util/Types.h>
72 #include <blaze/util/Unused.h>
73 
74 
75 namespace blaze {
76 
77 //=================================================================================================
78 //
79 // CLASS TSMATTSMATMULTEXPR
80 //
81 //=================================================================================================
82 
83 //*************************************************************************************************
90 template< typename MT1 // Type of the left-hand side sparse matrix
91  , typename MT2 > // Type of the right-hand side sparse matrix
92 class TSMatTSMatMultExpr : public SparseMatrix< TSMatTSMatMultExpr<MT1,MT2>, true >
93  , private MatMatMultExpr
94  , private Computation
95 {
96  private:
97  //**Type definitions****************************************************************************
98  typedef typename MT1::ResultType RT1;
99  typedef typename MT2::ResultType RT2;
100  typedef typename MT1::CompositeType CT1;
101  typedef typename MT2::CompositeType CT2;
102  //**********************************************************************************************
103 
104  public:
105  //**Type definitions****************************************************************************
108  typedef typename ResultType::OppositeType OppositeType;
109  typedef typename ResultType::TransposeType TransposeType;
110  typedef typename ResultType::ElementType ElementType;
111  typedef const ElementType ReturnType;
112  typedef const ResultType CompositeType;
113 
115  typedef typename SelectType< IsExpression<MT1>::value, const MT1, const MT1& >::Type LeftOperand;
116 
118  typedef typename SelectType< IsExpression<MT2>::value, const MT2, const MT2& >::Type RightOperand;
119  //**********************************************************************************************
120 
121  //**Constructor*********************************************************************************
127  explicit inline TSMatTSMatMultExpr( const MT1& lhs, const MT2& rhs )
128  : lhs_( lhs ) // Left-hand side sparse matrix of the multiplication expression
129  , rhs_( rhs ) // Right-hand side sparse matrix of the multiplication expression
130  {
131  BLAZE_INTERNAL_ASSERT( lhs.columns() == rhs.rows(), "Invalid matrix sizes" );
132  }
133  //**********************************************************************************************
134 
135  //**Access operator*****************************************************************************
142  inline ReturnType operator()( size_t i, size_t j ) const {
143  BLAZE_INTERNAL_ASSERT( i < lhs_.rows() , "Invalid row access index" );
144  BLAZE_INTERNAL_ASSERT( j < rhs_.columns(), "Invalid column access index" );
145 
146  typedef typename RemoveReference<CT2>::Type::ConstIterator ConstIterator;
147 
148  ElementType tmp = ElementType();
149 
150  // Early exit
151  if( lhs_.columns() == 0UL )
152  return tmp;
153 
154  // Fast computation in case the right-hand side sparse matrix directly provides iterators
156  {
157  // Evaluation of the right-hand side sparse matrix operand
158  CT2 B( rhs_ );
159 
160  const ConstIterator end( B.end(j) );
161  ConstIterator element( B.begin(j) );
162 
163  // Early exit in case row i is empty
164  if( element == end )
165  return tmp;
166 
167  // Calculating element (i,j)
168  tmp = lhs_(i,element->index()) * element->value();
169  ++element;
170  for( ; element!=end; ++element )
171  tmp += lhs_(i,element->index()) * element->value();
172  }
173 
174  // Default computation in case the right-hand side sparse matrix doesn't provide iterators
175  else {
176  tmp = lhs_(i,0UL) * rhs_(0UL,j);
177  for( size_t k=1UL; k<lhs_.columns(); ++k ) {
178  tmp += lhs_(i,k) * rhs_(k,j);
179  }
180  }
181 
182  return tmp;
183  }
184  //**********************************************************************************************
185 
186  //**Rows function*******************************************************************************
191  inline size_t rows() const {
192  return lhs_.rows();
193  }
194  //**********************************************************************************************
195 
196  //**Columns function****************************************************************************
201  inline size_t columns() const {
202  return rhs_.columns();
203  }
204  //**********************************************************************************************
205 
206  //**NonZeros function***************************************************************************
211  inline size_t nonZeros() const {
212  return 0UL;
213  }
214  //**********************************************************************************************
215 
216  //**NonZeros function***************************************************************************
222  inline size_t nonZeros( size_t i ) const {
223  UNUSED_PARAMETER( i );
224  return 0UL;
225  }
226  //**********************************************************************************************
227 
228  //**Left operand access*************************************************************************
233  inline LeftOperand leftOperand() const {
234  return lhs_;
235  }
236  //**********************************************************************************************
237 
238  //**Right operand access************************************************************************
243  inline RightOperand rightOperand() const {
244  return rhs_;
245  }
246  //**********************************************************************************************
247 
248  //**********************************************************************************************
254  template< typename T >
255  inline bool canAlias( const T* alias ) const {
256  return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
257  }
258  //**********************************************************************************************
259 
260  //**********************************************************************************************
266  template< typename T >
267  inline bool isAliased( const T* alias ) const {
268  return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
269  }
270  //**********************************************************************************************
271 
272  private:
273  //**Member variables****************************************************************************
276  //**********************************************************************************************
277 
278  //**Default assignment to dense matrices********************************************************
292  template< typename MT // Type of the target dense matrix
293  , bool SO > // Storage order of the target dense matrix
294  friend inline typename EnableIf< IsResizable<typename MT::ElementType> >::Type
295  assign( DenseMatrix<MT,SO>& lhs, const TSMatTSMatMultExpr& rhs )
296  {
298 
299  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
300  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
301 
302  typedef typename RemoveReference<CT1>::Type::ConstIterator LeftIterator;
303  typedef typename RemoveReference<CT2>::Type::ConstIterator RightIterator;
304 
305  CT1 A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
306  CT2 B( rhs.rhs_ ); // Evaluation of the right-hand side sparse matrix operand
307 
308  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
309  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
310  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
311  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
312  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
313  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
314 
315  for( size_t j=0UL; j<(~lhs).columns(); ++j ) {
316  const RightIterator rend( B.end(j) );
317  for( RightIterator relem=B.begin(j); relem!=rend; ++relem ) {
318  const LeftIterator lend( A.end( relem->index() ) );
319  for( LeftIterator lelem=A.begin( relem->index() ); lelem!=lend; ++lelem )
320  {
321  if( isDefault( (~lhs)(lelem->index(),j) ) ) {
322  (~lhs)(lelem->index(),j) = lelem->value() * relem->value();
323  }
324  else {
325  (~lhs)(lelem->index(),j) += lelem->value() * relem->value();
326  }
327  }
328  }
329  }
330  }
332  //**********************************************************************************************
333 
334  //**Optimized assignment to dense matrices******************************************************
348  template< typename MT // Type of the target dense matrix
349  , bool SO > // Storage order of the target dense matrix
350  friend inline typename DisableIf< IsResizable<typename MT::ElementType> >::Type
351  assign( DenseMatrix<MT,SO>& lhs, const TSMatTSMatMultExpr& rhs )
352  {
354 
355  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
356  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
357 
358  typedef typename RemoveReference<CT1>::Type::ConstIterator LeftIterator;
359  typedef typename RemoveReference<CT2>::Type::ConstIterator RightIterator;
360 
361  CT1 A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
362  CT2 B( rhs.rhs_ ); // Evaluation of the right-hand side sparse matrix operand
363 
364  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
365  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
366  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
367  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
368  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
369  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
370 
371  for( size_t j=0UL; j<(~lhs).columns(); ++j ) {
372  const RightIterator rend( B.end(j) );
373  for( RightIterator relem=B.begin(j); relem!=rend; ++relem ) {
374  const LeftIterator lend( A.end( relem->index() ) );
375  for( LeftIterator lelem=A.begin( relem->index() ); lelem!=lend; ++lelem ) {
376  (~lhs)(lelem->index(),j) += lelem->value() * relem->value();
377  }
378  }
379  }
380  }
382  //**********************************************************************************************
383 
384  //**Assignment to row-major sparse matrices*****************************************************
397  template< typename MT > // Type of the target sparse matrix
398  friend inline void assign( SparseMatrix<MT,false>& lhs, const TSMatTSMatMultExpr& rhs )
399  {
401 
402  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
403  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
404 
407 
408  const ResultType tmp( rhs );
409  (~lhs).reserve( tmp.nonZeros() );
410  assign( ~lhs, tmp );
411  }
413  //**********************************************************************************************
414 
415  //**Assignment to column-major sparse matrices**************************************************
428  template< typename MT > // Type of the target sparse matrix
429  friend inline void assign( SparseMatrix<MT,true>& lhs, const TSMatTSMatMultExpr& rhs )
430  {
432 
433  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
434  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
435 
436  typedef typename RemoveReference<CT1>::Type::ConstIterator LeftIterator;
437  typedef typename RemoveReference<CT2>::Type::ConstIterator RightIterator;
438 
439  CT1 A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
440  CT2 B( rhs.rhs_ ); // Evaluation of the right-hand side sparse matrix operand
441 
442  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
443  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
444  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
445  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
446  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
447  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
448 
449  // (Over-)Estimating the number of non-zero entries in the resulting matrix
450  size_t nonzeros( 0UL );
451 
452  for( size_t j=0UL; j<(~lhs).columns(); ++j ) {
453  const RightIterator rend( B.end(j) );
454  for( RightIterator relem=B.begin(j); relem!=rend; ++relem ) {
455  nonzeros += A.nonZeros( relem->index() );
456  }
457  }
458 
459  if( nonzeros > (~lhs).rows() * (~lhs).columns() ) {
460  nonzeros = (~lhs).rows() * (~lhs).columns();
461  }
462 
463  (~lhs).reserve( nonzeros );
464  nonzeros = 0UL;
465 
466  // Performing the matrix-matrix multiplication
467  std::vector<ElementType> values ( (~lhs).rows(), ElementType() );
468  std::vector<byte> valid ( (~lhs).rows(), 0 );
469  std::vector<size_t> indices( (~lhs).rows(), 0UL );
470  size_t minIndex( inf ), maxIndex( 0UL );
471 
472  for( size_t j=0UL; j<(~lhs).columns(); ++j )
473  {
474  const RightIterator rend( B.end(j) );
475  for( RightIterator relem=B.begin(j); relem!=rend; ++relem )
476  {
477  const LeftIterator lend( A.end( relem->index() ) );
478  for( LeftIterator lelem=A.begin( relem->index() ); lelem!=lend; ++lelem )
479  {
480  if( !valid[lelem->index()] ) {
481  values[lelem->index()] = lelem->value() * relem->value();
482  valid [lelem->index()] = 1;
483  indices[nonzeros] = lelem->index();
484  ++nonzeros;
485  if( lelem->index() < minIndex ) minIndex = lelem->index();
486  if( lelem->index() > maxIndex ) maxIndex = lelem->index();
487  }
488  else {
489  values[lelem->index()] += lelem->value() * relem->value();
490  }
491  }
492  }
493 
494  BLAZE_INTERNAL_ASSERT( nonzeros <= (~lhs).rows(), "Invalid number of non-zero elements" );
495 
496  if( nonzeros > 0UL )
497  {
498  BLAZE_INTERNAL_ASSERT( minIndex <= maxIndex, "Invalid index detected" );
499 
500  if( ( nonzeros + nonzeros ) < ( maxIndex - minIndex ) )
501  {
502  std::sort( indices.begin(), indices.begin() + nonzeros );
503 
504  for( size_t i=0UL; i<nonzeros; ++i )
505  {
506  const size_t index( indices[i] );
507  if( !isDefault( values[index] ) ) {
508  (~lhs).append( index, j, values[index] );
509  reset( values[index] );
510  }
511 
512  reset( valid [index] );
513  }
514  }
515  else {
516  for( size_t i=minIndex; i<=maxIndex; ++i )
517  {
518  if( !isDefault( values[i] ) ) {
519  (~lhs).append( i, j, values[i] );
520  reset( values[i] );
521  }
522 
523  reset( valid [i] );
524  }
525  }
526 
527  nonzeros = 0UL;
528  minIndex = inf;
529  maxIndex = 0UL;
530  }
531 
532  (~lhs).finalize( j );
533  }
534  }
536  //**********************************************************************************************
537 
538  //**Addition assignment to dense matrices*******************************************************
551  template< typename MT // Type of the target dense matrix
552  , bool SO > // Storage order of the target dense matarix
553  friend inline void addAssign( DenseMatrix<MT,SO>& lhs, const TSMatTSMatMultExpr& rhs )
554  {
556 
557  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
558  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
559 
560  typedef typename RemoveReference<CT1>::Type::ConstIterator LeftIterator;
561  typedef typename RemoveReference<CT2>::Type::ConstIterator RightIterator;
562 
563  CT1 A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
564  CT2 B( rhs.rhs_ ); // Evaluation of the right-hand side sparse matrix operand
565 
566  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
567  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
568  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
569  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
570  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
571  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
572 
573  for( size_t j=0UL; j<(~lhs).columns(); ++j ) {
574  const RightIterator rend( B.end(j) );
575  for( RightIterator relem=B.begin(j); relem!=rend; ++relem ) {
576  const LeftIterator lend( A.end( relem->index() ) );
577  for( LeftIterator lelem=A.begin( relem->index() ); lelem!=lend; ++lelem ) {
578  (~lhs)(lelem->index(),j) += lelem->value() * relem->value();
579  }
580  }
581  }
582  }
584  //**********************************************************************************************
585 
586  //**Addition assignment to sparse matrices******************************************************
587  // No special implementation for the addition assignment to sparse matrices.
588  //**********************************************************************************************
589 
590  //**Subtraction assignment to dense matrices****************************************************
603  template< typename MT // Type of the target dense matrix
604  , bool SO > // Storage order of the target dense matarix
605  friend inline void subAssign( DenseMatrix<MT,SO>& lhs, const TSMatTSMatMultExpr& rhs )
606  {
608 
609  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
610  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
611 
612  typedef typename RemoveReference<CT1>::Type::ConstIterator LeftIterator;
613  typedef typename RemoveReference<CT2>::Type::ConstIterator RightIterator;
614 
615  CT1 A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
616  CT2 B( rhs.rhs_ ); // Evaluation of the right-hand side sparse matrix operand
617 
618  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
619  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
620  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
621  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
622  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
623  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
624 
625  for( size_t j=0UL; j<(~lhs).columns(); ++j ) {
626  const RightIterator rend( B.end(j) );
627  for( RightIterator relem=B.begin(j); relem!=rend; ++relem ) {
628  const LeftIterator lend( A.end( relem->index() ) );
629  for( LeftIterator lelem=A.begin( relem->index() ); lelem!=lend; ++lelem ) {
630  (~lhs)(lelem->index(),j) -= lelem->value() * relem->value();
631  }
632  }
633  }
634  }
636  //**********************************************************************************************
637 
638  //**Subtraction assignment to sparse matrices***************************************************
639  // No special implementation for the subtraction assignment to sparse matrices.
640  //**********************************************************************************************
641 
642  //**Multiplication assignment to dense matrices*************************************************
643  // No special implementation for the multiplication assignment to dense matrices.
644  //**********************************************************************************************
645 
646  //**Multiplication assignment to sparse matrices************************************************
647  // No special implementation for the multiplication assignment to sparse matrices.
648  //**********************************************************************************************
649 
650  //**Compile time checks*************************************************************************
657  //**********************************************************************************************
658 };
659 //*************************************************************************************************
660 
661 
662 
663 
664 //=================================================================================================
665 //
666 // GLOBAL BINARY ARITHMETIC OPERATORS
667 //
668 //=================================================================================================
669 
670 //*************************************************************************************************
697 template< typename T1 // Type of the left-hand side sparse matrix
698  , typename T2 > // Type of the right-hand side sparse matrix
699 inline const TSMatTSMatMultExpr<T1,T2>
701 {
703 
704  if( (~lhs).columns() != (~rhs).rows() )
705  throw std::invalid_argument( "Matrix sizes do not match" );
706 
707  return TSMatTSMatMultExpr<T1,T2>( ~lhs, ~rhs );
708 }
709 //*************************************************************************************************
710 
711 
712 
713 
714 //=================================================================================================
715 //
716 // EXPRESSION TRAIT SPECIALIZATIONS
717 //
718 //=================================================================================================
719 
720 //*************************************************************************************************
722 template< typename MT1, typename MT2, typename VT >
723 struct TSMatDVecMultExprTrait< TSMatTSMatMultExpr<MT1,MT2>, VT >
724 {
725  public:
726  //**********************************************************************************************
727  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
728  IsSparseMatrix<MT2>::value && IsColumnMajorMatrix<MT2>::value &&
729  IsDenseVector<VT>::value && !IsTransposeVector<VT>::value
730  , typename TSMatDVecMultExprTrait< MT1, typename TSMatDVecMultExprTrait<MT2,VT>::Type >::Type
731  , INVALID_TYPE >::Type Type;
732  //**********************************************************************************************
733 };
735 //*************************************************************************************************
736 
737 
738 //*************************************************************************************************
740 template< typename MT1, typename MT2, typename VT >
741 struct TSMatSVecMultExprTrait< TSMatTSMatMultExpr<MT1,MT2>, VT >
742 {
743  public:
744  //**********************************************************************************************
745  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
746  IsSparseMatrix<MT2>::value && IsColumnMajorMatrix<MT2>::value &&
747  IsSparseVector<VT>::value && !IsTransposeVector<VT>::value
748  , typename TSMatDVecMultExprTrait< MT1, typename TSMatDVecMultExprTrait<MT2,VT>::Type >::Type
749  , INVALID_TYPE >::Type Type;
750  //**********************************************************************************************
751 };
753 //*************************************************************************************************
754 
755 
756 //*************************************************************************************************
758 template< typename VT, typename MT1, typename MT2 >
759 struct TDVecTSMatMultExprTrait< VT, TSMatTSMatMultExpr<MT1,MT2> >
760 {
761  public:
762  //**********************************************************************************************
763  typedef typename SelectType< IsDenseVector<VT>::value && IsTransposeVector<VT>::value &&
764  IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
765  IsSparseMatrix<MT2>::value && IsColumnMajorMatrix<MT2>::value
766  , typename TDVecTSMatMultExprTrait< typename TDVecTSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
767  , INVALID_TYPE >::Type Type;
768  //**********************************************************************************************
769 };
771 //*************************************************************************************************
772 
773 
774 //*************************************************************************************************
776 template< typename VT, typename MT1, typename MT2 >
777 struct TSVecTSMatMultExprTrait< VT, TSMatTSMatMultExpr<MT1,MT2> >
778 {
779  public:
780  //**********************************************************************************************
781  typedef typename SelectType< IsSparseVector<VT>::value && IsTransposeVector<VT>::value &&
782  IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
783  IsSparseMatrix<MT2>::value && IsColumnMajorMatrix<MT2>::value
784  , typename TSVecTSMatMultExprTrait< typename TSVecTSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
785  , INVALID_TYPE >::Type Type;
786  //**********************************************************************************************
787 };
789 //*************************************************************************************************
790 
791 
792 //*************************************************************************************************
794 template< typename MT1, typename MT2 >
795 struct RowExprTrait< TSMatTSMatMultExpr<MT1,MT2> >
796 {
797  public:
798  //**********************************************************************************************
799  typedef typename MultExprTrait< typename RowExprTrait<const MT1>::Type, MT2 >::Type Type;
800  //**********************************************************************************************
801 };
803 //*************************************************************************************************
804 
805 
806 //*************************************************************************************************
808 template< typename MT1, typename MT2 >
809 struct ColumnExprTrait< TSMatTSMatMultExpr<MT1,MT2> >
810 {
811  public:
812  //**********************************************************************************************
813  typedef typename MultExprTrait< MT1, typename ColumnExprTrait<const MT2>::Type >::Type Type;
814  //**********************************************************************************************
815 };
817 //*************************************************************************************************
818 
819 } // namespace blaze
820 
821 #endif