c++ - 矩阵模式。稀疏行运算符*(矩阵, vector )

标签 c++ matrix sparse-matrix

我正在实现修改后的压缩稀疏行矩阵 [reference] , 但是我有 Matrix * vector 乘法的问题,我写了这个函数但是我没有找到错误!

该类使用 2 个容器 (std::vector) 进行存储

  • 对角元素(aa_[0]aa_[dim])
  • 非对角线的非零值(aa_[dim+2]aa_[size_of_non_zero])
  • 行中第一个元素的指针(ja_[0]ja_[dim] )
  • 在前面的指针中使用了这个规则:ja_[0]=dim+1ja_[i+1]-ja[i]=第i行元素个数
  • 存储在 ja_[ja_[row]] 中的 ja_[row] 的列索引的范围是 ja[0]ja[dim+1] ,所以colum索引在ja_[dim+2]ja_[size_of_non_zero elment]

这里是最少的代码:

# include <initializer_list>
# include <vector>
# include <iosfwd>
# include <string>
# include <cstdlib>
# include <cassert>
# include <iomanip>
# include <cmath> for(auto i=0; i< A.dim ; i++)
 {
     //for(auto k=A.ja_.at(i) ; k <= A.ja_.at(i+1)-1 ; k++ )
     auto k=A.ja_.at(i)-1; 
     do 
     {    
          b.at(i) += A.aa_.at(k)* x.at(A.ja_.at(k)-1);
          k++ ; for(auto i=0; i< A.dim ; i++)
 {
     //for(auto k=A.ja_.at(i) ; k <= A.ja_.at(i+1)-1 ; k++ )
     auto k=A.ja_.at(i)-1; 
     do 
     {    
          b.at(i) += A.aa_.at(k)* x.at(A.ja_.at(k)-1);
          k++ ;
     }while (k < A.ja_.at(i+1)-1 ); // ;
 }
 return b;

     }while (k < A.ja_.at(i+1)-1 ); // ;
 }
 return b;

# include <set>
# include <fstream>



  template <typename data_type>
    class MCSRmatrix {
       public:
             using itype = std::size_t ;

    template <typename T>
          friend std::vector<T> operator*(const MCSRmatrix<T>& A, const std::vector<T>& x ) noexcept ;

       public:
     constexpr MCSRmatrix( std::initializer_list<std::initializer_list<data_type>> rows);


    private:

         std::vector<data_type> aa_ ;    // vector of value 
         std::vector<itype>     ja_ ;    // pointer vector 

         int dim ; 
    };

    //constructor 
    template <typename T>
    constexpr MCSRmatrix<T>::MCSRmatrix( std::initializer_list<std::initializer_list<T>> rows)
    {
          this->dim  = rows.size();
          auto _rows = *(rows.begin());

          aa_.resize(dim+1);
          ja_.resize(dim+1);

          if(dim != _rows.size()) for(auto i=0; i< A.dim ; i++)
 {
     //for(auto k=A.ja_.at(i) ; k <= A.ja_.at(i+1)-1 ; k++ )
     auto k=A.ja_.at(i)-1; 
     do 
     {    
          b.at(i) += A.aa_.at(k)* x.at(A.ja_.at(k)-1);
          k++ ;
     }while (k < A.ja_.at(i+1)-1 ); // ;
 }
 return b;

          {
              throw std::runtime_error("error matrix must be square");
          }

          itype w = 0 ;
          ja_.at(w) = dim+2 ;
          for(auto ii = rows.begin(), i=1; ii != rows.end() ; ++ii, i++)
          {
              for(auto ij = ii->begin(), j=1, elemCount = 0 ; ij != ii->end() ; ++ij, j++ )   
              {
                  if(i==j)
                     aa_[i-1] = *ij ;
                  else if( i != j && *ij != 0 )
                  {   
                     ja_.push_back(j); 
                     aa_.push_back(*ij); 
                     elemCount++ ;
                  }
                  ja_[i] = ja_[i-1] + elemCount;           
              }
          }     
      for(auto& x : aa_ )
          std::cout << x << ' ' ;
      std::cout << std::endl;

      for(auto& x : ja_ )
          std::cout << x << ' ' ;
      std::cout << std::endl;    
    }



    template <typename T>
    std::vector<T> operator*(const MCSRmatrix<T>& A, const std::vector<T>& x ) noexcept 
    {     

         std::vector<T> b(A.dim); 
         for(auto i=0; i < A.dim ; i++ )
             b.at(i) = A.aa_.at(i)* x.at(i) ;   


         for(auto i=0; i< A.dim ; i++)
         {
             for(auto k=A.ja_.at(i) ; k < A.ja_.at(i+1)-1 ; k++ )
             {    
                  b.at(i) += A.aa_.at(k)* x.at(A.ja_.at(k));
             }   
         }
         return b;
    }

最后是主要的

# include "ModCSRmatrix.H"


using namespace std;

int main(){
   std::vector<double> v1={0,1.3,4.2,0.8};
   MCSRmatrix<double> m1  = {{1.01, 0 , 2.34,0}, {0, 4.07, 0,0},{3.12,0,6.08,0},{1.06,0,2.2,9.9} }; 
    std::vector<double> v2 = m1*v1 ;

  for(auto& x : v2)
    cout << x << ' ' ;
  cout << endl;
}

