aboutsummaryrefslogtreecommitdiff
path: root/src/maths
diff options
context:
space:
mode:
Diffstat (limited to 'src/maths')
-rw-r--r--src/maths/complex.c122
-rw-r--r--src/maths/format.c265
-rw-r--r--src/maths/matrix.c192
-rw-r--r--src/maths/matrix.rs310
-rw-r--r--src/maths/simd.c424
-rw-r--r--src/maths/vector.c136
-rw-r--r--src/maths/vector.rs258
7 files changed, 596 insertions, 1111 deletions
diff --git a/src/maths/complex.c b/src/maths/complex.c
index 44e255f..419d0b0 100644
--- a/src/maths/complex.c
+++ b/src/maths/complex.c
@@ -4,126 +4,126 @@
struct PsiComplex psi_new_complex(double real, double imaginary)
{
- return (struct PsiComplex){
- real,
- imaginary,
- };
+ return (struct PsiComplex){
+ real,
+ imaginary,
+ };
}
struct PsiComplex psi_new_complex_from_real(double real)
{
- return (struct PsiComplex){
- real,
- 0.0,
- };
+ return (struct PsiComplex){
+ real,
+ 0.0,
+ };
}
struct PsiComplex psi_conjugate_complex(struct PsiComplex z)
{
- return (struct PsiComplex){
- z.real,
- -z.imaginary,
- };
+ return (struct PsiComplex){
+ z.real,
+ -z.imaginary,
+ };
}
struct PsiComplex psi_neg_complex(struct PsiComplex z)
{
- return (struct PsiComplex){
- -z.real,
- -z.imaginary,
- };
+ return (struct PsiComplex){
+ -z.real,
+ -z.imaginary,
+ };
}
double psi_phase_complex(struct PsiComplex z)
{
- return atan2(z.imaginary, z.real);
+ return atan2(z.imaginary, z.real);
}
double psi_norm2_complex(struct PsiComplex z)
{
- return z.real * z.real + z.imaginary * z.imaginary;
+ return z.real * z.real + z.imaginary * z.imaginary;
}
double psi_abs_complex(struct PsiComplex z)
{
- return sqrt(psi_norm2_complex(z));
+ return sqrt(psi_norm2_complex(z));
}
struct PsiComplex psi_sqrt_complex(struct PsiComplex z)
{
- double r = psi_abs_complex(z);
- double half_theta = psi_phase_complex(z) / 2.0;
- double sqrt_r = sqrt(r);
+ double r = psi_abs_complex(z);
+ double half_theta = psi_phase_complex(z) / 2.0;
+ double sqrt_r = sqrt(r);
- return (struct PsiComplex){
- sqrt_r * cos(half_theta),
- sqrt_r * sin(half_theta),
- };
+ return (struct PsiComplex){
+ sqrt_r * cos(half_theta),
+ sqrt_r * sin(half_theta),
+ };
}
struct PsiComplex psi_add_complex(struct PsiComplex a, struct PsiComplex b)
{
- return (struct PsiComplex){
- a.real + b.real,
- a.imaginary + b.imaginary,
- };
+ return (struct PsiComplex){
+ a.real + b.real,
+ a.imaginary + b.imaginary,
+ };
}
struct PsiComplex psi_sub_complex(struct PsiComplex a, struct PsiComplex b)
{
- return (struct PsiComplex){
- a.real - b.real,
- a.imaginary - b.imaginary,
- };
+ return (struct PsiComplex){
+ a.real - b.real,
+ a.imaginary - b.imaginary,
+ };
}
struct PsiComplex psi_mul_complex(struct PsiComplex a, struct PsiComplex b)
{
- // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
- return (struct PsiComplex){
- a.real * b.real - a.imaginary * b.imaginary,
- a.real * b.imaginary + a.imaginary * b.real,
- };
+ // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
+ return (struct PsiComplex){
+ a.real * b.real - a.imaginary * b.imaginary,
+ a.real * b.imaginary + a.imaginary * b.real,
+ };
}
struct PsiComplex psi_div_complex(struct PsiComplex a, struct PsiComplex b)
{
- // (a + bi) / (c + di) = ((ac + bd) + (bc - ad)i) / (c² + d²)
- double denom = b.real * b.real + b.imaginary * b.imaginary;
- return (struct PsiComplex){
- (a.real * b.real + a.imaginary * b.imaginary) / denom,
- (a.imaginary * b.real - a.real * b.imaginary) / denom,
- };
+ // (a + bi) / (c + di) = ((ac + bd) + (bc - ad)i) / (c² + d²)
+ double denom = b.real * b.real + b.imaginary * b.imaginary;
+ return (struct PsiComplex){
+ (a.real * b.real + a.imaginary * b.imaginary) / denom,
+ (a.imaginary * b.real - a.real * b.imaginary) / denom,
+ };
}
struct PsiComplex psi_add_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real + b,
- a.imaginary,
- };
+ return (struct PsiComplex){
+ a.real + b,
+ a.imaginary,
+ };
}
struct PsiComplex psi_sub_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real - b,
- a.imaginary,
- };
+ return (struct PsiComplex){
+ a.real - b,
+ a.imaginary,
+ };
}
struct PsiComplex psi_mul_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real * b,
- a.imaginary * b,
- };
+ return (struct PsiComplex){
+ a.real * b,
+ a.imaginary * b,
+ };
}
struct PsiComplex psi_div_complex_real(struct PsiComplex a, double b)
{
- return (struct PsiComplex){
- a.real / b,
- a.imaginary / b,
- };
+ return (struct PsiComplex){
+ a.real / b,
+ a.imaginary / b,
+ };
}
diff --git a/src/maths/format.c b/src/maths/format.c
index f3db83d..52b2b5a 100644
--- a/src/maths/format.c
+++ b/src/maths/format.c
@@ -12,136 +12,189 @@ static const double INV_SQRT_32 = 0.1767766952966369;
static bool approx_eq(double a, double b)
{
- return fabs(a - b) < EPSILON;
+ return fabs(a - b) < EPSILON;
}
static bool real_symbolic(double v, char* out, size_t cap)
{
- double abs_v = fabs(v);
- const char* sign = v < 0.0 ? "-" : "";
+ double abs_v = fabs(v);
+ const char* sign = v < 0.0 ? "-" : "";
- if (approx_eq(abs_v, 0.0))
- {
- snprintf(out, cap, "%s", "0");
- return true;
- }
+ if (approx_eq(abs_v, 0.0))
+ {
+ snprintf(out, cap, "%s", "0");
+ return true;
+ }
- const char* sym = NULL;
- if (approx_eq(abs_v, 1.0))
- sym = "1";
- else if (approx_eq(abs_v, 0.5))
- sym = "½";
- else if (approx_eq(abs_v, 0.25))
- sym = "¼";
- else if (approx_eq(abs_v, 0.75))
- sym = "¾";
- else if (approx_eq(abs_v, 0.125))
- sym = "⅛";
- else if (approx_eq(abs_v, SQRT_2))
- sym = "√2";
- else if (approx_eq(abs_v, INV_SQRT_2))
- sym = "¹⁄√2";
- else if (approx_eq(abs_v, INV_SQRT_8))
- sym = "¹⁄√8";
- else if (approx_eq(abs_v, INV_SQRT_32))
- sym = "¹⁄√32";
- else if (approx_eq(abs_v, 2.0))
- sym = "2";
- else if (approx_eq(abs_v, 1.0 / 3.0))
- sym = "⅓";
- else if (approx_eq(abs_v, 2.0 / 3.0))
- sym = "⅔";
- else
- return false;
+ const char* sym = NULL;
+ if (approx_eq(abs_v, 1.0))
+ sym = "1";
+ else if (approx_eq(abs_v, 0.5))
+ sym = "½";
+ else if (approx_eq(abs_v, 0.25))
+ sym = "¼";
+ else if (approx_eq(abs_v, 0.75))
+ sym = "¾";
+ else if (approx_eq(abs_v, 0.125))
+ sym = "⅛";
+ else if (approx_eq(abs_v, SQRT_2))
+ sym = "√2";
+ else if (approx_eq(abs_v, INV_SQRT_2))
+ sym = "¹⁄√2";
+ else if (approx_eq(abs_v, INV_SQRT_8))
+ sym = "¹⁄√8";
+ else if (approx_eq(abs_v, INV_SQRT_32))
+ sym = "¹⁄√32";
+ else if (approx_eq(abs_v, 2.0))
+ sym = "2";
+ else if (approx_eq(abs_v, 1.0 / 3.0))
+ sym = "⅓";
+ else if (approx_eq(abs_v, 2.0 / 3.0))
+ sym = "⅔";
+ else
+ return false;
- snprintf(out, cap, "%s%s", sign, sym);
- return true;
+ snprintf(out, cap, "%s%s", sign, sym);
+ return true;
}
char* psi_format_amplitude(struct PsiComplex c, char* out, size_t cap)
{
- double re = c.real;
- double im = c.imaginary;
+ double re = c.real;
+ double im = c.imaginary;
- bool re_zero = approx_eq(fabs(re), 0.0);
- bool im_zero = approx_eq(fabs(im), 0.0);
+ bool re_zero = approx_eq(fabs(re), 0.0);
+ bool im_zero = approx_eq(fabs(im), 0.0);
- if (re_zero && im_zero)
- {
- snprintf(out, cap, "%s", "0");
- return out;
- }
+ if (re_zero && im_zero)
+ {
+ snprintf(out, cap, "%s", "0");
+ return out;
+ }
- if (im_zero)
- {
- if (!real_symbolic(re, out, cap))
- snprintf(out, cap, "%.4f", re);
+ if (im_zero)
+ {
+ if (!real_symbolic(re, out, cap))
+ snprintf(out, cap, "%.4f", re);
- return out;
- }
+ return out;
+ }
- if (re_zero)
- {
- if (approx_eq(fabs(im), 1.0))
- {
- snprintf(out, cap, "%s", im > 0.0 ? "i" : "-i");
- return out;
- }
+ if (re_zero)
+ {
+ if (approx_eq(fabs(im), 1.0))
+ {
+ snprintf(out, cap, "%s", im > 0.0 ? "i" : "-i");
+ return out;
+ }
- char sym[32];
- if (real_symbolic(im, sym, sizeof sym))
- snprintf(out, cap, "%si", sym);
- else
- snprintf(out, cap, "%.4fi", im);
+ char sym[32];
+ if (real_symbolic(im, sym, sizeof sym))
+ snprintf(out, cap, "%si", sym);
+ else
+ snprintf(out, cap, "%.4fi", im);
- return out;
- }
+ return out;
+ }
- char re_str[32];
- if (!real_symbolic(re, re_str, sizeof re_str))
- snprintf(re_str, sizeof re_str, "%.4f", re);
+ char re_str[32];
+ if (!real_symbolic(re, re_str, sizeof re_str))
+ snprintf(re_str, sizeof re_str, "%.4f", re);
- char im_str[32];
- if (approx_eq(fabs(im), 1.0))
- {
- snprintf(im_str, sizeof im_str, "%s", im > 0.0 ? "+i" : "-i");
- }
- else
- {
- const char* sign = im > 0.0 ? "+" : "-";
- char sym[32];
- if (real_symbolic(fabs(im), sym, sizeof sym))
- snprintf(im_str, sizeof im_str, "%s%si", sign, sym);
- else
- snprintf(im_str, sizeof im_str, "%s%.4fi", sign, fabs(im));
- }
+ char im_str[32];
+ if (approx_eq(fabs(im), 1.0))
+ {
+ snprintf(im_str, sizeof im_str, "%s", im > 0.0 ? "+i" : "-i");
+ }
+ else
+ {
+ const char* sign = im > 0.0 ? "+" : "-";
+ char sym[32];
+ if (real_symbolic(fabs(im), sym, sizeof sym))
+ snprintf(im_str, sizeof im_str, "%s%si", sign, sym);
+ else
+ snprintf(im_str, sizeof im_str, "%s%.4fi", sign, fabs(im));
+ }
- snprintf(out, cap, "%s%s", re_str, im_str);
- return out;
+ snprintf(out, cap, "%s%s", re_str, im_str);
+ return out;
}
char* psi_format_probability(double p, char* out, size_t cap)
{
- if (approx_eq(p, 0.0))
- snprintf(out, cap, "%s", "0");
- else if (approx_eq(p, 1.0))
- snprintf(out, cap, "%s", "1");
- else if (approx_eq(p, 0.5))
- snprintf(out, cap, "%s", "½");
- else if (approx_eq(p, 0.25))
- snprintf(out, cap, "%s", "¼");
- else if (approx_eq(p, 0.75))
- snprintf(out, cap, "%s", "¾");
- else if (approx_eq(p, 0.125))
- snprintf(out, cap, "%s", "⅛");
- else if (approx_eq(p, 0.0625))
- snprintf(out, cap, "%s", "¹⁄₁₆");
- else if (approx_eq(p, 1.0 / 3.0))
- snprintf(out, cap, "%s", "⅓");
- else if (approx_eq(p, 2.0 / 3.0))
- snprintf(out, cap, "%s", "⅔");
- else
- snprintf(out, cap, "%.4f", p);
+ if (approx_eq(p, 0.0))
+ snprintf(out, cap, "%s", "0");
+ else if (approx_eq(p, 1.0))
+ snprintf(out, cap, "%s", "1");
+ else if (approx_eq(p, 0.5))
+ snprintf(out, cap, "%s", "½");
+ else if (approx_eq(p, 0.25))
+ snprintf(out, cap, "%s", "¼");
+ else if (approx_eq(p, 0.75))
+ snprintf(out, cap, "%s", "¾");
+ else if (approx_eq(p, 0.125))
+ snprintf(out, cap, "%s", "⅛");
+ else if (approx_eq(p, 0.0625))
+ snprintf(out, cap, "%s", "¹⁄₁₆");
+ else if (approx_eq(p, 1.0 / 3.0))
+ snprintf(out, cap, "%s", "⅓");
+ else if (approx_eq(p, 2.0 / 3.0))
+ snprintf(out, cap, "%s", "⅔");
+ else
+ snprintf(out, cap, "%.4f", p);
- return out;
+ return out;
+}
+
+void psi_print_matrix(struct PsiMatrix m, FILE* out)
+{
+ int re_width = 0;
+ int im_width = 0;
+ for (size_t k = 0; k < m.rows * m.cols; k++)
+ {
+ int rl = snprintf(NULL, 0, "%.2f", m.data[k].real);
+ int il = snprintf(NULL, 0, "%.2f", fabs(m.data[k].imaginary));
+ if (rl > re_width)
+ re_width = rl;
+ if (il > im_width)
+ im_width = il;
+ }
+
+ for (size_t i = 0; i < m.rows; i++)
+ {
+ fputs(i == 0 ? "┌" : (i == m.rows - 1 ? "└" : "│"), out);
+
+ for (size_t j = 0; j < m.cols; j++)
+ {
+ struct PsiComplex e = m.data[i * m.cols + j];
+ const char* sign = e.imaginary > 0.0 ? "+" : "-";
+ fprintf(out, "%*.2f %s %*.2fi", re_width, e.real, sign, im_width, fabs(e.imaginary));
+ if (j != m.cols - 1)
+ fputs(", ", out);
+ }
+
+ fputs(i == 0 ? "┐" : (i == m.rows - 1 ? "┘" : "│"), out);
+ if (i != m.rows - 1)
+ fputc('\n', out);
+ }
+}
+
+void psi_print_vector(struct PsiVector v, FILE* out)
+{
+ if (v.kind == PSI_COLUMN_VECTOR)
+ {
+ struct PsiMatrix m = psi_matrix_from_vector(v);
+ psi_print_matrix(m, out);
+ psi_free_matrix(&m);
+ return;
+ }
+
+ fputc('[', out);
+ for (size_t i = 0; i < v.size; i++)
+ {
+ fprintf(out, "%g + %gi", v.data[i].real, v.data[i].imaginary);
+ if (i != v.size - 1)
+ fputs(", ", out);
+ }
+ fputc(']', out);
}
diff --git a/src/maths/matrix.c b/src/maths/matrix.c
index 2415395..8b41065 100644
--- a/src/maths/matrix.c
+++ b/src/maths/matrix.c
@@ -6,181 +6,181 @@
struct PsiMatrix psi_new_matrix(size_t rows, size_t cols)
{
- struct PsiComplex* data = calloc(rows * cols, sizeof(struct PsiComplex));
- assert(data != NULL || rows * cols == 0);
+ struct PsiComplex* data = calloc(rows * cols, sizeof(struct PsiComplex));
+ assert(data != NULL || rows * cols == 0);
- return (struct PsiMatrix){
- data,
- rows,
- cols,
- };
+ return (struct PsiMatrix){
+ data,
+ rows,
+ cols,
+ };
}
struct PsiMatrix psi_new_matrix_from(const struct PsiComplex* data, size_t rows, size_t cols)
{
- struct PsiMatrix m = psi_new_matrix(rows, cols);
- memcpy(m.data, data, rows * cols * sizeof(struct PsiComplex));
+ struct PsiMatrix m = psi_new_matrix(rows, cols);
+ memcpy(m.data, data, rows * cols * sizeof(struct PsiComplex));
- return m;
+ return m;
}
struct PsiMatrix psi_clone_matrix(struct PsiMatrix m)
{
- return psi_new_matrix_from(m.data, m.rows, m.cols);
+ return psi_new_matrix_from(m.data, m.rows, m.cols);
}
struct PsiMatrix psi_identity_matrix(size_t size)
{
- struct PsiMatrix m = psi_new_matrix(size, size);
- for (size_t i = 0; i < size; i++)
- m.data[i * size + i] = psi_new_complex(1.0, 0.0);
+ struct PsiMatrix m = psi_new_matrix(size, size);
+ for (size_t i = 0; i < size; i++)
+ m.data[i * size + i] = psi_new_complex(1.0, 0.0);
- return m;
+ return m;
}
void psi_free_matrix(struct PsiMatrix* m)
{
- free(m->data);
- m->data = NULL;
- m->rows = 0;
- m->cols = 0;
+ free(m->data);
+ m->data = NULL;
+ m->rows = 0;
+ m->cols = 0;
}
struct PsiComplex psi_get_matrix(struct PsiMatrix m, size_t row, size_t col)
{
- assert(row < m.rows && col < m.cols);
- return m.data[row * m.cols + col];
+ assert(row < m.rows && col < m.cols);
+ return m.data[row * m.cols + col];
}
void psi_set_matrix(struct PsiMatrix* m, size_t row, size_t col, struct PsiComplex value)
{
- assert(row < m->rows && col < m->cols);
- m->data[row * m->cols + col] = value;
+ assert(row < m->rows && col < m->cols);
+ m->data[row * m->cols + col] = value;
}
struct PsiMatrix psi_dot_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- assert(a.cols == b.rows);
+ assert(a.cols == b.rows);
- struct PsiMatrix result = psi_new_matrix(a.rows, b.cols);
- for (size_t i = 0; i < a.rows; i++)
- for (size_t j = 0; j < b.cols; j++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t k = 0; k < a.cols; k++)
- sum = psi_add_complex(
- sum, psi_mul_complex(a.data[i * a.cols + k], b.data[k * b.cols + j]));
+ struct PsiMatrix result = psi_new_matrix(a.rows, b.cols);
+ for (size_t i = 0; i < a.rows; i++)
+ for (size_t j = 0; j < b.cols; j++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t k = 0; k < a.cols; k++)
+ sum = psi_add_complex(
+ sum, psi_mul_complex(a.data[i * a.cols + k], b.data[k * b.cols + j]));
- result.data[i * result.cols + j] = sum;
- }
+ result.data[i * result.cols + j] = sum;
+ }
- return result;
+ return result;
}
struct PsiMatrix psi_kronecker_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- struct PsiMatrix result = psi_new_matrix(a.rows * b.rows, a.cols * b.cols);
- for (size_t i = 0; i < a.rows; i++)
- for (size_t j = 0; j < a.cols; j++)
- {
- struct PsiComplex a_val = a.data[i * a.cols + j];
- for (size_t k = 0; k < b.rows; k++)
- for (size_t l = 0; l < b.cols; l++)
- {
- size_t row = i * b.rows + k;
- size_t col = j * b.cols + l;
- result.data[row * result.cols + col] =
- psi_mul_complex(a_val, b.data[k * b.cols + l]);
- }
- }
+ struct PsiMatrix result = psi_new_matrix(a.rows * b.rows, a.cols * b.cols);
+ for (size_t i = 0; i < a.rows; i++)
+ for (size_t j = 0; j < a.cols; j++)
+ {
+ struct PsiComplex a_val = a.data[i * a.cols + j];
+ for (size_t k = 0; k < b.rows; k++)
+ for (size_t l = 0; l < b.cols; l++)
+ {
+ size_t row = i * b.rows + k;
+ size_t col = j * b.cols + l;
+ result.data[row * result.cols + col] =
+ psi_mul_complex(a_val, b.data[k * b.cols + l]);
+ }
+ }
- return result;
+ return result;
}
struct PsiMatrix psi_transpose_matrix(struct PsiMatrix m)
{
- struct PsiMatrix result = psi_new_matrix(m.cols, m.rows);
- for (size_t i = 0; i < m.rows; i++)
- for (size_t j = 0; j < m.cols; j++)
- result.data[j * result.cols + i] = m.data[i * m.cols + j];
+ struct PsiMatrix result = psi_new_matrix(m.cols, m.rows);
+ for (size_t i = 0; i < m.rows; i++)
+ for (size_t j = 0; j < m.cols; j++)
+ result.data[j * result.cols + i] = m.data[i * m.cols + j];
- return result;
+ return result;
}
struct PsiMatrix psi_add_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- assert(a.rows == b.rows && a.cols == b.cols);
+ assert(a.rows == b.rows && a.cols == b.cols);
- struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
- for (size_t i = 0; i < a.rows * a.cols; i++)
- result.data[i] = psi_add_complex(a.data[i], b.data[i]);
+ struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
+ for (size_t i = 0; i < a.rows * a.cols; i++)
+ result.data[i] = psi_add_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiMatrix psi_sub_matrix(struct PsiMatrix a, struct PsiMatrix b)
{
- assert(a.rows == b.rows && a.cols == b.cols);
+ assert(a.rows == b.rows && a.cols == b.cols);
- struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
- for (size_t i = 0; i < a.rows * a.cols; i++)
- result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
+ struct PsiMatrix result = psi_new_matrix(a.rows, a.cols);
+ for (size_t i = 0; i < a.rows * a.cols; i++)
+ result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiMatrix psi_scale_matrix(struct PsiMatrix m, struct PsiComplex scalar)
{
- struct PsiMatrix result = psi_new_matrix(m.rows, m.cols);
- for (size_t i = 0; i < m.rows * m.cols; i++)
- result.data[i] = psi_mul_complex(m.data[i], scalar);
+ struct PsiMatrix result = psi_new_matrix(m.rows, m.cols);
+ for (size_t i = 0; i < m.rows * m.cols; i++)
+ result.data[i] = psi_mul_complex(m.data[i], scalar);
- return result;
+ return result;
}
struct PsiMatrix psi_matrix_from_vector(struct PsiVector v)
{
- if (v.kind == PSI_ROW_VECTOR)
- return psi_new_matrix_from(v.data, 1, v.size);
+ if (v.kind == PSI_ROW_VECTOR)
+ return psi_new_matrix_from(v.data, 1, v.size);
- return psi_new_matrix_from(v.data, v.size, 1);
+ return psi_new_matrix_from(v.data, v.size, 1);
}
struct PsiVector psi_vector_from_matrix(struct PsiMatrix m, enum PsiVectorKind kind)
{
- return psi_new_vector_from(m.data, m.rows * m.cols, kind);
+ return psi_new_vector_from(m.data, m.rows * m.cols, kind);
}
struct PsiVector psi_mul_vector_matrix(struct PsiVector v, struct PsiMatrix m)
{
- if (v.kind == PSI_COLUMN_VECTOR)
- {
- assert(m.cols == v.size);
+ if (v.kind == PSI_COLUMN_VECTOR)
+ {
+ assert(m.cols == v.size);
- struct PsiVector result = psi_new_vector(m.rows, PSI_COLUMN_VECTOR);
- for (size_t i = 0; i < m.rows; i++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t j = 0; j < m.cols; j++)
- sum = psi_add_complex(sum, psi_mul_complex(m.data[i * m.cols + j], v.data[j]));
+ struct PsiVector result = psi_new_vector(m.rows, PSI_COLUMN_VECTOR);
+ for (size_t i = 0; i < m.rows; i++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t j = 0; j < m.cols; j++)
+ sum = psi_add_complex(sum, psi_mul_complex(m.data[i * m.cols + j], v.data[j]));
- result.data[i] = sum;
- }
+ result.data[i] = sum;
+ }
- return result;
- }
+ return result;
+ }
- assert(v.size == m.rows);
+ assert(v.size == m.rows);
- struct PsiVector result = psi_new_vector(m.cols, PSI_ROW_VECTOR);
- for (size_t j = 0; j < m.cols; j++)
- {
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < m.rows; i++)
- sum = psi_add_complex(sum, psi_mul_complex(v.data[i], m.data[i * m.cols + j]));
+ struct PsiVector result = psi_new_vector(m.cols, PSI_ROW_VECTOR);
+ for (size_t j = 0; j < m.cols; j++)
+ {
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < m.rows; i++)
+ sum = psi_add_complex(sum, psi_mul_complex(v.data[i], m.data[i * m.cols + j]));
- result.data[j] = sum;
- }
+ result.data[j] = sum;
+ }
- return result;
+ return result;
}
diff --git a/src/maths/matrix.rs b/src/maths/matrix.rs
deleted file mode 100644
index c9d96a4..0000000
--- a/src/maths/matrix.rs
+++ /dev/null
@@ -1,310 +0,0 @@
-use super::Float;
-use core::{fmt, ops};
-
-#[macro_export]
-macro_rules! matrix {
- ( $( $( $x:expr ),* );* ) => {{
- let mut data = Vec::new();
- let mut rows = 0;
- let mut cols = 0;
-
- $(
- let row_data = $( $x )*;
- if cols == 0 {
- cols = row_data.len();
- }
- assert_eq!(cols, row_data.len(), "All rows must have the same number of columns.");
- data.extend(row_data);
- rows += 1;
- )*
-
- $crate::Matrix::new(rows, cols, data)
- }};
-}
-
-macro_rules! impl_matrix_ops {
- ($($trait:ident, $method:ident, $other:ty, $output:ty, $scale_fn:ident),* $(,)?) => {
- $(
- impl<T: Float> core::ops::$trait<$other> for Matrix<T> {
- type Output = $output;
-
- fn $method(self, other: $other) -> Self::Output {
- self.$scale_fn(other)
- }
- }
- )*
- };
- ($($trait:ident, $method:ident, $other:ty, $scale_fn:ident),* $(,)?) => {
- $(
- impl<T: Float> core::ops::$trait<$other> for Matrix<T> {
- fn $method(&mut self, other: $other) {
- *self = self.$scale_fn(other);
- }
- }
- )*
- };
-}
-
-#[derive(Clone)]
-pub struct Matrix<T: Float> {
- pub data: Vec<T>,
- pub rows: usize,
- pub cols: usize,
-}
-
-impl<T: Float> Matrix<T> {
- pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Self {
- Matrix { data, rows, cols }
- }
-
- pub fn get(&self, row: usize, col: usize) -> T {
- self.data[row * self.cols + col]
- }
-
- pub fn set(&mut self, row: usize, col: usize, value: T) {
- self.data[row * self.cols + col] = value;
- }
-
- pub fn dot(&self, other: &Self) -> Option<Matrix<T>> {
- if self.cols != other.rows {
- return None;
- }
-
- let mut result = Matrix::new(
- self.rows,
- other.cols,
- vec![T::zero(); self.rows * other.cols],
- );
- for i in 0..self.rows {
- for j in 0..other.cols {
- let mut sum = T::zero();
- for k in 0..self.cols {
- sum += self.get(i, k) * other.get(k, j) ;
- }
- result.set(i, j, sum);
- }
- }
- Some(result)
- }
-
- pub fn kronecker(&self, other: &Self) -> Matrix<T> {
- let new_rows = self.rows * other.rows;
- let new_cols = self.cols * other.cols;
-
- let mut result = Matrix::new(new_rows, new_cols, vec![T::zero(); new_rows * new_cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let self_val = self.get(i, j);
- for k in 0..other.rows {
- for l in 0..other.cols {
- let result_row = i * other.rows + k;
- let result_col = j * other.cols + l;
- result.set(result_row, result_col, self_val * other.get(k, l));
- }
- }
- }
- }
-
- result
- }
-
- pub fn transpose(&self) -> Matrix<T> {
- let mut result = Matrix::new(self.cols, self.rows, vec![T::zero(); self.cols * self.rows]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let value = self.get(i, j);
- result.set(j, i, value);
- }
- }
-
- result
- }
-
- pub fn add_to(&self, other: &Self) -> Option<Matrix<T>> {
- if self.rows != other.rows || self.cols != other.cols {
- return None;
- }
-
- let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let sum = self.get(i, j) + other.get(i, j);
- result.set(i, j, sum);
- }
- }
- Some(result)
- }
-
- pub fn subtract(&self, other: &Self) -> Option<Matrix<T>> {
- if self.rows != other.rows || self.cols != other.cols {
- return None;
- }
-
- let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let diff = self.get(i, j) - other.get(i, j);
- result.set(i, j, diff);
- }
- }
- Some(result)
- }
-
- pub fn scale(&self, scalar: T) -> Matrix<T> {
- let mut result = Matrix::new(self.rows, self.cols, vec![T::zero(); self.rows * self.cols]);
-
- for i in 0..self.rows {
- for j in 0..self.cols {
- let scaled_value = self.get(i, j) * scalar;
- result.set(i, j, scaled_value);
- }
- }
- result
- }
-}
-
-impl<T: Float> ops::Index<(usize, usize)> for Matrix<T> {
- type Output = T;
-
- fn index(&self, index: (usize, usize)) -> &Self::Output {
- &self.data[index.0 * self.cols + index.1]
- }
-}
-
-impl<T: Float> ops::IndexMut<(usize, usize)> for Matrix<T> {
- fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
- &mut self.data[index.0 * self.cols + index.1]
- }
-}
-
-impl<T: Float> ops::AddAssign<&Matrix<T>> for Matrix<T> {
- fn add_assign(&mut self, other: &Matrix<T>) {
- if let Some(result) = self.add_to(other) {
- *self = result;
- }
- }
-}
-
-impl<T: Float> ops::SubAssign<&Matrix<T>> for Matrix<T> {
- fn sub_assign(&mut self, other: &Matrix<T>) {
- if let Some(result) = self.subtract(other) {
- *self = result;
- }
- }
-}
-
-impl_matrix_ops! {
- Add, add, &Matrix<T>, Option<Matrix<T>>, add_to,
- Sub, sub, &Matrix<T>, Option<Matrix<T>>, subtract,
- Mul, mul, T, Matrix<T>, scale,
- Div, div, T, Matrix<T>, scale,
-}
-
-impl_matrix_ops! {
- MulAssign, mul_assign, T, scale,
- DivAssign, div_assign, T, scale,
-}
-
-impl<T: Float + fmt::Debug> fmt::Debug for Matrix<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for i in 0..self.rows {
- for j in 0..self.cols {
- write!(f, "{:?} ", self.get(i, j))?;
- }
- writeln!(f)?;
- }
- Ok(())
- }
-}
-
-impl<T: Float + fmt::Display> fmt::Display for Matrix<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let elements: Vec<String> = self.data.iter().map(ToString::to_string).collect();
- let is_complex = elements.iter().any(|element| element.contains("i"));
-
- let normalized: Vec<(f64, f64)> = self
- .data
- .iter()
- .map(|element| {
- let element_string = element.to_string();
-
- if is_complex {
- let element_string = element_string.trim_end_matches('i').trim();
- let element_split: Vec<&str> = element_string.split_whitespace().collect();
- let real = element_split[0].parse::<f64>().unwrap();
- let imaginary = element_split
- .get(2)
- .map_or(0.0, |&s| s.parse::<f64>().unwrap());
- (real, imaginary)
- } else {
- (element_string.parse::<f64>().unwrap(), 0.0)
- }
- })
- .collect();
-
- let max_widths = normalized
- .iter()
- .fold((0, 0), |(max_0, max_1), &(real, imag)| {
- let new_max_0 = max_0.max(format!("{:.2}", real).len());
- let new_max_1 = if is_complex {
- max_1.max(format!("{:.2}", imag.abs()).len())
- } else {
- max_1
- };
- (new_max_0, new_max_1)
- });
-
- let aligned: Vec<String> = normalized
- .iter()
- .map(|&(real, imag)| {
- if is_complex {
- format!(
- "{:>rewidth$.2} {} {:>imwidth$.2}i",
- real,
- if imag > 0.0 { "+" } else { "-" },
- imag.abs(),
- rewidth = max_widths.0,
- imwidth = max_widths.1,
- )
- } else {
- format!("{:>width$.2}", real, width = max_widths.0)
- }
- })
- .collect();
-
- for i in 0..self.rows {
- if i == 0 {
- write!(f, "┌")?;
- } else if i == self.rows - 1 {
- write!(f, "└")?;
- } else {
- write!(f, "│")?;
- }
-
- for j in 0..self.cols {
- write!(f, "{}", aligned[i + j * self.rows])?;
- if j != self.cols - 1 {
- write!(f, ", ")?;
- }
- }
-
- if i == 0 {
- write!(f, "┐")?;
- } else if i == self.rows - 1 {
- write!(f, "┘")?;
- } else {
- write!(f, "│")?;
- }
-
- if i != self.rows - 1 {
- writeln!(f)?;
- }
- }
-
- Ok(())
- }
-}
diff --git a/src/maths/simd.c b/src/maths/simd.c
index 9e83dcc..fc25de8 100644
--- a/src/maths/simd.c
+++ b/src/maths/simd.c
@@ -12,144 +12,144 @@
enum PsiSimdCapability psi_detect_simd(void)
{
#if defined(__x86_64__) || defined(__i386__)
- if (__builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq"))
- return PSI_SIMD_AVX512;
- if (__builtin_cpu_supports("avx2") && __builtin_cpu_supports("fma"))
- return PSI_SIMD_AVX2;
+ if (__builtin_cpu_supports("avx512f") && __builtin_cpu_supports("avx512dq"))
+ return PSI_SIMD_AVX512;
+ if (__builtin_cpu_supports("avx2") && __builtin_cpu_supports("fma"))
+ return PSI_SIMD_AVX2;
- return PSI_SIMD_NONE;
+ return PSI_SIMD_NONE;
#elif defined(__aarch64__)
- return PSI_SIMD_NEON;
+ return PSI_SIMD_NEON;
#else
- return PSI_SIMD_NONE;
+ return PSI_SIMD_NONE;
#endif
}
const char* psi_simd_name(enum PsiSimdCapability cap)
{
- switch (cap)
- {
- case PSI_SIMD_NONE: return "Scalar";
- case PSI_SIMD_AVX2: return "AVX2+FMA";
- case PSI_SIMD_AVX512: return "AVX-512";
- case PSI_SIMD_NEON: return "NEON";
- }
+ switch (cap)
+ {
+ case PSI_SIMD_NONE: return "Scalar";
+ case PSI_SIMD_AVX2: return "AVX2+FMA";
+ case PSI_SIMD_AVX512: return "AVX-512";
+ case PSI_SIMD_NEON: return "NEON";
+ }
- return "Scalar";
+ return "Scalar";
}
static void apply_pair(struct PsiComplex* state, size_t i, size_t j, struct PsiComplex g00,
struct PsiComplex g01, struct PsiComplex g10, struct PsiComplex g11)
{
- struct PsiComplex s0 = state[i];
- struct PsiComplex s1 = state[j];
+ struct PsiComplex s0 = state[i];
+ struct PsiComplex s1 = state[j];
- state[i] = psi_new_complex(s0.real * g00.real - s0.imaginary * g00.imaginary +
- s1.real * g01.real - s1.imaginary * g01.imaginary,
- s0.real * g00.imaginary + s0.imaginary * g00.real +
- s1.real * g01.imaginary + s1.imaginary * g01.real);
- state[j] = psi_new_complex(s0.real * g10.real - s0.imaginary * g10.imaginary +
- s1.real * g11.real - s1.imaginary * g11.imaginary,
- s0.real * g10.imaginary + s0.imaginary * g10.real +
- s1.real * g11.imaginary + s1.imaginary * g11.real);
+ state[i] = psi_new_complex(s0.real * g00.real - s0.imaginary * g00.imaginary +
+ s1.real * g01.real - s1.imaginary * g01.imaginary,
+ s0.real * g00.imaginary + s0.imaginary * g00.real +
+ s1.real * g01.imaginary + s1.imaginary * g01.real);
+ state[j] = psi_new_complex(s0.real * g10.real - s0.imaginary * g10.imaginary +
+ s1.real * g11.real - s1.imaginary * g11.imaginary,
+ s0.real * g10.imaginary + s0.imaginary * g10.real +
+ s1.real * g11.imaginary + s1.imaginary * g11.real);
}
static void apply_scalar(struct PsiComplex* state, const struct PsiComplex gate[2][2],
size_t target, size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- for (size_t i = 0; i < dim; i++)
- {
- if ((i >> target_bit) & 1)
- continue;
+ for (size_t i = 0; i < dim; i++)
+ {
+ if ((i >> target_bit) & 1)
+ continue;
- apply_pair(state, i, i | step, gate[0][0], gate[0][1], gate[1][0], gate[1][1]);
- }
+ apply_pair(state, i, i | step, gate[0][0], gate[0][1], gate[1][0], gate[1][1]);
+ }
}
static size_t (*build_pairs(size_t dim, size_t target_bit, size_t step, size_t* out_count))[2]
{
- size_t (*pairs)[2] = malloc((dim / 2) * sizeof(*pairs));
- assert(pairs != NULL || dim == 0);
+ size_t (*pairs)[2] = malloc((dim / 2) * sizeof(*pairs));
+ assert(pairs != NULL || dim == 0);
- size_t n = 0;
- for (size_t i = 0; i < dim; i++)
- if (((i >> target_bit) & 1) == 0)
- {
- pairs[n][0] = i;
- pairs[n][1] = i | step;
- n++;
- }
+ size_t n = 0;
+ for (size_t i = 0; i < dim; i++)
+ if (((i >> target_bit) & 1) == 0)
+ {
+ pairs[n][0] = i;
+ pairs[n][1] = i | step;
+ n++;
+ }
- *out_count = n;
- return pairs;
+ *out_count = n;
+ return pairs;
}
#if defined(__aarch64__)
static void apply_neon(struct PsiComplex* state, const struct PsiComplex gate[2][2], size_t target,
size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex g00 = gate[0][0];
- struct PsiComplex g01 = gate[0][1];
- struct PsiComplex g10 = gate[1][0];
- struct PsiComplex g11 = gate[1][1];
+ struct PsiComplex g00 = gate[0][0];
+ struct PsiComplex g01 = gate[0][1];
+ struct PsiComplex g10 = gate[1][0];
+ struct PsiComplex g11 = gate[1][1];
- size_t np;
- size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
- size_t chunks = np / 2;
+ size_t np;
+ size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
+ size_t chunks = np / 2;
- float64x2_t g00_re = vdupq_n_f64(g00.real);
- float64x2_t g00_im = vdupq_n_f64(g00.imaginary);
- float64x2_t g01_re = vdupq_n_f64(g01.real);
- float64x2_t g01_im = vdupq_n_f64(g01.imaginary);
- float64x2_t g10_re = vdupq_n_f64(g10.real);
- float64x2_t g10_im = vdupq_n_f64(g10.imaginary);
- float64x2_t g11_re = vdupq_n_f64(g11.real);
- float64x2_t g11_im = vdupq_n_f64(g11.imaginary);
+ float64x2_t g00_re = vdupq_n_f64(g00.real);
+ float64x2_t g00_im = vdupq_n_f64(g00.imaginary);
+ float64x2_t g01_re = vdupq_n_f64(g01.real);
+ float64x2_t g01_im = vdupq_n_f64(g01.imaginary);
+ float64x2_t g10_re = vdupq_n_f64(g10.real);
+ float64x2_t g10_im = vdupq_n_f64(g10.imaginary);
+ float64x2_t g11_re = vdupq_n_f64(g11.real);
+ float64x2_t g11_im = vdupq_n_f64(g11.imaginary);
- for (size_t chunk = 0; chunk < chunks; chunk++)
- {
- size_t i0 = pairs[chunk * 2][0];
- size_t j0 = pairs[chunk * 2][1];
- size_t i1 = pairs[chunk * 2 + 1][0];
- size_t j1 = pairs[chunk * 2 + 1][1];
+ for (size_t chunk = 0; chunk < chunks; chunk++)
+ {
+ size_t i0 = pairs[chunk * 2][0];
+ size_t j0 = pairs[chunk * 2][1];
+ size_t i1 = pairs[chunk * 2 + 1][0];
+ size_t j1 = pairs[chunk * 2 + 1][1];
- double s0r[2] = { state[i0].real, state[i1].real };
- double s0i[2] = { state[i0].imaginary, state[i1].imaginary };
- double s1r[2] = { state[j0].real, state[j1].real };
- double s1i[2] = { state[j0].imaginary, state[j1].imaginary };
+ double s0r[2] = { state[i0].real, state[i1].real };
+ double s0i[2] = { state[i0].imaginary, state[i1].imaginary };
+ double s1r[2] = { state[j0].real, state[j1].real };
+ double s1i[2] = { state[j0].imaginary, state[j1].imaginary };
- float64x2_t s0_re = vld1q_f64(s0r);
- float64x2_t s0_im = vld1q_f64(s0i);
- float64x2_t s1_re = vld1q_f64(s1r);
- float64x2_t s1_im = vld1q_f64(s1i);
+ float64x2_t s0_re = vld1q_f64(s0r);
+ float64x2_t s0_im = vld1q_f64(s0i);
+ float64x2_t s1_re = vld1q_f64(s1r);
+ float64x2_t s1_im = vld1q_f64(s1i);
- float64x2_t new0_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g00_re), s0_im, g00_im),
- vfmsq_f64(vmulq_f64(s1_re, g01_re), s1_im, g01_im));
- float64x2_t new0_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g00_im), s0_im, g00_re),
- vfmaq_f64(vmulq_f64(s1_re, g01_im), s1_im, g01_re));
- float64x2_t new1_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g10_re), s0_im, g10_im),
- vfmsq_f64(vmulq_f64(s1_re, g11_re), s1_im, g11_im));
- float64x2_t new1_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g10_im), s0_im, g10_re),
- vfmaq_f64(vmulq_f64(s1_re, g11_im), s1_im, g11_re));
+ float64x2_t new0_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g00_re), s0_im, g00_im),
+ vfmsq_f64(vmulq_f64(s1_re, g01_re), s1_im, g01_im));
+ float64x2_t new0_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g00_im), s0_im, g00_re),
+ vfmaq_f64(vmulq_f64(s1_re, g01_im), s1_im, g01_re));
+ float64x2_t new1_re = vaddq_f64(vfmsq_f64(vmulq_f64(s0_re, g10_re), s0_im, g10_im),
+ vfmsq_f64(vmulq_f64(s1_re, g11_re), s1_im, g11_im));
+ float64x2_t new1_im = vaddq_f64(vfmaq_f64(vmulq_f64(s0_re, g10_im), s0_im, g10_re),
+ vfmaq_f64(vmulq_f64(s1_re, g11_im), s1_im, g11_re));
- state[i0] = psi_new_complex(vgetq_lane_f64(new0_re, 0), vgetq_lane_f64(new0_im, 0));
- state[j0] = psi_new_complex(vgetq_lane_f64(new1_re, 0), vgetq_lane_f64(new1_im, 0));
- state[i1] = psi_new_complex(vgetq_lane_f64(new0_re, 1), vgetq_lane_f64(new0_im, 1));
- state[j1] = psi_new_complex(vgetq_lane_f64(new1_re, 1), vgetq_lane_f64(new1_im, 1));
- }
+ state[i0] = psi_new_complex(vgetq_lane_f64(new0_re, 0), vgetq_lane_f64(new0_im, 0));
+ state[j0] = psi_new_complex(vgetq_lane_f64(new1_re, 0), vgetq_lane_f64(new1_im, 0));
+ state[i1] = psi_new_complex(vgetq_lane_f64(new0_re, 1), vgetq_lane_f64(new0_im, 1));
+ state[j1] = psi_new_complex(vgetq_lane_f64(new1_re, 1), vgetq_lane_f64(new1_im, 1));
+ }
- for (size_t p = chunks * 2; p < np; p++)
- apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
+ for (size_t p = chunks * 2; p < np; p++)
+ apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
- free(pairs);
+ free(pairs);
}
#endif
@@ -158,167 +158,167 @@ __attribute__((target("avx2,fma"))) static void apply_avx2(struct PsiComplex* st
const struct PsiComplex gate[2][2],
size_t target, size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex g00 = gate[0][0];
- struct PsiComplex g01 = gate[0][1];
- struct PsiComplex g10 = gate[1][0];
- struct PsiComplex g11 = gate[1][1];
+ struct PsiComplex g00 = gate[0][0];
+ struct PsiComplex g01 = gate[0][1];
+ struct PsiComplex g10 = gate[1][0];
+ struct PsiComplex g11 = gate[1][1];
- size_t np;
- size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
- size_t chunks = np / 2;
+ size_t np;
+ size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
+ size_t chunks = np / 2;
- for (size_t chunk = 0; chunk < chunks; chunk++)
- {
- size_t i0 = pairs[chunk * 2][0];
- size_t j0 = pairs[chunk * 2][1];
- size_t i1 = pairs[chunk * 2 + 1][0];
- size_t j1 = pairs[chunk * 2 + 1][1];
+ for (size_t chunk = 0; chunk < chunks; chunk++)
+ {
+ size_t i0 = pairs[chunk * 2][0];
+ size_t j0 = pairs[chunk * 2][1];
+ size_t i1 = pairs[chunk * 2 + 1][0];
+ size_t j1 = pairs[chunk * 2 + 1][1];
- __m256d s0_re =
- _mm256_set_pd(state[j1].real, state[i1].real, state[j0].real, state[i0].real);
- __m256d s0_im = _mm256_set_pd(state[j1].imaginary, state[i1].imaginary, state[j0].imaginary,
- state[i0].imaginary);
+ __m256d s0_re =
+ _mm256_set_pd(state[j1].real, state[i1].real, state[j0].real, state[i0].real);
+ __m256d s0_im = _mm256_set_pd(state[j1].imaginary, state[i1].imaginary, state[j0].imaginary,
+ state[i0].imaginary);
- __m256d g_re_0 = _mm256_set_pd(g01.real, g00.real, g01.real, g00.real);
- __m256d g_im_0 = _mm256_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
- __m256d g_re_1 = _mm256_set_pd(g11.real, g10.real, g11.real, g10.real);
- __m256d g_im_1 = _mm256_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
+ __m256d g_re_0 = _mm256_set_pd(g01.real, g00.real, g01.real, g00.real);
+ __m256d g_im_0 = _mm256_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
+ __m256d g_re_1 = _mm256_set_pd(g11.real, g10.real, g11.real, g10.real);
+ __m256d g_im_1 = _mm256_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
- __m256d prod0_re = _mm256_fmsub_pd(s0_re, g_re_0, _mm256_mul_pd(s0_im, g_im_0));
- __m256d prod0_im = _mm256_fmadd_pd(s0_re, g_im_0, _mm256_mul_pd(s0_im, g_re_0));
- __m256d prod1_re = _mm256_fmsub_pd(s0_re, g_re_1, _mm256_mul_pd(s0_im, g_im_1));
- __m256d prod1_im = _mm256_fmadd_pd(s0_re, g_im_1, _mm256_mul_pd(s0_im, g_re_1));
+ __m256d prod0_re = _mm256_fmsub_pd(s0_re, g_re_0, _mm256_mul_pd(s0_im, g_im_0));
+ __m256d prod0_im = _mm256_fmadd_pd(s0_re, g_im_0, _mm256_mul_pd(s0_im, g_re_0));
+ __m256d prod1_re = _mm256_fmsub_pd(s0_re, g_re_1, _mm256_mul_pd(s0_im, g_im_1));
+ __m256d prod1_im = _mm256_fmadd_pd(s0_re, g_im_1, _mm256_mul_pd(s0_im, g_re_1));
- double res0_re[4];
- double res0_im[4];
- double res1_re[4];
- double res1_im[4];
+ double res0_re[4];
+ double res0_im[4];
+ double res1_re[4];
+ double res1_im[4];
- _mm256_storeu_pd(res0_re, prod0_re);
- _mm256_storeu_pd(res0_im, prod0_im);
- _mm256_storeu_pd(res1_re, prod1_re);
- _mm256_storeu_pd(res1_im, prod1_im);
+ _mm256_storeu_pd(res0_re, prod0_re);
+ _mm256_storeu_pd(res0_im, prod0_im);
+ _mm256_storeu_pd(res1_re, prod1_re);
+ _mm256_storeu_pd(res1_im, prod1_im);
- state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
- state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
- state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
- state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
- }
+ state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
+ state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
+ state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
+ state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
+ }
- for (size_t p = chunks * 2; p < np; p++)
- apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
+ for (size_t p = chunks * 2; p < np; p++)
+ apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
- free(pairs);
+ free(pairs);
}
__attribute__((target("avx512f,avx512dq"))) static void
apply_avx512(struct PsiComplex* state, const struct PsiComplex gate[2][2], size_t target,
size_t num_qubits)
{
- size_t target_bit = num_qubits - 1 - target;
- size_t step = (size_t)1 << target_bit;
- size_t dim = (size_t)1 << num_qubits;
+ size_t target_bit = num_qubits - 1 - target;
+ size_t step = (size_t)1 << target_bit;
+ size_t dim = (size_t)1 << num_qubits;
- struct PsiComplex g00 = gate[0][0];
- struct PsiComplex g01 = gate[0][1];
- struct PsiComplex g10 = gate[1][0];
- struct PsiComplex g11 = gate[1][1];
+ struct PsiComplex g00 = gate[0][0];
+ struct PsiComplex g01 = gate[0][1];
+ struct PsiComplex g10 = gate[1][0];
+ struct PsiComplex g11 = gate[1][1];
- size_t np;
- size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
- size_t chunks = np / 4;
+ size_t np;
+ size_t (*pairs)[2] = build_pairs(dim, target_bit, step, &np);
+ size_t chunks = np / 4;
- for (size_t chunk = 0; chunk < chunks; chunk++)
- {
- size_t base = chunk * 4;
- size_t i0 = pairs[base][0], j0 = pairs[base][1];
- size_t i1 = pairs[base + 1][0], j1 = pairs[base + 1][1];
- size_t i2 = pairs[base + 2][0], j2 = pairs[base + 2][1];
- size_t i3 = pairs[base + 3][0], j3 = pairs[base + 3][1];
+ for (size_t chunk = 0; chunk < chunks; chunk++)
+ {
+ size_t base = chunk * 4;
+ size_t i0 = pairs[base][0], j0 = pairs[base][1];
+ size_t i1 = pairs[base + 1][0], j1 = pairs[base + 1][1];
+ size_t i2 = pairs[base + 2][0], j2 = pairs[base + 2][1];
+ size_t i3 = pairs[base + 3][0], j3 = pairs[base + 3][1];
- __m512d s0_re =
- _mm512_set_pd(state[j3].real, state[i3].real, state[j2].real, state[i2].real,
- state[j1].real, state[i1].real, state[j0].real, state[i0].real);
- __m512d s0_im = _mm512_set_pd(state[j3].imaginary, state[i3].imaginary, state[j2].imaginary,
- state[i2].imaginary, state[j1].imaginary, state[i1].imaginary,
- state[j0].imaginary, state[i0].imaginary);
+ __m512d s0_re =
+ _mm512_set_pd(state[j3].real, state[i3].real, state[j2].real, state[i2].real,
+ state[j1].real, state[i1].real, state[j0].real, state[i0].real);
+ __m512d s0_im = _mm512_set_pd(state[j3].imaginary, state[i3].imaginary, state[j2].imaginary,
+ state[i2].imaginary, state[j1].imaginary, state[i1].imaginary,
+ state[j0].imaginary, state[i0].imaginary);
- __m512d g_re_0 = _mm512_set_pd(g01.real, g00.real, g01.real, g00.real, g01.real, g00.real,
- g01.real, g00.real);
- __m512d g_im_0 = _mm512_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary,
- g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
- __m512d g_re_1 = _mm512_set_pd(g11.real, g10.real, g11.real, g10.real, g11.real, g10.real,
- g11.real, g10.real);
- __m512d g_im_1 = _mm512_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary,
- g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
+ __m512d g_re_0 = _mm512_set_pd(g01.real, g00.real, g01.real, g00.real, g01.real, g00.real,
+ g01.real, g00.real);
+ __m512d g_im_0 = _mm512_set_pd(g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary,
+ g01.imaginary, g00.imaginary, g01.imaginary, g00.imaginary);
+ __m512d g_re_1 = _mm512_set_pd(g11.real, g10.real, g11.real, g10.real, g11.real, g10.real,
+ g11.real, g10.real);
+ __m512d g_im_1 = _mm512_set_pd(g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary,
+ g11.imaginary, g10.imaginary, g11.imaginary, g10.imaginary);
- __m512d prod0_re = _mm512_fmsub_pd(s0_re, g_re_0, _mm512_mul_pd(s0_im, g_im_0));
- __m512d prod0_im = _mm512_fmadd_pd(s0_re, g_im_0, _mm512_mul_pd(s0_im, g_re_0));
- __m512d prod1_re = _mm512_fmsub_pd(s0_re, g_re_1, _mm512_mul_pd(s0_im, g_im_1));
- __m512d prod1_im = _mm512_fmadd_pd(s0_re, g_im_1, _mm512_mul_pd(s0_im, g_re_1));
+ __m512d prod0_re = _mm512_fmsub_pd(s0_re, g_re_0, _mm512_mul_pd(s0_im, g_im_0));
+ __m512d prod0_im = _mm512_fmadd_pd(s0_re, g_im_0, _mm512_mul_pd(s0_im, g_re_0));
+ __m512d prod1_re = _mm512_fmsub_pd(s0_re, g_re_1, _mm512_mul_pd(s0_im, g_im_1));
+ __m512d prod1_im = _mm512_fmadd_pd(s0_re, g_im_1, _mm512_mul_pd(s0_im, g_re_1));
- double res0_re[8];
- double res0_im[8];
- double res1_re[8];
- double res1_im[8];
+ double res0_re[8];
+ double res0_im[8];
+ double res1_re[8];
+ double res1_im[8];
- _mm512_storeu_pd(res0_re, prod0_re);
- _mm512_storeu_pd(res0_im, prod0_im);
- _mm512_storeu_pd(res1_re, prod1_re);
- _mm512_storeu_pd(res1_im, prod1_im);
+ _mm512_storeu_pd(res0_re, prod0_re);
+ _mm512_storeu_pd(res0_im, prod0_im);
+ _mm512_storeu_pd(res1_re, prod1_re);
+ _mm512_storeu_pd(res1_im, prod1_im);
- state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
- state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
- state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
- state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
- state[i2] = psi_new_complex(res0_re[4] + res0_re[5], res0_im[4] + res0_im[5]);
- state[j2] = psi_new_complex(res1_re[4] + res1_re[5], res1_im[4] + res1_im[5]);
- state[i3] = psi_new_complex(res0_re[6] + res0_re[7], res0_im[6] + res0_im[7]);
- state[j3] = psi_new_complex(res1_re[6] + res1_re[7], res1_im[6] + res1_im[7]);
- }
+ state[i0] = psi_new_complex(res0_re[0] + res0_re[1], res0_im[0] + res0_im[1]);
+ state[j0] = psi_new_complex(res1_re[0] + res1_re[1], res1_im[0] + res1_im[1]);
+ state[i1] = psi_new_complex(res0_re[2] + res0_re[3], res0_im[2] + res0_im[3]);
+ state[j1] = psi_new_complex(res1_re[2] + res1_re[3], res1_im[2] + res1_im[3]);
+ state[i2] = psi_new_complex(res0_re[4] + res0_re[5], res0_im[4] + res0_im[5]);
+ state[j2] = psi_new_complex(res1_re[4] + res1_re[5], res1_im[4] + res1_im[5]);
+ state[i3] = psi_new_complex(res0_re[6] + res0_re[7], res0_im[6] + res0_im[7]);
+ state[j3] = psi_new_complex(res1_re[6] + res1_re[7], res1_im[6] + res1_im[7]);
+ }
- for (size_t p = chunks * 4; p < np; p++)
- apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
+ for (size_t p = chunks * 4; p < np; p++)
+ apply_pair(state, pairs[p][0], pairs[p][1], g00, g01, g10, g11);
- free(pairs);
+ free(pairs);
}
#endif
void psi_apply_single_qubit_gate_simd(struct PsiComplex* state, const struct PsiComplex gate[2][2],
size_t target, size_t num_qubits)
{
- enum PsiSimdCapability cap = psi_detect_simd();
+ enum PsiSimdCapability cap = psi_detect_simd();
#if defined(__x86_64__) || defined(__i386__)
- if (cap == PSI_SIMD_AVX512)
- {
- apply_avx512(state, gate, target, num_qubits);
- return;
- }
- if (cap == PSI_SIMD_AVX2)
- {
- apply_avx2(state, gate, target, num_qubits);
- return;
- }
+ if (cap == PSI_SIMD_AVX512)
+ {
+ apply_avx512(state, gate, target, num_qubits);
+ return;
+ }
+ if (cap == PSI_SIMD_AVX2)
+ {
+ apply_avx2(state, gate, target, num_qubits);
+ return;
+ }
#elif defined(__aarch64__)
- if (cap == PSI_SIMD_NEON)
- {
- apply_neon(state, gate, target, num_qubits);
- return;
- }
+ if (cap == PSI_SIMD_NEON)
+ {
+ apply_neon(state, gate, target, num_qubits);
+ return;
+ }
#endif
- (void)cap;
- apply_scalar(state, gate, target, num_qubits);
+ (void)cap;
+ apply_scalar(state, gate, target, num_qubits);
}
void psi_apply_single_qubit_gate_simd_parallel(struct PsiComplex* state,
const struct PsiComplex gate[2][2], size_t target,
size_t num_qubits)
{
- apply_scalar(state, gate, target, num_qubits);
+ apply_scalar(state, gate, target, num_qubits);
}
diff --git a/src/maths/vector.c b/src/maths/vector.c
index 1c5c4f9..5cd49e0 100644
--- a/src/maths/vector.c
+++ b/src/maths/vector.c
@@ -6,155 +6,155 @@
static enum PsiVectorKind flip_kind(enum PsiVectorKind kind)
{
- if (kind == PSI_ROW_VECTOR)
- return PSI_COLUMN_VECTOR;
+ if (kind == PSI_ROW_VECTOR)
+ return PSI_COLUMN_VECTOR;
- return PSI_ROW_VECTOR;
+ return PSI_ROW_VECTOR;
}
struct PsiVector psi_new_vector(size_t size, enum PsiVectorKind kind)
{
- struct PsiComplex* data = calloc(size, sizeof(struct PsiComplex));
- assert(data != NULL || size == 0);
+ struct PsiComplex* data = calloc(size, sizeof(struct PsiComplex));
+ assert(data != NULL || size == 0);
- return (struct PsiVector){
- data,
- size,
- kind,
- };
+ return (struct PsiVector){
+ data,
+ size,
+ kind,
+ };
}
struct PsiVector psi_new_vector_from(const struct PsiComplex* data, size_t size,
enum PsiVectorKind kind)
{
- struct PsiVector v = psi_new_vector(size, kind);
- memcpy(v.data, data, size * sizeof(struct PsiComplex));
+ struct PsiVector v = psi_new_vector(size, kind);
+ memcpy(v.data, data, size * sizeof(struct PsiComplex));
- return v;
+ return v;
}
struct PsiVector psi_clone_vector(struct PsiVector v)
{
- return psi_new_vector_from(v.data, v.size, v.kind);
+ return psi_new_vector_from(v.data, v.size, v.kind);
}
void psi_free_vector(struct PsiVector* v)
{
- free(v->data);
- v->data = NULL;
- v->size = 0;
+ free(v->data);
+ v->data = NULL;
+ v->size = 0;
}
struct PsiComplex psi_get_vector(struct PsiVector v, size_t index)
{
- assert(index < v.size);
- return v.data[index];
+ assert(index < v.size);
+ return v.data[index];
}
void psi_set_vector(struct PsiVector* v, size_t index, struct PsiComplex value)
{
- assert(index < v->size);
- v->data[index] = value;
+ assert(index < v->size);
+ v->data[index] = value;
}
struct PsiComplex psi_dot_vector(struct PsiVector a, struct PsiVector b)
{
- assert(a.size == b.size);
+ assert(a.size == b.size);
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < a.size; i++)
- sum = psi_add_complex(sum, psi_mul_complex(a.data[i], b.data[i]));
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < a.size; i++)
+ sum = psi_add_complex(sum, psi_mul_complex(a.data[i], b.data[i]));
- return sum;
+ return sum;
}
struct PsiComplex psi_norm_vector(struct PsiVector v)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < v.size; i++)
- sum = psi_add_complex(sum, psi_mul_complex(v.data[i], v.data[i]));
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < v.size; i++)
+ sum = psi_add_complex(sum, psi_mul_complex(v.data[i], v.data[i]));
- return psi_sqrt_complex(sum);
+ return psi_sqrt_complex(sum);
}
struct PsiComplex psi_sum_vector(struct PsiVector v)
{
- struct PsiComplex sum = psi_new_complex(0.0, 0.0);
- for (size_t i = 0; i < v.size; i++)
- sum = psi_add_complex(sum, v.data[i]);
+ struct PsiComplex sum = psi_new_complex(0.0, 0.0);
+ for (size_t i = 0; i < v.size; i++)
+ sum = psi_add_complex(sum, v.data[i]);
- return sum;
+ return sum;
}
static int less_than(struct PsiComplex a, struct PsiComplex b)
{
- if (a.real != b.real)
- return a.real < b.real;
+ if (a.real != b.real)
+ return a.real < b.real;
- return a.imaginary < b.imaginary;
+ return a.imaginary < b.imaginary;
}
struct PsiComplex psi_max_vector(struct PsiVector v)
{
- if (v.size == 0)
- return psi_new_complex(0.0, 0.0);
+ if (v.size == 0)
+ return psi_new_complex(0.0, 0.0);
- struct PsiComplex best = v.data[0];
- for (size_t i = 1; i < v.size; i++)
- if (less_than(best, v.data[i]))
- best = v.data[i];
+ struct PsiComplex best = v.data[0];
+ for (size_t i = 1; i < v.size; i++)
+ if (less_than(best, v.data[i]))
+ best = v.data[i];
- return best;
+ return best;
}
struct PsiComplex psi_min_vector(struct PsiVector v)
{
- if (v.size == 0)
- return psi_new_complex(0.0, 0.0);
+ if (v.size == 0)
+ return psi_new_complex(0.0, 0.0);
- struct PsiComplex best = v.data[0];
- for (size_t i = 1; i < v.size; i++)
- if (less_than(v.data[i], best))
- best = v.data[i];
+ struct PsiComplex best = v.data[0];
+ for (size_t i = 1; i < v.size; i++)
+ if (less_than(v.data[i], best))
+ best = v.data[i];
- return best;
+ return best;
}
struct PsiVector psi_add_vector(struct PsiVector a, struct PsiVector b)
{
- assert(a.size == b.size);
+ assert(a.size == b.size);
- struct PsiVector result = psi_new_vector(a.size, a.kind);
- for (size_t i = 0; i < a.size; i++)
- result.data[i] = psi_add_complex(a.data[i], b.data[i]);
+ struct PsiVector result = psi_new_vector(a.size, a.kind);
+ for (size_t i = 0; i < a.size; i++)
+ result.data[i] = psi_add_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiVector psi_sub_vector(struct PsiVector a, struct PsiVector b)
{
- assert(a.size == b.size);
+ assert(a.size == b.size);
- struct PsiVector result = psi_new_vector(a.size, a.kind);
- for (size_t i = 0; i < a.size; i++)
- result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
+ struct PsiVector result = psi_new_vector(a.size, a.kind);
+ for (size_t i = 0; i < a.size; i++)
+ result.data[i] = psi_sub_complex(a.data[i], b.data[i]);
- return result;
+ return result;
}
struct PsiVector psi_scale_vector(struct PsiVector v, struct PsiComplex scalar)
{
- struct PsiVector result = psi_new_vector(v.size, v.kind);
- for (size_t i = 0; i < v.size; i++)
- result.data[i] = psi_mul_complex(v.data[i], scalar);
+ struct PsiVector result = psi_new_vector(v.size, v.kind);
+ for (size_t i = 0; i < v.size; i++)
+ result.data[i] = psi_mul_complex(v.data[i], scalar);
- return result;
+ return result;
}
struct PsiVector psi_transpose_vector(struct PsiVector v)
{
- struct PsiVector result = psi_clone_vector(v);
- result.kind = flip_kind(v.kind);
+ struct PsiVector result = psi_clone_vector(v);
+ result.kind = flip_kind(v.kind);
- return result;
+ return result;
}
diff --git a/src/maths/vector.rs b/src/maths/vector.rs
deleted file mode 100644
index 11f3d29..0000000
--- a/src/maths/vector.rs
+++ /dev/null
@@ -1,258 +0,0 @@
-use super::{Float, Matrix};
-use core::{fmt, ops};
-
-#[macro_export]
-macro_rules! row_vector {
- ($($x:expr),*) => {
- RowVector::new(vec![$($x),*])
- };
- ($($x:expr,)*) => {
- RowVector::new(vec![$($x),*])
- };
-}
-
-#[macro_export]
-macro_rules! column_vector {
- ($($x:expr),*) => {
- ColumnVector::new(vec![$($x),*])
- };
- ($($x:expr,)*) => {
- ColumnVector::new(vec![$($x),*])
- };
-}
-
-pub trait Vector<T: Float> {
- fn new(data: Vec<T>) -> Self;
- fn get(&self, index: usize) -> T;
- fn set(&mut self, index: usize, value: T);
- fn size(&self) -> usize;
-
- fn dot(&self, other: &Self) -> T;
- fn norm(&self) -> T;
-
- fn max(&self) -> T;
- fn min(&self) -> T;
- fn sum(&self) -> T;
-
- fn from_matrix(matrix: &Matrix<T>) -> Self;
-}
-
-pub trait VectorMatrix<T: Float> {
- fn to_matrix(&self) -> Matrix<T>;
-}
-
-#[derive(Clone)]
-pub struct VectorImpl<T: Float, const ROWS: usize, const COLS: usize>(Vec<T>);
-pub type RowVector<T> = VectorImpl<T, 1, 0>;
-pub type ColumnVector<T> = VectorImpl<T, 0, 1>;
-
-impl<T: Float> ColumnVector<T> {
- pub fn mul_matrix(&self, matrix: &Matrix<T>) -> Option<ColumnVector<T>> {
- if matrix.cols != self.size() {
- return None;
- }
-
- let mut result = ColumnVector::new(vec![T::zero(); matrix.rows]);
-
- for i in 0..matrix.rows {
- let mut sum = T::zero();
- for j in 0..matrix.cols {
- sum += matrix.get(i, j) * self.get(j) ;
- }
- result.set(i, sum);
- }
-
- Some(result)
- }
-
- pub fn transpose(&self) -> RowVector<T> {
- RowVector::new(self.0.clone())
- }
-}
-
-impl<T: Float> RowVector<T> {
- pub fn mul_matrix(&self, matrix: &Matrix<T>) -> Option<RowVector<T>> {
- if self.size() != matrix.rows {
- return None;
- }
-
- let mut result = RowVector::new(vec![T::zero(); matrix.cols]);
-
- for j in 0..matrix.cols {
- let mut sum = T::zero();
- for i in 0..matrix.rows {
- sum += self.get(i) * matrix.get(i, j) ;
- }
- result.set(j, sum);
- }
-
- Some(result)
- }
-
- pub fn transpose(&self) -> ColumnVector<T> {
- ColumnVector::new(self.0.clone())
- }
-}
-
-impl<T: Float> VectorMatrix<T> for RowVector<T> {
- fn to_matrix(&self) -> Matrix<T> {
- Matrix::new(1, self.size(), self.0.clone())
- }
-}
-
-impl<T: Float> VectorMatrix<T> for ColumnVector<T> {
- fn to_matrix(&self) -> Matrix<T> {
- Matrix::new(self.size(), 1, self.0.clone())
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> Vector<T> for VectorImpl<T, ROWS, COLS> {
- fn from_matrix(matrix: &Matrix<T>) -> Self {
- Self::new(matrix.data.clone())
- }
-
- fn new(data: Vec<T>) -> Self {
- Self(data)
- }
-
- fn get(&self, index: usize) -> T {
- self.0[index]
- }
-
- fn set(&mut self, index: usize, value: T) {
- self.0[index] = value;
- }
-
- fn size(&self) -> usize {
- self.0.len()
- }
-
- fn dot(&self, other: &Self) -> T {
- self.0
- .iter()
- .zip(other.0.iter())
- .map(|(a, b)| *a * *b)
- .fold(T::zero(), |acc, x| acc + x)
- }
-
- fn norm(&self) -> T {
- self.0
- .iter()
- .map(|x| *x * *x)
- .fold(T::zero(), |acc, x| acc + x)
- .sqrt()
- }
-
- fn max(&self) -> T {
- *self
- .0
- .iter()
- .max_by(|a, b| a.partial_cmp(b).unwrap())
- .unwrap_or(&T::zero())
- }
-
- fn min(&self) -> T {
- *self
- .0
- .iter()
- .min_by(|a, b| a.partial_cmp(b).unwrap())
- .unwrap_or(&T::zero())
- }
-
- fn sum(&self) -> T {
- self.0.iter().fold(T::zero(), |acc, x| acc + *x)
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> VectorImpl<T, ROWS, COLS> {
- pub fn add_to(&self, other: &Self) -> Option<VectorImpl<T, ROWS, COLS>> {
- if self.size() != other.size() {
- return None;
- }
-
- let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]);
-
- for i in 0..self.size() {
- let sum = self.get(i) + other.get(i);
- result.set(i, sum);
- }
-
- Some(result)
- }
-
- pub fn subtract(&self, other: &Self) -> Option<VectorImpl<T, ROWS, COLS>> {
- if self.size() != other.size() {
- return None;
- }
-
- let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]);
-
- for i in 0..self.size() {
- let sum = self.get(i) - other.get(i);
- result.set(i, sum);
- }
-
- Some(result)
- }
-
- pub fn scale(&self, scalar: T) -> VectorImpl<T, ROWS, COLS> {
- let mut result = VectorImpl::new(vec![T::zero(); ROWS * COLS]);
-
- for i in 0..self.size() {
- let product = self.get(i) * scalar;
- result.set(i, product);
- }
-
- result
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> ops::Index<usize>
- for VectorImpl<T, ROWS, COLS>
-{
- type Output = T;
-
- fn index(&self, index: usize) -> &Self::Output {
- &self.0[index]
- }
-}
-
-impl<T: Float, const ROWS: usize, const COLS: usize> ops::IndexMut<usize>
- for VectorImpl<T, ROWS, COLS>
-{
- fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- &mut self.0[index]
- }
-}
-
-impl<T: Float + fmt::Debug> fmt::Debug for RowVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "RowVector({:?})", self.0)
- }
-}
-
-impl<T: Float + fmt::Debug> fmt::Debug for ColumnVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "ColumnVector({:?})", self.0)
- }
-}
-
-impl<T: Float + fmt::Display> fmt::Display for RowVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "[{}]",
- self.0
- .iter()
- .map(|x| x.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- )
- }
-}
-
-impl<T: Float + fmt::Display> fmt::Display for ColumnVector<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.to_matrix())
- }
-}