объясни каждую функцию и вкратце как они работают

S21Matrix::S21Matrix() noexcept : rows_(0), cols_(0), matrix_(nullptr) {}

S21Matrix::S21Matrix(int rows, int cols) : rows_(rows), cols_(cols) {
  if (rows_ < 1 || cols_ < 1) {
    throw std::length_error("Matrix size must be greater or equal than 1");
  }

  matrix_ = new double*[rows_];
  for (int i = 0; i < rows_; i++) {
    matrix_[i] = new double[cols_];
  }
}

S21Matrix::S21Matrix(const S21Matrix& other)
    : rows_(other.rows_), cols_(other.cols_) {
  matrix_ = new double*[rows_];
  for (int i = 0; i < rows_; i++) {
    matrix_[i] = new double[cols_];
    std::memcpy(matrix_[i], other.matrix_[i], cols_ * sizeof(double));
  }
}

S21Matrix::S21Matrix(S21Matrix&& other) noexcept
    : rows_(other.rows_), cols_(other.cols_), matrix_(other.matrix_) {
  other.matrix_ = nullptr;
  other.rows_ = 0;
  other.cols_ = 0;
}

S21Matrix::~S21Matrix() {
  for (int i = 0; i < rows_; ++i) {
    delete[] matrix_[i];
  }
  delete[] matrix_;
  rows_ = 0;
  cols_ = 0;
}

int S21Matrix::get_rows() const noexcept { return rows_; }

int S21Matrix::get_cols() const noexcept { return cols_; }

void S21Matrix::set_rows(int new_rows) {
  if (new_rows < 1) {
    throw std::length_error(
        "The number of rows of the matrix must be greater than 1");
  }

  if (new_rows != rows_) {
    S21Matrix tmp{new_rows, cols_};
    int min = std::min(rows_, new_rows);
    for (int i = 0; i < min; ++i) {
      for (int j = 0; j < cols_; ++j) {
        tmp(i, j) = (*this)(i, j);
      }
    }
    *this = std::move(tmp);
  }
}

void S21Matrix::set_cols(int new_cols) {
  if (new_cols < 0) {
    throw std::length_error(
        "The number of columns of the matrix must be greater than 1");
  }

  if (new_cols != cols_) {
    S21Matrix tmp{rows_, new_cols};
    int min = std::min(cols_, new_cols);
    for (int i = 0; i < rows_; ++i) {
      for (int j = 0; j < min; ++j) {
        tmp(i, j) = (*this)(i, j);
      }
    }
    *this = std::move(tmp);
  }
}

bool S21Matrix::EqMatrix(const S21Matrix& other) const {
  bool status = true;

  if (rows_ != other.rows_ || cols_ != other.cols_) {
    status = false;
  }

  for (int i = 0; i < rows_ && status != false; ++i) {
    for (int j = 0; j < cols_; ++j) {
      if (std::fabs(matrix_[i][j] - other.matrix_[i][j]) > 1e-07) {
        status = false;
      }
    }
  }

  return status;
}

void S21Matrix::SumMatrix(const S21Matrix& other) {
  if (rows_ != other.rows_ || cols_ != other.cols_) {
    throw std::logic_error("Incorrect matrix size for Sum");
  }

  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j < cols_; ++j) {
      matrix_[i][j] += other.matrix_[i][j];
      if (!std::isfinite(matrix_[i][j])) {
        throw std::runtime_error("Non-finite result encountered");
      }
    }
  }
}

void S21Matrix::SubMatrix(const S21Matrix& other) {
  if (rows_ != other.rows_ || cols_ != other.cols_) {
    throw std::logic_error("Incorrect matrix size for Sub");
  }

  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j < cols_; ++j) {
      matrix_[i][j] -= other.matrix_[i][j];
      if (!std::isfinite(matrix_[i][j])) {
        throw std::runtime_error("Non-finite result encountered");
      }
    }
  }
}

void S21Matrix::MulNumber(const double num) {
  if (rows_ < 1 || cols_ < 1 || !std::isfinite(num)) {
    throw std::logic_error("Incorrect matrix size for Sub or non-finite num");
  }

  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j < cols_; ++j) {
      matrix_[i][j] *= num;
      if (!std::isfinite(matrix_[i][j])) {
        throw std::runtime_error("Non-finite result encountered");
      }
    }
  }
}

void S21Matrix::MulMatrix(const S21Matrix& other) {
  if (cols_ != other.rows_) {
    throw std::logic_error("Incorrect matrix size for Mul");
  }

  S21Matrix result{rows_, other.cols_};

  for (int i = 0; i < result.rows_; ++i) {
    for (int j = 0; j < result.cols_; ++j) {
      result.matrix_[i][j] = 0;
      for (int k = 0; k < cols_; ++k) {
        result.matrix_[i][j] += matrix_[i][k] * other.matrix_[k][j];
      }
      if (!std::isfinite(result.matrix_[i][j])) {
        throw std::runtime_error("Non-finite result encountered");
      }
    }
  }
  *this = std::move(result);
}

S21Matrix S21Matrix::s21_minor_matrix(const int skip_rows,
                                      const int skip_cols) const {
  S21Matrix result{rows_ - 1, cols_ - 1};

  int new_row = 0;
  for (int i = 0; i < rows_; ++i) {
    if (i == skip_rows) {
      continue;
    }

    int new_col = 0;
    for (int j = 0; j < cols_; ++j) {
      if (j == skip_cols) {
        continue;
      }

      result.matrix_[new_row][new_col] = matrix_[i][j];
      new_col++;
    }
    new_row++;
  }
  return result;
}

