CMU 15-445/645 2020 Project0 C++11实现矩阵类的练习项目

这个主要是C++ 11的练习项目,实现一个矩阵类,并实现简单的矩阵运算,不需要用到复杂的运算符重载,以及底层复杂并行等算法,这不是重点。

开发IDE使用Clion,调试能力(断点调试)比较弱,需要加强。

实现矩阵基类:

知识点:C++构造和析构函数,以及线性动态内存分配,纯虚函数,protected关键字,模版。

template <typename T>
class Matrix {
 protected:
  Matrix(int r, int c):rows(r),cols(c),linear(new T[r*c]) {
    for(int i=0;i<r*c;i++) { linear[i] = 0;}
  }

  // # of rows in the matrix
  int rows;
  // # of Columns in the matrix
  int cols;
  // Flattened array containing the elements of the matrix
  // Allocate the array in the constructor. Don't forget to free up
  // the array in the destructor.
  T *linear;

 public:
  // Return the # of rows in the matrix
  virtual int GetRows() = 0;

  // Return the # of columns in the matrix
  virtual int GetColumns() = 0;

  // Return the (i,j)th  matrix element
  virtual T GetElem(int i, int j) = 0;

  // Sets the (i,j)th  matrix element to val
  virtual void SetElem(int i, int j, T val) = 0;

  // Sets the matrix elements based on the array arr
  virtual void MatImport(T *arr) = 0;

  virtual ~Matrix(){
    delete [] linear;
  }
};

行优先存储的矩阵基类,二维数组的动态内存分配以及回收,指针数组。

思考一个问题:在这个实现中,二维数组和一维数组是共用内存的吗?

template <typename T>
class RowMatrix : public Matrix<T> {
 public:
  RowMatrix(int r, int c) : Matrix<T>(r, c) {
    data_ = new T* [r];
    for(int i=0;i<r;i++){
      data_[i] = new T[c];
    }
    for(int i=0;i<r;i++){
      for(int j=0;j<c;j++){
        data_[i][j] = 0;
      }
    }
  }

  int GetRows() override { return this->rows; }

  int GetColumns() override { return this->cols; }

  T GetElem(int i, int j) override {
    if(i<0||i>=this->GetRows()||j<0||j>=this->GetColumns()) return 0;
    return data_[i][j];
  }

  void SetElem(int i, int j, T val) override {
    if(i<0||i>=this->GetRows()||j<0||j>=this->GetColumns()) return;
    this->linear[i*this->GetColumns()+j] = val;
    data_[i][j] = val;
  }

  void MatImport(T *arr) override {
    int k = 0;
    for(int i=0;i<this->GetRows();i++){
      for(int j=0;j<this->GetColumns();j++){
        this->linear[k] = arr[k];
        data_[i][j] = arr[k++];
      }
    }
  }

  ~RowMatrix() override{
    for(int i=0;i<this->GetRows();i++) { delete [] data_[i];}
    delete [] data_;
  }

 private:
  // 2D array containing the elements of the matrix in row-major format
  // Allocate the array of row pointers in the constructor. Use these pointers
  // to point to corresponding elements of the 'linear' array.
  // Don't forget to free up the array in the destructor.
  T **data_;
};

最后是矩阵运算实现,主要是unique_str当成普通的指针用就好。注意这种指针是唯一的。

template <typename T>
class RowMatrixOperations {
 public:
  // Compute (mat1 + mat2) and return the result.
  // Return nullptr if dimensions mismatch for input matrices.
  static std::unique_ptr<RowMatrix<T>> AddMatrices(std::unique_ptr<RowMatrix<T>> mat1,
                                                   std::unique_ptr<RowMatrix<T>> mat2) {
    if(mat1->GetRows()!=mat2->GetRows()||mat1->GetColumns()!=mat2->GetColumns()){
      return std::unique_ptr<RowMatrix<T>>(nullptr);
    }
    int row = mat1->GetRows();
    int col = mat1->GetColumns();
    std::unique_ptr<RowMatrix<T>> mat(new RowMatrix<T>(row,col));
    for(int i=0;i<row;i++){
      for(int j=0;j<col;j++){
        mat->SetElem(i,j,mat1->GetElem(i,j)+mat2->GetElem(i,j));
      }
    }
    return mat;
  }

