All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SMatDMatMultExpr.h
Go to the documentation of this file.
1 //=================================================================================================
20 //=================================================================================================
21 
22 #ifndef _BLAZE_MATH_EXPRESSIONS_SMATDMATMULTEXPR_H_
23 #define _BLAZE_MATH_EXPRESSIONS_SMATDMATMULTEXPR_H_
24 
25 
26 //*************************************************************************************************
27 // Includes
28 //*************************************************************************************************
29 
30 #include <stdexcept>
31 #include <boost/type_traits/remove_reference.hpp>
39 #include <blaze/math/shims/Reset.h>
58 #include <blaze/util/Assert.h>
59 #include <blaze/util/DisableIf.h>
60 #include <blaze/util/EnableIf.h>
61 #include <blaze/util/InvalidType.h>
62 #include <blaze/util/SelectType.h>
63 #include <blaze/util/Types.h>
64 
65 
66 namespace blaze {
67 
68 //=================================================================================================
69 //
70 // CLASS SMATDMATMULTEXPR
71 //
72 //=================================================================================================
73 
74 //*************************************************************************************************
81 template< typename MT1 // Type of the left-hand side sparse matrix
82  , typename MT2 > // Type of the right-hand side dense matrix
83 class SMatDMatMultExpr : public DenseMatrix< SMatDMatMultExpr<MT1,MT2>, false >
84  , private Expression
85  , private Computation
86 {
87  private:
88  //**Type definitions****************************************************************************
89  typedef typename MT1::ResultType RT1;
90  typedef typename MT2::ResultType RT2;
91  typedef typename MT1::ElementType ET1;
92  typedef typename MT2::ElementType ET2;
93  typedef typename MT1::CompositeType CT1;
94  typedef typename MT2::CompositeType CT2;
95  //**********************************************************************************************
96 
97  public:
98  //**Type definitions****************************************************************************
101  typedef typename ResultType::OppositeType OppositeType;
102  typedef typename ResultType::TransposeType TransposeType;
103  typedef typename ResultType::ElementType ElementType;
104  typedef const ElementType ReturnType;
105  typedef const ResultType CompositeType;
106 
108  typedef typename SelectType< IsExpression<MT1>::value, const MT1, const MT1& >::Type LeftOperand;
109 
111  typedef typename SelectType< IsExpression<MT2>::value, const MT2, const MT2& >::Type RightOperand;
112 
114  typedef typename SelectType< IsComputation<MT1>::value, const RT1, CT1 >::Type LT;
115 
117  typedef typename SelectType< IsComputation<MT2>::value, const RT2, CT2 >::Type RT;
118  //**********************************************************************************************
119 
120  //**Compilation flags***************************************************************************
122  enum { vectorizable = 0 };
123 
125  enum { canAlias = !IsComputation<MT2>::value };
126  //**********************************************************************************************
127 
128  //**Constructor*********************************************************************************
134  explicit inline SMatDMatMultExpr( const MT1& lhs, const MT2& rhs )
135  : lhs_( lhs ) // Left-hand side sparse matrix of the multiplication expression
136  , rhs_( rhs ) // Right-hand side dense matrix of the multiplication expression
137  {
138  BLAZE_INTERNAL_ASSERT( lhs.columns() == rhs.rows(), "Invalid matrix sizes" );
139  }
140  //**********************************************************************************************
141 
142  //**Access operator*****************************************************************************
149  inline ReturnType operator()( size_t i, size_t j ) const {
150  BLAZE_INTERNAL_ASSERT( i < lhs_.rows() , "Invalid row access index" );
151  BLAZE_INTERNAL_ASSERT( j < rhs_.columns(), "Invalid column access index" );
152 
153  typedef typename boost::remove_reference<CT1>::type::ConstIterator ConstIterator;
154 
155  ElementType tmp = ElementType();
156 
157  // Early exit
158  if( lhs_.columns() == 0 )
159  return tmp;
160 
161  // Fast computation in case the left-hand side sparse matrix directly provides iterators
163  {
164  CT1 A( lhs_ ); // Evaluation of the left-hand side sparse matrix operand
165 
166  const ConstIterator end( A.end(i) );
167  ConstIterator element( A.begin(i) );
168 
169  // Early exit in case row i is empty
170  if( element == end )
171  return tmp;
172 
173  // Calculating element (i,j)
174  tmp = element->value() * rhs_(element->index(),j);
175  ++element;
176  for( ; element!=end; ++element )
177  tmp += element->value() * rhs_(element->index(),j);
178  }
179 
180  // Default computation in case the left-hand side sparse matrix doesn't provide iterators
181  else {
182  tmp = lhs_(i,0) * rhs_(0,j);
183  for( size_t k=1; k<lhs_.columns(); ++k ) {
184  tmp += lhs_(i,k) * rhs_(k,j);
185  }
186  }
187 
188  return tmp;
189  }
190  //**********************************************************************************************
191 
192  //**Rows function*******************************************************************************
197  inline size_t rows() const {
198  return lhs_.rows();
199  }
200  //**********************************************************************************************
201 
202  //**Columns function****************************************************************************
207  inline size_t columns() const {
208  return rhs_.columns();
209  }
210  //**********************************************************************************************
211 
212  //**Left operand access*************************************************************************
217  inline LeftOperand leftOperand() const {
218  return lhs_;
219  }
220  //**********************************************************************************************
221 
222  //**Right operand access************************************************************************
227  inline RightOperand rightOperand() const {
228  return rhs_;
229  }
230  //**********************************************************************************************
231 
232  //**********************************************************************************************
238  template< typename T >
239  inline bool isAliased( const T* alias ) const {
240  return ( !IsComputation<MT2>::value && rhs_.isAliased( alias ) );
241  }
242  //**********************************************************************************************
243 
244  private:
245  //**Member variables****************************************************************************
248  //**********************************************************************************************
249 
250  //**Default assignment to dense matrices********************************************************
263  template< typename MT // Type of the target dense matrix
264  , bool SO > // Storage order of the target dense matrix
265  friend inline typename EnableIf< IsResizable<typename MT::ElementType> >::Type
266  assign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
267  {
268  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
269  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
270 
271  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
272 
273  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
274  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
275 
276  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
277  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
278  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
279  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
280  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
281  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
282 
283  for( size_t i=0; i<A.rows(); ++i )
284  {
285  const ConstIterator end( A.end(i) );
286 
287  for( size_t j=0; j<B.columns(); ++j )
288  {
289  ConstIterator element( A.begin(i) );
290 
291  if( element != end ) {
292  (~lhs)(i,j) = element->value() * B(element->index(),j);
293  ++element;
294  for( ; element!=end; ++element ) {
295  (~lhs)(i,j) += element->value() * B(element->index(),j);
296  }
297  }
298  else {
299  reset( (~lhs)(i,j) );
300  }
301  }
302  }
303  }
305  //**********************************************************************************************
306 
307  //**Optimized assignment to dense matrices******************************************************
320  template< typename MT // Type of the target dense matrix
321  , bool SO > // Storage order of the target dense matrix
322  friend inline typename DisableIf< IsResizable<typename MT::ElementType> >::Type
323  assign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
324  {
325  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
326  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
327 
328  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
329 
330  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
331  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
332 
333  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
334  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
335  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
336  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
337  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
338  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
339 
340  reset( ~lhs );
341 
342  BLAZE_INTERNAL_ASSERT( ( B.columns() - ( B.columns() % 4UL ) ) == ( B.columns() & size_t(-4) ), "Invalid end calculation" );
343  const size_t jend( B.columns() & size_t(-4) );
344 
345  for( size_t i=0UL; i<A.rows(); ++i ) {
346  const ConstIterator end( A.end(i) );
347  ConstIterator element( A.begin(i) );
348 
349  const size_t nonzeros( A.nonZeros(i) );
350  const size_t kend( nonzeros & size_t(-4) );
351 
352  for( size_t k=0UL; k<kend; k+=4UL ) {
353  const size_t i1( element->index() );
354  const ET1 v1( element->value() );
355  ++element;
356  const size_t i2( element->index() );
357  const ET1 v2( element->value() );
358  ++element;
359  const size_t i3( element->index() );
360  const ET1 v3( element->value() );
361  ++element;
362  const size_t i4( element->index() );
363  const ET1 v4( element->value() );
364  ++element;
365 
366  for( size_t j=0UL; j<jend; j+=4UL ) {
367  (~lhs)(i,j ) += v1 * B(i1,j ) + v2 * B(i2,j ) + v3 * B(i3,j ) + v4 * B(i4,j );
368  (~lhs)(i,j+1UL) += v1 * B(i1,j+1UL) + v2 * B(i2,j+1UL) + v3 * B(i3,j+1UL) + v4 * B(i4,j+1UL);
369  (~lhs)(i,j+2UL) += v1 * B(i1,j+2UL) + v2 * B(i2,j+2UL) + v3 * B(i3,j+2UL) + v4 * B(i4,j+2UL);
370  (~lhs)(i,j+3UL) += v1 * B(i1,j+3UL) + v2 * B(i2,j+3UL) + v3 * B(i3,j+3UL) + v4 * B(i4,j+3UL);
371  }
372  for( size_t j=jend; j<B.columns(); ++j ) {
373  (~lhs)(i,j) += v1 * B(i1,j) + v2 * B(i2,j) + v3 * B(i3,j) + v4 * B(i4,j);
374  }
375  }
376 
377  for( ; element!=end; ++element ) {
378  for( size_t j=0UL; j<jend; j+=4UL ) {
379  (~lhs)(i,j ) += element->value() * B(element->index(),j );
380  (~lhs)(i,j+1UL) += element->value() * B(element->index(),j+1UL);
381  (~lhs)(i,j+2UL) += element->value() * B(element->index(),j+2UL);
382  (~lhs)(i,j+3UL) += element->value() * B(element->index(),j+3UL);
383  }
384  for( size_t j=jend; j<B.columns(); ++j ) {
385  (~lhs)(i,j) += element->value() * B(element->index(),j);
386  }
387  }
388  }
389  }
391  //**********************************************************************************************
392 
393  //**Assignment to sparse matrices***************************************************************
405  template< typename MT // Type of the target sparse matrix
406  , bool SO > // Storage order of the target sparse matrix
407  friend inline void assign( SparseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
408  {
409  typedef typename SelectType< SO, OppositeType, ResultType >::Type TmpType;
410 
416  BLAZE_CONSTRAINT_MUST_BE_REFERENCE_TYPE( typename TmpType::CompositeType );
417 
418  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
419  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
420 
421  const TmpType tmp( rhs );
422  assign( ~lhs, tmp );
423  }
425  //**********************************************************************************************
426 
427  //**Addition assignment to dense matrices*******************************************************
439  template< typename MT // Type of the target dense matrix
440  , bool SO > // Storage order of the target dense matrix
441  friend inline void addAssign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
442  {
443  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
444  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
445 
446  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
447 
448  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
449  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
450 
451  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
452  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
453  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
454  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
455  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
456  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
457 
458  BLAZE_INTERNAL_ASSERT( ( B.columns() - ( B.columns() % 4UL ) ) == ( B.columns() & size_t(-4) ), "Invalid end calculation" );
459  const size_t kend( B.columns() & size_t(-4) );
460 
461  for( size_t i=0UL; i<A.rows(); ++i ) {
462  const ConstIterator end( A.end(i) );
463  ConstIterator element( A.begin(i) );
464  for( ; element!=end; ++element ) {
465  for( size_t k=0UL; k<kend; k+=4UL ) {
466  (~lhs)(i,k ) += element->value() * B(element->index(),k );
467  (~lhs)(i,k+1UL) += element->value() * B(element->index(),k+1UL);
468  (~lhs)(i,k+2UL) += element->value() * B(element->index(),k+2UL);
469  (~lhs)(i,k+3UL) += element->value() * B(element->index(),k+3UL);
470  }
471  for( size_t k=kend; k<B.columns(); ++k ) {
472  (~lhs)(i,k) += element->value() * B(element->index(),k);
473  }
474  }
475  }
476  }
478  //**********************************************************************************************
479 
480  //**Addition assignment to sparse matrices******************************************************
481  // No special implementation for the addition assignment to sparse matrices.
482  //**********************************************************************************************
483 
484  //**Subtraction assignment to dense matrices****************************************************
496  template< typename MT // Type of the target dense matrix
497  , bool SO > // Storage order of the target dense matrix
498  friend inline void subAssign( DenseMatrix<MT,SO>& lhs, const SMatDMatMultExpr& rhs )
499  {
500  BLAZE_INTERNAL_ASSERT( (~lhs).rows() == rhs.rows() , "Invalid number of rows" );
501  BLAZE_INTERNAL_ASSERT( (~lhs).columns() == rhs.columns(), "Invalid number of columns" );
502 
503  typedef typename boost::remove_reference<LT>::type::ConstIterator ConstIterator;
504 
505  LT A( rhs.lhs_ ); // Evaluation of the left-hand side sparse matrix operand
506  RT B( rhs.rhs_ ); // Evaluation of the right-hand side dense matrix operand
507 
508  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.lhs_.rows() , "Invalid number of rows" );
509  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.lhs_.columns(), "Invalid number of columns" );
510  BLAZE_INTERNAL_ASSERT( B.rows() == rhs.rhs_.rows() , "Invalid number of rows" );
511  BLAZE_INTERNAL_ASSERT( B.columns() == rhs.rhs_.columns(), "Invalid number of columns" );
512  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).rows() , "Invalid number of rows" );
513  BLAZE_INTERNAL_ASSERT( B.columns() == (~lhs).columns() , "Invalid number of columns" );
514 
515  BLAZE_INTERNAL_ASSERT( ( B.columns() - ( B.columns() % 4UL ) ) == ( B.columns() & size_t(-4) ), "Invalid end calculation" );
516  const size_t kend( B.columns() & size_t(-4) );
517 
518  for( size_t i=0UL; i<A.rows(); ++i ) {
519  const ConstIterator end( A.end(i) );
520  ConstIterator element( A.begin(i) );
521  for( ; element!=end; ++element ) {
522  for( size_t k=0UL; k<kend; k+=4UL ) {
523  (~lhs)(i,k ) -= element->value() * B(element->index(),k );
524  (~lhs)(i,k+1UL) -= element->value() * B(element->index(),k+1UL);
525  (~lhs)(i,k+2UL) -= element->value() * B(element->index(),k+2UL);
526  (~lhs)(i,k+3UL) -= element->value() * B(element->index(),k+3UL);
527  }
528  for( size_t k=kend; k<B.columns(); ++k ) {
529  (~lhs)(i,k) -= element->value() * B(element->index(),k);
530  }
531  }
532  }
533  }
535  //**********************************************************************************************
536 
537  //**Subtraction assignment to sparse matrices***************************************************
538  // No special implementation for the subtraction assignment to sparse matrices.
539  //**********************************************************************************************
540 
541  //**Multiplication assignment to dense matrices*************************************************
542  // No special implementation for the multiplication assignment to dense matrices.
543  //**********************************************************************************************
544 
545  //**Multiplication assignment to sparse matrices************************************************
546  // No special implementation for the multiplication assignment to sparse matrices.
547  //**********************************************************************************************
548 
549  //**Compile time checks*************************************************************************
556  //**********************************************************************************************
557 };
558 //*************************************************************************************************
559 
560 
561 
562 
563 //=================================================================================================
564 //
565 // GLOBAL BINARY ARITHMETIC OPERATORS
566 //
567 //=================================================================================================
568 
569 //*************************************************************************************************
598 template< typename T1 // Type of the left-hand side sparse matrix
599  , typename T2 > // Type of the right-hand side dense matrix
600 inline const SMatDMatMultExpr<T1,T2>
602 {
603  if( (~lhs).columns() != (~rhs).rows() )
604  throw std::invalid_argument( "Matrix sizes do not match" );
605 
606  return SMatDMatMultExpr<T1,T2>( ~lhs, ~rhs );
607 }
608 //*************************************************************************************************
609 
610 
611 
612 
613 //=================================================================================================
614 //
615 // EXPRESSION TRAIT SPECIALIZATIONS
616 //
617 //=================================================================================================
618 
619 //*************************************************************************************************
621 template< typename MT1, typename MT2, typename VT >
622 struct DMatDVecMultExprTrait< SMatDMatMultExpr<MT1,MT2>, VT >
623 {
624  public:
625  //**********************************************************************************************
626  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
627  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value &&
628  IsDenseVector<VT>::value && !IsTransposeVector<VT>::value
629  , typename SMatDVecMultExprTrait< MT1, typename DMatDVecMultExprTrait<MT2,VT>::Type >::Type
630  , INVALID_TYPE >::Type Type;
631  //**********************************************************************************************
632 };
634 //*************************************************************************************************
635 
636 
637 //*************************************************************************************************
639 template< typename MT1, typename MT2, typename VT >
640 struct DMatSVecMultExprTrait< SMatDMatMultExpr<MT1,MT2>, VT >
641 {
642  public:
643  //**********************************************************************************************
644  typedef typename SelectType< IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
645  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value &&
646  IsSparseVector<VT>::value && !IsTransposeVector<VT>::value
647  , typename SMatDVecMultExprTrait< MT1, typename DMatSVecMultExprTrait<MT2,VT>::Type >::Type
648  , INVALID_TYPE >::Type Type;
649  //**********************************************************************************************
650 };
652 //*************************************************************************************************
653 
654 
655 //*************************************************************************************************
657 template< typename VT, typename MT1, typename MT2 >
658 struct TDVecDMatMultExprTrait< VT, SMatDMatMultExpr<MT1,MT2> >
659 {
660  public:
661  //**********************************************************************************************
662  typedef typename SelectType< IsDenseVector<VT>::value && IsTransposeVector<VT>::value &&
663  IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
664  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value
665  , typename TDVecDMatMultExprTrait< typename TDVecSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
666  , INVALID_TYPE >::Type Type;
667  //**********************************************************************************************
668 };
670 //*************************************************************************************************
671 
672 
673 //*************************************************************************************************
675 template< typename VT, typename MT1, typename MT2 >
676 struct TSVecDMatMultExprTrait< VT, SMatDMatMultExpr<MT1,MT2> >
677 {
678  public:
679  //**********************************************************************************************
680  typedef typename SelectType< IsSparseVector<VT>::value && IsTransposeVector<VT>::value &&
681  IsSparseMatrix<MT1>::value && IsRowMajorMatrix<MT1>::value &&
682  IsDenseMatrix<MT2>::value && IsRowMajorMatrix<MT2>::value
683  , typename TSVecDMatMultExprTrait< typename TSVecSMatMultExprTrait<VT,MT1>::Type, MT2 >::Type
684  , INVALID_TYPE >::Type Type;
685  //**********************************************************************************************
686 };
688 //*************************************************************************************************
689 
690 } // namespace blaze
691 
692 #endif