TSMatDMatMultExpr.h
Go to the documentation of this file.
1 //=================================================================================================
33 //=================================================================================================
34 
35 #ifndef _BLAZE_MATH_EXPRESSIONS_TSMATDMATMULTEXPR_H_
36 #define _BLAZE_MATH_EXPRESSIONS_TSMATDMATMULTEXPR_H_
37 
38 
39 //*************************************************************************************************
40 // Includes
41 //*************************************************************************************************
42 
53 #include <blaze/math/Functions.h>
55 #include <blaze/math/shims/Reset.h>
99 #include <blaze/util/Assert.h>
100 #include <blaze/util/DisableIf.h>
101 #include <blaze/util/EnableIf.h>
102 #include <blaze/util/Exception.h>
103 #include <blaze/util/InvalidType.h>
105 #include <blaze/util/mpl/And.h>
106 #include <blaze/util/mpl/Or.h>
107 #include <blaze/util/SelectType.h>
108 #include <blaze/util/Types.h>
111 
112 
113 namespace blaze {
114 
115 //=================================================================================================
116 //
117 // CLASS SMATDMATMULTEXPR
118 //
119 //=================================================================================================
120 
121 //*************************************************************************************************
128 template< typename MT1 // Type of the left-hand side dense matrix
129  , typename MT2 > // Type of the right-hand side sparse matrix
130 class TSMatDMatMultExpr : public DenseMatrix< TSMatDMatMultExpr<MT1,MT2>, true >
131  , private MatMatMultExpr
132  , private Computation
133 {
134  private:
135  //**Type definitions****************************************************************************
136  typedef typename MT1::ResultType RT1;
137  typedef typename MT2::ResultType RT2;
138  typedef typename RT1::ElementType ET1;
139  typedef typename RT2::ElementType ET2;
140  typedef typename MT1::CompositeType CT1;
141  typedef typename MT2::CompositeType CT2;
142  //**********************************************************************************************
143 
144  //**********************************************************************************************
147  //**********************************************************************************************
148 
149  //**********************************************************************************************
151  enum { evaluateRight = IsComputation<MT2>::value || RequiresEvaluation<MT2>::value };
152  //**********************************************************************************************
153 
154  //**********************************************************************************************
156 
161  template< typename T1, typename T2, typename T3 >
162  struct CanExploitSymmetry {
163  enum { value = IsSymmetric<T2>::value };
164  };
166  //**********************************************************************************************
167 
168  //**********************************************************************************************
170 
174  template< typename T1, typename T2, typename T3 >
175  struct IsEvaluationRequired {
176  enum { value = ( evaluateLeft || evaluateRight ) &&
177  !CanExploitSymmetry<T1,T2,T3>::value };
178  };
180  //**********************************************************************************************
181 
182  //**********************************************************************************************
184 
188  template< typename T1, typename T2, typename T3 >
189  struct UseOptimizedKernel {
190  enum { value = useOptimizedKernels &&
191  !IsDiagonal<T3>::value &&
192  !IsResizable<typename T1::ElementType>::value &&
193  !IsResizable<ET1>::value };
194  };
196  //**********************************************************************************************
197 
198  //**********************************************************************************************
200 
203  template< typename T1, typename T2, typename T3 >
204  struct UseDefaultKernel {
205  enum { value = !UseOptimizedKernel<T1,T2,T3>::value };
206  };
208  //**********************************************************************************************
209 
210  public:
211  //**Type definitions****************************************************************************
217  typedef const ElementType ReturnType;
218  typedef const ResultType CompositeType;
219 
221  typedef typename SelectType< IsExpression<MT1>::value, const MT1, const MT1& >::Type LeftOperand;
222 
224  typedef typename SelectType< IsExpression<MT2>::value, const MT2, const MT2& >::Type RightOperand;
225 
228 
231  //**********************************************************************************************
232 
233  //**Compilation flags***************************************************************************
235  enum { vectorizable = 0 };
236 
238  enum { smpAssignable = !evaluateLeft && MT1::smpAssignable &&
239  !evaluateRight && MT2::smpAssignable };
240  //**********************************************************************************************
241 
242  //**Constructor*********************************************************************************
248  explicit inline TSMatDMatMultExpr( const MT1& lhs, const MT2& rhs )
249  : lhs_( lhs ) // Left-hand side sparse matrix of the multiplication expression
250  , rhs_( rhs ) // Right-hand side dense matrix of the multiplication expression
251  {
252  BLAZE_INTERNAL_ASSERT( lhs.columns() == rhs.rows(), "Invalid matrix sizes" );
253  }
254  //**********************************************************************************************
255 
256  //**Access operator*****************************************************************************
263  inline ReturnType operator()( size_t i, size_t j ) const {
264  BLAZE_INTERNAL_ASSERT( i < lhs_.rows() , "Invalid row access index" );
265  BLAZE_INTERNAL_ASSERT( j < rhs_.columns(), "Invalid column access index" );
266 
267  const size_t kbegin( ( IsUpper<MT1>::value )
268  ?( ( IsLower<MT2>::value )
269  ?( max( ( IsStrictlyUpper<MT1>::value ? i+1UL : i )
270  , ( IsStrictlyLower<MT2>::value ? j+1UL : j ) ) )
271  :( IsStrictlyUpper<MT1>::value ? i+1UL : i ) )
272  :( ( IsLower<MT2>::value )
273  ?( IsStrictlyLower<MT2>::value ? j+1UL : j )
274  :( 0UL ) ) );
275  const size_t kend( ( IsLower<MT1>::value )
276  ?( ( IsUpper<MT2>::value )
277  ?( min( ( IsStrictlyLower<MT1>::value ? i : i+1UL )
278  , ( IsStrictlyUpper<MT2>::value ? j : j+1UL ) ) )
279  :( IsStrictlyLower<MT1>::value ? i : i+1UL ) )
280  :( ( IsUpper<MT2>::value )
281  ?( IsStrictlyUpper<MT2>::value ? j : j+1UL )
282  :( lhs_.columns() ) ) );
283 
284  if( lhs_.columns() == 0UL ||
285  ( ( IsTriangular<MT1>::value || IsTriangular<MT2>::value ) && kbegin >= kend ) )
286  return ElementType();
287 
288  ElementType tmp( lhs_(i,kbegin) * rhs_(kbegin,j) );
289  for( size_t k=kbegin+1UL; k<kend; ++k ) {
290  tmp += lhs_(i,k) * rhs_(k,j);
291  }
292 
293  return tmp;
294  }
295  //**********************************************************************************************
296 
297  //**At function*********************************************************************************
305  inline ReturnType at( size_t i, size_t j ) const {
306  if( i >= lhs_.rows() ) {
307  BLAZE_THROW_OUT_OF_RANGE( "Invalid row access index" );
308  }
309  if( j >= rhs_.columns() ) {
310  BLAZE_THROW_OUT_OF_RANGE( "Invalid column access index" );
311  }
312  return (*this)(i,j);
313  }
314  //**********************************************************************************************
315 
316  //**Rows function*******************************************************************************
321  inline size_t rows() const {
322  return lhs_.rows();
323  }
324  //**********************************************************************************************
325 
326  //**Columns function****************************************************************************
331  inline size_t columns() const {
332  return rhs_.columns();
333  }
334  //**********************************************************************************************
335 
336  //**Left operand access*************************************************************************
341  inline LeftOperand leftOperand() const {
342  return lhs_;
343  }
344  //**********************************************************************************************
345 
346  //**Right operand access************************************************************************
351  inline RightOperand rightOperand() const {
352  return rhs_;
353  }
354  //**********************************************************************************************
355 
356  //**********************************************************************************************
362  template< typename T >
363  inline bool canAlias( const T* alias ) const {
364  return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
365  }
366  //**********************************************************************************************
367 
368  //**********************************************************************************************
374  template< typename T >
375  inline bool isAliased( const T* alias ) const {
376  return ( lhs_.isAliased( alias ) || rhs_.isAliased( alias ) );
377  }
378  //**********************************************************************************************
379 
380  //**********************************************************************************************
385  inline bool isAligned() const {
386  return rhs_.isAligned();
387  }
388  //**********************************************************************************************
389 
390  //**********************************************************************************************
395  inline bool canSMPAssign() const {
396  return ( columns() > SMP_TSMATDMATMULT_THRESHOLD );
397  }
398  //**********************************************************************************************
399 
400  private:
401  //**Member variables****************************************************************************
402  LeftOperand lhs_;
403  RightOperand rhs_;
404  //**********************************************************************************************
405 
406  //**Assignment to dense matrices****************************************************************
419  template< typename MT // Type of the target dense matrix
420  , bool SO > // Storage order of the target dense matrix
421  friend inline typename DisableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
422  assign( DenseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
423  {
425 
426  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
427  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
428 
429  LT A( serial( rhs.lhs_ ) ); // Evaluation of the right-hand side sparse matrix operand
430  RT B( serial( rhs.rhs_ ) ); // Evaluation of the left-hand side dense matrix operand
431 
432  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
433  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
434  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
435  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
436  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
437  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
438 
439  TSMatDMatMultExpr::selectAssignKernel( ~lhs, A, B );
440  }
442  //**********************************************************************************************
443 
444  //**Assignment to dense matrices (kernel selection)*********************************************
455  template< typename MT3 // Type of the left-hand side target matrix
456  , typename MT4 // Type of the left-hand side matrix operand
457  , typename MT5 > // Type of the right-hand side matrix operand
458  static inline void selectAssignKernel( MT3& C, const MT4& A, const MT5& B )
459  {
460  const size_t size( C.rows() * C.columns() );
461 
462  if( ( IsRowMajorMatrix<MT3>::value && size < TSMATDMATMULT_THRESHOLD ) ||
463  ( IsColumnMajorMatrix<MT3>::value && size < 625UL ) )
464  selectSmallAssignKernel( C, A, B );
465  else
466  selectLargeAssignKernel( C, A, B );
467  }
469  //**********************************************************************************************
470 
471  //**Default assignment to dense matrices********************************************************
486  template< typename MT3 // Type of the left-hand side target matrix
487  , typename MT4 // Type of the left-hand side matrix operand
488  , typename MT5 > // Type of the right-hand side matrix operand
489  static inline void selectDefaultAssignKernel( MT3& C, const MT4& A, const MT5& B )
490  {
491  typedef typename MT4::ConstIterator ConstIterator;
492 
493  reset( C );
494 
495  if( IsDiagonal<MT5>::value )
496  {
497  for( size_t i=0UL; i<A.columns(); ++i )
498  {
499  const ConstIterator end( A.end(i) );
500  ConstIterator element( A.begin(i) );
501 
502  for( ; element!=end; ++element ) {
503  C(element->index(),i) = element->value() * B(i,i);
504  }
505  }
506  }
507  else
508  {
509  const size_t block( IsRowMajorMatrix<MT3>::value ? 256UL : 8UL );
510 
511  for( size_t jj=0UL; jj<B.columns(); jj+=block )
512  {
513  const size_t jpos( ( jj+block > B.columns() )?( B.columns() ):( jj+block ) );
514 
515  for( size_t i=0UL; i<A.columns(); ++i )
516  {
517  const ConstIterator end( A.end(i) );
518  ConstIterator element( A.begin(i) );
519 
520  const size_t jbegin( ( IsUpper<MT5>::value )
521  ?( max( IsStrictlyUpper<MT5>::value ? i+1UL : i, jj ) )
522  :( jj ) );
523  const size_t jend( ( IsLower<MT5>::value )
524  ?( min( IsStrictlyLower<MT5>::value ? i : i+1UL, jpos ) )
525  :( jpos ) );
526 
527  if( jbegin >= jend )
528  continue;
529 
530  for( ; element!=end; ++element ) {
531  for( size_t j=jbegin; j<jend; ++j ) {
532  if( isDefault( C(element->index(),j) ) )
533  C(element->index(),j) = element->value() * B(i,j);
534  else
535  C(element->index(),j) += element->value() * B(i,j);
536  }
537  }
538  }
539  }
540  }
541  }
543  //**********************************************************************************************
544 
545  //**Default assignment to dense matrices (small matrices)***************************************
559  template< typename MT3 // Type of the left-hand side target matrix
560  , typename MT4 // Type of the left-hand side matrix operand
561  , typename MT5 > // Type of the right-hand side matrix operand
562  static inline typename EnableIf< UseDefaultKernel<MT3,MT4,MT5> >::Type
563  selectSmallAssignKernel( MT3& C, const MT4& A, const MT5& B )
564  {
565  selectDefaultAssignKernel( C, A, B );
566  }
568  //**********************************************************************************************
569 
570  //**Optimized assignment to dense matrices (small matrices)*************************************
585  template< typename MT3 // Type of the left-hand side target matrix
586  , typename MT4 // Type of the left-hand side matrix operand
587  , typename MT5 > // Type of the right-hand side matrix operand
588  static inline typename EnableIf< UseOptimizedKernel<MT3,MT4,MT5> >::Type
589  selectSmallAssignKernel( MT3& C, const MT4& A, const MT5& B )
590  {
591  typedef typename MT4::ConstIterator ConstIterator;
592 
593  const size_t block( ( IsRowMajorMatrix<MT3>::value )?( 256UL ):( 8UL ) );
594 
595  reset( C );
596 
597  for( size_t jj=0UL; jj<B.columns(); jj+=block )
598  {
599  const size_t jpos( ( jj+block > B.columns() )?( B.columns() ):( jj+block ) );
600 
601  for( size_t i=0UL; i<A.columns(); ++i )
602  {
603  const size_t jbegin( ( IsUpper<MT5>::value )
604  ?( max( IsStrictlyUpper<MT5>::value ? i+1UL : i, jj ) )
605  :( jj ) );
606  const size_t jend( ( IsLower<MT5>::value )
607  ?( min( IsStrictlyLower<MT5>::value ? i : i+1UL, jpos ) )
608  :( jpos ) );
609 
610  if( jbegin >= jend )
611  continue;
612 
613  const ConstIterator end( A.end(i) );
614  ConstIterator element( A.begin(i) );
615 
616  const size_t nonzeros( A.nonZeros(i) );
617  const size_t kpos( nonzeros & size_t(-4) );
618  BLAZE_INTERNAL_ASSERT( ( nonzeros - ( nonzeros % 4UL ) ) == kpos, "Invalid end calculation" );
619 
620  for( size_t k=0UL; k<kpos; k+=4UL )
621  {
622  const size_t i1( element->index() );
623  const ET1 v1( element->value() );
624  ++element;
625  const size_t i2( element->index() );
626  const ET1 v2( element->value() );
627  ++element;
628  const size_t i3( element->index() );
629  const ET1 v3( element->value() );
630  ++element;
631  const size_t i4( element->index() );
632  const ET1 v4( element->value() );
633  ++element;
634 
635  BLAZE_INTERNAL_ASSERT( i1 < i2 && i2 < i3 && i3 < i4, "Invalid sparse matrix index detected" );
636 
637  for( size_t j=jbegin; j<jend; ++j ) {
638  C(i1,j) += v1 * B(i,j);
639  C(i2,j) += v2 * B(i,j);
640  C(i3,j) += v3 * B(i,j);
641  C(i4,j) += v4 * B(i,j);
642  }
643  }
644 
645  for( ; element!=end; ++element ) {
646  for( size_t j=jbegin; j<jend; ++j ) {
647  C(element->index(),j) += element->value() * B(i,j);
648  }
649  }
650  }
651  }
652  }
654  //**********************************************************************************************
655 
656  //**Default assignment to dense matrices (large matrices)***************************************
670  template< typename MT3 // Type of the left-hand side target matrix
671  , typename MT4 // Type of the left-hand side matrix operand
672  , typename MT5 > // Type of the right-hand side matrix operand
673  static inline typename EnableIf< UseDefaultKernel<MT3,MT4,MT5> >::Type
674  selectLargeAssignKernel( MT3& C, const MT4& A, const MT5& B )
675  {
676  selectDefaultAssignKernel( C, A, B );
677  }
679  //**********************************************************************************************
680 
681  //**Optimized assignment to dense matrices (large matrices)*************************************
696  template< typename MT3 // Type of the left-hand side target matrix
697  , typename MT4 // Type of the left-hand side matrix operand
698  , typename MT5 > // Type of the right-hand side matrix operand
699  static inline typename EnableIf< UseOptimizedKernel<MT3,MT4,MT5> >::Type
700  selectLargeAssignKernel( MT3& C, const MT4& A, const MT5& B )
701  {
703 
704  const typename MT4::OppositeType tmp( serial( A ) );
705  assign( C, tmp * B );
706  }
708  //**********************************************************************************************
709 
710  //**Assignment to sparse matrices***************************************************************
723  template< typename MT // Type of the target sparse matrix
724  , bool SO > // Storage order of the target sparse matrix
725  friend inline typename DisableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
726  assign( SparseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
727  {
729 
730  typedef typename SelectType< SO, ResultType, OppositeType >::Type TmpType;
731 
738 
739  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
740  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
741 
742  const TmpType tmp( serial( rhs ) );
743  assign( ~lhs, tmp );
744  }
746  //**********************************************************************************************
747 
748  //**Restructuring assignment to row-major matrices**********************************************
763  template< typename MT // Type of the target matrix
764  , bool SO > // Storage order of the target matrix
765  friend inline typename EnableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
766  assign( Matrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
767  {
769 
771 
772  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
773  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
774 
775  assign( ~lhs, trans( rhs.lhs_ ) * rhs.rhs_ );
776  }
778  //**********************************************************************************************
779 
780  //**Addition assignment to dense matrices*******************************************************
793  template< typename MT // Type of the target dense matrix
794  , bool SO > // Storage order of the target dense matrix
795  friend inline typename DisableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
796  addAssign( DenseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
797  {
799 
800  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
801  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
802 
803  LT A( serial( rhs.lhs_ ) ); // Evaluation of the right-hand side sparse matrix operand
804  RT B( serial( rhs.rhs_ ) ); // Evaluation of the left-hand side dense matrix operand
805 
806  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
807  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
808  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
809  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
810  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
811  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
812 
813  TSMatDMatMultExpr::selectAddAssignKernel( ~lhs, A, B );
814  }
816  //**********************************************************************************************
817 
818  //**Addition assignment to dense matrices (kernel selection)************************************
829  template< typename MT3 // Type of the left-hand side target matrix
830  , typename MT4 // Type of the left-hand side matrix operand
831  , typename MT5 > // Type of the right-hand side matrix operand
832  static inline void selectAddAssignKernel( MT3& C, const MT4& A, const MT5& B )
833  {
834  const size_t size( C.rows() * C.columns() );
835 
836  if( ( IsRowMajorMatrix<MT3>::value && size < TSMATDMATMULT_THRESHOLD ) ||
837  ( IsColumnMajorMatrix<MT3>::value && size < 625UL ) )
838  selectSmallAddAssignKernel( C, A, B );
839  else
840  selectLargeAddAssignKernel( C, A, B );
841  }
843  //**********************************************************************************************
844 
845  //**Default addition assignment to dense matrices***********************************************
860  template< typename MT3 // Type of the left-hand side target matrix
861  , typename MT4 // Type of the left-hand side matrix operand
862  , typename MT5 > // Type of the right-hand side matrix operand
863  static inline void selectDefaultAddAssignKernel( MT3& C, const MT4& A, const MT5& B )
864  {
865  typedef typename MT4::ConstIterator ConstIterator;
866 
867  if( IsDiagonal<MT5>::value )
868  {
869  for( size_t i=0UL; i<A.columns(); ++i )
870  {
871  const ConstIterator end( A.end(i) );
872  ConstIterator element( A.begin(i) );
873 
874  for( ; element!=end; ++element ) {
875  C(element->index(),i) += element->value() * B(i,i);
876  }
877  }
878  }
879  else
880  {
881  const size_t block( IsRowMajorMatrix<MT3>::value ? 256UL : 8UL );
882 
883  for( size_t jj=0UL; jj<B.columns(); jj+=block )
884  {
885  const size_t jpos( ( jj+block > B.columns() )?( B.columns() ):( jj+block ) );
886 
887  for( size_t i=0UL; i<A.columns(); ++i )
888  {
889  const ConstIterator end( A.end(i) );
890  ConstIterator element( A.begin(i) );
891 
892  const size_t jbegin( ( IsUpper<MT5>::value )
893  ?( max( IsStrictlyUpper<MT5>::value ? i+1UL : i, jj ) )
894  :( jj ) );
895  const size_t jend( ( IsLower<MT5>::value )
896  ?( min( IsStrictlyLower<MT5>::value ? i : i+1UL, jpos ) )
897  :( jpos ) );
898 
899  if( jbegin >= jend )
900  continue;
901 
902  for( ; element!=end; ++element ) {
903  for( size_t j=jbegin; j<jend; ++j ) {
904  C(element->index(),j) += element->value() * B(i,j);
905  }
906  }
907  }
908  }
909  }
910  }
912  //**********************************************************************************************
913 
914  //**Default addition assignment to dense matrices (small matrices)******************************
928  template< typename MT3 // Type of the left-hand side target matrix
929  , typename MT4 // Type of the left-hand side matrix operand
930  , typename MT5 > // Type of the right-hand side matrix operand
931  static inline typename EnableIf< UseDefaultKernel<MT3,MT4,MT5> >::Type
932  selectSmallAddAssignKernel( MT3& C, const MT4& A, const MT5& B )
933  {
934  selectDefaultAddAssignKernel( C, A, B );
935  }
937  //**********************************************************************************************
938 
939  //**Optimized addition assignment to dense matrices (small matrices)****************************
954  template< typename MT3 // Type of the left-hand side target matrix
955  , typename MT4 // Type of the left-hand side matrix operand
956  , typename MT5 > // Type of the right-hand side matrix operand
957  static inline typename EnableIf< UseOptimizedKernel<MT3,MT4,MT5> >::Type
958  selectSmallAddAssignKernel( MT3& C, const MT4& A, const MT5& B )
959  {
960  typedef typename MT4::ConstIterator ConstIterator;
961 
962  const size_t block( ( IsRowMajorMatrix<MT3>::value )?( 256UL ):( 8UL ) );
963 
964  for( size_t jj=0UL; jj<B.columns(); jj+=block )
965  {
966  const size_t jpos( ( jj+block > B.columns() )?( B.columns() ):( jj+block ) );
967 
968  for( size_t i=0UL; i<A.columns(); ++i )
969  {
970  const size_t jbegin( ( IsUpper<MT5>::value )
971  ?( max( IsStrictlyUpper<MT5>::value ? i+1UL : i, jj ) )
972  :( jj ) );
973  const size_t jend( ( IsLower<MT5>::value )
974  ?( min( IsStrictlyLower<MT5>::value ? i : i+1UL, jpos ) )
975  :( jpos ) );
976 
977  if( jbegin >= jend )
978  continue;
979 
980  const ConstIterator end( A.end(i) );
981  ConstIterator element( A.begin(i) );
982 
983  const size_t nonzeros( A.nonZeros(i) );
984  const size_t kpos( nonzeros & size_t(-4) );
985  BLAZE_INTERNAL_ASSERT( ( nonzeros - ( nonzeros % 4UL ) ) == kpos, "Invalid end calculation" );
986 
987  for( size_t k=0UL; k<kpos; k+=4UL )
988  {
989  const size_t i1( element->index() );
990  const ET1 v1( element->value() );
991  ++element;
992  const size_t i2( element->index() );
993  const ET1 v2( element->value() );
994  ++element;
995  const size_t i3( element->index() );
996  const ET1 v3( element->value() );
997  ++element;
998  const size_t i4( element->index() );
999  const ET1 v4( element->value() );
1000  ++element;
1001 
1002  BLAZE_INTERNAL_ASSERT( i1 < i2 && i2 < i3 && i3 < i4, "Invalid sparse matrix index detected" );
1003 
1004  for( size_t j=jbegin; j<jend; ++j ) {
1005  C(i1,j) += v1 * B(i,j);
1006  C(i2,j) += v2 * B(i,j);
1007  C(i3,j) += v3 * B(i,j);
1008  C(i4,j) += v4 * B(i,j);
1009  }
1010  }
1011 
1012  for( ; element!=end; ++element ) {
1013  for( size_t j=jbegin; j<jend; ++j ) {
1014  C(element->index(),j) += element->value() * B(i,j);
1015  }
1016  }
1017  }
1018  }
1019  }
1021  //**********************************************************************************************
1022 
1023  //**Default addition assignment to dense matrices (large matrices)******************************
1037  template< typename MT3 // Type of the left-hand side target matrix
1038  , typename MT4 // Type of the left-hand side matrix operand
1039  , typename MT5 > // Type of the right-hand side matrix operand
1040  static inline typename EnableIf< UseDefaultKernel<MT3,MT4,MT5> >::Type
1041  selectLargeAddAssignKernel( MT3& C, const MT4& A, const MT5& B )
1042  {
1043  selectDefaultAddAssignKernel( C, A, B );
1044  }
1046  //**********************************************************************************************
1047 
1048  //**Optimized addition assignment to dense matrices (large matrices)****************************
1063  template< typename MT3 // Type of the left-hand side target matrix
1064  , typename MT4 // Type of the left-hand side matrix operand
1065  , typename MT5 > // Type of the right-hand side matrix operand
1066  static inline typename EnableIf< UseOptimizedKernel<MT3,MT4,MT5> >::Type
1067  selectLargeAddAssignKernel( MT3& C, const MT4& A, const MT5& B )
1068  {
1070 
1071  const typename MT4::OppositeType tmp( serial( A ) );
1072  addAssign( C, tmp * B );
1073  }
1075  //**********************************************************************************************
1076 
1077  //**Restructuring addition assignment to row-major matrices*************************************
1092  template< typename MT // Type of the target matrix
1093  , bool SO > // Storage order of the target matrix
1094  friend inline typename EnableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
1095  addAssign( Matrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1096  {
1098 
1100 
1101  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1102  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1103 
1104  addAssign( ~lhs, trans( rhs.lhs_ ) * rhs.rhs_ );
1105  }
1107  //**********************************************************************************************
1108 
1109  //**Addition assignment to sparse matrices******************************************************
1110  // No special implementation for the addition assignment to sparse matrices.
1111  //**********************************************************************************************
1112 
1113  //**Subtraction assignment to dense matrices****************************************************
1126  template< typename MT // Type of the target dense matrix
1127  , bool SO > // Storage order of the target dense matrix
1128  friend inline typename DisableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
1129  subAssign( DenseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1130  {
1132 
1133  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1134  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1135 
1136  LT A( serial( rhs.lhs_ ) ); // Evaluation of the right-hand side sparse matrix operand
1137  RT B( serial( rhs.rhs_ ) ); // Evaluation of the left-hand side dense matrix operand
1138 
1139  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
1140  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
1141  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
1142  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
1143  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
1144  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
1145 
1146  TSMatDMatMultExpr::selectSubAssignKernel( ~lhs, A, B );
1147  }
1149  //**********************************************************************************************
1150 
1151  //**Subtraction assignment to dense matrices (kernel selection)*********************************
1162  template< typename MT3 // Type of the left-hand side target matrix
1163  , typename MT4 // Type of the left-hand side matrix operand
1164  , typename MT5 > // Type of the right-hand side matrix operand
1165  static inline void selectSubAssignKernel( MT3& C, const MT4& A, const MT5& B )
1166  {
1167  const size_t size( C.rows() * C.columns() );
1168 
1169  if( ( IsRowMajorMatrix<MT3>::value && size < TSMATDMATMULT_THRESHOLD ) ||
1170  ( IsColumnMajorMatrix<MT3>::value && size < 625UL ) )
1171  selectSmallSubAssignKernel( C, A, B );
1172  else
1173  selectLargeSubAssignKernel( C, A, B );
1174  }
1176  //**********************************************************************************************
1177 
1178  //**Default subtraction assignment to dense matrices********************************************
1193  template< typename MT3 // Type of the left-hand side target matrix
1194  , typename MT4 // Type of the left-hand side matrix operand
1195  , typename MT5 > // Type of the right-hand side matrix operand
1196  static inline void selectDefaultSubAssignKernel( MT3& C, const MT4& A, const MT5& B )
1197  {
1198  typedef typename MT4::ConstIterator ConstIterator;
1199 
1200  if( IsDiagonal<MT5>::value )
1201  {
1202  for( size_t i=0UL; i<A.columns(); ++i )
1203  {
1204  const ConstIterator end( A.end(i) );
1205  ConstIterator element( A.begin(i) );
1206 
1207  for( ; element!=end; ++element ) {
1208  C(element->index(),i) -= element->value() * B(i,i);
1209  }
1210  }
1211  }
1212  else
1213  {
1214  const size_t block( IsRowMajorMatrix<MT3>::value ? 256UL : 8UL );
1215 
1216  for( size_t jj=0UL; jj<B.columns(); jj+=block )
1217  {
1218  const size_t jpos( ( jj+block > B.columns() )?( B.columns() ):( jj+block ) );
1219 
1220  for( size_t i=0UL; i<A.columns(); ++i )
1221  {
1222  const ConstIterator end( A.end(i) );
1223  ConstIterator element( A.begin(i) );
1224 
1225  const size_t jbegin( ( IsUpper<MT5>::value )
1226  ?( max( IsStrictlyUpper<MT5>::value ? i+1UL : i, jj ) )
1227  :( jj ) );
1228  const size_t jend( ( IsLower<MT5>::value )
1229  ?( min( IsStrictlyLower<MT5>::value ? i : i+1UL, jpos ) )
1230  :( jpos ) );
1231 
1232  if( jbegin >= jend )
1233  continue;
1234 
1235  for( ; element!=end; ++element ) {
1236  for( size_t j=jbegin; j<jend; ++j ) {
1237  C(element->index(),j) -= element->value() * B(i,j);
1238  }
1239  }
1240  }
1241  }
1242  }
1243  }
1245  //**********************************************************************************************
1246 
1247  //**Default subtraction assignment to dense matrices (small matrices)***************************
1261  template< typename MT3 // Type of the left-hand side target matrix
1262  , typename MT4 // Type of the left-hand side matrix operand
1263  , typename MT5 > // Type of the right-hand side matrix operand
1264  static inline typename EnableIf< UseDefaultKernel<MT3,MT4,MT5> >::Type
1265  selectSmallSubAssignKernel( MT3& C, const MT4& A, const MT5& B )
1266  {
1267  selectDefaultSubAssignKernel( C, A, B );
1268  }
1270  //**********************************************************************************************
1271 
1272  //**Optimized subtraction assignment to dense matrices (small matrices)*************************
1287  template< typename MT3 // Type of the left-hand side target matrix
1288  , typename MT4 // Type of the left-hand side matrix operand
1289  , typename MT5 > // Type of the right-hand side matrix operand
1290  static inline typename EnableIf< UseOptimizedKernel<MT3,MT4,MT5> >::Type
1291  selectSmallSubAssignKernel( MT3& C, const MT4& A, const MT5& B )
1292  {
1293  typedef typename MT4::ConstIterator ConstIterator;
1294 
1295  const size_t block( ( IsRowMajorMatrix<MT3>::value )?( 256UL ):( 8UL ) );
1296 
1297  for( size_t jj=0UL; jj<B.columns(); jj+=block )
1298  {
1299  const size_t jpos( ( jj+block > B.columns() )?( B.columns() ):( jj+block ) );
1300 
1301  for( size_t i=0UL; i<A.columns(); ++i )
1302  {
1303  const size_t jbegin( ( IsUpper<MT5>::value )
1304  ?( max( IsStrictlyUpper<MT5>::value ? i+1UL : i, jj ) )
1305  :( jj ) );
1306  const size_t jend( ( IsLower<MT5>::value )
1307  ?( min( IsStrictlyLower<MT5>::value ? i : i+1UL, jpos ) )
1308  :( jpos ) );
1309 
1310  if( jbegin >= jend )
1311  continue;
1312 
1313  const ConstIterator end( A.end(i) );
1314  ConstIterator element( A.begin(i) );
1315 
1316  const size_t nonzeros( A.nonZeros(i) );
1317  const size_t kpos( nonzeros & size_t(-4) );
1318  BLAZE_INTERNAL_ASSERT( ( nonzeros - ( nonzeros % 4UL ) ) == kpos, "Invalid end calculation" );
1319 
1320  for( size_t k=0UL; k<kpos; k+=4UL )
1321  {
1322  const size_t i1( element->index() );
1323  const ET1 v1( element->value() );
1324  ++element;
1325  const size_t i2( element->index() );
1326  const ET1 v2( element->value() );
1327  ++element;
1328  const size_t i3( element->index() );
1329  const ET1 v3( element->value() );
1330  ++element;
1331  const size_t i4( element->index() );
1332  const ET1 v4( element->value() );
1333  ++element;
1334 
1335  BLAZE_INTERNAL_ASSERT( i1 < i2 && i2 < i3 && i3 < i4, "Invalid sparse matrix index detected" );
1336 
1337  for( size_t j=jbegin; j<jend; ++j ) {
1338  C(i1,j) -= v1 * B(i,j);
1339  C(i2,j) -= v2 * B(i,j);
1340  C(i3,j) -= v3 * B(i,j);
1341  C(i4,j) -= v4 * B(i,j);
1342  }
1343  }
1344 
1345  for( ; element!=end; ++element ) {
1346  for( size_t j=jbegin; j<jend; ++j ) {
1347  C(element->index(),j) -= element->value() * B(i,j);
1348  }
1349  }
1350  }
1351  }
1352  }
1354  //**********************************************************************************************
1355 
1356  //**Default subtraction assignment to dense matrices (large matrices)***************************
1370  template< typename MT3 // Type of the left-hand side target matrix
1371  , typename MT4 // Type of the left-hand side matrix operand
1372  , typename MT5 > // Type of the right-hand side matrix operand
1373  static inline typename EnableIf< UseDefaultKernel<MT3,MT4,MT5> >::Type
1374  selectLargeSubAssignKernel( MT3& C, const MT4& A, const MT5& B )
1375  {
1376  selectDefaultSubAssignKernel( C, A, B );
1377  }
1379  //**********************************************************************************************
1380 
1381  //**Optimized subtraction assignment to dense matrices (large matrices)*************************
1396  template< typename MT3 // Type of the left-hand side target matrix
1397  , typename MT4 // Type of the left-hand side matrix operand
1398  , typename MT5 > // Type of the right-hand side matrix operand
1399  static inline typename EnableIf< UseOptimizedKernel<MT3,MT4,MT5> >::Type
1400  selectLargeSubAssignKernel( MT3& C, const MT4& A, const MT5& B )
1401  {
1403 
1404  const typename MT4::OppositeType tmp( serial( A ) );
1405  subAssign( C, tmp * B );
1406  }
1408  //**********************************************************************************************
1409 
1410  //**Restructuring subtraction assignment to row-major matrices**********************************
1425  template< typename MT // Type of the target matrix
1426  , bool SO > // Storage order of the target matrix
1427  friend inline typename EnableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
1428  subAssign( Matrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1429  {
1431 
1433 
1434  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1435  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1436 
1437  subAssign( ~lhs, trans( rhs.lhs_ ) * rhs.rhs_ );
1438  }
1440  //**********************************************************************************************
1441 
1442  //**Subtraction assignment to sparse matrices***************************************************
1443  // No special implementation for the subtraction assignment to sparse matrices.
1444  //**********************************************************************************************
1445 
1446  //**Multiplication assignment to dense matrices*************************************************
1447  // No special implementation for the multiplication assignment to dense matrices.
1448  //**********************************************************************************************
1449 
1450  //**Multiplication assignment to sparse matrices************************************************
1451  // No special implementation for the multiplication assignment to sparse matrices.
1452  //**********************************************************************************************
1453 
1454  //**SMP assignment to dense matrices************************************************************
1470  template< typename MT // Type of the target dense matrix
1471  , bool SO > // Storage order of the target dense matrix
1472  friend inline typename EnableIf< IsEvaluationRequired<MT,MT1,MT2> >::Type
1473  smpAssign( DenseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1474  {
1476 
1477  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1478  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1479 
1480  LT A( rhs.lhs_ ); // Evaluation of the right-hand side sparse matrix operand
1481  RT B( rhs.rhs_ ); // Evaluation of the left-hand side dense matrix operand
1482 
1483  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
1484  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
1485  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
1486  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
1487  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
1488  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
1489 
1490  smpAssign( ~lhs, A * B );
1491  }
1493  //**********************************************************************************************
1494 
1495  //**SMP assignment to sparse matrices***********************************************************
1511  template< typename MT // Type of the target sparse matrix
1512  , bool SO > // Storage order of the target sparse matrix
1513  friend inline typename EnableIf< IsEvaluationRequired<MT,MT1,MT2> >::Type
1514  smpAssign( SparseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1515  {
1517 
1518  typedef typename SelectType< SO, ResultType, OppositeType >::Type TmpType;
1519 
1526 
1527  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1528  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1529 
1530  const TmpType tmp( rhs );
1531  smpAssign( ~lhs, tmp );
1532  }
1534  //**********************************************************************************************
1535 
1536  //**Restructuring SMP assignment to row-major matrices******************************************
1551  template< typename MT // Type of the target matrix
1552  , bool SO > // Storage order of the target matrix
1553  friend inline typename EnableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
1554  smpAssign( Matrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1555  {
1557 
1558  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1559  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1560 
1561  smpAssign( ~lhs, trans( rhs.lhs_ ) * rhs.rhs_ );
1562  }
1564  //**********************************************************************************************
1565 
1566  //**SMP addition assignment to dense matrices***************************************************
1582  template< typename MT // Type of the target dense matrix
1583  , bool SO > // Storage order of the target dense matrix
1584  friend inline typename EnableIf< IsEvaluationRequired<MT,MT1,MT2> >::Type
1585  smpAddAssign( DenseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1586  {
1588 
1589  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1590  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1591 
1592  LT A( rhs.lhs_ ); // Evaluation of the right-hand side sparse matrix operand
1593  RT B( rhs.rhs_ ); // Evaluation of the left-hand side dense matrix operand
1594 
1595  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
1596  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
1597  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
1598  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
1599  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
1600  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
1601 
1602  smpAddAssign( ~lhs, A * B );
1603  }
1605  //**********************************************************************************************
1606 
1607  //**Restructuring SMP addition assignment to row-major matrices*********************************
1622  template< typename MT // Type of the target matrix
1623  , bool SO > // Storage order of the target matrix
1624  friend inline typename EnableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
1625  smpAddAssign( Matrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1626  {
1628 
1629  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1630  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1631 
1632  smpAddAssign( ~lhs, trans( rhs.lhs_ ) * rhs.rhs_ );
1633  }
1635  //**********************************************************************************************
1636 
1637  //**SMP addition assignment to sparse matrices**************************************************
1638  // No special implementation for the SMP addition assignment to sparse matrices.
1639  //**********************************************************************************************
1640 
1641  //**SMP subtraction assignment to dense matrices************************************************
1657  template< typename MT // Type of the target dense matrix
1658  , bool SO > // Storage order of the target dense matrix
1659  friend inline typename EnableIf< IsEvaluationRequired<MT,MT1,MT2> >::Type
1660  smpSubAssign( DenseMatrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1661  {
1663 
1664  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1665  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1666 
1667  LT A( rhs.lhs_ ); // Evaluation of the right-hand side sparse matrix operand
1668  RT B( rhs.rhs_ ); // Evaluation of the left-hand side dense matrix operand
1669 
1670  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
1671  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
1672  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
1673  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
1674  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
1675  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
1676 
1677  smpSubAssign( ~lhs, A * B );
1678  }
1680  //**********************************************************************************************
1681 
1682  //**Restructuring SMP subtraction assignment to row-major matrices******************************
1697  template< typename MT // Type of the target matrix
1698  , bool SO > // Storage order of the target matrix
1699  friend inline typename EnableIf< CanExploitSymmetry<MT,MT1,MT2> >::Type
1700  smpSubAssign( Matrix<MT,SO>& lhs, const TSMatDMatMultExpr& rhs )
1701  {
1703 
1704  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
1705  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
1706 
1707  smpSubAssign( ~lhs, trans( rhs.lhs_ ) * rhs.rhs_ );
1708  }
1710  //**********************************************************************************************
1711 
1712  //**SMP subtraction assignment to sparse matrices***********************************************
1713  // No special implementation for the SMP subtraction assignment to sparse matrices.
1714  //**********************************************************************************************
1715 
1716  //**SMP multiplication assignment to dense matrices*********************************************
1717  // No special implementation for the SMP multiplication assignment to dense matrices.
1718  //**********************************************************************************************
1719 
1720  //**SMP multiplication assignment to sparse matrices********************************************
1721  // No special implementation for the SMP multiplication assignment to sparse matrices.
1722  //**********************************************************************************************
1723 
1724  //**Compile time checks*************************************************************************
1732  //**********************************************************************************************
1733 };
1734 //*************************************************************************************************
1735 
1736 
1737 
1738 
1739 //=================================================================================================
1740 //
1741 // GLOBAL BINARY ARITHMETIC OPERATORS
1742 //
1743 //=================================================================================================
1744 
1745 //*************************************************************************************************
1776 template< typename T1 // Type of the left-hand side sparse matrix
1777  , typename T2 > // Type of the right-hand side dense matrix
1778 inline const TSMatDMatMultExpr<T1,T2>
1780 {
1782 
1783  if( (~lhs).columns() != (~rhs).rows() ) {
1784  BLAZE_THROW_INVALID_ARGUMENT( "Matrix sizes do not match" );
1785  }
1786 
1787  return TSMatDMatMultExpr<T1,T2>( ~lhs, ~rhs );
1788 }
1789 //*************************************************************************************************
1790 
1791 
1792 
1793 
1794 //=================================================================================================
1795 //
1796 // ROWS SPECIALIZATIONS
1797 //
1798 //=================================================================================================
1799 
1800 //*************************************************************************************************
1802 template< typename MT1, typename MT2 >
1803 struct Rows< TSMatDMatMultExpr<MT1,MT2> > : public Rows<MT1>
1804 {};
1806 //*************************************************************************************************
1807 
1808 
1809 
1810 
1811 //=================================================================================================
1812 //
1813 // COLUMNS SPECIALIZATIONS
1814 //
1815 //=================================================================================================
1816 
1817 //*************************************************************************************************
1819 template< typename MT1, typename MT2 >
1820 struct Columns< TSMatDMatMultExpr<MT1,MT2> > : public Columns<MT2>
1821 {};
1823 //*************************************************************************************************
1824 
1825 
1826 
1827 
1828 //=================================================================================================
1829 //
1830 // ISALIGNED SPECIALIZATIONS
1831 //
1832 //=================================================================================================
1833 
1834 //*************************************************************************************************
1836 template< typename MT1, typename MT2 >
1837 struct IsAligned< TSMatDMatMultExpr<MT1,MT2> > : public IsTrue< IsAligned<MT2>::value >
1838 {};
1840 //*************************************************************************************************
1841 
1842 
1843 
1844 
1845 //=================================================================================================
1846 //
1847 // ISLOWER SPECIALIZATIONS
1848 //
1849 //=================================================================================================
1850 
1851 //*************************************************************************************************
1853 template< typename MT1, typename MT2 >
1854 struct IsLower< TSMatDMatMultExpr<MT1,MT2> >
1855  : public IsTrue< And< IsLower<MT1>, IsLower<MT2> >::value >
1856 {};
1858 //*************************************************************************************************
1859 
1860 
1861 
1862 
1863 //=================================================================================================
1864 //
1865 // ISUNILOWER SPECIALIZATIONS
1866 //
1867 //=================================================================================================
1868 
1869 //*************************************************************************************************
1871 template< typename MT1, typename MT2 >
1872 struct IsUniLower< TSMatDMatMultExpr<MT1,MT2> >
1873  : public IsTrue< And< IsUniLower<MT1>, IsUniLower<MT2> >::value >
1874 {};
1876 //*************************************************************************************************
1877 
1878 
1879 
1880 
1881 //=================================================================================================
1882 //
1883 // ISSTRICTLYLOWER SPECIALIZATIONS
1884 //
1885 //=================================================================================================
1886 
1887 //*************************************************************************************************
1889 template< typename MT1, typename MT2 >
1890 struct IsStrictlyLower< TSMatDMatMultExpr<MT1,MT2> >
1891  : public IsTrue< Or< And< IsStrictlyLower<MT1>, IsLower<MT2> >
1892  , And< IsStrictlyLower<MT2>, IsLower<MT1> > >::value >
1893 {};
1895 //*************************************************************************************************
1896 
1897 
1898 
1899 
1900 //=================================================================================================
1901 //
1902 // ISUPPER SPECIALIZATIONS
1903 //
1904 //=================================================================================================
1905 
1906 //*************************************************************************************************
1908 template< typename MT1, typename MT2 >
1909 struct IsUpper< TSMatDMatMultExpr<MT1,MT2> >
1910  : public IsTrue< And< IsUpper<MT1>, IsUpper<MT2> >::value >
1911 {};
1913 //*************************************************************************************************
1914 
1915 
1916 
1917 
1918 //=================================================================================================
1919 //
1920 // ISUNIUPPER SPECIALIZATIONS
1921 //
1922 //=================================================================================================
1923 
1924 //*************************************************************************************************
1926 template< typename MT1, typename MT2 >
1927 struct IsUniUpper< TSMatDMatMultExpr<MT1,MT2> >
1928  : public IsTrue< And< IsUniUpper<MT1>, IsUniUpper<MT2> >::value >
1929 {};
1931 //*************************************************************************************************
1932 
1933 
1934 
1935 
1936 //=================================================================================================
1937 //
1938 // ISSTRICTLYUPPER SPECIALIZATIONS
1939 //
1940 //=================================================================================================
1941 
1942 //*************************************************************************************************
1944 template< typename MT1, typename MT2 >
1945 struct IsStrictlyUpper< TSMatDMatMultExpr<MT1,MT2> >
1946  : public IsTrue< Or< And< IsStrictlyUpper<MT1>, IsUpper<MT2> >
1947  , And< IsStrictlyUpper<MT2>, IsUpper<MT1> > >::value >
1948 {};
1950 //*************************************************************************************************
1951 
1952 
1953 
1954 
1955 //=================================================================================================
1956 //
1957 // EXPRESSION TRAIT SPECIALIZATIONS
1958 //
1959 //=================================================================================================
1960 
1961 //*************************************************************************************************
1963 template< typename MT1, typename MT2, typename VT >
1964 struct TDMatDVecMultExprTrait< TSMatDMatMultExpr<MT1,MT2>, VT >
1965 {
1966  public:
1967  //**********************************************************************************************
1968  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
1969  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value &&
1970  IsDenseVector<VT>::value && IsColumnVector<VT>::value
1971  , typename TSMatDVecMultExprTrait< MT1, typename DMatDVecMultExprTrait<MT2,VT>::Type >::Type
1972  , INVALID_TYPE >::Type Type;
1973  //**********************************************************************************************
1974 };
1976 //*************************************************************************************************
1977 
1978 
1979 //*************************************************************************************************
1981 template< typename MT1, typename MT2, typename VT >
1982 struct TDMatSVecMultExprTrait< TSMatDMatMultExpr<MT1,MT2>, VT >
1983 {
1984  public:
1985  //**********************************************************************************************
1986  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
1987  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value &&
1988  IsSparseVector<VT>::value && IsColumnVector<VT>::value
1989  , typename TSMatDVecMultExprTrait< MT1, typename DMatSVecMultExprTrait<MT2,VT>::Type >::Type
1990  , INVALID_TYPE >::Type Type;
1991  //**********************************************************************************************
1992 };
1994 //*************************************************************************************************
1995 
1996 
1997 //*************************************************************************************************
1999 template< typename VT, typename MT1, typename MT2 >
2000 struct TDVecTDMatMultExprTrait< VT, TSMatDMatMultExpr<MT1,MT2> >
2001 {
2002  public:
2003  //**********************************************************************************************
2004  typedef typename SelectType< IsDenseVector<VT>::value && IsRowVector<VT>::value &&
2005  IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
2006  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value
2007  , typename TDVecDMatMultExprTrait< typename TDVecTSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
2008  , INVALID_TYPE >::Type Type;
2009  //**********************************************************************************************
2010 };
2012 //*************************************************************************************************
2013 
2014 
2015 //*************************************************************************************************
2017 template< typename VT, typename MT1, typename MT2 >
2018 struct TSVecTDMatMultExprTrait< VT, TSMatDMatMultExpr<MT1,MT2> >
2019 {
2020  public:
2021  //**********************************************************************************************
2022  typedef typename SelectType< IsSparseVector<VT>::value && IsRowVector<VT>::value &&
2023  IsSparseMatrix<MT1>::value && IsColumnMajorMatrix<MT1>::value &&
2024  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value
2025  , typename TDVecDMatMultExprTrait< typename TDVecTSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
2026  , INVALID_TYPE >::Type Type;
2027  //**********************************************************************************************
2028 };
2030 //*************************************************************************************************
2031 
2032 
2033 //*************************************************************************************************
2035 template< typename MT1, typename MT2, bool AF >
2036 struct SubmatrixExprTrait< TSMatDMatMultExpr<MT1,MT2>, AF >
2037 {
2038  public:
2039  //**********************************************************************************************
2040  typedef typename MultExprTrait< typename SubmatrixExprTrait<const MT1,AF>::Type
2041  , typename SubmatrixExprTrait<const MT2,AF>::Type >::Type Type;
2042  //**********************************************************************************************
2043 };
2045 //*************************************************************************************************
2046 
2047 
2048 //*************************************************************************************************
2050 template< typename MT1, typename MT2 >
2051 struct RowExprTrait< TSMatDMatMultExpr<MT1,MT2> >
2052 {
2053  public:
2054  //**********************************************************************************************
2055  typedef typename MultExprTrait< typename RowExprTrait<const MT1>::Type, MT2 >::Type Type;
2056  //**********************************************************************************************
2057 };
2059 //*************************************************************************************************
2060 
2061 
2062 //*************************************************************************************************
2064 template< typename MT1, typename MT2 >
2065 struct ColumnExprTrait< TSMatDMatMultExpr<MT1,MT2> >
2066 {
2067  public:
2068  //**********************************************************************************************
2069  typedef typename MultExprTrait< MT1, typename ColumnExprTrait<const MT2>::Type >::Type Type;
2070  //**********************************************************************************************
2071 };
2073 //*************************************************************************************************
2074 
2075 } // namespace blaze
2076 
2077 #endif
LeftOperand lhs_
Left-hand side sparse matrix of the multiplication expression.
Definition: TSMatDMatMultExpr.h:402
#define BLAZE_THROW_INVALID_ARGUMENT(MESSAGE)
Macro for the emission of a std::invalid_argument exceptionThis macro encapsulates the default way of...
Definition: Exception.h:187
const MT::ElementType max(const DenseMatrix< MT, SO > &dm)
Returns the largest element of the dense matrix.
Definition: DenseMatrix.h:1729
Compile time check whether the given type is a computational expression template.This type trait clas...
Definition: IsComputation.h:89
Header file for mathematical functions.
SelectType< evaluateLeft, const RT1, CT1 >::Type LT
Type for the assignment of the left-hand side sparse matrix operand.
Definition: TSMatDMatMultExpr.h:227
Header file for the Rows type trait.
Header file for the IsUniUpper type trait.
const DMatDMatMultExpr< T1, T2 > operator*(const DenseMatrix< T1, false > &lhs, const DenseMatrix< T2, false > &rhs)
Multiplication operator for the multiplication of two row-major dense matrices ( ).
Definition: DMatDMatMultExpr.h:7820
Compile time check for triangular matrix types.This type trait tests whether or not the given templat...
Definition: IsTriangular.h:105
Header file for basic type definitions.
MT2::CompositeType CT2
Composite type of the right-hand side dense matrix expression.
Definition: TSMatDMatMultExpr.h:141
BLAZE_ALWAYS_INLINE size_t size(const Vector< VT, TF > &vector)
Returns the current size/dimension of the vector.
Definition: Vector.h:252
BLAZE_ALWAYS_INLINE MT::Iterator end(Matrix< MT, SO > &matrix, size_t i)
Returns an iterator just past the last element of row/column i.
Definition: Matrix.h:250
Header file for the IsSparseMatrix type trait.
Efficient implementation of a compressed matrix.The CompressedMatrix class template is the represent...
Definition: CompressedMatrix.h:207
Header file for the IsDiagonal type trait.
#define BLAZE_CONSTRAINT_MUST_BE_DENSE_MATRIX_TYPE(T)
Constraint on the data type.In case the given data type T is not a dense, N-dimensional matrix type...
Definition: DenseMatrix.h:79
Header file for the ColumnExprTrait class template.
Header file for the IsColumnMajorMatrix type trait.
void reset(const DiagonalProxy< MT > &proxy)
Resetting the represented element to the default initial values.
Definition: DiagonalProxy.h:507
Header file for the TSVecTSMatMultExprTrait class template.
const This & CompositeType
Data type for composite expression templates.
Definition: CompressedMatrix.h:2588
Header file for the IsRowVector type trait.
Type ElementType
Type of the sparse matrix elements.
Definition: CompressedMatrix.h:259
Header file for the And class template.
Compile time check for lower triangular matrices.This type trait tests whether or not the given templ...
Definition: IsLower.h:90
const DMatSerialExpr< MT, SO > serial(const DenseMatrix< MT, SO > &dm)
Forces the serial evaluation of the given dense matrix expression dm.
Definition: DMatSerialExpr.h:721
Header file for the Computation base class.
Header file for the MatMatMultExpr base class.
Compile time check for upper triangular matrices.This type trait tests whether or not the given templ...
Definition: IsUpper.h:90
Constraints on the storage order of matrix types.
Header file for the RequiresEvaluation type trait.
System settings for performance optimizations.
size_t rows() const
Returns the current number of rows of the matrix.
Definition: TSMatDMatMultExpr.h:321
Header file for the IsUniLower type trait.
CompressedMatrix< Type, false > OppositeType
Result type with opposite storage order for expression template evaluations.
Definition: CompressedMatrix.h:2584
Base class for dense matrices.The DenseMatrix class is a base class for all dense matrix classes...
Definition: DenseMatrix.h:70
Base class for sparse matrices.The SparseMatrix class is a base class for all sparse matrix classes...
Definition: Forward.h:117
bool canSMPAssign() const
Returns whether the expression can be used in SMP assignments.
Definition: TSMatDMatMultExpr.h:395
bool isDefault(const DiagonalProxy< MT > &proxy)
Returns whether the represented element is in default state.
Definition: DiagonalProxy.h:547
Constraint on the data type.
Constraint on the data type.
Header file for the MultExprTrait class template.
size_t columns() const
Returns the current number of columns of the matrix.
Definition: TSMatDMatMultExpr.h:331
Compile time check to query the requirement to evaluate an expression.Via this type trait it is possi...
Definition: RequiresEvaluation.h:90
Compile time type selection.The SelectType class template selects one of the two given types T1 and T...
Definition: SelectType.h:59
Header file for the DisableIf class template.
SelectType< IsExpression< MT2 >::value, const MT2, const MT2 & >::Type RightOperand
Composite type of the right-hand side dense matrix expression.
Definition: TSMatDMatMultExpr.h:224
Header file for the multiplication trait.
Header file for the IsStrictlyUpper type trait.
Header file for the IsSymmetric type trait.
SelectType< evaluateRight, const RT2, CT2 >::Type RT
Type for the assignment of the right-hand side dense matrix operand.
Definition: TSMatDMatMultExpr.h:230
Namespace of the Blaze C++ math library.
Definition: Blaze.h:57
Compile time check for row-major matrix types.This type trait tests whether or not the given template...
Definition: IsRowMajorMatrix.h:110
ResultType::OppositeType OppositeType
Result type with opposite storage order for expression template evaluations.
Definition: TSMatDMatMultExpr.h:214
#define BLAZE_CONSTRAINT_MUST_BE_COLUMN_MAJOR_MATRIX_TYPE(T)
Constraint on the data type.In case the given data type T is not a column-major dense or sparse matri...
Definition: ColumnMajorMatrix.h:79
ReturnType operator()(size_t i, size_t j) const
2D-access to the matrix elements.
Definition: TSMatDMatMultExpr.h:263
Header file for the TSVecTDMatMultExprTrait class template.
const Element * ConstIterator
Iterator over constant elements.
Definition: CompressedMatrix.h:2592
Header file for the Or class template.
Header file for the TDMatSVecMultExprTrait class template.
bool isAliased(const T *alias) const
Returns whether the expression is aliased with the given address alias.
Definition: TSMatDMatMultExpr.h:375
Header file for the TDVecTSMatMultExprTrait class template.
#define BLAZE_THROW_OUT_OF_RANGE(MESSAGE)
Macro for the emission of a std::out_of_range exceptionThis macro encapsulates the default way of Bla...
Definition: Exception.h:331
const MT::ElementType min(const DenseMatrix< MT, SO > &dm)
Returns the smallest element of the dense matrix.
Definition: DenseMatrix.h:1682
Header file for the DenseMatrix base class.
Header file for the Columns type trait.
Header file for the TSMatDVecMultExprTrait class template.
Header file for the DMatDVecMultExprTrait class template.
Header file for the IsLower type trait.
Header file for the IsAligned type trait.
TSMatDMatMultExpr(const MT1 &lhs, const MT2 &rhs)
Constructor for the TSMatDMatMultExpr class.
Definition: TSMatDMatMultExpr.h:248
#define BLAZE_CONSTRAINT_MUST_BE_REFERENCE_TYPE(T)
Constraint on the data type.In case the given data type T is not a reference type, a compilation error is created.
Definition: Reference.h:78
RT1::ElementType ET1
Element type of the left-hand side dense matrix expression.
Definition: TSMatDMatMultExpr.h:138
Header file for the IsTriangular type trait.
Constraints on the storage order of matrix types.
MultTrait< RT1, RT2 >::Type ResultType
Result type for expression template evaluations.
Definition: TSMatDMatMultExpr.h:213
Compile time check for strictly upper triangular matrices.This type trait tests whether or not the gi...
Definition: IsStrictlyUpper.h:86
Type ElementType
Type of the sparse matrix elements.
Definition: CompressedMatrix.h:2586
Header file for the SelectType class template.
Header file for the RowExprTrait class template.
Header file for all forward declarations for expression class templates.
Header file for the IsDenseMatrix type trait.
bool isAligned() const
Returns whether the operands of the expression are properly aligned in memory.
Definition: TSMatDMatMultExpr.h:385
Header file for the EnableIf class template.
Header file for the IsStrictlyLower type trait.
MT1::ResultType RT1
Result type of the left-hand side sparse matrix expression.
Definition: TSMatDMatMultExpr.h:136
Header file for the serial shim.
#define BLAZE_CONSTRAINT_MUST_FORM_VALID_MATMATMULTEXPR(T1, T2)
Constraint on the data type.In case the given data types T1 and T2 do not form a valid matrix/matrix ...
Definition: MatMatMultExpr.h:165
ResultType::TransposeType TransposeType
Transpose type for expression template evaluations.
Definition: TSMatDMatMultExpr.h:215
TSMatDMatMultExpr< MT1, MT2 > This
Type of this TSMatDMatMultExpr instance.
Definition: TSMatDMatMultExpr.h:212
EnableIf< IsDenseMatrix< MT1 > >::Type smpSubAssign(Matrix< MT1, SO1 > &lhs, const Matrix< MT2, SO2 > &rhs)
Default implementation of the SMP subtraction assignment of a matrix to dense matrix.
Definition: DenseMatrix.h:160
Header file for the IsSparseVector type trait.
#define BLAZE_CONSTRAINT_MUST_NOT_BE_SYMMETRIC_MATRIX_TYPE(T)
Constraint on the data type.In case the given data type T is a symmetric matrix type, a compilation error is created.
Definition: Symmetric.h:116
Header file for the SubmatrixExprTrait class template.
#define BLAZE_CONSTRAINT_MUST_BE_ROW_MAJOR_MATRIX_TYPE(T)
Constraint on the data type.In case the given data type T is not a row-major dense or sparse matrix t...
Definition: RowMajorMatrix.h:79
const ElementType ReturnType
Return type for expression template evaluations.
Definition: TSMatDMatMultExpr.h:217
LeftOperand leftOperand() const
Returns the left-hand side transpose sparse matrix operand.
Definition: TSMatDMatMultExpr.h:341
Header file for run time assertion macros.
Compile time check for column-major matrix types.This type trait tests whether or not the given templ...
Definition: IsColumnMajorMatrix.h:110
EnableIf< IsDenseMatrix< MT1 > >::Type smpAssign(Matrix< MT1, SO1 > &lhs, const Matrix< MT2, SO2 > &rhs)
Default implementation of the SMP assignment of a matrix to a dense matrix.
Definition: DenseMatrix.h:98
Utility type for generic codes.
Base template for the MultTrait class.
Definition: MultTrait.h:138
ReturnType at(size_t i, size_t j) const
Checked access to the matrix elements.
Definition: TSMatDMatMultExpr.h:305
RT2::ElementType ET2
Element type of the right-hand side sparse matrix expression.
Definition: TSMatDMatMultExpr.h:139
RightOperand rightOperand() const
Returns the right-hand side dense matrix operand.
Definition: TSMatDMatMultExpr.h:351
const ResultType CompositeType
Data type for composite expression templates.
Definition: TSMatDMatMultExpr.h:218
RightOperand rhs_
Right-hand side dense matrix of the multiplication expression.
Definition: TSMatDMatMultExpr.h:403
const bool useOptimizedKernels
Configuration switch for optimized kernels.This configuration switch enables/disables all optimized c...
Definition: Optimizations.h:84
Header file for the reset shim.
Header file for the isDefault shim.
MT1::CompositeType CT1
Composite type of the left-hand side sparse matrix expression.
Definition: TSMatDMatMultExpr.h:140
Constraints on the storage order of matrix types.
Header file for the RemoveReference type trait.
Substitution Failure Is Not An Error (SFINAE) class.The DisableIf class template is an auxiliary tool...
Definition: DisableIf.h:184
#define BLAZE_CONSTRAINT_MATRICES_MUST_HAVE_SAME_STORAGE_ORDER(T1, T2)
Constraint on the data type.In case either of the two given data types T1 or T2 is not a matrix type ...
Definition: StorageOrder.h:122
Header file for the IsDenseVector type trait.
bool canAlias(const T *alias) const
Returns whether the expression can alias with the given address alias.
Definition: TSMatDMatMultExpr.h:363
Compile time check for strictly lower triangular matrices.This type trait tests whether or not the gi...
Definition: IsStrictlyLower.h:86
Header file for the IsRowMajorMatrix type trait.
ResultType::ElementType ElementType
Resulting element type.
Definition: TSMatDMatMultExpr.h:216
const DMatTransExpr< MT,!SO > trans(const DenseMatrix< MT, SO > &dm)
Calculation of the transpose of the given dense matrix.
Definition: DMatTransExpr.h:944
Header file for the IsComputation type trait class.
MT2::ResultType RT2
Result type of the right-hand side dense matrix expression.
Definition: TSMatDMatMultExpr.h:137
Expression object for transpose sparse matrix-dense matrix multiplications.The TSMatDMatMultExpr clas...
Definition: Forward.h:150
Header file for the TDVecDMatMultExprTrait class template.
EnableIf< IsDenseMatrix< MT1 > >::Type smpAddAssign(Matrix< MT1, SO1 > &lhs, const Matrix< MT2, SO2 > &rhs)
Default implementation of the SMP addition assignment of a matrix to a dense matrix.
Definition: DenseMatrix.h:129
Header file for the TDMatDVecMultExprTrait class template.
#define BLAZE_FUNCTION_TRACE
Function trace macro.This macro can be used to reliably trace function calls. In case function tracin...
Definition: FunctionTrace.h:157
This ResultType
Result type for expression template evaluations.
Definition: CompressedMatrix.h:2583
Header file for the IsTrue value trait.
Header file for the TSVecDMatMultExprTrait class template.
Header file for the IsUpper type trait.
Header file for exception macros.
Header file for the DMatSVecMultExprTrait class template.
Header file for the IsColumnVector type trait.
SelectType< IsExpression< MT1 >::value, const MT1, const MT1 & >::Type LeftOperand
Composite type of the left-hand side sparse matrix expression.
Definition: TSMatDMatMultExpr.h:221
Constraint on the data type.
Header file for the IsResizable type trait.
Header file for the thresholds for matrix/vector and matrix/matrix multiplications.
#define BLAZE_INTERNAL_ASSERT(expr, msg)
Run time assertion macro for internal checks.In case of an invalid run time expression, the program execution is terminated. The BLAZE_INTERNAL_ASSERT macro can be disabled by setting the BLAZE_USER_ASSERTION flag to zero or by defining NDEBUG during the compilation.
Definition: Assert.h:101
Header file for the TDVecTDMatMultExprTrait class template.
#define BLAZE_CONSTRAINT_MUST_BE_SPARSE_MATRIX_TYPE(T)
Constraint on the data type.In case the given data type T is not a sparse, N-dimensional matrix type...
Definition: SparseMatrix.h:79
Header file for the IsExpression type trait class.
Header file for the FunctionTrace class.