#ifndef _matrix_n_ #define _matrix_n_ #include "./utils/vector.h" #include "./utils/random.h" #ifdef _OPENMP #include #endif #include #include namespace utils{ //####################################### //# MATRIX TYPE # //# Backed by utils::Vector # //####################################### template class Matrix{ public: Matrix() : rows_(0), cols_(0), data_() {} // Default constructor #include // Constructor to initialize matrix with rows × cols and a fill value Matrix(uint64_t rows, uint64_t cols, const T& value = T()) : rows_(rows), cols_(cols), data_(rows * cols, value) {} // Construct from list-of-lists: // utils::Mf A{{1,2,3}, {4,5,6}}; Matrix(std::initializer_list> init) { rows_ = static_cast(init.size()); if (rows_ > 0) { cols_ = static_cast(init.begin()->size()); } else { cols_ = 0; } // Validate all rows have the same length for (const auto& row : init) { if (row.size() != cols_) { throw std::runtime_error("Matrix(list of lists): ragged rows"); } } data_.resize(rows_ * cols_); uint64_t r = 0; for (uint64_t i = 0; i < init.size(); ++i, ++r){ const std::initializer_list& row = *(init.begin() + i); uint64_t c = 0; for (uint64_t j = 0; j < row.size(); ++j, ++c){ const T& val = *(row.begin() + j); data_[r * cols_ + c] = val; } } } // Assign from list-of-lists after default construction: // utils::Md M; M = {{1,2},{3,4}}; Matrix& operator=(std::initializer_list> init) { // Set sizes rows_ = static_cast(init.size()); if (rows_ > 0) { cols_ = static_cast((init.begin())->size()); } else { cols_ = 0; } // Validate: all rows must have same length for (uint64_t i = 0; i < rows_; ++i) { const std::initializer_list& row = *(init.begin() + i); if (row.size() != cols_) { throw std::runtime_error("Matrix(list of lists): ragged rows"); } } // Allocate storage data_.resize(rows_ * cols_); // Copy data row by row for (uint64_t i = 0; i < rows_; ++i) { const std::initializer_list& row = *(init.begin() + i); for (uint64_t j = 0; j < cols_; ++j) { const T& val = *(row.begin() + j); data_[i * cols_ + j] = val; } } return *this; } //# MATRIX: basic properties # uint64_t rows() const noexcept {return rows_;} uint64_t cols() const noexcept {return cols_;} //# MATRIX: element access (fast; unchecked) # T& operator()(uint64_t i, uint64_t j) { return data_[i * cols_ + j]; } const T& operator()(uint64_t i, uint64_t j) const { return data_[i * cols_ + j]; } //# MATRIX: data access # T* data() noexcept { return data_.data(); } const T* data() const noexcept { return data_.data(); } void resize(uint64_t rows, uint64_t cols, const T& value = T(0)){ rows_ = rows; cols_ = cols; data_.resize(rows_*cols_, value); } void random(uint64_t rows, uint64_t cols, const T& lower, const T& higher){ rows_ = rows; cols_ = cols; data_.resize(rows_*cols_, 0); // Copy data row by row for (uint64_t i = 0; i < rows_; ++i) { for (uint64_t j = 0; j < cols_; ++j) { data_[i * cols_ + j] = utils::random(lower, higher); } } } //# MATRIX: row helpers (copy out) # // Read whole row as an owning Vector // utils::Vf v = M.get_row(2); Vector get_row(const uint64_t row) const { if (row >= rows_) { throw std::out_of_range("Matrix::get_row -> row index"); } utils::Vector result(cols_, T{}); for (uint64_t i = 0; i < cols_; ++i){ result[i] = data_[row * cols_ + i]; } return result; } //# MATRIX: row helpers (copy in) # // Assign a whole Vector to a row // M.set_row(2) = v; void set_row(const uint64_t row, const Vector& vector){ if (row >= rows_) { throw std::out_of_range("Matrix::set_row -> row index"); } if (vector.size() != cols_){ throw std::runtime_error("Matrix::set_row -> size mismatch"); } for (uint64_t i = 0; i < cols_; ++i){ data_[row * cols_ + i] = vector[i]; } } //# MATRIX: col helpers (copy out) # // Read whole col as an owning Vector // utils::Vf v = M.get_col(2); Vector get_col(const uint64_t col) const { if (col >= cols_) { throw std::out_of_range("Matrix::get_col -> col index"); } utils::Vector result(rows_, T{}); for (uint64_t i = 0; i < rows_; ++i){ result[i] = data_[i * cols_ + col]; } return result; } //# MATRIX: col helpers (copy in) # // Assign a whole Vector to a col // M.set_col(2) = v; void set_col(const uint64_t col, const Vector& vector){ if (col >= cols_) { throw std::out_of_range("Matrix::set_col -> col index"); } if (vector.size() != rows_){ throw std::runtime_error("Matrix::set_col -> size mismatch"); } for (uint64_t i = 0; i < rows_; ++i){ data_[i * cols_ + col] = vector[i]; } } void swap_rows(uint64_t a, uint64_t b){ if (a >= rows_ || b >= rows_) { throw std::out_of_range("Matrix::swap_rows -> row index"); } if (a == b){ return; } for (uint64_t i = 0; i < cols_; ++i){ T tmp = data_[a * cols_ + i]; data_[a * cols_ + i] = data_[b * cols_ + i]; data_[b * cols_ + i] = tmp; } } void swap_cols(uint64_t a, uint64_t b){ if (a >= cols_ || b >= cols_) { throw std::out_of_range("Matrix::swap_cols -> col index"); } if (a == b){ return; } for (uint64_t i = 0; i < rows_; ++i){ T tmp = data_[i * cols_ + a]; data_[i * cols_ + a] = data_[i * cols_ + b]; data_[i * cols_ + b] = tmp; } } inline friend std::ostream& operator<<(std::ostream& out, const Matrix& M) { out << "["; for (uint64_t i = 0; i < M.rows_; ++i) { out << "["; for (uint64_t j = 0; j < M.cols_; ++j) { out << std::setw(4) << std::setprecision(3) << std::fixed << M(i, j); if (j + 1 < M.cols_) out << ", "; } out << "]"; if (i + 1 < M.rows_) out << ",\n "; } out << "]"; return out; } void print() const { std::cout << *this << std::endl; } private: uint64_t rows_, cols_; std::vector data_; }; typedef Matrix Mi; typedef Matrix Mf; typedef Matrix Md; } #endif // _matrix_n_