/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #ifndef _GCTL_MATRIX_H #define _GCTL_MATRIX_H #include #include "array.h" namespace gctl { template class matrix; /* * Here we define some commonly used array types. */ typedef matrix _2i_matrix; ///< 2-D integer array typedef matrix _2f_matrix; ///< 2-D single-precision floating-point array typedef matrix _2d_matrix; ///< 2-D double-precision floating-point array typedef matrix _2s_matrix; ///< 2-D string array typedef matrix > _2cf_matrix; ///< 1-D complex float array typedef matrix > _2cd_matrix; ///< 1-D complex double array /** * @brief 二维数组模版 * * 二维数组模版是一个简单的二维动态数组实现,包含简单的数组操作与IO操作函数。 * * @tparam MatValType 数组元素模版类型 */ template class matrix { protected: MatValType **val; ///< 二维数组数据 size_t row_length, col_length; ///< 二维数组的行列数 public: /** * @brief 默认构造函数 */ matrix(); /** * @brief 构造函数:初始化二维数组空间 * * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ matrix(size_t row_len, size_t col_len); /** * @brief 构造函数:初始化二维数组空间并赋处值 * * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 * @param[in] init_val 数组元素的初始值 */ matrix(size_t row_len, size_t col_len, MatValType init_val); /** * @brief 构造函数:从一维数组初始化二维数组 * * @param init_mat 输入的一维数组 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ matrix(MatValType *init_mat, size_t row_len, size_t col_len); /** * @brief 构造函数:从二维数组初始化二维数组 * * @param init_mat 输入的二维数组 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ matrix(MatValType **init_mat, size_t row_len, size_t col_len); /** * @brief 构造函数:从一维向量初始化二维数组 * * @param[in] b 输入向量的引用 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ matrix(const std::vector &b, size_t row_len, size_t col_len); /** * @brief 构造函数:从二维向量初始化二维数组 * * @param[in] b 输入向量的引用 */ explicit matrix(const std::vector > &b); /** * @brief 构造函数:从一维数组初始化二维数组 * * @param[in] b 输入数组的引用 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ matrix(const array &b, size_t row_len, size_t col_len); /** * @brief 拷贝构造函数 * * @param[in] b 拷贝数组 */ matrix(const matrix &b); /** * @brief 赋值操作符重载 * * @param[in] b 赋值数组 * * @return 新建数组 */ matrix& operator= (const matrix &b); /** * @brief 析构函数 */ virtual ~matrix(); /** * @brief 初始化二维数组空间 * * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ void resize(size_t row_len, size_t col_len); /** * @brief 构造函数:初始化二维数组空间并赋处值 * * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 * @param[in] init_val 数组元素的初始值 */ void resize(size_t row_len, size_t col_len, MatValType init_val); /** * @brief 构造函数:从一维数组初始化二维数组 * * @param init_mat 输入的一维数组 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ void resize(MatValType *init_mat, size_t row_len, size_t col_len); /** * @brief 构造函数:从二维数组初始化二维数组 * * @param init_mat 输入的二维数组 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ void resize(MatValType **init_mat, size_t row_len, size_t col_len); /** * @brief 构造函数:从一维向量初始化二维数组 * * @param[in] b 输入向量的引用 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ void resize(const std::vector &b, size_t row_len, size_t col_len); /** * @brief 从二维向量初始化二维数组 * * @param[in] b 输入向量的引用 */ void resize(const std::vector > &b); /** * @brief 构造函数:从一维数组初始化二维数组 * * @param[in] b 输入数组的引用 * @param[in] row_len 二维数组行数 * @param[in] col_len 二维数组列数 */ void resize(const array &b, size_t row_len, size_t col_len); /** * @brief 从二维数组初始化二维数组 * * @param[in] b 输入数组 */ void resize(const matrix &b); /** * @brief 清除并重置数组空间 */ void clear(); /** * @brief Initialize the array with selected random types. * * @param[in] np1 Mean (Gauss) or low bound value (Even) * @param[in] np2 Standard deviation (Gauss) or hig bound value (Even). * @param[in] mode Random types. 'RdNormal' for Gaussian distributed numbers and * 'RdUniform' for even distributed numbers. */ void random_float(MatValType np1, MatValType np2, random_type_e mode = RdNormal, unsigned int seed = 0); /** * @brief Initialize the array with selected random types. * * @param[in] np1 Mean (Gauss) or low bound value (Even) * @param[in] np2 Standard deviation (Gauss) or hig bound value (Even). * @param[in] mode Random types. 'RdNormal' for Gaussian distributed numbers and * 'RdUniform' for even distributed numbers. */ void random_int(MatValType np1, MatValType np2, unsigned int seed = 0); /** * @brief 对全体元素进行赋值 * * @param[in] in_val 输入值 */ void assign_all(MatValType in_val); /** * @brief 对全体元素进行缩放 * * @param s 缩放的比例 */ void scale(MatValType s); /** * @brief 按行或列计算元素平均值 * * @param m 均值数组 * @param odr 计算行或列的平均值 */ void mean(array &m, matrix_order_e odr = RowMajor); /** * @brief 计算矩阵的模长 * * @param n_type 模的类型 */ double norm(norm_type_e n_type = L2) const; /** * @brief Set elements' value as a sequent. * * @param st_val Start value. * @param row_inc Row increasement. * @param col_inc Column increasement. */ void sequence(MatValType st_val, MatValType row_inc, MatValType col_inc); /** * @brief 获取索引位置元素值 * * @note 可用于指针情况 * * @param[in] row_index 行索引值 * @param[in] col_index 列索引值 * * @return 索引处元素 */ MatValType &at(size_t row_index, size_t col_index); /** * @brief 获取索引位置元素值(常量重载) * * @note 可用于指针情况 * * @param[in] row_index 行索引值 * @param[in] col_index 列索引值 * * @return 索引处元素 */ MatValType &at(size_t row_index, size_t col_index) const; /** * @brief 下标符号重载:获取索引位置元素值 * * @note 不可用于指针情况,对于二维数组只需重载一次下标符号就行。 * * @param[in] index 索引值 * * @return 索引处元素 */ MatValType *operator[](size_t index); /** * @brief 下标符号重载:获取索引位置元素值(常量重载) * * @note 不可用于指针情况,对于二维数组只需重载一次下标符号就行。 * * @param[in] index 索引值 * * @return 索引处元素 */ MatValType *operator[](size_t index) const; /** * @brief 获取成员数组裸指针 * * @param[in] row_index 行索引值 row_index = 0 时数组指针为全部矩阵数据的头指针 * * @return 单个元素的指针 */ MatValType *get(size_t row_index = 0) const; /** * @brief 判断数组是否为空 * * @return 数组为空返回真,否则返回假 */ bool empty() const; /** * @brief 返回矩阵行大小 * * @return 矩阵行大小 */ size_t row_size() const; /** * @brief 返回矩阵列大小 * * @return 矩阵列大小 */ size_t col_size() const; /** * @brief 返回矩阵数组大小 * * @return 数组大小 */ size_t val_size() const; /** * @brief 拷贝数组到新的二维数组 * * @param b 拷贝对象数组 */ void copy_to(matrix &b) const; /** * @brief 拷贝数组到二维向量 * * @param b 拷贝对象向量 */ void copy_to(std::vector > &b) const; /** * @brief 提取二维数组的行或者列到输出数组 * * @param b 输出一维数组 * @param[in] index 行或者列的索引值 * @param[in] order 按行或者列输出 */ void extract(array &b, size_t index, matrix_order_e order = RowMajor) const; /** * @brief 将二维数组转换为一维数组 * * @warning 此函数会重置输出的一维数组 * * @param b 转换后数组 * @param[in] order 按行或者列优先排列输出 */ void reform(array &b, matrix_order_e order = RowMajor) const; /** * @brief element operate function pointer * */ typedef void (*foreach_m_ptr)(MatValType &ele_ptr, size_t r_id, size_t c_id); /** * @brief Operate on each and every element * * @param func operation function */ void for_each(foreach_m_ptr func); /** * @brief Display the elements. * */ void show(std::ostream &os = std::cout, char sep = '\t') const; }; template matrix::matrix() { row_length = col_length = 0; val = nullptr; } template matrix::matrix(size_t row_len, size_t col_len) { row_length = col_length = 0; val = nullptr; resize(row_len, col_len); } template matrix::matrix(size_t row_len, size_t col_len, MatValType init_val) { row_length = col_length = 0; val = nullptr; resize(row_len, col_len, init_val); } template matrix::matrix(MatValType *init_mat, size_t row_len, size_t col_len) { row_length = col_length = 0; val = nullptr; resize(init_mat, row_len, col_len); } template matrix::matrix(MatValType **init_mat, size_t row_len, size_t col_len) { row_length = col_length = 0; val = nullptr; resize(init_mat, row_len, col_len); } template matrix::matrix(const std::vector &b, size_t row_len, size_t col_len) { row_length = col_length = 0; val = nullptr; resize(b, row_len, col_len); } template matrix::matrix(const std::vector > &b) { row_length = col_length = 0; val = nullptr; resize(b); } template matrix::matrix(const array &b, size_t row_len, size_t col_len) { row_length = col_length = 0; val = nullptr; resize(b, row_len, col_len); } template matrix::matrix(const matrix &b) { row_length = col_length = 0; val = nullptr; resize(b); } template matrix& matrix::operator= (const matrix &b) { if (b.empty()) { clear(); } else { resize(b.row_size(), b.col_size()); for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = b[i][j]; } } } return *this; } template matrix::~matrix() { clear(); } template void matrix::resize(size_t row_len, size_t col_len) { if (row_len == 0 || col_len == 0) { throw std::invalid_argument("[gctl::matrix::resize] Invalid matrix size."); } // nothing needs to be done if (row_len == row_length && col_len == col_length) { return; } // re-indexing if (row_len*col_len == row_length*col_length) { row_length = row_len; col_length = col_len; // construct new row-indexing MatValType *t_ptr = val[0]; delete[] val; val = new MatValType* [row_len]; val[0] = t_ptr; for (size_t i = 1; i < row_len; i++) { val[i] = val[i-1] + col_len; } return; } // re-allocate if (!empty()) clear(); row_length = row_len; col_length = col_len; val = new MatValType* [row_len]; val[0] = new MatValType [row_len*col_len]; for (size_t i = 1; i < row_len; i++) { val[i] = val[i-1] + col_len; } return; } template void matrix::resize(size_t row_len, size_t col_len, MatValType init_val) { resize(row_len, col_len); for (size_t i = 0; i < row_len; i++) { for (size_t j = 0; j < col_len; j++) { val[i][j] = init_val; } } return; } template void matrix::resize(MatValType *init_mat, size_t row_len, size_t col_len) { if (init_mat == nullptr) { throw std::domain_error("[gctl::matrix::resize] Invalid pointer."); } resize(row_len, col_len); for (size_t i = 0; i < row_len; i++) { for (size_t j = 0; j < col_len; j++) { val[i][j] = init_mat[j + i*col_len]; } } return; } template void matrix::resize(MatValType **init_mat, size_t row_len, size_t col_len) { if (init_mat == nullptr) { throw std::domain_error("[gctl::matrix::resize] Invalid pointer."); } resize(row_len, col_len); for (size_t i = 0; i < row_len; i++) { for (size_t j = 0; j < col_len; j++) { val[i][j] = init_mat[i][j]; } } return; } template void matrix::resize(const std::vector &b, size_t row_len, size_t col_len) { if (!b.empty()) { resize(row_len, col_len); for (size_t i = 0; i < row_len; i++) { for (size_t j = 0; j < col_len; j++) { val[i][j] = b[j + i*col_len]; } } return; } return; } template void matrix::resize(const std::vector > &b) { if (!b.empty()) { size_t max_col = 0; for (size_t i = 0; i < b.size(); i++) { max_col = std::max(max_col, b[i].size()); } resize(b.size(), max_col, 0); for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < b[i].size(); j++) { val[i][j] = b[i][j]; } } return; } return; } template void matrix::resize(const array &b, size_t row_len, size_t col_len) { if (!b.empty()) { if (b.size() != row_len*col_len) { throw std::runtime_error("[gctl::matrix::resize] Invalid matrix parameters."); } resize(row_len, col_len); for (size_t i = 0; i < row_len; i++) { for (size_t j = 0; j < col_len; j++) { val[i][j] = b[j + i*col_len]; } } return; } return; } template void matrix::resize(const matrix &b) { if (!b.empty()) { resize(b.row_size(), b.col_size()); for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = b[i][j]; } } return; } return; } template void matrix::clear() { row_length = col_length = 0; if (val != nullptr) { delete[] val[0]; delete[] val; val = nullptr; } return; } template void matrix::random_float(MatValType np1, MatValType np2, random_type_e mode, unsigned int seed) { static_assert(std::is_floating_point::value, "gctl::matrix::random_float(...) could only be used with a float point type."); if (seed == 0) seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); if (mode == RdNormal) { std::normal_distribution dist(np1, np2); // 添加高斯分布的随机值 for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = dist(generator); } } return; } std::uniform_real_distribution dist(np1, np2); // /添加均匀分布的随机值 for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = dist(generator); } } return; } template void matrix::random_int(MatValType np1, MatValType np2, unsigned int seed) { static_assert(std::is_integral::value, "gctl::matrix::random_int(...) could only be used with an integral type."); if (seed == 0) seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); //添加均匀分布的随机值 std::uniform_int_distribution dist(np1, np2); for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = dist(generator); } } return; } template void matrix::assign_all(MatValType in_val) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = in_val; } } return; } template void matrix::scale(MatValType s) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] *= s; } } return; } template void matrix::mean(array &m, matrix_order_e odr) { if (odr == RowMajor) { m.resize(col_length); for (size_t j = 0; j < col_length; j++) { m[j] = 0.0; for (size_t i = 0; i < row_length; i++) { m[j] += val[i][j]; } m[j] /= row_length; } } else { m.resize(row_length); for (size_t i = 0; i < row_length; i++) { m[i] = 0.0; for (size_t j = 0; j < col_length; j++) { m[i] += val[i][j]; } m[i] /= col_length; } } return; } template double matrix::norm(norm_type_e n_type) const { MatValType nval = (MatValType) 0; if (n_type == L0) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { if (val[i][j] != (MatValType) 0) { nval += (MatValType) 1; } } } return nval; } if (n_type == L1) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { nval += GCTL_FABS(val[i][j]); } } return nval; } if (n_type == L2) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { nval += val[i][j]*val[i][j]; } } return sqrt(nval); } nval = val[0][0]; for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { nval = GCTL_MAX(nval, val[i][j]); } } return sqrt(nval); } template void matrix::sequence(MatValType st_val, MatValType row_inc, MatValType col_inc) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { val[i][j] = st_val + i*row_inc + j*col_inc; } } return; } template MatValType *matrix::get(size_t row_index) const { #ifdef GCTL_BOUND_CHECK if (row_index >= row_length || col_index >= col_length) throw std::out_of_range("[gctl::matrix::get] Invalid index."); #endif // GCTL_BOUND_CHECK return val[row_index]; } template MatValType &matrix::at(size_t row_index, size_t col_index) { #ifdef GCTL_BOUND_CHECK if (row_index >= row_length || col_index >= col_length) throw std::out_of_range("[gctl::matrix::at] Invalid index."); #endif // GCTL_BOUND_CHECK return val[row_index][col_index]; } template MatValType &matrix::at(size_t row_index, size_t col_index) const { #ifdef GCTL_BOUND_CHECK if (row_index >= row_length || col_index >= col_length) throw std::out_of_range("[gctl::matrix::at] Invalid index."); #endif // GCTL_BOUND_CHECK return val[row_index][col_index]; } template MatValType *matrix::operator[](size_t index) { return val[index]; } template MatValType *matrix::operator[](size_t index) const { return val[index]; } template bool matrix::empty() const { if (row_length == 0 && col_length == 0) return true; else return false; } template size_t matrix::row_size() const { return row_length; } template size_t matrix::col_size() const { return col_length; } template size_t matrix::val_size() const { return row_length*col_length; } template void matrix::copy_to(matrix &b) const { b.resize(row_length, col_length); for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { b[i][j] = val[i][j]; } } return; } template void matrix::copy_to(std::vector > &b) const { if (!b.empty()) { for (size_t i = 0; i < b.size(); i++) { b[i].clear(); } b.clear(); } b.resize(row_length); for (size_t i = 0; i < row_length; i++) { b[i].resize(col_length); } for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { b[i][j] = val[i][j]; } } return; } template void matrix::extract(array &b, size_t index, matrix_order_e order) const { if (order == RowMajor) { if (index >= row_length) { throw std::out_of_range("[gctl::matrix::extract] Invalid index."); } b.resize(col_length); for (size_t i = 0; i < col_length; i++) { b[i] = val[index][i]; } return; } if (index >= col_length) { throw std::out_of_range("[gctl::matrix::extract] Invalid index."); } b.resize(row_length); for (size_t i = 0; i < row_length; i++) { b[i] = val[i][index]; } return; } template void matrix::reform(array &b, matrix_order_e order) const { b.resize(row_length*col_length); if (order == RowMajor) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { b[j+i*col_length] = val[i][j]; } } return; } for (size_t j = 0; j < col_length; j++) { for (size_t i = 0; i < row_length; i++) { b[i+j*row_length] = val[i][j]; } } return; } template void matrix::for_each(foreach_m_ptr func) { for (size_t i = 0; i < row_length; i++) { for (size_t j = 0; j < col_length; j++) { func(val[i][j], i, j); } } return; } template void matrix::show(std::ostream &os, char sep) const { for (size_t i = 0; i < row_length; i++) { os << val[i][0]; for (size_t j = 1; j < col_length; j++) { os << sep << val[i][j]; } os << std::endl; } return; } }; #endif // _GCTL_MATRIX_H