Matrix Mod。稀疏行运算符*(矩阵,向量)

时间:2017-11-18 16:24:21

标签: c++ matrix sparse-matrix

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

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

  • 对角线元素(aa_[0]aa_[dim]
  • 非零值非对角线(aa_[dim+2]aa_[size_of_non_zero]
  • 行中第一个元素的指针(ja_[0]ja_[dim]
  • 在上一个指针中使用了这个规则:ja_[0]=dim+1;第{i行}中ja_[i+1]-ja[i]=个元素数
  • 上面ja_[ja_[row]] ja_[row]中存储的
  • 列索引的范围为ja[0]ja[dim+1],因此列表索引位于ja_[dim+2]到{{1} }}

这里是最小代码:

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; }

但使用八度音程获得的正确结果是:

0 5.291 25.536 9.68

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

9.8280  5.2910  25.5360  17.1600

在上面的代码中,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 aa的值由放置此成员的c ++构造函数给出

ja

并在构造函数结束时调用它!现在我在构造函数的末尾添加了成员​​的行,所以如果你尝试构造函数,你会得到与fortran代码中写的完全相同的向量

谢谢我按照你的建议@Paul H.并重写操作符+如下: (我没有更改ja_索引,因为在我的课程中我已经有很多或多或少没有错误的方法)

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;
}

你可以看到我使用索引从所有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; } 中减去1:

  • ja_代替x.at(A.ja_.at(k)-1)
  • 索引K x.at(A.ja_.at(k))
  • 的不同开头
  • 和cicle的不同结尾(我使用了do而不是for)

1 个答案:

答案 0 :(得分:0)

调试器是你的朋友!为了将来参考,这里有一个关于调试小程序的非常好的博客文章的链接: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++)