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>
49 #include <blaze/util/Assert.h>
51 #include <blaze/util/DisableIf.h>
52 #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  //**Compilation flags***************************************************************************
114  //**********************************************************************************************
115 
116  //**Constructor*********************************************************************************
122  explicit inline SMatSVecMultExpr( const MT& mat, const VT& vec )
123  : mat_( mat ) // Left-hand side sparse matrix of the multiplication expression
124  , vec_( vec ) // Right-hand side sparse vector of the multiplication expression
125  {
126  BLAZE_INTERNAL_ASSERT( mat_.columns() == vec_.size(), "Invalid matrix and vector sizes" );
127  }
128  //**********************************************************************************************
129 
130  //**Subscript operator**************************************************************************
136  inline ReturnType operator[]( size_t index ) const {
137  BLAZE_INTERNAL_ASSERT( index < mat_.rows(), "Invalid vector access index" );
138 
139  typedef typename boost::remove_reference<MCT>::type::ConstIterator MatrixIterator;
140  typedef typename boost::remove_reference<VCT>::type::ConstIterator VectorIterator;
141 
142  ElementType res = ElementType();
143 
144  // Early exit
145  if( vec_.size() == 0UL )
146  return res;
147 
148  // Fast computation in case both the left-hand side matrix operand and the right-hand
149  // side vector operand directly provide iterators
151  {
152  MCT A( mat_ ); // Evaluation of the left-hand side sparse matrix operand
153  VCT x( vec_ ); // Evaluation of the right-hand side sparse vector operand
154 
155  MatrixIterator melem( A.begin(index) );
156  const MatrixIterator mend( A.end(index) );
157  if( melem == mend ) {
158  return res;
159  }
160 
161  VectorIterator velem( x.begin() );
162  const VectorIterator vend( x.end() );
163  if( velem == vend ) {
164  return res;
165  }
166 
167  while( true ) {
168  if( melem->index() < velem->index() ) {
169  ++melem;
170  if( melem == mend ) break;
171  }
172  else if( velem->index() < melem->index() ) {
173  ++velem;
174  if( velem == vend ) break;
175  }
176  else {
177  res = melem->value() * velem->value();
178  ++melem;
179  ++velem;
180  break;
181  }
182  }
183 
184  if( melem != mend && velem != vend )
185  {
186  while( true ) {
187  if( melem->index() < velem->index() ) {
188  ++melem;
189  if( melem == mend ) break;
190  }
191  else if( velem->index() < melem->index() ) {
192  ++velem;
193  if( velem == vend ) break;
194  }
195  else {
196  res += melem->value() * velem->value();
197  ++melem;
198  if( melem == mend ) break;
199  ++velem;
200  if( velem == vend ) break;
201  }
202  }
203  }
204  }
205 
206  // Optimized computation in case the left-hand side matrix operand directly provides iterators
208  {
209  MCT A( mat_ ); // Evaluation of the left-hand side sparse matrix operand
210 
211  MatrixIterator melem( A.begin(index) );
212  const MatrixIterator mend( A.end(index) );
213 
214  if( melem == mend )
215  return res;
216 
217  res = melem->value() * vec_[melem->index()];
218  ++melem;
219  for( ; melem!=mend; ++melem ) {
220  res += melem->value() * vec_[melem->index()];
221  }
222  }
223 
224  // Optimized computation in case the right-hand side vector operand directly provides iterators
226  {
227  VCT x( vec_ ); // Evaluation of the right-hand side sparse vector operand
228 
229  VectorIterator velem( x.begin() );
230  const VectorIterator vend( x.end() );
231 
232  if( velem == vend )
233  return res;
234 
235  res = mat_(index,velem->index()) * velem->value();
236  ++velem;
237  for( ; velem!=vend; ++velem ) {
238  res += mat_(index,velem->index()) * velem->value();
239  }
240  }
241 
242  // Default computation in case both operands don't provide iterators
243  else {
244  res = mat_(index,0UL) * vec_[0UL];
245  for( size_t j=1UL; j<vec_.size(); ++j ) {
246  res += mat_(index,j) * vec_[j];
247  }
248  }
249 
250  return res;
251  }
252  //**********************************************************************************************
253 
254  //**Size function*******************************************************************************
259  inline size_t size() const {
260  return mat_.rows();
261  }
262  //**********************************************************************************************
263 
264  //**NonZeros function***************************************************************************
269  inline size_t nonZeros() const {
270  return mat_.rows();
271  }
272  //**********************************************************************************************
273 
274  //**Left function*******************************************************************************
279  inline LeftOperand leftOperand() const {
280  return mat_;
281  }
282  //**********************************************************************************************
283 
284  //**Right function******************************************************************************
289  inline RightOperand rightOperand() const {
290  return vec_;
291  }
292  //**********************************************************************************************
293 
294  //**********************************************************************************************
300  template< typename T >
301  inline bool isAliased( const T* alias ) const {
303  CanAlias<MT>::value && mat_.isAliased( alias ) ) ||
304  ( !IsComputation<VT>::value && vec_.isAliased( alias ) );
305  }
306  //**********************************************************************************************
307 
308  private:
309  //**Member variables****************************************************************************
312  //**********************************************************************************************
313 
314  //**Assignment to dense vectors*****************************************************************
326  template< typename VT1 > // Type of the target dense vector
327  friend inline void assign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
328  {
329  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
330 
331  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
332  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
333 
334  // Resetting the left-hand side target dense vector
335  reset( ~lhs );
336 
337  // Evaluation of the right-hand side sparse vector operand
338  RT x( rhs.vec_ );
339  if( x.nonZeros() == 0UL ) return;
340 
341  // Evaluation of the left-hand side sparse matrix operand
342  LT A( rhs.mat_ );
343 
344  // Checking the evaluated operators
345  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
346  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
347  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
348  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
349 
350  // Performing the sparse matrix-sparse vector multiplication
351  const VectorIterator vend( x.end() );
352 
353  for( size_t i=0UL; i<(~lhs).size(); ++i )
354  {
355  const MatrixIterator mend ( A.end(i) );
356  MatrixIterator melem( A.begin(i) );
357 
358  if( melem == mend ) continue;
359 
360  VectorIterator velem( x.begin() );
361 
362  while( true ) {
363  if( melem->index() < velem->index() ) {
364  ++melem;
365  if( melem == mend ) break;
366  }
367  else if( velem->index() < melem->index() ) {
368  ++velem;
369  if( velem == vend ) break;
370  }
371  else {
372  (~lhs)[i] = melem->value() * velem->value();
373  ++melem;
374  ++velem;
375  break;
376  }
377  }
378 
379  if( melem != mend && velem != vend )
380  {
381  while( true ) {
382  if( melem->index() < velem->index() ) {
383  ++melem;
384  if( melem == mend ) break;
385  }
386  else if( velem->index() < melem->index() ) {
387  ++velem;
388  if( velem == vend ) break;
389  }
390  else {
391  (~lhs)[i] += melem->value() * velem->value();
392  ++melem;
393  if( melem == mend ) break;
394  ++velem;
395  if( velem == vend ) break;
396  }
397  }
398  }
399  }
400  }
402  //**********************************************************************************************
403 
404  //**Assignment to sparse vectors****************************************************************
416  template< typename VT1 > // Type of the target sparse vector
417  friend inline void assign( SparseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
418  {
419  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
420 
421  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
422  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
423 
424  RT x( rhs.vec_ ); // Evaluation of the right-hand side sparse vector operand
425  if( x.nonZeros() == 0UL ) return;
426 
427  LT A( rhs.mat_ ); // Evaluation of the left-hand side sparse matrix operand
428 
429  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
430  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
431  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
432  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
433 
434  ElementType accu;
435  const VectorIterator vend( x.end() );
436 
437  for( size_t i=0UL; i<(~lhs).size(); ++i )
438  {
439  const MatrixIterator mend ( A.end(i) );
440  MatrixIterator melem( A.begin(i) );
441 
442  if( melem == mend ) continue;
443 
444  VectorIterator velem( x.begin() );
445 
446  reset( accu );
447 
448  while( true ) {
449  if( melem->index() < velem->index() ) {
450  ++melem;
451  if( melem == mend ) break;
452  }
453  else if( velem->index() < melem->index() ) {
454  ++velem;
455  if( velem == vend ) break;
456  }
457  else {
458  accu = melem->value() * velem->value();
459  ++melem;
460  ++velem;
461  break;
462  }
463  }
464 
465  if( melem != mend && velem != vend )
466  {
467  while( true ) {
468  if( melem->index() < velem->index() ) {
469  ++melem;
470  if( melem == mend ) break;
471  }
472  else if( velem->index() < melem->index() ) {
473  ++velem;
474  if( velem == vend ) break;
475  }
476  else {
477  accu += melem->value() * velem->value();
478  ++melem;
479  if( melem == mend ) break;
480  ++velem;
481  if( velem == vend ) break;
482  }
483  }
484  }
485 
486  if( !isDefault( accu ) )
487  (~lhs).insert( i, accu );
488  }
489  }
491  //**********************************************************************************************
492 
493  //**Addition assignment to dense vectors********************************************************
505  template< typename VT1 > // Type of the target dense vector
506  friend inline void addAssign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
507  {
508  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
509 
510  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
511  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
512 
513  // Evaluation of the right-hand side sparse vector operand
514  RT x( rhs.vec_ );
515  if( x.nonZeros() == 0UL ) return;
516 
517  // Evaluation of the left-hand side sparse matrix operand
518  LT A( rhs.mat_ );
519 
520  // Checking the evaluated operators
521  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
522  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
523  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
524  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
525 
526  // Performing the sparse matrix-sparse vector multiplication
527  const VectorIterator vend( x.end() );
528 
529  for( size_t i=0UL; i<(~lhs).size(); ++i )
530  {
531  const MatrixIterator mend ( A.end(i) );
532  MatrixIterator melem( A.begin(i) );
533 
534  if( melem == mend ) continue;
535 
536  VectorIterator velem( x.begin() );
537 
538  while( true ) {
539  if( melem->index() < velem->index() ) {
540  ++melem;
541  if( melem == mend ) break;
542  }
543  else if( velem->index() < melem->index() ) {
544  ++velem;
545  if( velem == vend ) break;
546  }
547  else {
548  (~lhs)[i] += melem->value() * velem->value();
549  ++melem;
550  if( melem == mend ) break;
551  ++velem;
552  if( velem == vend ) break;
553  }
554  }
555  }
556  }
558  //**********************************************************************************************
559 
560  //**Addition assignment to sparse vectors*******************************************************
561  // No special implementation for the addition assignment to sparse vectors.
562  //**********************************************************************************************
563 
564  //**Subtraction assignment to dense vectors*****************************************************
576  template< typename VT1 > // Type of the target dense vector
577  friend inline void subAssign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
578  {
579  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
580 
581  typedef typename boost::remove_reference<LT>::type::ConstIterator MatrixIterator;
582  typedef typename boost::remove_reference<RT>::type::ConstIterator VectorIterator;
583 
584  // Evaluation of the right-hand side sparse vector operand
585  RT x( rhs.vec_ );
586  if( x.nonZeros() == 0UL ) return;
587 
588  // Evaluation of the left-hand side sparse matrix operand
589  LT A( rhs.mat_ );
590 
591  // Checking the evaluated operators
592  BLAZE_INTERNAL_ASSERT( A.rows() == rhs.mat_.rows() , "Invalid number of rows" );
593  BLAZE_INTERNAL_ASSERT( A.columns() == rhs.mat_.columns(), "Invalid number of columns" );
594  BLAZE_INTERNAL_ASSERT( x.size() == rhs.vec_.size() , "Invalid vector size" );
595  BLAZE_INTERNAL_ASSERT( A.rows() == (~lhs).size() , "Invalid vector size" );
596 
597  // Performing the sparse matrix-sparse vector multiplication
598  const VectorIterator vend( x.end() );
599 
600  for( size_t i=0UL; i<(~lhs).size(); ++i )
601  {
602  const MatrixIterator mend ( A.end(i) );
603  MatrixIterator melem( A.begin(i) );
604 
605  if( melem == mend ) continue;
606 
607  VectorIterator velem( x.begin() );
608 
609  while( true ) {
610  if( melem->index() < velem->index() ) {
611  ++melem;
612  if( melem == mend ) break;
613  }
614  else if( velem->index() < melem->index() ) {
615  ++velem;
616  if( velem == vend ) break;
617  }
618  else {
619  (~lhs)[i] -= melem->value() * velem->value();
620  ++melem;
621  if( melem == mend ) break;
622  ++velem;
623  if( velem == vend ) break;
624  }
625  }
626  }
627  }
629  //**********************************************************************************************
630 
631  //**Subtraction assignment to sparse vectors****************************************************
632  // No special implementation for the subtraction assignment to sparse vectors.
633  //**********************************************************************************************
634 
635  //**Multiplication assignment to dense vectors**************************************************
647  template< typename VT1 > // Type of the target dense vector
648  friend inline void multAssign( DenseVector<VT1,false>& lhs, const SMatSVecMultExpr& rhs )
649  {
652  BLAZE_CONSTRAINT_MUST_BE_REFERENCE_TYPE( typename ResultType::CompositeType );
653 
654  BLAZE_INTERNAL_ASSERT( (~lhs).size() == rhs.size(), "Invalid vector sizes" );
655 
656  const ResultType tmp( rhs );
657  multAssign( ~lhs, tmp );
658  }
660  //**********************************************************************************************
661 
662  //**Multiplication assignment to sparse vectors*************************************************
663  // No special implementation for the multiplication assignment to sparse vectors.
664  //**********************************************************************************************
665 
666  //**Compile time checks*************************************************************************
673  //**********************************************************************************************
674 };
675 //*************************************************************************************************
676 
677 
678 
679 
680 //=================================================================================================
681 //
682 // GLOBAL BINARY ARITHMETIC OPERATORS
683 //
684 //=================================================================================================
685 
686 //*************************************************************************************************
717 template< typename T1 // Type of the left-hand side sparse matrix
718  , typename T2 > // Type of the right-hand side sparse vector
719 inline const typename DisableIf< IsMatMatMultExpr<T1>, SMatSVecMultExpr<T1,T2> >::Type
721 {
722  if( (~mat).columns() != (~vec).size() )
723  throw std::invalid_argument( "Matrix and vector sizes do not match" );
724 
725  return SMatSVecMultExpr<T1,T2>( ~mat, ~vec );
726 }
727 //*************************************************************************************************
728 
729 
730 
731 
732 //=================================================================================================
733 //
734 // GLOBAL RESTRUCTURING BINARY ARITHMETIC OPERATORS
735 //
736 //=================================================================================================
737 
738 //*************************************************************************************************
751 template< typename T1 // Type of the left-hand side sparse matrix
752  , bool SO // Storage order of the left-hand side sparse matrix
753  , typename T2 > // Type of the right-hand side sparse vector
754 inline const typename EnableIf< IsMatMatMultExpr<T1>, MultExprTrait<T1,T2> >::Type::Type
756 {
757  return (~mat).leftOperand() * ( (~mat).rightOperand() * vec );
758 }
759 //*************************************************************************************************
760 
761 } // namespace blaze
762 
763 #endif