From 17598056a69a14e0390a07251d383f413ded9eea Mon Sep 17 00:00:00 2001 From: hachem Date: Fri, 18 Sep 2026 12:25:32 +0200 Subject: feat: add matrix, vector, and circuit display + fmt --- src/maths/format.c | 293 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 173 insertions(+), 120 deletions(-) (limited to 'src/maths/format.c') 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 ? "-" : ""; - - 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; - - snprintf(out, cap, "%s%s", sign, sym); - return true; + 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; + } + + 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; } char* psi_format_amplitude(struct PsiComplex c, char* out, size_t cap) { - 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); - - 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); - - 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); - - return out; - } - - 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)); - } - - snprintf(out, cap, "%s%s", re_str, im_str); - return out; + 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); + + 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); + + 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); + + return out; + } + + 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)); + } + + 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); - - return out; + 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; +} + +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); } -- cgit v1.3