  // Compute matrix multiplication (mat1 * mat2) and return the result.
  // Return nullptr if dimensions mismatch for input matrices.
  static std::unique_ptr<RowMatrix<T>> MultiplyMatrices(std::unique_ptr<RowMatrix<T>> mat1,
                                                        std::unique_ptr<RowMatrix<T>> mat2) {
    if(mat1->GetColumns()!=mat2->GetRows()){
      return std::unique_ptr<RowMatrix<T>>(nullptr);
    }

    int row = mat1->GetRows();
    int col = mat2->GetColumns();

    std::unique_ptr<RowMatrix<T>> mat(new RowMatrix<T>(row,col));
    for(int i=0;i<row;i++){
      for(int j=0;j<col;j++){
        for(int k=0;k<mat1->GetColumns();k++){
          mat->SetElem(i,j,mat->GetElem(i,j)+mat1->GetElem(i,k)*mat2->GetElem(k,j));
        }
      }
    }
    return mat;
  }

  // Simplified GEMM (general matrix multiply) operation
  // Compute (matA * matB + matC). Return nullptr if dimensions mismatch for input matrices
  static std::unique_ptr<RowMatrix<T>> GemmMatrices(std::unique_ptr<RowMatrix<T>> matA,
                                                    std::unique_ptr<RowMatrix<T>> matB,
                                                    std::unique_ptr<RowMatrix<T>> matC) {

    std::unique_ptr<RowMatrix<T>> mat_tmp = std::move(MultiplyMatrices(matA,matB));
    if(mat_tmp== nullptr){
      return std::unique_ptr<RowMatrix<T>>(nullptr);
    }

    return AddMatrices(matA,matB);
    //std::unique_ptr<RowMatrix<T>> mat = std::move(AddMatrices(matA,matB));
    //return mat;

  }
};
}  // namespace bustub

最后是一个Google测试框架的测试

 namespace bustub {

TEST(StarterTest, SampleTest) {
  int a = 1;
  EXPECT_EQ(a, 1);
}

TEST(StarterTest, AddMatricesTest) {
  std::unique_ptr<RowMatrix<int>> mat1_ptr{new RowMatrix<int>(3, 3)};
  int arr1[9] = {1, 4, 2, 5, 2, -1, 0, 3, 1};
  mat1_ptr->MatImport(&arr1[0]);

  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      EXPECT_EQ(arr1[i * 3 + j], mat1_ptr->GetElem(i, j));
    }
  }

  int arr2[9] = {2, -3, 1, 4, 6, 7, 0, 5, -2};
  std::unique_ptr<RowMatrix<int>> mat2_ptr{new RowMatrix<int>(3, 3)};
  mat2_ptr->MatImport(&arr2[0]);
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      EXPECT_EQ(arr2[i * 3 + j], mat2_ptr->GetElem(i, j));
    }
  }

  int arr3[9] = {3, 1, 3, 9, 8, 6, 0, 8, -1};
  std::unique_ptr<RowMatrix<int>> sum_ptr = RowMatrixOperations<int>::AddMatrices(move(mat1_ptr), move(mat2_ptr));
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      EXPECT_EQ(arr3[i * 3 + j], sum_ptr->GetElem(i, j));
    }
  }
}

TEST(StarterTest, MultiplyMatricesTest) {
  // Multiply
  int arr1[6] = {1, 2, 3, 4, 5, 6};
  std::unique_ptr<RowMatrix<int>> mat1_ptr{new RowMatrix<int>(2, 3)};
  mat1_ptr->MatImport(&arr1[0]);
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
      EXPECT_EQ(arr1[i * 3 + j], mat1_ptr->GetElem(i, j));
    }
  }
  int arr2[6] = {-2, 1, -2, 2, 2, 3};
  std::unique_ptr<RowMatrix<int>> mat2_ptr{new RowMatrix<int>(3, 2)};
  mat2_ptr->MatImport(&arr2[0]);
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
      EXPECT_EQ(arr2[i * 2 + j], mat2_ptr->GetElem(i, j));
    }
  }
  int arr3[4] = {0, 14, -6, 32};
  std::unique_ptr<RowMatrix<int>> product_ptr =
      RowMatrixOperations<int>::MultiplyMatrices(move(mat1_ptr), move(mat2_ptr));
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
      EXPECT_EQ(arr3[i * 2 + j], product_ptr->GetElem(i, j));
    }
  }
}
}  // namespace bustub

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页