重构
This commit is contained in:
+289
-431
@@ -1,493 +1,351 @@
|
||||
#include <c_Matrix.h>
|
||||
#include <c_Memory.h>
|
||||
|
||||
// 初始化矩阵(由外部传入结构体指针 self,内部只分配绑定的 c_Array 内存)
|
||||
c_err_t c_Matrix_Init(c_Matrix_t* self, c_size_t rows, c_size_t cols, c_size_t element_size) {
|
||||
if (!self) return C_ERR_PARAM;
|
||||
if (rows == 0 || cols == 0 || element_size == 0) return C_ERR_PARAM;
|
||||
c_err_t c_Matrix_Init(c_Matrix_t* self, c_size_t rows, c_size_t cols, c_size_t item_size, c_Allocator_t* allocator) {
|
||||
if (!self || rows == 0 || cols == 0 || item_size == 0) return C_ERR_PARAM;
|
||||
|
||||
// 分配底层封装的一维泛型数组
|
||||
self->array = c_Array_New(rows * cols, element_size);
|
||||
if (!self->array) {
|
||||
return C_ERR_NOMEM;
|
||||
}
|
||||
// 防止 rows * cols * item_size 发生整型乘法回绕引发的堆踩踏
|
||||
if (rows > (c_size_t)-1 / (cols * item_size)) return C_ERR_OUTOFBOUND;
|
||||
|
||||
self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator;
|
||||
self->rows = rows;
|
||||
self->cols = cols;
|
||||
return C_SUCCESS;
|
||||
self->item_size = item_size;
|
||||
|
||||
// 一次性开辟完美的连续空间
|
||||
c_size_t total_bytes = self->rows * self->cols * self->item_size;
|
||||
self->data = c_Allocator_Alloc(&self->allocator, total_bytes);
|
||||
if (!self->data) return C_ERR_NOMEM;
|
||||
|
||||
// 默认执行物理抹零清洁
|
||||
memset(self->data, 0, total_bytes);
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
// 销毁矩阵(释放内部资源,不释放 self 本身,由外部决定 self 释放方式)
|
||||
// 物理销毁
|
||||
void c_Matrix_Destroy(c_Matrix_t* self) {
|
||||
if (self) {
|
||||
if (self->array) {
|
||||
c_Array_Delete(&self->array);
|
||||
self->array = NULL;
|
||||
}
|
||||
self->rows = 0;
|
||||
self->cols = 0;
|
||||
if (!self) return;
|
||||
if (self->data) {
|
||||
c_Allocator_Free(&self->allocator, self->data);
|
||||
self->data = NULL;
|
||||
}
|
||||
self->rows = 0;
|
||||
self->cols = 0;
|
||||
}
|
||||
|
||||
// 获取单个元素字节大小
|
||||
c_size_t c_Matrix_ElementSize(c_Matrix_t* self) {
|
||||
if (!self || !self->array) return 0;
|
||||
return c_Array_Size(self->array);
|
||||
// 定点安全写入 (值深度复制)
|
||||
c_err_t c_Matrix_Write(c_Matrix_t* self, c_size_t r, c_size_t c, const void* item) {
|
||||
if (!self || !item || r >= self->rows || c >= self->cols) return C_ERR_PARAM;
|
||||
|
||||
// 行优先扁平化寻址计算
|
||||
c_size_t index = r * self->cols + c;
|
||||
char* target = (char*)self->data + (index * self->item_size);
|
||||
memcpy(target, item, self->item_size);
|
||||
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
// 获取矩阵元素(通过二级指针 value 返回该元素的内部指针,并返回状态码)
|
||||
c_err_t c_Matrix_Get(c_Matrix_t* self, c_size_t row, c_size_t col, void** value) {
|
||||
if (!self || !value) return C_ERR_PARAM;
|
||||
if (row >= self->rows || col >= self->cols) return C_ERR_PARAM;
|
||||
// 定点安全读取 (安全拷贝副本)
|
||||
c_err_t c_Matrix_Read(const c_Matrix_t* self, c_size_t r, c_size_t c, void* out_item) {
|
||||
if (!self || !out_item || r >= self->rows || c >= self->cols) return C_ERR_PARAM;
|
||||
|
||||
// 计算一维索引:index = row * cols + col
|
||||
const c_size_t index = row * self->cols + col;
|
||||
c_size_t index = r * self->cols + c;
|
||||
const char* source = (const char*)self->data + (index * self->item_size);
|
||||
memcpy(out_item, source, self->item_size);
|
||||
|
||||
c_err_t err = c_Array_Get(self->array, index, value);
|
||||
if (err!=C_ERR_OK) return err;
|
||||
|
||||
return C_SUCCESS;
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
// 写入矩阵元素
|
||||
c_err_t c_Matrix_Put(c_Matrix_t* self, c_size_t row, c_size_t col, void* value) {
|
||||
if (!self || !value) return C_ERR_PARAM;
|
||||
if (row >= self->rows || col >= self->cols) return C_ERR_PARAM;
|
||||
|
||||
const c_size_t index = row * self->cols + col;
|
||||
return c_Array_Put(self->array, index, value);
|
||||
// 只读原位窥探指针 (由于是固定一维连续空间,只要不销毁,此指针极其平稳安全)
|
||||
void* c_Matrix_Get(const c_Matrix_t* self, c_size_t r, c_size_t c) {
|
||||
if (!self || r >= self->rows || c >= self->cols) return NULL;
|
||||
c_size_t index = r * self->cols + c;
|
||||
return (char*)self->data + (index * self->item_size);
|
||||
}
|
||||
|
||||
// 矩阵转置:dst 必须是已经初始化好的大小为 (src->cols x src->rows) 的矩阵
|
||||
c_err_t c_Matrix_TransposeTo(c_Matrix_t* src, c_Matrix_t* dst) {
|
||||
if (!src || !dst) return C_ERR_PARAM;
|
||||
if (src->cols != dst->rows || src->rows != dst->cols) return C_ERR_PARAM;
|
||||
// 批量全局抹值填充
|
||||
c_err_t c_Matrix_Fill(c_Matrix_t* self, const void* item) {
|
||||
if (!self || !item) return C_ERR_PARAM;
|
||||
|
||||
for (c_size_t i = 0; i < src->rows; i++) {
|
||||
for (c_size_t j = 0; j < src->cols; j++) {
|
||||
void* temp = NULL;
|
||||
c_Matrix_Get(src, i, j, (void**)&temp);
|
||||
c_Matrix_Put(dst, j, i, temp); // 行列互换写入
|
||||
}
|
||||
c_size_t total_elements = self->rows * self->cols;
|
||||
char* target = (char*)self->data;
|
||||
|
||||
for (c_size_t i = 0; i < total_elements; i++) {
|
||||
memcpy(target, item, self->item_size);
|
||||
target += self->item_size;
|
||||
}
|
||||
|
||||
return C_SUCCESS;
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
// 矩阵乘法:C = A * B (以 float 为例)
|
||||
c_err_t c_Matrix_Multiply(const c_Matrix_t* A, const c_Matrix_t* B, c_Matrix_t* C, void (*multiply)(const void* a, const void* b, void** c)) {
|
||||
// 1. 基础健壮性检查
|
||||
if (!A || !B || !C || !multiply) return C_ERR_PARAM;
|
||||
// 极致高速的一整行搬迁导出接口 (常用于图像处理的一行扫描线批量搬运)
|
||||
c_err_t c_Matrix_CopyRow(const c_Matrix_t* self, c_size_t r, void* out_row_buffer) {
|
||||
if (!self || !out_row_buffer || r >= self->rows) return C_ERR_PARAM;
|
||||
|
||||
// 2. 矩阵乘法维度匹配检查 (A的列数必须等于B的行数,C的尺寸必须是 A.rows x B.cols)
|
||||
if (A->cols != B->rows || C->rows != A->rows || C->cols != B->cols) {
|
||||
return C_ERR_PARAM;
|
||||
}
|
||||
// 因为行优先存储,整行的数据在物理上是 100% 绝对连续的一条线
|
||||
// 我们可以直接通过一次 memcpy 瞬时打包带走一整行,效率达到硬件总线传输极限
|
||||
const char* row_start = (const char*)self->data + (r * self->cols * self->item_size);
|
||||
size_t row_bytes = self->cols * self->item_size;
|
||||
|
||||
const c_size_t elem_size = c_Matrix_ElementSize((c_Matrix_t*)A);
|
||||
|
||||
// 4. 三重循环计算矩阵乘法
|
||||
for (c_size_t i = 0; i < A->rows; i++) {
|
||||
for (c_size_t j = 0; j < B->cols; j++) {
|
||||
|
||||
// 在计算当前 C[i][j] 的点积前,必须先获取 C[i][j] 现有的物理指针
|
||||
void* c_item_ptr = NULL;
|
||||
c_Matrix_Get(C, i, j, &c_item_ptr);
|
||||
|
||||
// 将当前位置的数据清零(初始化累加器)
|
||||
memset(c_item_ptr, 0, elem_size);
|
||||
|
||||
for (c_size_t k = 0; k < A->cols; k++) {
|
||||
void *a_item_ptr = NULL;
|
||||
void *b_item_ptr = NULL;
|
||||
|
||||
// 安全获取 A[i][k] 和 B[k][j]
|
||||
c_Matrix_Get((c_Matrix_t*)A, i, k, &a_item_ptr);
|
||||
c_Matrix_Get((c_Matrix_t*)B, k, j, &b_item_ptr);
|
||||
|
||||
// 核心:调用用户自定义的单元素乘法
|
||||
// 指针传参解释:
|
||||
// &prod_res 是一个二级指针 (void**),回调函数内部会将计算结果写入到 prod_res 指向的缓冲区
|
||||
void* ctx_ptr = c_item_ptr;
|
||||
multiply(a_item_ptr, b_item_ptr, (void**)&ctx_ptr);
|
||||
|
||||
// 执行累加:这里需要对通用泛型执行加法
|
||||
// 由于 C 语言泛型限制,我们在这里进行一维数组层面的二进制或特定类型累加。
|
||||
// 工业级做法通常会将“加法”也作为回调,或者假设前几个字节可加。
|
||||
// 针对最常见的数值类型,我们可以根据用户传进来的回调结果,在当前位置累加:
|
||||
// 为使设计更严谨,通常让 multiply 内部直接实现:*(Type*)c_item_ptr += *(Type*)a * *(Type*)b
|
||||
// 如果你的 multiply 语义是:*c = a * b,则需要外部进行特定类型的累加,例如以 float 为例:
|
||||
// *(float*)c_item_ptr += *(float*)prod_res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return C_SUCCESS;
|
||||
memcpy(out_row_buffer, row_start, row_bytes);
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
// 辅助函数:根据一维索引,计算转置后该元素应当去往的新一维索引
|
||||
// 公式:新行 = 旧列,新列 = 旧行 -> new_index = (old_index % cols) * rows + (old_index / cols)
|
||||
C_STATIC_FORCE_INLINE
|
||||
c_size_t get_transposed_source_index(c_size_t curr_index, c_size_t old_rows, c_size_t old_cols) {
|
||||
return (curr_index % old_rows) * old_cols + (curr_index / old_rows);
|
||||
}
|
||||
// 辅助寻址内部宏
|
||||
#define MAT_ELEMENT(mat, idx) ((char*)(mat)->data + ((idx) * (mat)->item_size))
|
||||
|
||||
c_err_t c_Matrix_InPlaceTranspose(c_Matrix_t* self) {
|
||||
if (!self || !self->array) return C_ERR_PARAM;
|
||||
|
||||
c_size_t rows = self->rows;
|
||||
c_size_t cols = self->cols;
|
||||
c_size_t elem_size = c_Matrix_ElementSize(self);
|
||||
|
||||
if (rows <= 1 && cols <= 1) {
|
||||
return C_SUCCESS;
|
||||
/**
|
||||
* @brief 逐元素(Element-wise)矩阵运算通用驱动函数(内部私有)
|
||||
*/
|
||||
static c_err_t c_Matrix_ElementWiseCore(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs,
|
||||
c_Matrix_OpFn_t op, void* ud) {
|
||||
if (!out || !lhs || !rhs || !op) return C_ERR_PARAM;
|
||||
// 强御安全校验:矩阵运算要求维度必须完全空间对齐一致
|
||||
if (lhs->rows != rhs->rows || lhs->cols != rhs->cols ||
|
||||
lhs->rows != out->rows || lhs->cols != out->cols ||
|
||||
lhs->item_size != rhs->item_size || lhs->item_size != out->item_size) {
|
||||
return C_ERR_OUTOFBOUND;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// 场景 A:方阵原地转置(不变,原本就是正确的)
|
||||
// --------------------------------------------------------------------------------
|
||||
if (rows == cols) {
|
||||
#define SWAP_BUF_SIZE 256
|
||||
uint8_t swap_buf[SWAP_BUF_SIZE];
|
||||
uint8_t* temp = swap_buf;
|
||||
if (elem_size > SWAP_BUF_SIZE) {
|
||||
temp = (uint8_t*)C_ALLOC(elem_size);
|
||||
if (!temp) return C_ERR_NOMEM;
|
||||
}
|
||||
for (c_size_t i = 0; i < rows; i++) {
|
||||
for (c_size_t j = i + 1; j < cols; j++) {
|
||||
void *cell_a = NULL, *cell_b = NULL;
|
||||
c_Matrix_Get(self, i, j, &cell_a);
|
||||
c_Matrix_Get(self, j, i, &cell_b);
|
||||
memcpy(temp, cell_a, elem_size);
|
||||
memcpy(cell_a, cell_b, elem_size);
|
||||
memcpy(cell_b, temp, elem_size);
|
||||
}
|
||||
}
|
||||
if (elem_size > SWAP_BUF_SIZE) C_FREE(temp);
|
||||
#undef SWAP_BUF_SIZE
|
||||
return C_SUCCESS;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// 场景 B:非方阵原地转置(已完全修复环路拉取逻辑)
|
||||
// --------------------------------------------------------------------------------
|
||||
c_size_t total_elements = rows * cols;
|
||||
|
||||
c_size_t bitmask_size = (total_elements + 7) / 8;
|
||||
uint8_t* visited = (uint8_t*)C_CALLOC(bitmask_size, sizeof(uint8_t));
|
||||
if (!visited) return C_ERR_NOMEM;
|
||||
|
||||
uint8_t* cycle_buf = (uint8_t*)C_ALLOC(elem_size);
|
||||
if (!cycle_buf) {
|
||||
C_FREE(visited);
|
||||
return C_ERR_NOMEM;
|
||||
}
|
||||
|
||||
void* base_data = NULL;
|
||||
c_err_t array_err = c_Array_Get(self->array, 0, &base_data);
|
||||
if (array_err != C_SUCCESS || !base_data) {
|
||||
C_FREE(cycle_buf);
|
||||
C_FREE(visited);
|
||||
return array_err;
|
||||
}
|
||||
c_size_t total_elements = lhs->rows * lhs->cols;
|
||||
|
||||
// 【工业级内核性能极致拉平】:直接抛弃二维坐标计算,用一维指针流极速推进
|
||||
for (c_size_t i = 0; i < total_elements; i++) {
|
||||
if (visited[i / 8] & (1 << (i % 8))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
c_size_t curr_idx = i;
|
||||
// 使用修正后的逆向映射函数
|
||||
c_size_t next_idx = get_transposed_source_index(curr_idx, rows, cols);
|
||||
|
||||
if (next_idx == curr_idx) {
|
||||
visited[curr_idx / 8] |= (1 << (curr_idx % 8));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 暂存当前起点元素
|
||||
memcpy(cycle_buf, (char*)base_data + (curr_idx * elem_size), elem_size);
|
||||
|
||||
// 沿着逆向数据源环路追溯拉取
|
||||
while (next_idx != i) {
|
||||
void* src = (char*)base_data + (next_idx * elem_size);
|
||||
void* dst = (char*)base_data + (curr_idx * elem_size);
|
||||
|
||||
memcpy(dst, src, elem_size); // 正确地拉取源数据
|
||||
visited[curr_idx / 8] |= (1 << (curr_idx % 8));
|
||||
|
||||
curr_idx = next_idx;
|
||||
next_idx = get_transposed_source_index(curr_idx, rows, cols);
|
||||
}
|
||||
|
||||
// 闭合环路
|
||||
void* dst = (char*)base_data + (curr_idx * elem_size);
|
||||
memcpy(dst, cycle_buf, elem_size);
|
||||
visited[curr_idx / 8] |= (1 << (curr_idx % 8));
|
||||
void* out_ptr = MAT_ELEMENT(out, i);
|
||||
const void* lhs_ptr = MAT_ELEMENT(lhs, i);
|
||||
const void* rhs_ptr = MAT_ELEMENT(rhs, i);
|
||||
op(out_ptr, lhs_ptr, rhs_ptr, ud); // 驱动具体类型算子
|
||||
}
|
||||
|
||||
C_FREE(cycle_buf);
|
||||
C_FREE(visited);
|
||||
|
||||
// 修改元数据宽高
|
||||
self->rows = cols;
|
||||
self->cols = rows;
|
||||
|
||||
return C_SUCCESS;
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_Determinant(const c_Matrix_t* self, const c_MatrixOps_t* ops, void* out_det) {
|
||||
if (!self || !ops || !out_det) return C_ERR_PARAM;
|
||||
if (self->rows != self->cols) return C_ERR_PARAM;
|
||||
c_err_t c_Matrix_Add(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t add_op, void* ud) {
|
||||
return c_Matrix_ElementWiseCore(out, lhs, rhs, add_op, ud);
|
||||
}
|
||||
|
||||
c_size_t n = self->rows;
|
||||
c_size_t elem_size = c_Matrix_ElementSize((c_Matrix_t*)self);
|
||||
c_err_t c_Matrix_Sub(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t sub_op, void* ud) {
|
||||
return c_Matrix_ElementWiseCore(out, lhs, rhs, sub_op, ud);
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_Div(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t div_op, void* ud) {
|
||||
return c_Matrix_ElementWiseCore(out, lhs, rhs, div_op, ud);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 经典线性代数标准矩阵乘法 (Matrix Multiplication: O(N^3))
|
||||
* @note 满足拓扑条件:lhs(M x K) * rhs(K x N) = out(M x N)
|
||||
*/
|
||||
c_err_t c_Matrix_Mul(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs,
|
||||
c_Matrix_OpFn_t mul_op, c_Matrix_OpFn_t add_op, void* ud) {
|
||||
if (!out || !lhs || !rhs || !mul_op || !add_op) return C_ERR_PARAM;
|
||||
// 拓扑几何边界校验
|
||||
if (lhs->cols != rhs->rows || out->rows != lhs->rows || out->cols != rhs->cols ||
|
||||
lhs->item_size != rhs->item_size || lhs->item_size != out->item_size) {
|
||||
return C_ERR_OUTOFBOUND;
|
||||
}
|
||||
|
||||
c_size_t M = lhs->rows;
|
||||
c_size_t K = lhs->cols;
|
||||
c_size_t N = rhs->cols;
|
||||
|
||||
// 分配一个栈上的临时缓冲区,用来暂存单次乘法的中间值(避免频繁分配堆内存导致碎片)
|
||||
// 由于是泛型,大小通过 item_size 动态抹平
|
||||
void* temp_mul_res = c_Allocator_Alloc(&out->allocator, out->item_size);
|
||||
if (!temp_mul_res) return C_ERR_NOMEM;
|
||||
|
||||
for (c_size_t i = 0; i < M; i++) {
|
||||
for (c_size_t j = 0; j < N; j++) {
|
||||
void* out_cell = (char*)out->data + ((i * N + j) * out->item_size);
|
||||
|
||||
// 每次计算新格子前,首先执行干净的物理抹零(清空历史残存值)
|
||||
memset(out_cell, 0, out->item_size);
|
||||
|
||||
for (c_size_t k = 0; k < K; k++) {
|
||||
const void* lhs_cell = (char*)lhs->data + ((i * K + k) * lhs->item_size);
|
||||
const void* rhs_cell = (char*)rhs->data + ((k * N + j) * rhs->item_size);
|
||||
|
||||
// 1. 计算当前权重的乘积:temp_mul_res = lhs_cell * rhs_cell
|
||||
mul_op(temp_mul_res, lhs_cell, rhs_cell, ud);
|
||||
|
||||
// 2. 累加到目标格子中:out_cell = out_cell + temp_mul_res
|
||||
add_op(out_cell, out_cell, temp_mul_res, ud);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c_Allocator_Free(&out->allocator, temp_mul_res);
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标量运算通用驱动核心(内部私有)
|
||||
*/
|
||||
static c_err_t c_Matrix_ScalarCore(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar,
|
||||
c_Matrix_OpFn_t op, void* ud) {
|
||||
if (!out || !in || !scalar || !op) return C_ERR_PARAM;
|
||||
if (in->rows != out->rows || in->cols != out->cols || in->item_size != out->item_size) {
|
||||
return C_ERR_OUTOFBOUND;
|
||||
}
|
||||
|
||||
c_size_t total_elements = in->rows * in->cols;
|
||||
for (c_size_t i = 0; i < total_elements; i++) {
|
||||
void* out_ptr = MAT_ELEMENT(out, i);
|
||||
const void* in_ptr = MAT_ELEMENT(in, i);
|
||||
op(out_ptr, in_ptr, scalar, ud); // 驱动单元素与标量运算
|
||||
}
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_AddScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t add_op, void* ud) {
|
||||
return c_Matrix_ScalarCore(out, in, scalar, add_op, ud);
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_SubScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t sub_op, void* ud) {
|
||||
return c_Matrix_ScalarCore(out, in, scalar, sub_op, ud);
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_MulScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t mul_op, void* ud) {
|
||||
return c_Matrix_ScalarCore(out, in, scalar, mul_op, ud);
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_DivScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t div_op, void* ud) {
|
||||
return c_Matrix_ScalarCore(out, in, scalar, div_op, ud);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
// 矩阵转置实现 (M x N -> N x M)
|
||||
c_err_t c_Matrix_Transpose(c_Matrix_t* out, const c_Matrix_t* in) {
|
||||
if (!out || !in || !out->data || !in->data) return C_ERR_PARAM;
|
||||
|
||||
// 空间几何拓扑强校验
|
||||
if (out->rows != in->cols || out->cols != in->rows || out->item_size != in->item_size) {
|
||||
return C_ERR_OUTOFBOUND;
|
||||
}
|
||||
|
||||
c_size_t r_max = in->rows;
|
||||
c_size_t c_max = in->cols;
|
||||
c_size_t item_sz = in->item_size;
|
||||
|
||||
// 行优先数据错位映射搬运:in(r, c) -> out(c, r)
|
||||
for (c_size_t r = 0; r < r_max; r++) {
|
||||
for (c_size_t c = 0; c < c_max; c++) {
|
||||
const char* src_cell = (const char*)in->data + ((r * c_max + c) * item_sz);
|
||||
char* dst_cell = (char*)out->data + ((c * r_max + r) * item_sz);
|
||||
memcpy(dst_cell, src_cell, item_sz); // 泛型值原装迁徙
|
||||
}
|
||||
}
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 内部私有递归核心:拉普拉斯代数余子式展开
|
||||
*/
|
||||
static void c_Matrix_DetInternal(c_Matrix_t* mat, void* out_det,
|
||||
c_Matrix_OpFn_t add_op, c_Matrix_OpFn_t sub_op,
|
||||
c_Matrix_OpFn_t mul_op, c_Matrix_NegFn_t neg_op,
|
||||
void* ud) {
|
||||
c_size_t n = mat->rows;
|
||||
c_size_t item_sz = mat->item_size;
|
||||
|
||||
// 基本边界 1: 1x1 方阵,行列式值即为其唯一的单体元素本身
|
||||
if (n == 1) {
|
||||
void* cell = NULL;
|
||||
c_Matrix_Get((c_Matrix_t*)self, 0, 0, &cell);
|
||||
memcpy(out_det, cell, elem_size);
|
||||
return C_SUCCESS;
|
||||
memcpy(out_det, mat->data, item_sz);
|
||||
return;
|
||||
}
|
||||
|
||||
c_Matrix_t temp_mat;
|
||||
c_err_t err = c_Matrix_Init(&temp_mat, n, n, elem_size);
|
||||
if (err != C_SUCCESS) return err;
|
||||
// 基本边界 2: 2x2 方阵,计算 ad - bc 快速通路,消除不必要的低层递归
|
||||
if (n == 2) {
|
||||
char* a = (char*)mat->data + (0 * item_sz);
|
||||
char* b = (char*)mat->data + (1 * item_sz);
|
||||
char* c = (char*)mat->data + (2 * item_sz);
|
||||
char* d = (char*)mat->data + (3 * item_sz);
|
||||
|
||||
void* src_base = NULL;
|
||||
void* dst_base = NULL;
|
||||
c_Array_Get(self->array, 0, &src_base);
|
||||
c_Array_Get(temp_mat.array, 0, &dst_base);
|
||||
memcpy(dst_base, src_base, n * n * elem_size);
|
||||
// 分配栈上局部存储,避开堆碎片
|
||||
void* ad = c_Allocator_Alloc(&mat->allocator, item_sz);
|
||||
void* bc = c_Allocator_Alloc(&mat->allocator, item_sz);
|
||||
|
||||
ops->one(out_det);
|
||||
int sign = 1;
|
||||
mul_op(ad, a, d, ud); // a * d
|
||||
mul_op(bc, b, c, ud); // b * c
|
||||
sub_op(out_det, ad, bc, ud); // ad - bc
|
||||
|
||||
// 分配真正独立的单元素计算缓冲区
|
||||
void* pivot_val = C_ALLOC(elem_size);
|
||||
void* factor = C_ALLOC(elem_size);
|
||||
void* temp_val = C_ALLOC(elem_size);
|
||||
|
||||
if (!pivot_val || !factor || !temp_val) {
|
||||
C_FREE(pivot_val);
|
||||
C_FREE(factor);
|
||||
C_FREE(temp_val);
|
||||
return C_ERR_NOMEM;
|
||||
c_Allocator_Free(&mat->allocator, ad);
|
||||
c_Allocator_Free(&mat->allocator, bc);
|
||||
return;
|
||||
}
|
||||
|
||||
for (c_size_t i = 0; i < n; i++) {
|
||||
// --- 部分主元选择 ---
|
||||
c_size_t pivot_row = i;
|
||||
void* max_cell = NULL;
|
||||
c_Matrix_Get(&temp_mat, i, i, &max_cell);
|
||||
// 递归分支: n > 2,固定沿第 0 行进行展开
|
||||
memset(out_det, 0, item_sz); // 抹零累加器
|
||||
|
||||
for (c_size_t k = i + 1; k < n; k++) {
|
||||
void* check_cell = NULL;
|
||||
c_Matrix_Get(&temp_mat, k, i, &check_cell);
|
||||
if (ops->compare_abs(check_cell, max_cell) > 0) {
|
||||
max_cell = check_cell;
|
||||
pivot_row = k;
|
||||
// 原地创建子方阵控制头 (大小为 n-1)
|
||||
c_Matrix_t sub_mat;
|
||||
sub_mat.allocator = mat->allocator;
|
||||
sub_mat.rows = n - 1;
|
||||
sub_mat.cols = n - 1;
|
||||
sub_mat.item_size = item_sz;
|
||||
|
||||
c_size_t sub_bytes = sub_mat.rows * sub_mat.cols * item_sz;
|
||||
sub_mat.data = c_Allocator_Alloc(&mat->allocator, sub_bytes);
|
||||
if (!sub_mat.data) return;
|
||||
|
||||
void* sub_det = c_Allocator_Alloc(&mat->allocator, item_sz);
|
||||
void* term = c_Allocator_Alloc(&mat->allocator, item_sz);
|
||||
void* neg_term = c_Allocator_Alloc(&mat->allocator, item_sz);
|
||||
|
||||
// 遍历第 0 行的每一列 c
|
||||
for (c_size_t c = 0; c < n; c++) {
|
||||
// 构建割裂后的代数余子式子方阵数据块
|
||||
c_size_t sub_r = 0;
|
||||
for (c_size_t r = 1; r < n; r++) { // 跳过第 0 行
|
||||
c_size_t sub_c = 0;
|
||||
for (c_size_t j = 0; j < n; j++) {
|
||||
if (j == c) continue; // 跳过当前列
|
||||
|
||||
const char* src = (const char*)mat->data + ((r * n + j) * item_sz);
|
||||
char* dst = (char*)sub_mat.data + ((sub_r * (n - 1) + sub_c) * item_sz);
|
||||
memcpy(dst, src, item_sz);
|
||||
sub_c++;
|
||||
}
|
||||
sub_r++;
|
||||
}
|
||||
|
||||
if (ops->is_zero(max_cell)) {
|
||||
ops->zero(out_det);
|
||||
goto _cleanup;
|
||||
// 递归求解子方阵的行列式
|
||||
c_Matrix_DetInternal(&sub_mat, sub_det, add_op, sub_op, mul_op, neg_op, ud);
|
||||
|
||||
// 计算当前项的系数乘积 term = mat(0, c) * sub_det
|
||||
const void* current_element = (const char*)mat->data + (c * item_sz);
|
||||
mul_op(term, current_element, sub_det, ud);
|
||||
|
||||
// 根据棋盘格正负号规则 ((-1)^(r+c)):当前第 0 行第 c 列,当 c 为奇数时取反
|
||||
if (c % 2 == 1) {
|
||||
neg_op(neg_term, term, ud); // 取负号
|
||||
add_op(out_det, out_det, neg_term, ud); // 累加负项
|
||||
} else {
|
||||
add_op(out_det, out_det, term, ud); // 累加正项
|
||||
}
|
||||
|
||||
if (pivot_row != i) {
|
||||
for (c_size_t j = i; j < n; j++) {
|
||||
void *cell_a = NULL, *cell_b = NULL;
|
||||
c_Matrix_Get(&temp_mat, i, j, &cell_a);
|
||||
c_Matrix_Get(&temp_mat, pivot_row, j, &cell_b);
|
||||
|
||||
memcpy(temp_val, cell_a, elem_size);
|
||||
memcpy(cell_a, cell_b, elem_size);
|
||||
memcpy(cell_b, temp_val, elem_size);
|
||||
}
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
// --- 🛠️ 核心修复点:安全获取当前主元的数据 ---
|
||||
void* internal_pivot_ptr = NULL;
|
||||
c_Matrix_Get(&temp_mat, i, i, &internal_pivot_ptr); // 此时被覆盖的是临时的 internal_pivot_ptr
|
||||
memcpy(pivot_val, internal_pivot_ptr, elem_size); // 将真实数据拷贝到我们的 C_ALLOC 缓冲区中,保持 pivot_val 的指针值不变
|
||||
|
||||
// --- 消元 ---
|
||||
for (c_size_t k = i + 1; k < n; k++) {
|
||||
void* current_col_cell = NULL;
|
||||
c_Matrix_Get(&temp_mat, k, i, ¤t_col_cell);
|
||||
|
||||
if (ops->is_zero(current_col_cell)) continue;
|
||||
|
||||
ops->div(current_col_cell, pivot_val, factor);
|
||||
|
||||
for (c_size_t j = i; j < n; j++) {
|
||||
void *row_i_cell = NULL, *row_k_cell = NULL;
|
||||
c_Matrix_Get(&temp_mat, i, j, &row_i_cell);
|
||||
c_Matrix_Get(&temp_mat, k, j, &row_k_cell);
|
||||
|
||||
ops->mul(row_i_cell, factor, temp_val);
|
||||
ops->sub(row_k_cell, temp_val, row_k_cell);
|
||||
}
|
||||
}
|
||||
|
||||
// 累乘对角线元素
|
||||
ops->mul(out_det, pivot_val, out_det);
|
||||
}
|
||||
|
||||
if (sign == -1) {
|
||||
ops->zero(temp_val);
|
||||
ops->sub(temp_val, out_det, out_det);
|
||||
}
|
||||
|
||||
_cleanup:
|
||||
// 此时的指针地址完美保持初始 C_ALLOC 状态,可以安全 C_FREE!
|
||||
C_FREE(pivot_val);
|
||||
C_FREE(factor);
|
||||
C_FREE(temp_val);
|
||||
c_Matrix_Destroy(&temp_mat);
|
||||
return C_SUCCESS;
|
||||
// 异常安全性层级强力物理释放,绝不产生多级残留
|
||||
c_Allocator_Free(&mat->allocator, sub_mat.data);
|
||||
c_Allocator_Free(&mat->allocator, sub_det);
|
||||
c_Allocator_Free(&mat->allocator, term);
|
||||
c_Allocator_Free(&mat->allocator, neg_term);
|
||||
}
|
||||
|
||||
c_err_t c_Matrix_Solve(const c_Matrix_t* A, const c_Matrix_t* b, c_Matrix_t* x, const c_MatrixOps_t* ops) {
|
||||
// 1. 基础健壮性检查
|
||||
if (!A || !b || !x || !ops) return C_ERR_PARAM;
|
||||
if (A->rows != A->cols) return C_ERR_PARAM; // A 必须是方阵
|
||||
if (b->rows != A->rows || b->cols != 1) return C_ERR_PARAM; // b 必须是 Nx1
|
||||
if (x->rows != A->rows || x->cols != 1) return C_ERR_PARAM; // x 必须是 Nx1
|
||||
// 行列式主驱动包装接口
|
||||
c_err_t c_Matrix_Determinant(c_Matrix_t* self, void* out_det,
|
||||
c_Matrix_OpFn_t add_op, c_Matrix_OpFn_t sub_op,
|
||||
c_Matrix_OpFn_t mul_op, c_Matrix_NegFn_t neg_op,
|
||||
void* ud) {
|
||||
if (!self || !out_det || !add_op || !sub_op || !mul_op || !neg_op) return C_ERR_PARAM;
|
||||
|
||||
c_size_t n = A->rows;
|
||||
c_size_t elem_size = c_Matrix_ElementSize((c_Matrix_t*)A);
|
||||
|
||||
// 2. 初始化 Nx(N+1) 的增广矩阵
|
||||
c_Matrix_t aug;
|
||||
c_err_t err = c_Matrix_Init(&aug, n, n + 1, elem_size);
|
||||
if (err != C_SUCCESS) return err;
|
||||
|
||||
// 填充增广矩阵:前 n 列拷贝 A,第 n+1 列拷贝 b
|
||||
for (c_size_t i = 0; i < n; i++) {
|
||||
for (c_size_t j = 0; j < n; j++) {
|
||||
void* cell_A = NULL;
|
||||
c_Matrix_Get((c_Matrix_t*)A, i, j, &cell_A);
|
||||
c_Matrix_Put(&aug, i, j, cell_A);
|
||||
}
|
||||
void* cell_b = NULL;
|
||||
c_Matrix_Get((c_Matrix_t*)b, i, 0, &cell_b);
|
||||
c_Matrix_Put(&aug, i, n, cell_b); // 最后一列
|
||||
// 强行约束约束:只有正方矩阵具备行列式
|
||||
if (self->rows != self->cols || self->rows == 0) {
|
||||
return C_ERR_OUTOFBOUND;
|
||||
}
|
||||
|
||||
// 分配独立的计算缓冲区,严格保护指针地址不被 Get 覆盖
|
||||
void* pivot_val = C_ALLOC(elem_size);
|
||||
void* factor = C_ALLOC(elem_size);
|
||||
void* temp_val = C_ALLOC(elem_size);
|
||||
void* sum_val = C_ALLOC(elem_size);
|
||||
|
||||
if (!pivot_val || !factor || !temp_val || !sum_val) {
|
||||
C_FREE(pivot_val);
|
||||
C_FREE(factor);
|
||||
C_FREE(temp_val);
|
||||
C_FREE(sum_val);
|
||||
return C_ERR_NOMEM;
|
||||
}
|
||||
|
||||
// 3. 高斯消元主循环(化为上三角矩阵)
|
||||
for (c_size_t i = 0; i < n; i++) {
|
||||
// --- 3.1 部分主元选择(选绝对值最大的行交换上来,提高数值稳定性) ---
|
||||
c_size_t pivot_row = i;
|
||||
void* max_cell = NULL;
|
||||
c_Matrix_Get(&aug, i, i, &max_cell);
|
||||
|
||||
for (c_size_t k = i + 1; k < n; k++) {
|
||||
void* check_cell = NULL;
|
||||
c_Matrix_Get(&aug, k, i, &check_cell);
|
||||
if (ops->compare_abs(check_cell, max_cell) > 0) {
|
||||
max_cell = check_cell;
|
||||
pivot_row = k;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果主元极度接近 0,说明矩阵奇异(无解或无数解)
|
||||
if (ops->is_zero(max_cell)) {
|
||||
err = C_ERR_SINGULAR;
|
||||
goto _cleanup;
|
||||
}
|
||||
|
||||
// 行交换
|
||||
if (pivot_row != i) {
|
||||
for (c_size_t j = i; j <= n; j++) {
|
||||
void *cell_a = NULL, *cell_b = NULL;
|
||||
c_Matrix_Get(&aug, i, j, &cell_a);
|
||||
c_Matrix_Get(&aug, pivot_row, j, &cell_b);
|
||||
|
||||
memcpy(temp_val, cell_a, elem_size);
|
||||
memcpy(cell_a, cell_b, elem_size);
|
||||
memcpy(cell_b, temp_val, elem_size);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3.2 保护性安全读取当前行的主元数据 ---
|
||||
void* internal_pivot_ptr = NULL;
|
||||
c_Matrix_Get(&aug, i, i, &internal_pivot_ptr);
|
||||
memcpy(pivot_val, internal_pivot_ptr, elem_size); // 复制数据,保证 pivot_val 的 C_ALLOC 指针不被踩坏
|
||||
|
||||
// --- 3.3 消元过程 ---
|
||||
for (c_size_t k = i + 1; k < n; k++) {
|
||||
void* current_col_cell = NULL;
|
||||
c_Matrix_Get(&aug, k, i, ¤t_col_cell);
|
||||
|
||||
if (ops->is_zero(current_col_cell)) continue;
|
||||
|
||||
// factor = aug[k][i] / pivot_val
|
||||
ops->div(current_col_cell, pivot_val, factor);
|
||||
|
||||
for (c_size_t j = i; j <= n; j++) {
|
||||
void *row_i_cell = NULL, *row_k_cell = NULL;
|
||||
c_Matrix_Get(&aug, i, j, &row_i_cell);
|
||||
c_Matrix_Get(&aug, k, j, &row_k_cell);
|
||||
|
||||
ops->mul(row_i_cell, factor, temp_val); // temp = aug[i][j] * factor
|
||||
ops->sub(row_k_cell, temp_val, row_k_cell); // aug[k][j] -= temp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 回代法求解(Back Substitution)
|
||||
// 公式:x[i] = (aug[i][n] - sum(aug[i][j] * x[j])) / aug[i][i]
|
||||
for (int i = (int)n - 1; i >= 0; i--) {
|
||||
ops->zero(sum_val); // sum = 0
|
||||
|
||||
for (c_size_t j = (c_size_t)i + 1; j < n; j++) {
|
||||
void *aug_cell = NULL, *x_cell = NULL;
|
||||
c_Matrix_Get(&aug, (c_size_t)i, j, &aug_cell);
|
||||
c_Matrix_Get(x, j, 0, &x_cell);
|
||||
|
||||
ops->mul(aug_cell, x_cell, temp_val); // temp = aug[i][j] * x[j]
|
||||
ops->add(sum_val, temp_val, sum_val); // sum += temp
|
||||
}
|
||||
|
||||
void *aug_b_cell = NULL, *aug_diag_cell = NULL;
|
||||
c_Matrix_Get(&aug, (c_size_t)i, n, &aug_b_cell); // 最后一列的常数项
|
||||
c_Matrix_Get(&aug, (c_size_t)i, (c_size_t)i, &aug_diag_cell); // 对角线主元
|
||||
|
||||
ops->sub(aug_b_cell, sum_val, temp_val); // temp = b_item - sum
|
||||
|
||||
void* x_dest_slot = NULL;
|
||||
c_Matrix_Get(x, (c_size_t)i, 0, &x_dest_slot);
|
||||
ops->div(temp_val, aug_diag_cell, x_dest_slot); // x[i] = temp / aug[i][i]
|
||||
}
|
||||
|
||||
err = C_SUCCESS;
|
||||
|
||||
_cleanup:
|
||||
C_FREE(pivot_val);
|
||||
C_FREE(factor);
|
||||
C_FREE(temp_val);
|
||||
C_FREE(sum_val);
|
||||
c_Matrix_Destroy(&aug);
|
||||
return err;
|
||||
c_Matrix_DetInternal(self, out_det, add_op, sub_op, mul_op, neg_op, ud);
|
||||
return C_ERR_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user