但结果与 Octave 得到的结果不一样!

我已经更正了代码,现在可以编译了!它给了我结果:

0 5.291 25.536 9.68

但是使用 Octave 获得的正确结果是:

9.8280 5.2910 25.5360 17.1600

奇怪的是,用 Fortran 编写的相同代码却能工作!

MODULE MSR
 IMPLICIT NONE

CONTAINS
     subroutine amuxms (n, x, y, a,ja)
      real*8  x(*), y(*), a(*)
      integer n, ja(*)
      integer i, k
      do 10 i=1, n
        y(i) = a(i)*x(i)
 10     continue
      do 100 i = 1,n

         do 99 k=ja(i), ja(i+1)-1
            y(i) = y(i) + a(k) *x(ja(k))
 99      continue
 100  continue

      return

      end

END MODULE

PROGRAM MSRtest
USE MSR
IMPLICIT NONE
INTEGER :: i
REAL(KIND(0.D0)), DIMENSION(4) :: y, x= (/0.,1.3,4.2,0.8/)

REAL(KIND(0.D0)), DIMENSION(9) :: AA = (/ 1.01, 4.07, 6.08, 9.9, 0., 2.34, 3.12, 1.06, 2.2/) 
INTEGER , DIMENSION(9)         :: JA = (/6, 7, 7, 8, 10, 3, 1, 1, 3/)



WRITE(6,FMT='(4F8.3)') (x(I), I=1,4)    

CALL amuxms(4,x,y,aa,ja)

WRITE(6,FMT='(4F8.3)') (y(I), I=1,4)    

END PROGRAM

在上面的代码中,aaja 的值由放置此成员的 c++ 构造函数给出

template <typename T>
inline auto constexpr MCSRmatrix<T>::printMCSR() const noexcept 
{
      for(auto& x : aa_ )
          std::cout << x << ' ' ;
      std::cout << std::endl;

      for(auto& x : ja_ )
          std::cout << x << ' ' ;
      std::cout << std::endl;
}

并在构造函数的末尾调用它!现在我在构造函数的末尾添加了成员​​的行,所以如果你尝试构造函数,你会得到用 Fortran 代码编写的完全相同的 vector

谢谢我听从了你的建议@Paul H. 并重写了运算符 + 如下: (我没有更改 ja_ 索引,因为在我的类里面我有很多或多或少已经没有错误的方法)

template <typename T>
std::vector<T> operator*(const MCSRmatrix<T>& A, const std::vector<T>& x ) noexcept 
{     

     std::vector<T> b(A.dim); 
     for(auto i=0; i < A.dim ; i++ )
         b.at(i) = A.aa_.at(i)* x.at(i) ;   


     for(auto i=0; i< A.dim ; i++)
     {
         //for(auto k=A.ja_.at(i) ; k <= A.ja_.at(i+1)-1 ; k++ )
         auto k=A.ja_.at(i)-1; 
         do 
         {    
              b.at(i) += A.aa_.at(k)* x.at(A.ja_.at(k)-1);
              k++ ;
         }while (k < A.ja_.at(i+1)-1 ); // ;
     }
     return b;
}

如您所见,我从所有 ja_ 中减去 1 作为索引:

  • x.at(A.ja_.at(k)-1) 而不是 x.at(A.ja_.at(k))
  • 索引 K 的不同开始 k=A.ja_.at(i)-1
  • 和 cicle 的另一端(我用了 do while 而不是 for)

最佳答案

调试器是你的 friend !为了将来引用,这里有一个关于调试小程序的非常好的博客文章的链接:How to debug small programs . 您的代码中有几个错误。如果您在链接到的引用中创建用作示例的 4 x 4 矩阵,您将看到 ja_您计算的值都相差一个。 Fortran 版本有效的原因是 Fortran 中的数组默认从 1 而不是 0 开始索引。因此在 class MCSRmatrix 中改变

ja_.at(w) = dim+2;

ja_.at(w) = dim+1;

ja_.push_back(j);

ja_.push_back(j-1);

然后在你的operator*方法改变

for(auto k=A.ja_.at(i) ; k < A.ja_.at(i+1)-1 ; k++ )

for(auto k = A.ja_.at(i); k < A.ja_.at(i+1); k++)

关于c++ - 矩阵模式。稀疏行运算符*(矩阵, vector ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47368287/

相关文章:

c++ - 将变量赋值给函数内部的引用。

C++为什么结构对象值在循环结束时重置回零

c++ - QListWidgdet resizeEvent QPainter::begin: Paint 设备返回 engine == 0, type: 2

r - R 中矩阵列表的标准偏差

r - R S4 类和 Matrix 包中重载 + 运算符

c++ - 如何将对象的构造限制为几种方法?

excel - 如何根据第一行和第一列中的值对一系列矩阵求和 - Excel VBA

r - 填充R中距离矩阵中缺失的行/列

javascript - 在 JavaScript 中遍历负数组索引

r - R 中是否有对 dist 函数的稀疏支持?