All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SMatSVecMultExpr.h
Go to the documentation of this file.
1 //=================================================================================================
20 //=================================================================================================
21 
22 #ifndef _BLAZE_MATH_EXPRESSIONS_SMATSVECMULTEXPR_H_
23 #define _BLAZE_MATH_EXPRESSIONS_SMATSVECMULTEXPR_H_
24 
25 
26 //*************************************************************************************************
27 // Includes
28 //*************************************************************************************************
29 
30 #include <stdexcept>
31 #include <boost/type_traits/remove_reference.hpp>
41 #include <blaze/math/shims/Reset.h>
48 #include <blaze/util/Assert.h>
50 #include <blaze/util/DisableIf.h>
51 #include <blaze/util/EnableIf.h>
53 #include <blaze/util/SelectType.h>
54 #include <blaze/util/Types.h>
55 
56 
57 namespace blaze {
58 
59 //=================================================================================================
60 //
61 // CLASS SMATDVECMULTEXPR
62 //
63 //=================================================================================================
64 
65 //*************************************************************************************************
72 template< typename MT // Type of the left-hand side sparse matrix
73  , typename VT > // Type of the right-hand side sparse vector
74 class SMatSVecMultExpr : public SparseVector< SMatSVecMultExpr<MT,VT>, false >
75  , private Expression
76  , private Computation
77 {
78  private:
79  //**Type definitions****************************************************************************
80  typedef typename MT::ResultType MRT;
81  typedef typename VT::ResultType VRT;
82  typedef typename MT::CompositeType MCT;
83  typedef typename VT::CompositeType VCT;
84  //**********************************************************************************************
85 
86  public:
87  //**Type definitions****************************************************************************
90  typedef typename ResultType::TransposeType TransposeType;
91  typedef typename ResultType::ElementType ElementType;
92  typedef const ElementType ReturnType;
93 
95  typedef const ResultType CompositeType;
96 
98  typedef typename SelectType< IsExpression<MT>::value, const MT, const MT& >::Type LeftOperand;
99 
101  typedef typename SelectType< IsExpression<VT>::value, const VT, const VT& >::Type RightOperand;
102 
104  typedef MCT LT;
105 
107  typedef typename SelectType< IsComputation<VT>::value, const VRT, VCT >::Type RT;
108  //**********************************************************************************************
109 
110  //**Constructor*********************************************************************************
116  explicit inline SMatSVecMultExpr( const MT& mat, const VT& vec )
117  : mat_( mat ) // Left-hand side sparse matrix of the multiplication expression
118  , vec_( vec ) // Right-hand side sparse vector of the multiplication expression
119  {
120  BLAZE_INTERNAL_ASSERT( mat_.columns() == vec_.size(), "Invalid matrix and vector sizes" );
121  }
122  //**********************************************************************************************
123 
124  //**Subscript operator**************************************************************************
130  inline ReturnType operator[]( size_t index ) const {
131  BLAZE_INTERNAL_ASSERT( index < mat_.rows(), "Invalid vector access index" );
132 
133  typedef typename boost::remove_reference<MCT>::type::ConstIterator MatrixIterator;
134  typedef typename boost::remove_reference<VCT>::type::ConstIterator VectorIterator;
135 
136  ElementType res = ElementType();
137 
138  // Early exit
139  if( vec_.size() == 0UL )
140  return res;
141 
142  // Fast computation in case both the left-hand side matrix operand and the right-hand
143  // side vector operand directly provide iterators
145  {
146  MCT A( mat_ ); // Evaluation of the left-hand side sparse matrix operand
147  VCT x( vec_ ); // Evaluation of the right-hand side sparse vector operand
148 
149  MatrixIterator melem( A.begin(index) );
150  const MatrixIterator mend( A.end(index) );
151  if( melem == mend ) {
152  return res;
153  }
154 
155  VectorIterator velem( x.begin() );
156  const VectorIterator vend( x.end() );
157  if( velem == vend ) {
158  return res;
159  }
160 
161  while( true ) {
162  if( melem->index() < velem->index() ) {
163  ++melem;
164  if( melem == mend ) break;
165  }
166  else if( velem->index() < melem->index() ) {
167  ++velem;
168  if( velem == vend ) break;
169  }
170  else {
171  res = melem->value() * velem->value();
172  ++melem;
173  ++velem;
174  break;
175  }
176  }
177 
178  if( melem != mend && velem != vend )
179  {
180  while( true ) {
181  if( melem->index() < velem->index() ) {
182  ++melem;
183  if( melem == mend ) break;
184  }
185  else if( velem->index() < melem->index() ) {
186  ++velem;
187  if( velem == vend ) break;
188  }
189  else {
190  res += melem->value() * velem->value();
191  ++melem;
192  if( melem == mend ) break;
193  ++velem;
194  if( velem == vend ) break;
195  }
196  }
197  }
198  }
199 
200  // Optimized computation in case the left-hand side matrix operand directly provides iterators
202  {
203  MCT A( mat_ ); // Evaluation of the left-hand side sparse matrix operand
204 
205  MatrixIterator melem( A.begin(index) );
206  const MatrixIterator mend( A.end(index) );
207 
208  if( melem == mend )
209  return res;
210 
211  res = melem->value() * vec_[melem->index()];
212  ++melem;
213  for( ; melem!=mend; ++melem ) {
214  res += melem->value() * vec_[melem->index()];
215  }
216  }
217 
218  // Optimized computation in case the right-hand side vector operand directly provides iterators
220  {
221  VCT x( vec_ ); // Evaluation of the right-hand side sparse vector operand
222 
223  VectorIterator velem( x.begin() );
224  const VectorIterator vend( x.end() );
225 
226  if( velem == vend )
227  return res;
228 
229  res = mat_(index,velem->index()) * velem->value();
230  ++velem;
231  for( ; velem!=vend; ++velem ) {
232  res += mat_(index,velem->index()) * velem->value();
233  }
234  }
235 
236  // Default computation in case both operands don't provide iterators
237  else {
238  res = mat_(index,0UL) * vec_[0UL];
239  for( size_t j=1UL; j<vec_.size(); ++j ) {
240  res += mat_(index,j) * vec_[j];
241  }
242  }
243 
244  return res;
245  }
246  //**********************************************************************************************
247 
248  //**Size function*******************************************************************************
253  inline size_t size() const {
254  return mat_.rows();
255  }
256  //**********************************************************************************************
257 
258  //**NonZeros function***************************************************************************
263  inline size_t nonZeros() const {
264  return mat_.rows();
265  }
266  //**********************************************************************************************
267 
268  //**Left function*******************************************************************************
273  inline LeftOperand leftOperand() const {
274  return mat_;
275  }
276  //**********************************************************************************************
277 
278  //**Right function******************************************************************************
283  inline RightOperand rightOperand() const {
284  return vec_;
285  }
286  //**********************************************************************************************
287 
288  //**********************************************************************************************
294  template< typename T >
295  inline bool canAlias( const T* alias ) const {
296  return ( mat_.isAliased( alias ) || vec_.isAliased( alias ) );
297  }
298  //**********************************************************************************************
299 
300  //**********************************************************************************************
306  template< typename T >
307  inline bool isAliased( const T* alias ) const {
308  return ( mat_.isAliased( alias ) || vec_.isAliased( alias ) );
309  }
310  //**********************************************************************************************
311 
312  private:
313  //**Member variables****************************************************************************
316  //**********************************************************************************************
317 
318  //**Assignment to dense vectors*****************************************************************
330  template< typename VT1 > // Type of the target dense vector
331  friend inline void assign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
332  {
334 
335  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
336 
337  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
338  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
339 
340  // Resetting the left-hand side target dense vector
341  reset( ~lhs );
342 
343  // Evaluation of the right-hand side sparse vector operand
344  RT x( rhs.vec_ );
345  if( x.nonZeros() == 0UL ) return;
346 
347  // Evaluation of the left-hand side sparse matrix operand
348  LT A( rhs.mat_ );
349 
350  // Checking the evaluated operators
351  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
352  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
353  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
354  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
355 
356  // Performing the sparse matrix-sparse vector multiplication
357  const VectorIterator vend( x.end() );
358 
359  for( size_t i=0UL; i<(~lhs).size(); ++i )
360  {
361  const MatrixIterator mend ( A.end(i) );
362  MatrixIterator melem( A.begin(i) );
363 
364  if( melem == mend ) continue;
365 
366  VectorIterator velem( x.begin() );
367 
368  while( true ) {
369  if( melem->index() < velem->index() ) {
370  ++melem;
371  if( melem == mend ) break;
372  }
373  else if( velem->index() < melem->index() ) {
374  ++velem;
375  if( velem == vend ) break;
376  }
377  else {
378  (~lhs)[i] = melem->value() * velem->value();
379  ++melem;
380  ++velem;
381  break;
382  }
383  }
384 
385  if( melem != mend && velem != vend )
386  {
387  while( true ) {
388  if( melem->index() < velem->index() ) {
389  ++melem;
390  if( melem == mend ) break;
391  }
392  else if( velem->index() < melem->index() ) {
393  ++velem;
394  if( velem == vend ) break;
395  }
396  else {
397  (~lhs)[i] += melem->value() * velem->value();
398  ++melem;
399  if( melem == mend ) break;
400  ++velem;
401  if( velem == vend ) break;
402  }
403  }
404  }
405  }
406  }
408  //**********************************************************************************************
409 
410  //**Assignment to sparse vectors****************************************************************
422  template< typename VT1 > // Type of the target sparse vector
423  friend inline void assign( SparseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
424  {
426 
427  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
428 
429  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
430  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
431 
432  RT x( rhs.vec_ ); // Evaluation of the right-hand side sparse vector operand
433  if( x.nonZeros() == 0UL ) return;
434 
435  LT A( rhs.mat_ ); // Evaluation of the left-hand side sparse matrix operand
436 
437  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
438  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
439  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
440  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
441 
442  ElementType accu;
443  const VectorIterator vend( x.end() );
444 
445  for( size_t i=0UL; i<(~lhs).size(); ++i )
446  {
447  const MatrixIterator mend ( A.end(i) );
448  MatrixIterator melem( A.begin(i) );
449 
450  if( melem == mend ) continue;
451 
452  VectorIterator velem( x.begin() );
453 
454  reset( accu );
455 
456  while( true ) {
457  if( melem->index() < velem->index() ) {
458  ++melem;
459  if( melem == mend ) break;
460  }
461  else if( velem->index() < melem->index() ) {
462  ++velem;
463  if( velem == vend ) break;
464  }
465  else {
466  accu = melem->value() * velem->value();
467  ++melem;
468  ++velem;
469  break;
470  }
471  }
472 
473  if( melem != mend && velem != vend )
474  {
475  while( true ) {
476  if( melem->index() < velem->index() ) {
477  ++melem;
478  if( melem == mend ) break;
479  }
480  else if( velem->index() < melem->index() ) {
481  ++velem;
482  if( velem == vend ) break;
483  }
484  else {
485  accu += melem->value() * velem->value();
486  ++melem;
487  if( melem == mend ) break;
488  ++velem;
489  if( velem == vend ) break;
490  }
491  }
492  }
493 
494  if( !isDefault( accu ) )
495  (~lhs).insert( i, accu );
496  }
497  }
499  //**********************************************************************************************
500 
501  //**Addition assignment to dense vectors********************************************************
513  template< typename VT1 > // Type of the target dense vector
514  friend inline void addAssign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
515  {
517 
518  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
519 
520  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
521  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
522 
523  // Evaluation of the right-hand side sparse vector operand
524  RT x( rhs.vec_ );
525  if( x.nonZeros() == 0UL ) return;
526 
527  // Evaluation of the left-hand side sparse matrix operand
528  LT A( rhs.mat_ );
529 
530  // Checking the evaluated operators
531  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
532  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
533  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
534  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
535 
536  // Performing the sparse matrix-sparse vector multiplication
537  const VectorIterator vend( x.end() );
538 
539  for( size_t i=0UL; i<(~lhs).size(); ++i )
540  {
541  const MatrixIterator mend ( A.end(i) );
542  MatrixIterator melem( A.begin(i) );
543 
544  if( melem == mend ) continue;
545 
546  VectorIterator velem( x.begin() );
547 
548  while( true ) {
549  if( melem->index() < velem->index() ) {
550  ++melem;
551  if( melem == mend ) break;
552  }
553  else if( velem->index() < melem->index() ) {
554  ++velem;
555  if( velem == vend ) break;
556  }
557  else {
558  (~lhs)[i] += melem->value() * velem->value();
559  ++melem;
560  if( melem == mend ) break;
561  ++velem;
562  if( velem == vend ) break;
563  }
564  }
565  }
566  }
568  //**********************************************************************************************
569 
570  //**Addition assignment to sparse vectors*******************************************************
571  // No special implementation for the addition assignment to sparse vectors.
572  //**********************************************************************************************
573 
574  //**Subtraction assignment to dense vectors*****************************************************
586  template< typename VT1 > // Type of the target dense vector
587  friend inline void subAssign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
588  {
590 
591  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
592 
593  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
594  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
595 
596  // Evaluation of the right-hand side sparse vector operand
597  RT x( rhs.vec_ );
598  if( x.nonZeros() == 0UL ) return;
599 
600  // Evaluation of the left-hand side sparse matrix operand
601  LT A( rhs.mat_ );
602 
603  // Checking the evaluated operators
604  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
605  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
606  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
607  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
608 
609  // Performing the sparse matrix-sparse vector multiplication
610  const VectorIterator vend( x.end() );
611 
612  for( size_t i=0UL; i<(~lhs).size(); ++i )
613  {
614  const MatrixIterator mend ( A.end(i) );
615  MatrixIterator melem( A.begin(i) );
616 
617  if( melem == mend ) continue;
618 
619  VectorIterator velem( x.begin() );
620 
621  while( true ) {
622  if( melem->index() < velem->index() ) {
623  ++melem;
624  if( melem == mend ) break;
625  }
626  else if( velem->index() < melem->index() ) {
627  ++velem;
628  if( velem == vend ) break;
629  }
630  else {
631  (~lhs)[i] -= melem->value() * velem->value();
632  ++melem;
633  if( melem == mend ) break;
634  ++velem;
635  if( velem == vend ) break;
636  }
637  }
638  }
639  }
641  //**********************************************************************************************
642 
643  //**Subtraction assignment to sparse vectors****************************************************
644  // No special implementation for the subtraction assignment to sparse vectors.
645  //**********************************************************************************************
646 
647  //**Multiplication assignment to dense vectors**************************************************
659  template< typename VT1 > // Type of the target dense vector
660  friend inline void multAssign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
661  {
663 
666  BLAZE_CONSTRAINT_MUST_BE_REFERENCE_TYPE( typename ResultType::CompositeType );
667 
668  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
669 
670  const ResultType tmp( rhs );
671  multAssign( ~lhs, tmp );
672  }
674  //**********************************************************************************************
675 
676  //**Multiplication assignment to sparse vectors*************************************************
677  // No special implementation for the multiplication assignment to sparse vectors.
678  //**********************************************************************************************
679 
680  //**Compile time checks*************************************************************************
687  //**********************************************************************************************
688 };
689 //*************************************************************************************************
690 
691 
692 
693 
694 //=================================================================================================
695 //
696 // GLOBAL BINARY ARITHMETIC OPERATORS
697 //
698 //=================================================================================================
699 
700 //*************************************************************************************************
731 template< typename T1 // Type of the left-hand side sparse matrix
732  , typename T2 > // Type of the right-hand side sparse vector
733 inline const typename DisableIf< IsMatMatMultExpr<T1>, SMatSVecMultExpr<T1,T2> >::Type
735 {
737 
738  if( (~mat).columns() != (~vec).size() )
739  throw std::invalid_argument( "Matrix and vector sizes do not match" );
740 
741  return SMatSVecMultExpr<T1,T2>( ~mat, ~vec );
742 }
743 //*************************************************************************************************
744 
745 
746 
747 
748 //=================================================================================================
749 //
750 // GLOBAL RESTRUCTURING BINARY ARITHMETIC OPERATORS
751 //
752 //=================================================================================================
753 
754 //*************************************************************************************************
767 template< typename T1 // Type of the left-hand side sparse matrix
768  , bool SO // Storage order of the left-hand side sparse matrix
769  , typename T2 > // Type of the right-hand side sparse vector
770 inline const typename EnableIf< IsMatMatMultExpr<T1>, MultExprTrait<T1,T2> >::Type::Type
772 {
774 
775  return (~mat).leftOperand() * ( (~mat).rightOperand() * vec );
776 }
777 //*************************************************************************************************
778 
779 } // namespace blaze
780 
781 #endif