File size: 5,246 Bytes
2166d7e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | #include "l1_pmat.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
cs_status pmat_new(pmat *m, size_t rows, size_t cols)
{
if (!m || rows == 0 || cols == 0) return CS_ERR_ARG;
if (rows > SIZE_MAX / cols || rows * cols > SIZE_MAX / sizeof(gl_t)) return CS_ERR_NOMEM;
m->d = calloc(rows * cols, sizeof(gl_t));
if (!m->d) return CS_ERR_NOMEM;
m->rows = rows;
m->cols = cols;
return CS_OK;
}
void pmat_free(pmat *m)
{
if (!m) return;
free(m->d);
m->d = NULL;
m->rows = m->cols = 0;
}
cs_status pmat_identity(pmat *m, size_t n)
{
cs_status s = pmat_new(m, n, n);
if (s != CS_OK) return s;
for (size_t i = 0; i < n; i++) m->d[i * n + i] = 1;
return CS_OK;
}
gl_t pmat_get(const pmat *m, size_t r, size_t c) { return m->d[r * m->cols + c]; }
void pmat_set(pmat *m, size_t r, size_t c, gl_t v) { m->d[r * m->cols + c] = gl_reduce(v); }
int pmat_equal(const pmat *a, const pmat *b)
{
return a->rows == b->rows && a->cols == b->cols &&
memcmp(a->d, b->d, a->rows * a->cols * sizeof(gl_t)) == 0;
}
static cs_status elementwise(const pmat *a, const pmat *b, pmat *out, int sub)
{
if (!a || !b || !out || !a->d || !b->d) return CS_ERR_ARG;
if (a->rows != b->rows || a->cols != b->cols) return CS_ERR_RANGE;
pmat r;
cs_status s = pmat_new(&r, a->rows, a->cols);
if (s != CS_OK) return s;
for (size_t i = 0; i < a->rows * a->cols; i++)
r.d[i] = sub ? gl_sub(a->d[i], b->d[i]) : gl_add(a->d[i], b->d[i]);
*out = r;
return CS_OK;
}
cs_status pmat_add(const pmat *a, const pmat *b, pmat *out) { return elementwise(a, b, out, 0); }
cs_status pmat_sub(const pmat *a, const pmat *b, pmat *out) { return elementwise(a, b, out, 1); }
cs_status pmat_scale(const pmat *a, gl_t k, pmat *out)
{
if (!a || !out || !a->d) return CS_ERR_ARG;
pmat r;
cs_status s = pmat_new(&r, a->rows, a->cols);
if (s != CS_OK) return s;
k = gl_reduce(k);
for (size_t i = 0; i < a->rows * a->cols; i++) r.d[i] = gl_mul(a->d[i], k);
*out = r;
return CS_OK;
}
cs_status pmat_mul(const pmat *a, const pmat *b, pmat *out)
{
if (!a || !b || !out || !a->d || !b->d) return CS_ERR_ARG;
if (a->cols != b->rows) return CS_ERR_RANGE;
pmat r;
cs_status s = pmat_new(&r, a->rows, b->cols);
if (s != CS_OK) return s;
for (size_t i = 0; i < a->rows; i++)
for (size_t k = 0; k < a->cols; k++) {
gl_t aik = a->d[i * a->cols + k];
for (size_t j = 0; j < b->cols; j++)
r.d[i * r.cols + j] = gl_add(r.d[i * r.cols + j], gl_mul(aik, b->d[k * b->cols + j]));
}
*out = r;
return CS_OK;
}
cs_status pmat_transpose(const pmat *a, pmat *out)
{
if (!a || !out || !a->d) return CS_ERR_ARG;
pmat r;
cs_status s = pmat_new(&r, a->cols, a->rows);
if (s != CS_OK) return s;
for (size_t i = 0; i < a->rows; i++)
for (size_t j = 0; j < a->cols; j++) r.d[j * r.cols + i] = a->d[i * a->cols + j];
*out = r;
return CS_OK;
}
/* Gauss-Jordan on [A | I]; accumulates the determinant. */
static cs_status eliminate(const pmat *a, pmat *inv_out, gl_t *det_out)
{
if (!a || !a->d) return CS_ERR_ARG;
if (a->rows != a->cols) return CS_ERR_RANGE;
size_t n = a->rows;
pmat w, id;
cs_status s = pmat_new(&w, n, n);
if (s != CS_OK) return s;
memcpy(w.d, a->d, n * n * sizeof(gl_t));
s = pmat_identity(&id, n);
if (s != CS_OK) { pmat_free(&w); return s; }
gl_t det = 1;
for (size_t col = 0; col < n; col++) {
size_t piv = col;
while (piv < n && w.d[piv * n + col] == 0) piv++;
if (piv == n) { det = 0; pmat_free(&w); pmat_free(&id); if (det_out) *det_out = 0; return CS_ERR_SINGULAR; }
if (piv != col) {
for (size_t j = 0; j < n; j++) {
gl_t t = w.d[piv * n + j]; w.d[piv * n + j] = w.d[col * n + j]; w.d[col * n + j] = t;
t = id.d[piv * n + j]; id.d[piv * n + j] = id.d[col * n + j]; id.d[col * n + j] = t;
}
det = gl_neg(det);
}
gl_t pv = w.d[col * n + col], pinv;
det = gl_mul(det, pv);
(void)gl_inv(pv, &pinv);
for (size_t j = 0; j < n; j++) {
w.d[col * n + j] = gl_mul(w.d[col * n + j], pinv);
id.d[col * n + j] = gl_mul(id.d[col * n + j], pinv);
}
for (size_t r = 0; r < n; r++) {
if (r == col) continue;
gl_t f = w.d[r * n + col];
if (f == 0) continue;
for (size_t j = 0; j < n; j++) {
w.d[r * n + j] = gl_sub(w.d[r * n + j], gl_mul(f, w.d[col * n + j]));
id.d[r * n + j] = gl_sub(id.d[r * n + j], gl_mul(f, id.d[col * n + j]));
}
}
}
if (det_out) *det_out = det;
pmat_free(&w);
if (inv_out) *inv_out = id; else pmat_free(&id);
return CS_OK;
}
cs_status pmat_det(const pmat *a, gl_t *det)
{
if (!det) return CS_ERR_ARG;
cs_status s = eliminate(a, NULL, det);
if (s == CS_ERR_SINGULAR) return CS_OK; /* det of a singular matrix is 0 */
return s;
}
cs_status pmat_inverse(const pmat *a, pmat *out)
{
if (!out) return CS_ERR_ARG;
return eliminate(a, out, NULL);
}
|