gctl/lib/core/spmat.h
2025-02-06 21:17:24 +08:00

3310 lines
80 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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 <http://www.gnu.org/licenses/>.
*
* 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_SPMAT_H
#define _GCTL_SPMAT_H
#include "matrix.h"
namespace gctl
{
template <typename MatrixValueType> class spmat;
/**
* 我们在下面定义一些常用的稀疏矩阵类型,方便我们使用。
*/
typedef spmat<int> _1i_spmat; ///< 整形浮点稀疏矩阵
typedef spmat<float> _1f_spmat; ///< 单精度浮点稀疏矩阵
typedef spmat<double> _1d_spmat; ///< 双精度浮点稀疏矩阵
typedef spmat<std::complex<float> > _1cf_spmat; ///< 单精度复浮点稀疏矩阵
typedef spmat<std::complex<double> > _1cd_spmat; ///< 双精度复浮点稀疏矩阵
/**
* @brief 稀疏矩阵的节点元素类型
*
* @tparam NodeValueType 模版变量类型
*/
template <typename NodeValueType>
struct mat_node
{
int r_id, c_id; ///< 节点的行列号
NodeValueType val; ///< 节点值
mat_node<NodeValueType> *next_right; ///< 指向同行右方节点的指针
mat_node<NodeValueType> *next_down; ///< 指向同列下方节点的指针
/**
* 构造函数
*/
mat_node()
{
val = (NodeValueType) 0;
r_id = c_id = -1;
next_right = next_down = nullptr;
}
mat_node(int r, int c, NodeValueType v)
{
r_id = r; c_id = c;
val = v;
next_right = next_down = nullptr;
}
NodeValueType value() const
{
return val;
}
void value(NodeValueType in_val)
{
val = in_val;
return;
}
};
/**
* @brief 基于十字指针的稀疏矩阵的模版类 定义常规的加减乘除与矩阵运算
*
* @tparam MatrixValueType 模版变量类型
*/
template <typename MatrixValueType>
class spmat
{
protected:
mat_node<MatrixValueType> **r_head, **c_head; ///< 行和列的头指针
mat_node<MatrixValueType> **r_end, **c_end; ///< 行和列的尾指针 这两个变量的使用主要是为了提高插入操作的效率
mat_node<MatrixValueType> **d_link; ///< 所有非零元素按行优先排序的指针数组,可在稀疏矩阵元素位置不变但值经常改变时快速索引并改变值
int *r_count, *c_count; ///< 行与列的非零元素的个数
int r_num, c_num; ///< 满矩阵的行列数
int d_num; ///< d_link长度
MatrixValueType zero_val; ///< 类型的0值
public:
/**
* @brief 默认构造函数
*/
spmat();
/**
* @brief 构造函数:空的行列头指针
*
* @param[in] in_rnum 矩阵行数
* @param[in] in_cnum 矩阵列数
* @param[in] null_val 矩阵零值
*/
spmat(int in_rnum, int in_cnum, MatrixValueType null_val);
/**
* @brief 拷贝构造函数
*
* @param[in] b 拷贝稀疏矩阵
*/
spmat(const spmat<MatrixValueType> &b);
/**
* @brief 析构函数
*/
virtual ~spmat();
/**
* @brief 初始化为空的行列头指针
*
* @param[in] in_rnum 矩阵行数
* @param[in] in_cnum 矩阵列数
* @param[in] null_val 矩阵零值
*/
void malloc(int in_rnum, int in_cnum, MatrixValueType null_val);
/**
* @brief 清空稀疏矩阵
*
* @note 清空整个矩阵时会删除所有元素和辅助数组必须重新调用malloc函数再能插入元素。删除某行时仅删除已有元素可以直接再次插入元素。
*
* @param[in] index 行或者列的索引号,如果为-1则清空整个稀疏矩阵
* @param[in] mode 清空制定的行或者列,默认为行模式
*/
void clear(int index = -1, matrix_order_e mode = RowMajor);
/**
* @brief 重置稀疏矩阵仅删除所有已有元素可以直接插入元素。相当于对所有行调用clear函数。
*
*/
void reset();
/**
* @brief 删除所有等于零值的元素
*/
void purge();
/**
* @brief 设置所有非零值为指定值如果输入为零值则直接调用reset函数
*
* @note 注意此函数可能会重置稀疏矩阵
*
* @param in_val 输入值
*/
void set_all(MatrixValueType in_val);
/**
* @brief 从三元组数组赋值,三元组的排列必须是按行优先方式排序,顺序增加,可有重复索引的元素(函数会检查并报错)
*
* @note 注意此函数会重置稀疏矩阵
*
* @param triplts 三元组数组
* @param val_mode 相同位置重复输入值的处理方式
*/
void set_triplts(const std::vector<mat_node<MatrixValueType> > &triplts, value_operator_e val_mode = AppendVal);
/**
* @brief 从COO格式储存的稀疏矩阵对矩阵进行赋值元素排列必须是按行优先方式排序顺序增加不可有重复索引的元素函数不检查和报错
*
* @note 注意此函数会重置稀疏矩阵
*
* @param row_idx 非零元素的行索引数组
* @param col_idx 非零元素的列索引数组
* @param data 非零元素数组
*/
void set_coo(const array<size_t> &row_idx, const array<size_t> &col_idx, const array<MatrixValueType> &data);
/**
* @brief 从CSR格式储存的稀疏矩阵对矩阵进行赋值元素排列必须是按行优先方式排序顺序增加不可有重复索引的元素函数不检查和报错
*
* @note 注意此函数会重置稀疏矩阵
*
* @param row_off 非零元素的行偏移数组
* @param col_idx 非零元素的列索引数组
* @param data 非零元素数组
*/
void set_csr(const array<size_t> &row_off, const array<size_t> &col_idx, const array<MatrixValueType> &data);
/**
* @brief 从二维向量对矩阵进行赋值
*
* @param[in] den_mat_ptr 二维向量
* @param[in] off_set 初始化时零值的偏差范围
*/
void set_2d_vector(const std::vector<std::vector<MatrixValueType> > &den_mat_ptr, MatrixValueType off_set);
/**
* @brief 从二维数组对矩阵进行赋值
*
* @param den_mat_ptr 二维数组的指针
* @param[in] off_set 初始化时零值的偏差范围
*/
void set_2d_array(MatrixValueType **den_mat_ptr, MatrixValueType off_set);
/**
* @brief 从matrix数组对矩阵进行赋值
*
* @param[in] den_mat_ptr matrix数组
* @param[in] off_set 初始化时零值的偏差范围
*/
void set_matrix(const matrix<MatrixValueType> &den_mat_ptr, MatrixValueType off_set);
/**
* @brief 储存非零元素的储存位置建立快速查找索引目前只在set_triplts函数中使用储存的位置
*
* @note 元素数量或位置改变后失效
*
*/
void init_pattern();
/**
* @brief 如果稀疏矩阵的行列数为零,则为空的稀疏矩阵
*
* @return 矩阵是否为空
*/
bool empty() const;
/**
* @brief 返回行数
*
* @return 行数
*/
int row_size() const;
/**
* @brief 返回列数
*
* @return 列数
*/
int col_size() const;
/**
* @brief 返回非0元素个数
*
* 此函数可返回矩阵中所有或者指定行或者列的零值元素个数
*
* @param[in] index 行或列的索引
* @param[in] mode 计算行还是列的非零元素个数
*
* @return 非0元素个数
*/
int ele_size(int index = -1, matrix_order_e mode = RowMajor) const;
/**
* @brief 返回0值
*
* @return 0值
*/
MatrixValueType zero_value() const;
/**
* @brief 按矩阵形式显示所有元素包括0元素
*/
void show_matrix(char delimiter = '\t') const;
/**
* @brief 按列表形式显示三元组
*
* @param[in] mode 按行优先或者列优先形式排序
*/
void show_list(matrix_order_e mode = RowMajor, char delimiter = ' ', bool full = false) const;
/**
* @brief 返回位于(i, j)位置的元素
*
* @param[in] i_index 行索引
* @param[in] j_index 列索引
*
* @return 矩阵元素
*/
MatrixValueType at(size_t i_index, size_t j_index) const;
/**
* @brief 输出稠密矩阵
*
* @param ret_arr2d 以引用形式返回的matrix数组
*/
void export_dense(matrix<MatrixValueType> &ret_arr2d) const;
/**
* @brief 输出矩阵中某一行或列
*
* @param[in] out_id 行或列的索引
* @param ret_arr 以引用形式返回的array数组
* @param[in] multipler 倍数默认为1.0
* @param[in] line_mode 是否为行优先
* @param[in] val_mode 返回数组的数值操作方式
*/
void export_dense(int out_id, array<MatrixValueType> &ret_arr,
double multipler = 1.0, matrix_order_e line_mode = RowMajor,
value_operator_e val_mode = ReplaceVal) const;
/**
* @brief 使用COO格式输出稀疏矩阵
*
* @param row_idx 非零元素的行索引数组
* @param col_idx 非零元素的列索引数组
* @param data 非零元素数组
*/
void export_coo(array<size_t> &row_idx, array<size_t> &col_idx, array<MatrixValueType> &data) const;
/**
* @brief 使用CSR格式输出稀疏矩阵
*
* @param row_off 非零元素的行偏移数组
* @param col_idx 非零元素的列索引数组
* @param data 非零元素数组
*/
void export_csr(array<size_t> &row_off, array<size_t> &col_idx, array<MatrixValueType> &data) const;
/**
* @brief 添加一个元素 若插入位置已有值则替换
*
* @param[in] r 行索引
* @param[in] c 列索引
* @param[in] v 插入值
*/
void insert(int r, int c, MatrixValueType v);
/**
* @brief 删除一个元素
*
* @param[in] r 行索引
* @param[in] c 列索引
*/
void remove(int r, int c);
/**
* @brief 计算非零元素值的总和
*
* @param[in] index 行或者列的索引号,如果为-1则计算整个稀疏矩阵
* @param[in] mode 清空制定的行或者列,默认为行模式
*/
MatrixValueType sum(int index = -1, matrix_order_e mode = RowMajor);
/**
* @brief 计算行或列的模长
*
* @param index 行或者列的索引号
* @param mode 切换行与列模式
* @return 测度值
*/
MatrixValueType module(int index, matrix_order_e mode = RowMajor);
/**
* @brief 单个元素位置的加法
*
* @param[in] r 行索引
* @param[in] c 列索引
* @param[in] v 被加数
*/
void add_scalar(int r, int c, MatrixValueType v);
/**
* @brief 单个元素位置的减法
*
* @param[in] r 行索引
* @param[in] c 列索引
* @param[in] v 被减数
*/
void minus_scalar(int r, int c, MatrixValueType v);
// 矩阵运算
/**
* @brief 稀疏矩阵相加
*
* @param[in] b 被加稀疏矩阵
*/
void add_sparse_matrix(const spmat<MatrixValueType> &b);
/**
* @brief 稀疏矩阵相减
*
* @param[in] b 被减稀疏矩阵
*/
void minus_sparse_matrix(const spmat<MatrixValueType> &b);
/**
* @brief 稠密矩阵相加
*
* @param[in] arr2d 引用的形式返回的相加后矩阵
*/
void add_matrix(matrix<MatrixValueType> &arr2d) const;
/**
* @brief 稠密矩阵相减
*
* @param arr2d 引用的形式返回的相减后矩阵
* @param[in] preposition 稠密矩阵为减数
*/
void minus_matrix(matrix<MatrixValueType> &arr2d, bool preposition = false) const;
/**
* @brief 映射某行或列的数据到另一行或列
*
* @param[in] from_index 来源行或列的索引
* @param[in] to_index 目标行或列的索引
* @param[in] multipler 倍数
* @param[in] line_mode 是否为行优先
* @param[in] val_mode 返回数组的数值操作方式
*/
void map(int from_index, int to_index, MatrixValueType multipler,
matrix_order_e line_mode = RowMajor, value_operator_e val_mode = AppendVal);
/**
* @brief 计算转置矩阵
*
* @param ret_mat 转置后矩阵
*/
void transpose(spmat<MatrixValueType> &ret_mat) const;
/**
* @brief 单个元素位置的乘法
*
* @param[in] r 行索引
* @param[in] c 列索引
* @param[in] v 乘数
*/
void multiply_scalar(int r, int c, MatrixValueType v);
/**
* @brief 稀疏矩阵的乘法
*
* @param[in] b 待乘稀疏矩阵
* @param ret_mat 乘积稀疏矩阵
*/
void multiply_sparse_matrix(const spmat<MatrixValueType> &b, spmat<MatrixValueType> &ret_mat) const;
/**
* @brief 矩阵乘法的母函数
*
* @param arr2d 待乘二维数组的指针(需提前开辟好内存空间)
* @param[in] arr2d_rsize 待乘二维数组的行数
* @param[in] arr2d_csize 待乘二维数组的列数
* @param ret_arr2d 乘积二维数组的指针(需提前开辟好内存空间)
* @param[in] ret_arr2d_rsize 乘积二维数组的行数
* @param[in] ret_arr2d_csize 乘积二维数组的列数
*/
void multiply_matrix(MatrixValueType **arr2d, int arr2d_rsize, int arr2d_csize,
MatrixValueType **ret_arr2d, int ret_arr2d_rsize, int ret_arr2d_csize) const;
/**
* @brief 矩阵乘法的母函数
*
* @note 稀疏矩阵与稠密矩阵的积也会是一个稠密的矩阵
*
* @param arr2d 待乘二维数组(需提前开辟好内存空间)
* @param ret_arr2d 乘积二维数组的指针
*/
void multiply_matrix(const matrix<MatrixValueType> &arr2d, matrix<MatrixValueType> &ret_arr2d) const;
/**
* @brief 矩阵与向量相乘
*
* @param[in] arr 输入数组指针
* @param[in] arr_size 输入数组大小
* @param ret_arr 输出数组指针
* @param[in] ret_size 输出数组大小
* @param[in] layout 是否使用稀疏矩阵的转置
*/
void multiply_vector(const MatrixValueType *arr, int arr_size, MatrixValueType *ret_arr,
int ret_size, matrix_layout_e layout = NoTrans) const;
/**
* @brief 稀疏矩阵与向量相乘
*
* 此函数会计算稀疏矩阵与一个向量的乘积向量(一维数组)
*
* @param[in] arr 待乘的向量数组
* @param ret_arr 乘积向量的数组
* @param[in] layout 是否使用稀疏矩阵的转置
*
*/
void multiply_vector(const array<MatrixValueType> &arr, array<MatrixValueType> &ret_arr,
matrix_layout_e layout = NoTrans) const;
/**
* @brief 稀疏矩阵的某行或列与向量相乘
*
* 此函数会计算稀疏矩阵的行或列与一个向量的乘积向量(一维数组)
*
* @param[in] arr 待乘的向量数组
* @param index 与向量相乘的稀疏矩阵的行或列索引
* @param[in] layout 是否使用稀疏矩阵的转置
*
*/
double multiply_vector(const array<MatrixValueType> &arr, int index,
matrix_layout_e layout = NoTrans) const;
/**
* @brief 按元素与向量相乘
*
* @param[in] oper_id 稀疏矩阵的行(非转置)或者列(转置)序号
* @param[in] arr 输入数组指针
* @param[in] arr_size 输入数组大小
* @param ret_arr 输出数组指针
* @param[in] layout 是否使用稀疏矩阵的转置
*/
void multiply_vector(int oper_id, const MatrixValueType *arr, int arr_size,
MatrixValueType *ret_arr, matrix_layout_e layout = NoTrans) const;
/**
* @brief 与对角矩阵相乘
*
* @param arr 输入的对角矩阵(保存为一个一维数组)
* @param ret_mat 乘积矩阵
* @param prepositioned 对角矩阵是否在稀疏矩阵前,为真表示对角矩阵乘稀疏矩阵,为假则表示稀疏矩阵乘对角矩阵
*/
void multiply_diagonal_matrix(const array<MatrixValueType> &arr, spmat<MatrixValueType> &ret_mat, bool prepositioned = false) const;
/**
* @brief 返回制定行或列的布尔数组reverse为真则布尔数组在无元素的位置为真
*
* @param[in] oper_id The operator identifier
* @param ret_arr The ret arr
* @param[in] ele_mode The ele mode
* @param[in] reverse The reverse
*/
void boolean(int oper_id, array<bool> &ret_arr, matrix_order_e ele_mode = RowMajor,
bool reverse = false) const;
/**
* @brief 按行或列对矩阵进行归一化
*
* @param[in] oper_id 行或列的索引
* @param[in] norm 归一化后的大小
* @param[in] line_mode 归一化的方向
*/
void normalize(int oper_id, MatrixValueType norm, matrix_order_e line_mode = RowMajor);
/**
* @brief 对矩阵元素进行缩放
*
* @param f 缩放倍数
* @param idx 行或列的索引
* @param ele_mode 行或列模式
*/
void scale(MatrixValueType f, int idx, matrix_order_e ele_mode = RowMajor);
/**
* @brief 返回对角线元素,只对方阵有效
*
* @param dia 对角线元素
*/
void get_diagonal(array<MatrixValueType> &dia);
/**
* @brief 重载赋值操作符
*
* @param[in] b { parameter_description }
*
* @return The result of the assignment
*/
spmat<MatrixValueType>& operator= (const spmat<MatrixValueType> &b);
#ifdef GCTL_EIGEN
/**
* @brief 稀疏矩阵与Eigen向量相乘
*
* 此函数会计算稀疏矩阵与一个竖或者横向量的乘积向量(一维数组)。
* 与竖向量相乘为矩阵乘向量,与横向量相乘为向量乘矩阵
*
* @param vec 待乘的向量数组
* @param ret_vec 乘积向量的数组
* @param row_vector 待乘向量是否为横向量,默认为假(即默认为竖向量)
*/
void multiply_vector(const Eigen::VectorXd &vec, Eigen::VectorXd &ret_vec,
bool row_vector = false) const;
#endif // GCTL_EIGEN
private:
/**
* @brief 单个矩阵元素操作
*
* @param[in] r 行索引
* @param[in] c 列索引
* @param[in] v 操作值
* @param[in] mode 操作类型(默认为替换,可用的类型请参考枚举类型的声明)
*
* @return 若元素操作后为零返回真,否则返回假
*/
bool change_element(int r, int c, MatrixValueType v, value_operator_e mode = ReplaceVal);
/**
* @brief 返回行头指针
* @return 头指针
*/
mat_node<MatrixValueType> **row_head() const;
/**
* @brief 返回列头指针
* @return 头指针
*/
mat_node<MatrixValueType> **col_head() const;
};
template <typename MatrixValueType>
spmat<MatrixValueType>::spmat()
{
r_num = c_num = d_num = 0;
r_head = c_head = nullptr;
r_end = c_end = nullptr;
d_link = nullptr;
r_count = c_count = nullptr;
zero_val = (MatrixValueType) 0;
}
template <typename MatrixValueType>
spmat<MatrixValueType>::spmat(int in_rnum, int in_cnum, MatrixValueType null_val)
{
malloc(in_rnum, in_cnum, null_val);
}
template <typename MatrixValueType>
spmat<MatrixValueType>::spmat(const spmat<MatrixValueType> &b)
{
malloc(b.row_size(), b.col_size(), b.zero_value());
mat_node<MatrixValueType> **br_head = b.row_head();
mat_node<MatrixValueType> *bp, *p, *q;
int i, j;
for (int r = 0; r < r_num; r++)
{
if (br_head[r] != nullptr)
{
bp = br_head[r]->next_right;
while (bp != nullptr)
{
mat_node<MatrixValueType>* new_node =
new mat_node<MatrixValueType>;
new_node->r_id = bp->r_id;
new_node->c_id = bp->c_id;
new_node->val = bp->val;
i = bp->r_id; j = bp->c_id;
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的 在尾部插入
{
p = r_end[i];
p->next_right = new_node;
r_end[i] = new_node;
r_count[i]++; // 增加行计数
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++; // 增加行计数
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
q = c_end[j];
q->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
bp = bp->next_right;
}
}
}
}
template <typename MatrixValueType>
spmat<MatrixValueType>::~spmat()
{
clear();
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::malloc(int in_rnum, int in_cnum, MatrixValueType null_val)
{
if (in_rnum <= 0 || in_cnum <= 0)
{
throw std::runtime_error("Invalid matrix size. From void spmat<T>::malloc(...)");
}
zero_val = null_val;
d_num = 0;
d_link = nullptr;
r_num = in_rnum; c_num = in_cnum;
r_head = new mat_node<MatrixValueType>* [in_rnum];
c_head = new mat_node<MatrixValueType>* [in_cnum];
r_end = new mat_node<MatrixValueType>* [in_rnum];
c_end = new mat_node<MatrixValueType>* [in_cnum];
r_count = new int [in_rnum];
c_count = new int [in_cnum];
for (int i = 0; i < r_num; i++)
{
r_head[i] = nullptr; r_end[i] = nullptr; r_count[i] = 0;
}
for (int i = 0; i < c_num; i++)
{
c_head[i] = nullptr; c_end[i] = nullptr; c_count[i] = 0;
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::clear(int index, matrix_order_e mode)
{
int r, c;
mat_node<MatrixValueType> *p, *q, *tmp_node;
if (index < 0)
{
if (r_head != nullptr && c_head != nullptr)
{
for (int i = 0; i < r_num; i++)
{
p = r_head[i];
while (p != nullptr)
{
q = p; p = p->next_right;
delete q; q = nullptr;
}
}
delete[] r_head; r_head = nullptr;
delete[] c_head; c_head = nullptr;
delete[] r_end; r_end = nullptr;
delete[] c_end; c_end = nullptr;
delete[] r_count; r_count = nullptr;
delete[] c_count; c_count = nullptr;
}
if (d_num)
{
delete[] d_link; d_link = nullptr;
d_num = 0;
}
r_num = c_num = 0;
}
else if (mode == RowMajor)
{
if (index >= r_num)
{
throw runtime_error("[gctl::spmat<T>::clear] Invalid index.");
}
if (r_head != nullptr && r_head[index] != nullptr)
{
p = r_head[index]->next_right;
while (p != nullptr)
{
tmp_node = p;
p = p->next_right;
c = tmp_node->c_id;
q = c_head[c];
while (index != q->next_down->r_id)
{
q = q->next_down;
}
if (q == c_head[c] && q->next_down->next_down == nullptr)
{
delete c_head[c];
c_head[c] = nullptr;
c_end[c] = nullptr;
}
else if (q->next_down == c_end[c])
{
q->next_down = nullptr;
c_end[c] = q;
}
else
{
q->next_down = q->next_down->next_down;
}
c_count[c]--;
delete tmp_node; tmp_node = nullptr;
}
r_head[index] = nullptr;
r_end[index] = nullptr;
r_count[index] = 0;
if (d_num)
{
delete[] d_link; d_link = nullptr;
d_num = 0;
}
}
}
else
{
if (index >= c_num)
{
throw runtime_error("[gctl::spmat<T>::clear] Invalid index.");
}
if (c_head != nullptr && c_head[index] != nullptr)
{
p = c_head[index]->next_down;
while (p != nullptr)
{
tmp_node = p;
p = p->next_down;
r = tmp_node->r_id;
q = r_head[r];
while (index != q->next_right->c_id)
{
q = q->next_right;
}
if (q == r_head[r] && q->next_right->next_right == nullptr)
{
delete r_head[r];
r_head[r] = nullptr;
r_end[r] = nullptr;
}
else if (q->next_right == r_end[r])
{
q->next_right = nullptr;
r_end[r] = q;
}
else
{
q->next_right = q->next_right->next_right;
}
r_count[r]--;
delete tmp_node; tmp_node = nullptr;
}
c_head[index] = nullptr;
c_end[index] = nullptr;
c_count[index] = 0;
if (d_num)
{
delete[] d_link; d_link = nullptr;
d_num = 0;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::reset()
{
mat_node<MatrixValueType> *p, *q;
for (int i = 0; i < r_num; i++)
{
p = r_head[i];
while (p != nullptr)
{
q = p; p = p->next_right;
delete q; q = nullptr;
}
}
for (int i = 0; i < r_num; i++)
{
r_head[i] = nullptr; r_end[i] = nullptr; r_count[i] = 0;
}
for (int i = 0; i < c_num; i++)
{
c_head[i] = nullptr; c_end[i] = nullptr; c_count[i] = 0;
}
if (d_num)
{
delete[] d_link; d_link = nullptr;
d_num = 0;
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::purge()
{
mat_node<MatrixValueType> *p, *q, *tmp_node;
for (int i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i];
while (p->next_right != nullptr)
{
if (p->next_right->val == zero_val)
{
// 更改行与列的计数
r_count[i]--;
c_count[p->next_right->c_id]--;
q = c_head[p->next_right->c_id];
while (i != q->next_down->r_id)
{
q = q->next_down;
}
if (q == c_head[p->next_right->c_id] &&
q->next_down->next_down == nullptr) // 在列首且仅有列首
{
delete c_head[p->next_right->c_id];
c_head[p->next_right->c_id] = nullptr;
c_end[p->next_right->c_id] = nullptr;
}
else if (q->next_down == c_end[p->next_right->c_id]) // 在列尾
{
q->next_down = nullptr;
c_end[p->next_right->c_id] = q;
}
else
{
// 此处不删除元素
q->next_down = q->next_down->next_down;
}
if (p == r_head[i] &&
p->next_right->next_right == nullptr)
{
delete p->next_right;
p->next_right = nullptr;
delete r_head[i];
r_head[i] = nullptr;
r_end[i] = nullptr;
break;
}
else if (p->next_right == r_end[i])
{
tmp_node = p->next_right;
p->next_right = nullptr;
delete tmp_node;
tmp_node = nullptr;
r_end[i] = p;
}
else
{
tmp_node = p->next_right;
p->next_right = p->next_right->next_right;
delete tmp_node;
tmp_node = nullptr;
}
}
else p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_all(MatrixValueType in_val)
{
if (in_val == zero_val) // reset the whole matrix to the initial state
{
reset();
return;
}
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
p->val = in_val;
p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_triplts(const std::vector<mat_node<MatrixValueType> > &triplts, value_operator_e val_mode)
{
// 如果存在d_link则只需要更改数值即可
if (d_num)
{
int c = 0;
int old_r = -1, old_c = -1;
for (size_t t = 0; t < triplts.size(); t++)
{
if(c > d_num) throw std::runtime_error("[gctl::spmat<T>::set_triplts] Invalid triplts' size.");
if (triplts[t].r_id == old_r && triplts[t].c_id == old_c) // 重复的元素位置
{
c--; // 索引减一 (默认会往前挪一位 所以要往回挪一位)
if (val_mode == AppendVal) {d_link[c]->val += triplts[t].val; c++;} // 索引加一
if (val_mode == ReplaceVal) {d_link[c]->val = triplts[t].val; c++;} // 索引加一
}
else // 新的元素位置
{
old_r = triplts[t].r_id;
old_c = triplts[t].c_id;
d_link[c]->val = triplts[t].val;
c++; // 索引加一
}
}
return;
}
// 如果矩阵已经初始化 重置稀疏矩阵
if (!empty()) reset();
else throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::set_triplts(...)");
int old_i = -1, old_j = -1;
int i, j;
for (size_t t = 0; t < triplts.size(); t++)
{
i = triplts[t].r_id;
j = triplts[t].c_id;
if (i < 0 || j < 0 || i >= r_num || j >= c_num)
{
throw std::runtime_error("Invalid triplt's index. From gctl::spmat<T>::set_triplts(...)");
}
if (old_i >= i && old_j > j) // 按行按列顺序添加
{
throw std::runtime_error("The input triplts are not properly arranged. From gctl::spmat<T>::set_triplts(...)");
}
if (old_i == i && old_j == j) // 重复输入 只需要改变值就行了
{
if (val_mode == ReplaceVal) r_end[i]->val = triplts[t].val;
if (val_mode == AppendVal) r_end[i]->val += triplts[t].val;
continue;
}
// 新元素
mat_node<MatrixValueType> *new_node = new mat_node<MatrixValueType>; // 创建新节点 这里必定是需要新建节点的
new_node->r_id = triplts[t].r_id;
new_node->c_id = triplts[t].c_id;
new_node->val = triplts[t].val;
old_i = i;
old_j = j;
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的
{
r_end[i]->next_right = new_node;
r_end[i] = new_node;
r_count[i]++;
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++;
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
c_end[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_coo(const array<size_t> &row_idx, const array<size_t> &col_idx, const array<MatrixValueType> &data)
{
if (row_idx.size() != col_idx.size() || col_idx.size() != data.size() || data.empty())
{
throw std::runtime_error("Invalid input COO sparse matrix. From gctl::spmat<T>::set_coo(...)");
}
// 如果矩阵已经初始化 重置稀疏矩阵
if (!empty()) reset();
else throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::set_coo(...)");
size_t i, j;
for (size_t t = 0; t < data.size(); t++)
{
if (row_idx[t] >= r_num || col_idx[t] >= c_num)
{
throw std::runtime_error("Invalid COO index. From gctl::spmat<T>::set_coo(...)");
}
// 新元素
mat_node<MatrixValueType> *new_node = new mat_node<MatrixValueType>; // 创建新节点 这里必定是需要新建节点的
i = row_idx[t];
j = col_idx[t];
new_node->r_id = row_idx[t];
new_node->c_id = col_idx[t];
new_node->val = data[t];
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的
{
r_end[i]->next_right = new_node;
r_end[i] = new_node;
r_count[i]++;
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++;
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
c_end[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_csr(const array<size_t> &row_off, const array<size_t> &col_idx, const array<MatrixValueType> &data)
{
if (row_off.size() < 2 || row_off[0] != 0 || row_off.back() != col_idx.size() || col_idx.size() != data.size() || data.empty())
{
throw std::runtime_error("Invalid input CSR sparse matrix. From gctl::spmat<T>::set_csr(...)");
}
// 如果矩阵已经初始化 重置稀疏矩阵
if (!empty()) reset();
else throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::set_csr(...)");
size_t i, j;
for (size_t r = 0; r < row_off.size() - 1; r++)
{
for (size_t t = row_off[r]; t < row_off[r+1]; t++)
{
if (r >= r_num || col_idx[t] >= c_num)
{
throw std::runtime_error("Invalid CSR index. From gctl::spmat<T>::set_csr(...)");
}
// 新元素
mat_node<MatrixValueType> *new_node = new mat_node<MatrixValueType>; // 创建新节点 这里必定是需要新建节点的
i = r;
j = col_idx[t];
new_node->r_id = r;
new_node->c_id = col_idx[t];
new_node->val = data[t];
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的
{
r_end[i]->next_right = new_node;
r_end[i] = new_node;
r_count[i]++;
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++;
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
c_end[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_2d_vector(const std::vector<std::vector<MatrixValueType> > &den_mat_ptr, MatrixValueType off_set)
{
if (den_mat_ptr.empty())
{
throw runtime_error("The input 2d vector is empty. From void gctl::spmat<T>::set_2d_vector(...)");
}
// 如果矩阵已经初始化 重置稀疏矩阵
if (!empty()) reset();
else throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::set_2d_vector(...)");
// 确定二维向量的最大列数
int max_cnum = 0;
for (int i = 0; i < den_mat_ptr.size(); i++)
{
max_cnum = GCTL_MAX(max_cnum, den_mat_ptr[i].size());
}
if (max_cnum > c_num || den_mat_ptr.size() > r_num)
{
throw runtime_error("The input 2d vector exceeds the maximal size. From void gctl::spmat<T>::set_2d_vector(...)");
}
mat_node<MatrixValueType> *p, *q;
for (int i = 0; i < den_mat_ptr.size(); i++)
{
for (int j = 0; j < den_mat_ptr[i].size(); j++)
{
if (den_mat_ptr[i][j] >= zero_val + off_set ||
den_mat_ptr[i][j] <= zero_val - off_set) // 输入值不为零则添加
{
mat_node<MatrixValueType> *new_node =
new mat_node<MatrixValueType>; // 创建新节点 这里必定是需要新建节点的
new_node->r_id = i;
new_node->c_id = j;
new_node->val = den_mat_ptr[i][j];
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的
{
p = r_end[i];
p->next_right = new_node;
r_end[i] = new_node;
r_count[i]++;
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++;
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
q = c_end[j];
q->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_2d_array(MatrixValueType **den_mat_ptr, MatrixValueType off_set)
{
if (den_mat_ptr == nullptr)
{
throw runtime_error("The input pointer is null. From void gctl::spmat<T>::set_2d_array(...)");
}
// 如果矩阵已经初始化 重置稀疏矩阵
if (!empty()) reset();
else throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::set_2d_array(...)");
mat_node<MatrixValueType> *p, *q;
for (int i = 0; i < r_num; i++)
{
for (int j = 0; j < c_num; j++)
{
if (den_mat_ptr[i][j] >= zero_val + off_set ||
den_mat_ptr[i][j] <= zero_val - off_set) // 输入值不为零则添加
{
mat_node<MatrixValueType> *new_node =
new mat_node<MatrixValueType>; // 创建新节点 这里必定是需要新建节点的
new_node->r_id = i;
new_node->c_id = j;
new_node->val = den_mat_ptr[i][j];
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的
{
p = r_end[i];
p->next_right = new_node;
r_end[i] = new_node;
r_count[i]++;
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++;
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
q = c_end[j];
q->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::set_matrix(const matrix<MatrixValueType> &den_mat_ptr, MatrixValueType off_set)
{
if (den_mat_ptr.row_size() > r_num || den_mat_ptr.col_size() > c_num)
{
throw runtime_error("The input matrix exceeds the maximal size. From void gctl::spmat<T>::set_matrix(...)");
}
set_2d_array(den_mat_ptr.get(), off_set);
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::init_pattern()
{
if (d_num)
{
delete[] d_link; d_link = nullptr;
d_num = 0;
}
d_num = ele_size();
if (d_num)
{
d_link = new mat_node<MatrixValueType>* [d_num];
for (int i = 0; i < d_num; i++)
{
d_link[i] = nullptr;
}
}
else return;
int c = 0;
mat_node<MatrixValueType>* p;
for (int i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
d_link[c] = p;
p = p->next_right;
c++;
}
}
}
return;
}
template <typename MatrixValueType>
bool spmat<MatrixValueType>::empty() const
{
if (r_num == 0 && c_num == 0) return true;
else return false;
}
template <typename MatrixValueType>
int spmat<MatrixValueType>::row_size() const
{
return r_num;
}
template <typename MatrixValueType>
int spmat<MatrixValueType>::col_size() const
{
return c_num;
}
template <typename MatrixValueType>
int spmat<MatrixValueType>::ele_size(int index, matrix_order_e mode) const
{
if (index == -1)
{
int sum = 0;
for (int i = 0; i < r_num; i++)
{
sum += r_count[i];
}
return sum;
}
else if (mode == RowMajor)
{
if (index < 0 || index >= r_num)
{
throw std::runtime_error("[gctl::spmat<T>::ele_size] Invalid index.");
}
return r_count[index];
}
else
{
if (index < 0 || index >= c_num)
{
throw std::runtime_error("[gctl::spmat<T>::ele_size] Invalid index.");
}
return c_count[index];
}
}
template <typename MatrixValueType>
MatrixValueType spmat<MatrixValueType>::zero_value() const
{
return zero_val;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::show_matrix(char delimiter) const
{
int st;
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
st = 0;
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
for (int s = st; s < p->c_id; s++)
std::cout << zero_val << delimiter;
std::cout << p->val << delimiter;
st = p->c_id + 1;
p = p->next_right;
}
}
if (st <= c_num-1)
{
for (int s = st; s < c_num; s++)
std::cout << zero_val << delimiter;
}
std::cout << std::endl;
}
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::show_list(matrix_order_e mode, char delimiter, bool full) const
{
int st;
if (mode == RowMajor)
{
std::cout << "# row" << delimiter << "col" << delimiter << "value" << std::endl;
mat_node<MatrixValueType> *p;
if (full)
{
for (int i = 0; i < r_num; i++)
{
st = 0;
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
for (int s = st; s < p->c_id; s++)
{
std::cout << i << delimiter << s << delimiter << zero_val << std::endl;
}
std::cout << i << delimiter << p->c_id << delimiter << p->val << std::endl;
st = p->c_id + 1;
p = p->next_right;
}
}
if (st <= c_num-1)
{
for (int s = st; s < c_num; s++)
std::cout << i << delimiter << s << delimiter << zero_val << std::endl;
}
}
return;
}
for (int i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
// 输出(row, col, val)三元组
std::cout << p->r_id << delimiter << p->c_id << delimiter << p->val << std::endl;
p = p->next_right;
}
}
}
return;
}
std::cout << "# col" << delimiter << "row" << delimiter << "value" << std::endl;
mat_node<MatrixValueType> *q;
if (full)
{
for (int i = 0; i < c_num; i++)
{
st = 0;
if (c_head[i] != nullptr)
{
q = c_head[i]->next_down;
while (q != nullptr)
{
for (int s = st; s < q->r_id; s++)
{
std::cout << i << delimiter << s << delimiter << zero_val << std::endl;
}
std::cout << i << delimiter << q->r_id << delimiter << q->val << std::endl;
st = q->r_id + 1;
q = q->next_down;
}
}
if (st <= r_num-1)
{
for (int s = st; s < r_num; s++)
std::cout << i << delimiter << s << delimiter << zero_val << std::endl;
}
}
return;
}
for (int i = 0; i < c_num; i++)
{
if (c_head[i] != nullptr)
{
q = c_head[i]->next_down;
while (q != nullptr)
{
// 输出(row, col, val)三元组
std::cout << q->c_id << delimiter << q->r_id << delimiter << q->val << std::endl;
q = q->next_down;
}
}
}
return;
}
template <typename MatrixValueType>
MatrixValueType spmat<MatrixValueType>::at(size_t i_index, size_t j_index) const
{
#ifdef GCTL_CHECK_BOUNDER
if (i_index >= r_num || j_index >= c_num)
{
throw std::runtime_error("Invalid index. From gctl::spmat<T>::at(...)");
}
#endif // GCTL_CHECK_BOUNDER
mat_node<MatrixValueType> *p, *q;
if (r_head[i_index] != nullptr && c_head[j_index] != nullptr)
{
p = r_end[i_index];
if (j_index > p->c_id) return zero_val;
p = r_head[i_index]->next_right;
if (j_index < p->c_id) return zero_val;
q = c_end[j_index];
if (i_index > q->r_id) return zero_val;
q = c_head[j_index]->next_down;
if (i_index < q->r_id) return zero_val;
if (r_count[i_index] <= c_count[j_index])
{
while (p != nullptr)
{
if (p->c_id == j_index)
{
return p->val;
}
p = p->next_right;
}
return zero_val;
}
while (q != nullptr)
{
if (q->r_id == i_index)
{
return q->val;
}
q = q->next_down;
}
return zero_val;
}
return zero_val;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::export_dense(matrix<MatrixValueType> &ret_arr2d) const
{
ret_arr2d.resize(r_num, c_num);
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
for (int j = 0; j < c_num; j++)
{
ret_arr2d[i][j] = zero_val;
}
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
ret_arr2d[i][p->c_id] = p->val;
p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::export_dense(int out_id, array<MatrixValueType> &ret_arr,
double multipler, matrix_order_e line_mode, value_operator_e val_mode) const
{
if (line_mode == RowMajor)
{
if (out_id < 0 || out_id >= r_num)
{
throw std::runtime_error("[gctl::spmat<T>::export_dense] Invalid index.");
}
if (val_mode != AppendVal)
{
ret_arr.resize(c_num, zero_val);
}
else if (ret_arr.size() != c_num)
{
throw std::runtime_error("[gctl::spmat<T>::export_dense] Incompatible array size.");
}
mat_node<MatrixValueType> *p;
if (r_head[out_id] != nullptr)
{
p = r_head[out_id]->next_right;
while (p != nullptr)
{
ret_arr[p->c_id] += p->val * multipler;
p = p->next_right;
}
}
}
else
{
if (out_id < 0 || out_id >= c_num)
{
throw std::runtime_error("[gctl::spmat<T>::export_dense] Invalid index.");
}
if (val_mode != AppendVal)
{
ret_arr.resize(r_num, zero_val);
}
else if (ret_arr.size() != r_num)
{
throw std::runtime_error("[gctl::spmat<T>::export_dense] Incompatible array size.");
}
mat_node<MatrixValueType> *q;
if (c_head[out_id] != nullptr)
{
q = c_head[out_id]->next_down;
while (q != nullptr)
{
ret_arr[q->r_id] += q->val * multipler;
q = q->next_down;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::export_coo(array<size_t> &row_idx, array<size_t> &col_idx, array<MatrixValueType> &data) const
{
if (empty()) throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::export_coo(...)");
size_t nz_num = ele_size();
row_idx.resize(nz_num);
col_idx.resize(nz_num);
data.resize(nz_num);
size_t c = 0;
mat_node<MatrixValueType> *p;
for (size_t i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
row_idx[c] = i;
col_idx[c] = p->c_id;
data[c] = p->val;
p = p->next_right;
c++;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::export_csr(array<size_t> &row_off, array<size_t> &col_idx, array<MatrixValueType> &data) const
{
if (empty()) throw std::runtime_error("The sparse matrix is not initialized. From gctl::spmat<T>::export_coo(...)");
size_t nz_num = ele_size();
col_idx.resize(nz_num);
data.resize(nz_num);
row_off.resize(r_num + 1);
row_off[0] = 0;
size_t r, c = 0;
mat_node<MatrixValueType> *p;
for (size_t i = 0; i < r_num; i++)
{
r = row_off[i];
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
col_idx[c] = p->c_id;
data[c] = p->val;
p = p->next_right;
c++;
r++;
}
}
row_off[i+1] = r;
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::insert(int r, int c, MatrixValueType v)
{
change_element(r, c, v);
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::remove(int r, int c)
{
if (r >= r_num || r < 0 || c >= c_num || c < 0)
{
std::string err_str = "Invalid index. From gctl::spmat<T>::remove(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *p, *q, *tmp_node;
p = r_head[r];
q = c_head[c];
if (p == nullptr || q == nullptr) // 元素不在序列中 直接返回
return;
while (p->next_right != nullptr)
{
if (c == p->next_right->c_id)
{
while (r != q->next_down->r_id)
{
q = q->next_down;
}
if (q == c_head[c] &&
q->next_down->next_down == nullptr)
{
delete c_head[c];
c_head[c] = nullptr;
c_end[c] = nullptr;
}
else if (q->next_down == c_end[c])
{
q->next_down = nullptr;
c_end[c] = q;
}
else
{
q->next_down = q->next_down->next_down;
}
if (p == r_head[r] &&
p->next_right->next_right == nullptr)
{
delete r_head[r]->next_right;
r_head[r]->next_right = nullptr;
delete r_head[r];
r_head[r] = nullptr;
r_end[r] = nullptr;
}
else if (p->next_right == r_end[r])
{
tmp_node = p->next_right;
p->next_right = nullptr;
delete tmp_node;
tmp_node = nullptr;
r_end[r] = p;
}
else
{
tmp_node = p->next_right;
p->next_right = p->next_right->next_right;
delete tmp_node;
tmp_node = nullptr;
}
// 更改行与列的计数
r_count[r]--;
c_count[c]--;
break;
}
p = p->next_right;
}
return;
}
template <typename MatrixValueType>
MatrixValueType spmat<MatrixValueType>::sum(int index, matrix_order_e mode)
{
MatrixValueType sum_val = 0;
if (index < 0)
{
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
sum_val = sum_val + p->val;
p = p->next_right;
}
}
}
}
else if (mode == RowMajor)
{
if (index < 0 || index >= r_num)
{
throw std::runtime_error("[gctl::spmat<T>::sum] Invalid index");
}
mat_node<MatrixValueType> *p;
if (r_head[index] != nullptr)
{
p = r_head[index]->next_right;
while (p != nullptr)
{
sum_val = sum_val + p->val;
p = p->next_right;
}
}
}
else
{
if (index < 0 || index >= c_num)
{
throw std::runtime_error("[gctl::spmat<T>::sum] Invalid index");
}
mat_node<MatrixValueType> *q;
if (c_head[index] != nullptr)
{
q = c_head[index]->next_down;
while (q != nullptr)
{
sum_val = sum_val + q->val;
q = q->next_down;
}
}
}
return sum_val;
}
template <typename MatrixValueType>
MatrixValueType spmat<MatrixValueType>::module(int index, matrix_order_e mode)
{
MatrixValueType sum_val = 0;
if (mode == RowMajor)
{
if (index < 0 || index >= r_num)
{
throw std::runtime_error("[gctl::spmat<T>::module] Invalid index");
}
mat_node<MatrixValueType> *p;
if (r_head[index] != nullptr)
{
p = r_head[index]->next_right;
while (p != nullptr)
{
sum_val = sum_val + pow(p->val, 2);
p = p->next_right;
}
return sqrt(sum_val);
}
}
else
{
if (index < 0 || index >= c_num)
{
throw std::runtime_error("[gctl::spmat<T>::module] Invalid index");
}
mat_node<MatrixValueType> *q;
if (c_head[index] != nullptr)
{
q = c_head[index]->next_down;
while (q != nullptr)
{
sum_val = sum_val + pow(q->val, 2);
q = q->next_down;
}
return sqrt(sum_val);
}
}
return 0;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::add_scalar(int r, int c, MatrixValueType v)
{
if (change_element(r, c, v, AppendVal))
remove(r, c);
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::minus_scalar(int r, int c, MatrixValueType v)
{
if (change_element(r, c, v, RemoveVal))
remove(r, c);
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::add_sparse_matrix(const spmat<MatrixValueType> &b)
{
if (b.row_size() > r_num || b.col_size() > c_num)
{
throw runtime_error("Invalid maximal matrix sizes. From gctl::spmat<T>::add_sparse_matrix(...)"); // 大小不匹配 不能操作
}
mat_node<MatrixValueType> **br_head = b.row_head();
bool re_flag = false;
mat_node<MatrixValueType> *pb; // 遍历b的指针
for (int i = 0; i < r_num; i++)
{
pb = br_head[i];
if (pb != nullptr)
{
pb = pb->next_right;
while (pb != nullptr)
{
// 调用逐个加法私有方法
if (change_element(pb->r_id, pb->c_id, pb->val, AppendVal))
{
re_flag = true;
}
pb = pb->next_right;
}
}
}
if (re_flag) purge();
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::minus_sparse_matrix(const spmat<MatrixValueType> &b)
{
if (b.row_size() > r_num || b.col_size() > c_num)
{
throw runtime_error("Invalid maximal matrix sizes. From gctl::spmat<T>::minus_sparse_matrix(...)"); // 大小不匹配 不能操作
}
mat_node<MatrixValueType> **br_head = b.row_head();
bool re_flag = false;
mat_node<MatrixValueType> *pb; // 遍历b的指针
for (int i = 0; i < r_num; i++)
{
pb = br_head[i];
if (pb != nullptr)
{
pb = pb->next_right;
while (pb != nullptr)
{
// 调用逐个减法私有方法
if (change_element(pb->r_id, pb->c_id, pb->val, RemoveVal))
{
re_flag = true;
}
pb = pb->next_right;
}
}
}
if (re_flag) purge();
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::add_matrix(matrix<MatrixValueType> &arr2d) const
{
if (r_num != arr2d.row_size() || c_num != arr2d.col_size())
{
throw std::runtime_error("Incompatible matrix sizes. From gctl::spmat<T>::add_matrix(...)");
}
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
p = r_head[i];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
arr2d[i][p->c_id] += p->val;
p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::minus_matrix(matrix<MatrixValueType> &arr2d, bool preposition) const
{
if (r_num != arr2d.row_size() || c_num != arr2d.col_size())
{
throw std::runtime_error("Incompatible matrix sizes. From gctl::spmat<T>::minus_matrix(...)");
}
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
p = r_head[i];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
if (preposition) arr2d[i][p->c_id] -= p->val;
else arr2d[i][p->c_id] = p->val - arr2d[i][p->c_id];
p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::map(int from_index, int to_index, MatrixValueType multipler,
matrix_order_e line_mode, value_operator_e val_mode)
{
std::string err_str;
if (line_mode == RowMajor)
{
if (from_index < 0 || from_index >= r_num ||
to_index < 0 || to_index >= r_num)
{
err_str = "Invalid index. From gctl::spmat<T>::map(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *p;
if (r_head[from_index] != nullptr)
{
p = r_head[from_index]->next_right;
while (p != nullptr)
{
change_element(to_index, p->c_id, multipler * p->val, val_mode);
p = p->next_right;
}
}
}
else
{
if (from_index < 0 || from_index >= c_num ||
to_index < 0 || to_index >= c_num)
{
err_str = "Invalid index. From gctl::spmat<T>::map(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *q;
if (c_head[from_index] != nullptr)
{
q = c_head[from_index]->next_down;
while (q != nullptr)
{
change_element(q->r_id, to_index, multipler * q->val, val_mode);
q = q->next_down;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::transpose(spmat<MatrixValueType> &ret_mat) const
{
if (!ret_mat.empty()) ret_mat.clear();
ret_mat.malloc(c_num, r_num, zero_val);
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
ret_mat.insert(p->c_id, p->r_id, p->val);
p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_scalar(int r, int c, MatrixValueType v)
{
if (r >= r_num || r < 0 || c >= c_num || c < 0)
{
std::string err_str = "Invalid index. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str);
}
if (v == zero_val)
return;
if (r_head != nullptr && r_head[r] != nullptr)
{
mat_node<MatrixValueType> *p = r_head[r]->next_right;
while (p != nullptr)
{
if (p->c_id == c)
{
p->val *= v;
break;
}
p = p->next_right;
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_sparse_matrix(const spmat<MatrixValueType> &b,
spmat<MatrixValueType> &ret_mat) const
{
int rb = b.row_size();
int cb = b.col_size();
if (c_num != rb)
{
throw runtime_error("Incompatible matrix sizes. From spmat<T>::multiply(...)"); // 大小不匹配 不能操作
}
if (!ret_mat.empty()) ret_mat.clear();
ret_mat.malloc(r_num, cb, zero_val);
mat_node<MatrixValueType> **bc_head = b.col_head();
mat_node<MatrixValueType> *p, *q;
MatrixValueType compute = zero_val;
bool has_value = false;
for (int i = 0; i < r_num; i++)
{
for (int j = 0; j < cb; j++)
{
has_value = false;
p = r_head[i];
q = bc_head[j];
compute = zero_val;
if (p != nullptr && q != nullptr)
{
p = p->next_right;
q = q->next_down;
while (p != nullptr && q != nullptr)
{
if (p->c_id < q->r_id) // q在p后面
{
p = p->next_right; // p往后赶
}
else if (p->c_id > q->r_id) // p在q后面
{
q = q->next_down; // q往后赶
}
else // p->col == q->row
{
has_value = true;
compute += p->val * q->val; // ans[i,j] += A[i,p] * B[p,j];
p = p->next_right; // p,q一起往后赶
q = q->next_down; // p,q一起往后赶
}
}
}
if (has_value && compute != zero_val) // 如果有非零值
{
ret_mat.insert(i, j, compute);
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_matrix(MatrixValueType **arr2d, int arr2d_rsize,
int arr2d_csize, MatrixValueType **ret_arr2d, int ret_arr2d_rsize, int ret_arr2d_csize) const
{
if (c_num != arr2d_rsize || ret_arr2d_csize != arr2d_csize || ret_arr2d_rsize != r_num)
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
mat_node<MatrixValueType> *p;
MatrixValueType sum;
for (int i = 0; i < r_num; i++)
{
for (int j = 0; j < arr2d_csize; j++)
{
p = r_head[i];
sum = zero_val;
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
sum += p->val * arr2d[p->c_id][j];
p = p->next_right;
}
}
ret_arr2d[i][j] = sum;
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_matrix(const matrix<MatrixValueType> &arr2d,
matrix<MatrixValueType> &ret_arr2d) const
{
if (c_num != arr2d.row_size())
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
ret_arr2d.resize(r_num, arr2d.col_size());
mat_node<MatrixValueType> *p;
MatrixValueType sum;
for (int i = 0; i < r_num; i++)
{
for (int j = 0; j < arr2d.col_size(); j++)
{
p = r_head[i];
sum = zero_val;
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
sum += p->val * arr2d[p->c_id][j];
p = p->next_right;
}
}
ret_arr2d[i][j] = sum;
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_vector(const MatrixValueType *arr, int arr_size,
MatrixValueType *ret_arr, int ret_size, matrix_layout_e layout) const
{
size_t i;
MatrixValueType sum;
// 待乘向量为横向量 按列与矩阵做乘法与加法
if (layout == Trans)
{
if (arr_size != r_num || ret_size != c_num) // 向量大小必须与矩阵行数相等
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
mat_node<MatrixValueType> *q;
#pragma omp parallel for private (i, sum, q) schedule(guided)
for (i = 0; i < c_num; i++)
{
sum = zero_val;
q = c_head[i];
if (q != nullptr)
{
q = q->next_down;
while (q != nullptr)
{
sum += q->val * arr[q->r_id];
q = q->next_down;
}
}
ret_arr[i] = sum;
}
}
else // 待乘向量为竖向量 按行与矩阵做乘法与加法
{
if (arr_size != c_num || ret_size != r_num)
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
mat_node<MatrixValueType> *p;
#pragma omp parallel for private (i, sum, p) schedule(guided)
for (i = 0; i < r_num; i++)
{
sum = zero_val;
p = r_head[i];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
sum += p->val * arr[p->c_id];
p = p->next_right;
}
}
ret_arr[i] = sum;
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_vector(const array<MatrixValueType> &arr,
array<MatrixValueType> &ret_arr, matrix_layout_e layout) const
{
size_t i;
MatrixValueType sum;
// 待乘向量为横向量 按列与矩阵做乘法与加法
if (layout == Trans)
{
if (arr.size() != r_num) // 向量大小必须与矩阵行数相等
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
ret_arr.resize(c_num);
mat_node<MatrixValueType> *q;
#pragma omp parallel for private (i, sum, q) schedule(guided)
for (i = 0; i < c_num; i++)
{
sum = zero_val;
q = c_head[i];
if (q != nullptr)
{
q = q->next_down;
while (q != nullptr)
{
sum += q->val * arr[q->r_id];
q = q->next_down;
}
}
ret_arr[i] = sum;
}
}
else // 待乘向量为竖向量 按行与矩阵做乘法与加法
{
if (arr.size() != c_num)
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
ret_arr.resize(r_num);
mat_node<MatrixValueType> *p;
#pragma omp parallel for private (i, sum, p) schedule(guided)
for (i = 0; i < r_num; i++)
{
sum = zero_val;
p = r_head[i];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
sum += p->val * arr[p->c_id];
p = p->next_right;
}
}
ret_arr[i] = sum;
}
}
return;
}
template <typename MatrixValueType>
double spmat<MatrixValueType>::multiply_vector(const array<MatrixValueType> &arr,
int index, matrix_layout_e layout) const
{
MatrixValueType sum = zero_val;
std::string err_str;
if (layout == Trans)
{
if (arr.size() != r_num)
{
err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
if (index < 0 || index >= c_num)
{
err_str = "Invalid index. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *q = c_head[index];
if (q != nullptr)
{
q = q->next_down;
while (q != nullptr)
{
sum += q->val * arr[q->r_id];
q = q->next_down;
}
}
}
else
{
if (arr.size() != c_num)
{
err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
if (index < 0 || index >= r_num)
{
err_str = "Invalid index. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *p = r_head[index];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
sum += p->val * arr[p->c_id];
p = p->next_right;
}
}
}
return sum;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_vector(int oper_id, const MatrixValueType *arr, int arr_size,
MatrixValueType *ret_arr, matrix_layout_e layout) const
{
std::string err_str;
if (layout == NoTrans)
{
if (oper_id < 0 || oper_id >= r_num)
{
err_str = "Invalid index. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str);
}
if (arr_size != c_num) // 向量大小必须与矩阵列数相等
{
err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
for (int i = 0; i < arr_size; i++)
ret_arr[i] = zero_val;
mat_node<MatrixValueType> *p;
if (r_head[oper_id] != nullptr)
{
p = r_head[oper_id]->next_right;
while (p != nullptr)
{
ret_arr[p->c_id] = arr[p->c_id] * p->val;
p = p->next_right;
}
}
}
// 待乘向量为竖向量 按行与矩阵做乘法与加法
else
{
if (oper_id < 0 || oper_id >= c_num)
{
err_str = "Invalid index. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str);
}
if (arr_size != r_num) // 向量大小必须与矩阵列数相等
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
for (int i = 0; i < arr_size; i++)
ret_arr[i] = zero_val;
mat_node<MatrixValueType> *q;
if (c_head[oper_id] != nullptr)
{
q = c_head[oper_id]->next_down;
while (q != nullptr)
{
ret_arr[q->r_id] = arr[q->r_id] * q->val;
q = q->next_down;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_diagonal_matrix(const array<MatrixValueType> &arr, spmat<MatrixValueType> &ret_mat, bool prepositioned) const
{
if (!ret_mat.empty()) ret_mat.clear();
double tmp_val;
if (prepositioned)
{
if (arr.size() != r_num)
{
throw runtime_error("Incompatible array sizes. From spmat<T>::multiply(...)");
}
ret_mat.malloc(r_num, c_num, zero_val);
mat_node<MatrixValueType> *q;
for (int j = 0; j < c_num; j++)
{
q = c_head[j];
if (q != nullptr)
{
q = q->next_down;
while (q != nullptr)
{
tmp_val = q->val * arr[q->r_id];
if (tmp_val != zero_val)
{
ret_mat.insert(q->r_id, j, tmp_val);
}
q = q->next_down;
}
}
}
}
else
{
if (arr.size() != c_num)
{
throw runtime_error("Incompatible array sizes. From spmat<T>::multiply(...)");
}
ret_mat.malloc(r_num, c_num, zero_val);
mat_node<MatrixValueType> *p;
for (int i = 0; i < r_num; i++)
{
p = r_head[i];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
tmp_val = p->val * arr[p->c_id];
if (tmp_val != zero_val)
{
ret_mat.insert(i, p->c_id, tmp_val);
}
p = p->next_right;
}
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::boolean(int oper_id, array<bool> &ret_arr, matrix_order_e ele_mode,
bool reverse) const
{
if (ele_mode == RowMajor)
{
if (reverse)
{
ret_arr.resize(c_num, true);
mat_node<MatrixValueType> *p;
if (r_head[oper_id] != nullptr)
{
p = r_head[oper_id]->next_right;
while (p != nullptr)
{
ret_arr.at(p->c_id) = false;
p = p->next_right;
}
}
}
else
{
ret_arr.resize(c_num, false);
mat_node<MatrixValueType> *p;
if (r_head[oper_id] != nullptr)
{
p = r_head[oper_id]->next_right;
while (p != nullptr)
{
ret_arr.at(p->c_id) = true;
p = p->next_right;
}
}
}
}
else
{
if (reverse)
{
ret_arr.resize(r_num, true);
mat_node<MatrixValueType> *q;
if (c_head[oper_id] != nullptr)
{
q = c_head[oper_id]->next_down;
while (q != nullptr)
{
ret_arr.at(q->r_id) = false;
q = q->next_down;
}
}
}
else
{
ret_arr.resize(r_num, false);
mat_node<MatrixValueType> *q;
if (c_head[oper_id] != nullptr)
{
q = c_head[oper_id]->next_down;
while (q != nullptr)
{
ret_arr.at(q->r_id) = true;
q = q->next_down;
}
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::normalize(int oper_id, MatrixValueType norm, matrix_order_e line_mode)
{
MatrixValueType sum;
std::string err_str;
if (line_mode == RowMajor)
{
if (oper_id < 0 || oper_id >= r_num)
{
err_str = "Invalid index. From gctl::spmat<T>::normalize(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *p;
if (r_head[oper_id] != nullptr)
{
p = r_head[oper_id]->next_right;
sum = p->val;
p = p->next_right;
while (p != nullptr)
{
sum += p->val;
p = p->next_right;
}
p = r_head[oper_id]->next_right;
while (p != nullptr)
{
p->val = p->val*norm/sum;
p = p->next_right;
}
}
}
else
{
if (oper_id < 0 || oper_id >= c_num)
{
err_str = "Invalid index. From gctl::spmat<T>::normalize(...)";
throw runtime_error(err_str);
}
mat_node<MatrixValueType> *q;
if (c_head[oper_id] != nullptr)
{
q = c_head[oper_id]->next_down;
sum = q->val;
q = q->next_down;
while (q != nullptr)
{
sum += q->val;
q = q->next_down;
}
q = c_head[oper_id]->next_down;
while (q != nullptr)
{
q->val = q->val*norm/sum;
q = q->next_down;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::scale(MatrixValueType f, int idx, matrix_order_e ele_mode)
{
if (ele_mode == RowMajor)
{
if (idx < 0 || idx >= r_num)
{
throw std::runtime_error("[gctl::spmat<T>::scale] Invalid index.");
}
mat_node<MatrixValueType> *p;
if (r_head[idx] != nullptr)
{
p = r_head[idx]->next_right;
while (p != nullptr)
{
p->val = p->val*f;
p = p->next_right;
}
}
}
else
{
if (idx < 0 || idx >= c_num)
{
throw std::runtime_error("[gctl::spmat<T>::scale] Invalid index.");
}
mat_node<MatrixValueType> *q;
if (c_head[idx] != nullptr)
{
q = c_head[idx]->next_down;
while (q != nullptr)
{
q->val = q->val*f;
q = q->next_down;
}
}
}
return;
}
template <typename MatrixValueType>
void spmat<MatrixValueType>::get_diagonal(array<MatrixValueType> &dia)
{
if (r_num != c_num)
{
throw gctl::runtime_error("Not a square matrix. From gctl::spmat<T>::get_diagonal(...)");
}
dia.resize(r_num, zero_val);
mat_node<MatrixValueType> *p;
for (size_t i = 0; i < r_num; i++)
{
if (r_head[i] != nullptr)
{
p = r_head[i]->next_right;
while (p != nullptr)
{
if (p->c_id == i)
{
dia[i] = p->val;
break;
}
p = p->next_right;
}
}
}
return;
}
template <typename MatrixValueType>
spmat<MatrixValueType>& spmat<MatrixValueType>::operator= (const spmat<MatrixValueType> &b)
{
if (!empty()) clear();
zero_val = b.zero_val;
r_num = b.row_size();
c_num = b.col_size();
r_head = new mat_node<MatrixValueType>* [r_num];
c_head = new mat_node<MatrixValueType>* [c_num];
r_end = new mat_node<MatrixValueType>* [r_num];
c_end = new mat_node<MatrixValueType>* [c_num];
r_count = new int [r_num];
c_count = new int [c_num];
mat_node<MatrixValueType> **br_head = b.row_head();
int i, j;
for (i = 0; i < r_num; i++)
{
r_head[i] = nullptr; r_end[i] = nullptr; r_count[i] = 0;
}
for (i = 0; i < c_num; i++)
{
c_head[i] = nullptr; c_end[i] = nullptr; c_count[i] = 0;
}
mat_node<MatrixValueType> *bp, *p, *q;
for (int r = 0; r < r_num; r++)
{
if (br_head[r] != nullptr)
{
bp = br_head[r]->next_right;
while (bp != nullptr)
{
mat_node<MatrixValueType>* new_node =
new mat_node<MatrixValueType>;
new_node->r_id = bp->r_id;
new_node->c_id = bp->c_id;
new_node->val = bp->val;
i = bp->r_id; j = bp->c_id;
// 我们首先处理行的指针
if (r_head[i] != nullptr) // 无需检查行尾指针 它们是同步变化的
{
p = r_end[i];
p->next_right = new_node;
r_end[i] = new_node;
r_count[i]++;
}
else
{
// 添加行首指针 注意行首指针并不等于第一个元素 而是行首的右向链为第一个元素
r_head[i] = new mat_node<MatrixValueType>;
r_head[i]->next_right = new_node;
// 添加行尾指针 行尾指针直接等于本行的最后一个元素
r_end[i] = new_node;
r_count[i]++;
}
// 接着处理列的指针
if (c_head[j] != nullptr)
{
q = c_end[j];
q->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
else
{
c_head[j] = new mat_node<MatrixValueType>;
c_head[j]->next_down = new_node;
c_end[j] = new_node;
c_count[j]++;
}
bp = bp->next_right;
}
}
}
return *this;
}
template <typename MatrixValueType>
bool spmat<MatrixValueType>::change_element(int r, int c, MatrixValueType v,
value_operator_e mode)
{
if (r >= r_num || r < 0 || c >= c_num || c < 0)
{
throw std::runtime_error("Invalid index. From gctl::spmat<T>::change_element(...)");
}
// 输入的值为0 无效的操作返回假
if (v == zero_val)
return false;
mat_node<MatrixValueType> *new_node = nullptr;
mat_node<MatrixValueType> *p, *q, *tmp_node;
MatrixValueType in_v;
if (mode == RemoveVal) in_v = -v;
else in_v = v;
bool d_flag = false;
// 首先处理行的指针序列
// 如果指针不为空 则需要判断插入的位置
if (r_head[r] != nullptr)
{
// 首先检查行尾值
if (c > r_end[r]->c_id) // 大于行尾的列值 在队尾添加
{
// 需要新建节点
new_node = new mat_node<MatrixValueType>;
new_node->r_id = r;
new_node->c_id = c;
new_node->val = in_v;
r_end[r]->next_right = new_node;
r_end[r] = new_node;
r_count[r]++;
}
else if (c == r_end[r]->c_id)
{
if (mode == ReplaceVal)
{
r_end[r]->val = in_v;
}
else if (mode == AppendVal || mode == RemoveVal)
{
r_end[r]->val += in_v;
if (r_end[r]->val == zero_val)
d_flag = true;
}
else // 操作类型是EraseVal 将元素值置为0 (一般不会用到)
{
r_end[r]->val = zero_val;
d_flag = true;
}
}
else
{
p = r_head[r]->next_right; // 该行的首个元素
if (c < p->c_id) // 输入列值小于行首元素的列值 更改行首元素
{
// 需要新建节点
new_node = new mat_node<MatrixValueType>;
new_node->r_id = r;
new_node->c_id = c;
new_node->val = in_v;
r_head[r]->next_right = new_node;
new_node->next_right = p;
r_count[r]++;
}
else if (c == p->c_id) // 列序列等于行首值,替换节点值就行了
{
if (mode == ReplaceVal)
{
p->val = in_v;
}
else if (mode == AppendVal || mode == RemoveVal)
{
p->val += in_v;
if (p->val == zero_val)
d_flag = true;
}
else // 操作类型是EraseVal 将元素值置为0 (一般不会用到)
{
p->val = zero_val;
d_flag = true;
}
}
else
{
// 这个寻址过程是影响效率的主要部分
while (p->next_right != nullptr)
{
if (p->next_right->c_id == c) // 该行的某个节点的列号与输入点一致
{
if (mode == ReplaceVal)
{
p->next_right->val = in_v;
}
else if (mode == AppendVal || mode == RemoveVal)
{
p->next_right->val += in_v;
if (p->next_right->val == zero_val)
d_flag = true;
}
else // 操作类型是EraseVal 将元素值置为0 (一般不会用到)
{
p->next_right->val = zero_val;
d_flag = true;
}
break;
}
else if (c > p->c_id && c < p->next_right->c_id)
{
// 需要新建节点
new_node = new mat_node<MatrixValueType>;
new_node->r_id = r;
new_node->c_id = c;
new_node->val = in_v;
tmp_node = p->next_right;
p->next_right = new_node;
new_node->next_right= tmp_node;
r_count[r]++;
break;
}
p = p->next_right;
}
}
}
}
// 若行指针为空 直接添加新元素即可
else
{
// 需要新建节点
new_node = new mat_node<MatrixValueType>;
new_node->r_id = r;
new_node->c_id = c;
new_node->val = in_v;
r_head[r] = new mat_node<MatrixValueType>;
r_head[r]->next_right = new_node;
r_end[r] = new_node;
r_count[r]++;
}
// 下面来处理列序列
// 如果指针不为空 则需要判断插入的位置
if (c_head[c] != nullptr)
{
// 首先检查列尾值
if (r > c_end[c]->r_id) // 大于行尾的列值 在队尾添加
{
c_end[c]->next_down = new_node;
c_end[c] = new_node;
c_count[c]++;
}
else
{
q = c_head[c]->next_down;
if (r < q->r_id) // 输入行小于列首行 替换即可
{
c_head[c]->next_down = new_node;
new_node->next_down = q;
c_count[c]++;
}
else
{
// 这个寻址过程是影响效率的主要部分
while (q->next_down != nullptr)
{
if (r == q->next_down->r_id)
break;
else if (r > q->r_id && r < q->next_down->r_id)
{
tmp_node = q->next_down;
q->next_down = new_node;
new_node->next_down = tmp_node;
c_count[c]++;
break;
}
q = q->next_down;
}
}
}
}
// 若行指针为空 直接添加新元素即可
else
{
c_head[c] = new mat_node<MatrixValueType>;
c_head[c]->next_down = new_node;
c_end[c] = new_node;
c_count[c]++;
}
// 如果触发删除标签则删除相应元素
if (d_flag) return true;
return false;
}
template <typename MatrixValueType>
mat_node<MatrixValueType> **spmat<MatrixValueType>::row_head() const
{
return r_head;
}
template <typename MatrixValueType>
mat_node<MatrixValueType> **spmat<MatrixValueType>::col_head() const
{
return c_head;
}
#ifdef GCTL_EIGEN
template <typename MatrixValueType>
void spmat<MatrixValueType>::multiply_vector(const Eigen::VectorXd &vec, Eigen::VectorXd &ret_vec, bool row_vector) const
{
size_t i;
MatrixValueType sum;
// 待乘向量为横向量 按列与矩阵做乘法与加法
if (row_vector)
{
if (vec.size() != r_num) // 向量大小必须与矩阵行数相等
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
ret_vec.resize(c_num);
mat_node<MatrixValueType> *q;
#pragma omp parallel for private (i, sum, q) schedule(guided)
for (i = 0; i < c_num; i++)
{
sum = zero_val;
q = c_head[i];
if (q != nullptr)
{
q = q->next_down;
while (q != nullptr)
{
sum += q->val * vec[q->r_id];
q = q->next_down;
}
}
ret_vec[i] = sum;
}
}
else // 待乘向量为竖向量 按行与矩阵做乘法与加法
{
if (vec.size() != c_num)
{
std::string err_str = "Incompatible matrix sizes. From gctl::spmat<T>::multiply(...)";
throw runtime_error(err_str); // 大小不匹配 不能操作
}
ret_vec.resize(r_num);
mat_node<MatrixValueType> *p;
#pragma omp parallel for private (i, sum, p) schedule(guided)
for (i = 0; i < r_num; i++)
{
sum = zero_val;
p = r_head[i];
if (p != nullptr)
{
p = p->next_right;
while (p != nullptr)
{
sum += p->val * vec[p->c_id];
p = p->next_right;
}
}
ret_vec[i] = sum;
}
}
return;
}
#endif // GCTL_EIGEN
};
#endif //_GCTL_SPMAT_H