double S21Matrix::Determinant() const {
  if (cols_ != rows_) {
    throw std::logic_error("The matrix is not square");
  }
  double result;
  if (rows_ == 1) {
    result = matrix_[0][0];
  } else if (rows_ == 2) {
    result = matrix_[0][0] * matrix_[1][1] - matrix_[0][1] * matrix_[1][0];
  } else {
    double det = 0.0;
    for (int i = 0; i < cols_; ++i) {
      S21Matrix minor_matrix = s21_minor_matrix(0, i);
      double sign = (i % 2 == 0) ? 1.0 : -1.0;
      det += sign * matrix_[0][i] * minor_matrix.Determinant();
    }
    result = det;
  }
  return result;
}

S21Matrix S21Matrix::Transpose() const {
  S21Matrix result{cols_, rows_};

  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j < cols_; ++j) {
      result.matrix_[j][i] = matrix_[i][j];
      if (!std::isfinite(result.matrix_[j][i])) {
        throw std::runtime_error("Non-finite result encountered");
      }
    }
  }
  return result;
}

S21Matrix S21Matrix::CalcComplements() const {
  if (rows_ != cols_) {
    throw std::logic_error("The matrix is not square");
  }

  if (rows_ == 1) {
    S21Matrix result{1, 1};
    result.matrix_[0][0] = 1;
    return result;
  }

  S21Matrix result{rows_, cols_};

  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j < cols_; ++j) {
      S21Matrix minor_matrix = s21_minor_matrix(i, j);
      result.matrix_[i][j] = minor_matrix.Determinant() * pow(-1, i + j);
    }
  }
  return result;
}

S21Matrix S21Matrix::InverseMatrix() const {
  if (cols_ != rows_) throw std::logic_error("The matrix is not square");

  double det = Determinant();
  if (std::fabs(det) < 1e-6)
    throw std::logic_error("Determinant must be non-zero to calculate Inverse");

  return Transpose().CalcComplements() * (1.0 / det);
}

S21Matrix S21Matrix::operator+(const S21Matrix& other) const {
  if (rows_ != other.rows_ || cols_ != other.cols_) {
    throw std::logic_error("Incorrect matrix size for Sum");
  }
  S21Matrix tmp{*this};
  tmp.SumMatrix(other);
  return tmp;
}

S21Matrix& S21Matrix::operator+=(const S21Matrix& other) {
  if (rows_ != other.rows_ || cols_ != other.cols_) {
    throw std::logic_error("Incorrect matrix size for Sum");
  }
  SumMatrix(other);
  return *this;
}

S21Matrix S21Matrix::operator-(const S21Matrix& other) const {
  if (rows_ != other.rows_ || cols_ != other.cols_) {
    throw std::logic_error("Incorrect matrix size for Sub");
  }
  S21Matrix tmp{*this};
  tmp.SubMatrix(other);
  return tmp;
}

S21Matrix& S21Matrix::operator-=(const S21Matrix& other) {
  if (rows_ != other.rows_ || cols_ != other.cols_) {
    throw std::logic_error("Incorrect matrix size for Sub");
  }
  SubMatrix(other);
  return *this;
}

S21Matrix S21Matrix::operator*(double number) const {
  S21Matrix tmp{*this};
  tmp.MulNumber(number);
  return tmp;
}

S21Matrix operator*(double number, const S21Matrix& matrix) noexcept {
  S21Matrix tmp = matrix * number;
  return tmp;
}

S21Matrix& S21Matrix::operator*=(double number) {
  MulNumber(number);
  return *this;
}

S21Matrix S21Matrix::operator*(const S21Matrix& other) const {
  if (cols_ != other.rows_) {
    throw std::logic_error("Incorrect matrix size for Mul");
  }
  S21Matrix tmp{*this};
  tmp.MulMatrix(other);
  return tmp;
}

S21Matrix& S21Matrix::operator*=(const S21Matrix& other) {
  if (cols_ != other.rows_) {
    throw std::logic_error("Incorrect matrix size for Mul");
  }
  MulMatrix(other);
  return *this;
}

S21Matrix& S21Matrix::operator=(const S21Matrix& other) {
  if (this == &other) return *this;

  S21Matrix copy{other};
  *this = std::move(copy);
  return *this;
}

S21Matrix& S21Matrix::operator=(S21Matrix&& other) noexcept {
  if (this != &other) {
    for (int i = 0; i < rows_; i++) {
      delete[] matrix_[i];
    }
    delete[] matrix_;
    rows_ = other.rows_;
    cols_ = other.cols_;
    matrix_ = other.matrix_;

    other.rows_ = 0;
    other.cols_ = 0;
    other.matrix_ = nullptr;
  }
  return *this;
}

bool S21Matrix::operator==(const S21Matrix& other) const {
  return EqMatrix(other);
}

double& S21Matrix::operator()(int row, int col) & {
  if (row >= rows_ || col >= cols_ || row < 0 || col < 0) {
    throw std::out_of_range("Index is out of matrix");
  }
  return matrix_[row][col];
}

const double& S21Matrix::operator()(int row, int col) const& {
  if (row >= rows_ || col >= cols_ || row < 0 || col < 0) {
    throw std::out_of_range("Index is out of matrix");
  }
  return matrix_[row][col];
}

void S21Matrix::FillMatrix(S21Matrix& matrix, double value) {
  for (int i = 0; i < matrix.get_rows(); ++i) {
    for (int j = 0; j < matrix.get_cols(); ++j) {
      matrix(i, j) = value;
    }
  }
}