| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <string.h> |
| #include <math.h> |
| #include <stdio.h> |
| #include "quhit_triality.h" |
| #include "s6_exotic.h" |
|
|
| |
| |
| |
|
|
| static const double W6_RE[6] = { |
| 1.0, 0.5, -0.5, -1.0, -0.5, 0.5 |
| }; |
| static const double W6_IM[6] = { |
| 0.0, 0.86602540378443864676, 0.86602540378443864676, |
| 0.0, -0.86602540378443864676, -0.86602540378443864676 |
| }; |
|
|
| |
| static const double W6I_RE[6] = { |
| 1.0, 0.5, -0.5, -1.0, -0.5, 0.5 |
| }; |
| static const double W6I_IM[6] = { |
| 0.0, -0.86602540378443864676, -0.86602540378443864676, |
| 0.0, 0.86602540378443864676, 0.86602540378443864676 |
| }; |
|
|
| static const double INV_SQRT6 = 0.40824829046386301637; |
| static const double INV_SQRT2 = 0.70710678118654752440; |
|
|
| |
| |
| |
|
|
| TrialityStats triality_stats = {0}; |
|
|
| void triality_stats_reset(void) { |
| memset(&triality_stats, 0, sizeof(triality_stats)); |
| } |
|
|
|
|
|
|
| |
| |
| |
|
|
| |
| static void dft6_forward(const double *in_re, const double *in_im, |
| double *out_re, double *out_im) |
| { |
| for (int j = 0; j < 6; j++) { |
| double sr = 0, si = 0; |
| for (int k = 0; k < 6; k++) { |
| int idx = (j * k) % 6; |
| double wr = W6_RE[idx], wi = W6_IM[idx]; |
| sr += in_re[k] * wr - in_im[k] * wi; |
| si += in_re[k] * wi + in_im[k] * wr; |
| } |
| out_re[j] = sr * INV_SQRT6; |
| out_im[j] = si * INV_SQRT6; |
| } |
| } |
|
|
| |
| static void dft6_inverse(const double *in_re, const double *in_im, |
| double *out_re, double *out_im) |
| { |
| for (int k = 0; k < 6; k++) { |
| double sr = 0, si = 0; |
| for (int j = 0; j < 6; j++) { |
| int idx = (j * k) % 6; |
| double wr = W6I_RE[idx], wi = W6I_IM[idx]; |
| sr += in_re[j] * wr - in_im[j] * wi; |
| si += in_re[j] * wi + in_im[j] * wr; |
| } |
| out_re[k] = sr * INV_SQRT6; |
| out_im[k] = si * INV_SQRT6; |
| } |
| } |
|
|
| |
| |
| |
|
|
| void triality_init(TrialityQuhit *q) { |
| memset(q, 0, sizeof(TrialityQuhit)); |
| q->edge_re[0] = 1.0; |
|
|
| |
| dft6_forward(q->edge_re, q->edge_im, q->vertex_re, q->vertex_im); |
| dft6_forward(q->vertex_re, q->vertex_im, q->diag_re, q->diag_im); |
|
|
| q->dirty = DIRTY_FOLDED | DIRTY_EXOTIC | DIRTY_TETRA; |
| q->primary = VIEW_EDGE; |
|
|
| |
| q->eigenstate_class = -1; |
| q->active_mask = 0x01; |
| q->active_count = 1; |
| q->real_valued = 1; |
| q->delta_valid = 0; |
| q->exotic_syntheme = 0; |
| } |
|
|
| void triality_init_basis(TrialityQuhit *q, int k) { |
| memset(q, 0, sizeof(TrialityQuhit)); |
| q->edge_re[k] = 1.0; |
| q->dirty = DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_EXOTIC | DIRTY_TETRA; |
| q->primary = VIEW_EDGE; |
| q->eigenstate_class = -1; |
| q->active_mask = (uint8_t)(1 << k); |
| q->active_count = 1; |
| q->real_valued = 1; |
| q->delta_valid = 0; |
| q->exotic_syntheme = 0; |
| } |
|
|
| void triality_copy(TrialityQuhit *dst, const TrialityQuhit *src) { |
| memcpy(dst, src, sizeof(*dst)); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| static double *view_re(TrialityQuhit *q, int v) { |
| switch(v) { |
| case VIEW_EDGE: return q->edge_re; |
| case VIEW_VERTEX: return q->vertex_re; |
| case VIEW_DIAGONAL: return q->diag_re; |
| case VIEW_FOLDED: return q->folded_re; |
| } |
| return q->edge_re; |
| } |
|
|
| static double *view_im(TrialityQuhit *q, int v) { |
| switch(v) { |
| case VIEW_EDGE: return q->edge_im; |
| case VIEW_VERTEX: return q->vertex_im; |
| case VIEW_DIAGONAL: return q->diag_im; |
| case VIEW_FOLDED: return q->folded_im; |
| } |
| return q->edge_im; |
| } |
|
|
| static int view_dirty_bit(int v) { |
| return 1 << v; |
| } |
|
|
| |
|
|
| |
| |
| |
| static void fold_forward(const double *in_re, const double *in_im, |
| double *out_re, double *out_im) |
| { |
| for (int k = 0; k < 3; k++) { |
| double a_re = in_re[k], a_im = in_im[k]; |
| double b_re = in_re[k + 3], b_im = in_im[k + 3]; |
| out_re[k] = INV_SQRT2 * (a_re + b_re); |
| out_im[k] = INV_SQRT2 * (a_im + b_im); |
| out_re[k + 3] = INV_SQRT2 * (a_re - b_re); |
| out_im[k + 3] = INV_SQRT2 * (a_im - b_im); |
| } |
| } |
|
|
| |
| static void fold_inverse(const double *in_re, const double *in_im, |
| double *out_re, double *out_im) |
| { |
| for (int k = 0; k < 3; k++) { |
| double v_re = in_re[k], v_im = in_im[k]; |
| double w_re = in_re[k + 3], w_im = in_im[k + 3]; |
| out_re[k] = INV_SQRT2 * (v_re + w_re); |
| out_im[k] = INV_SQRT2 * (v_im + w_im); |
| out_re[k + 3] = INV_SQRT2 * (v_re - w_re); |
| out_im[k + 3] = INV_SQRT2 * (v_im - w_im); |
| } |
| } |
|
|
| |
| |
| static void folded_to_vertex(const double *fold_re, const double *fold_im, |
| double *vert_re, double *vert_im) |
| { |
| static const double w3_re = -0.5; |
| static const double w3_im = 0.86602540378443864676; |
| static const double n3 = 0.57735026918962576451; |
|
|
| |
| double tw_re[6], tw_im[6]; |
| memcpy(tw_re, fold_re, 6 * sizeof(double)); |
| memcpy(tw_im, fold_im, 6 * sizeof(double)); |
| |
| { |
| double r = tw_re[4], i = tw_im[4]; |
| tw_re[4] = W6_RE[1] * r - W6_IM[1] * i; |
| tw_im[4] = W6_RE[1] * i + W6_IM[1] * r; |
| } |
| |
| { |
| double r = tw_re[5], i = tw_im[5]; |
| tw_re[5] = W6_RE[2] * r - W6_IM[2] * i; |
| tw_im[5] = W6_RE[2] * i + W6_IM[2] * r; |
| } |
|
|
| |
| for (int p = 0; p < 2; p++) { |
| double a_re = tw_re[0 + p*3], a_im = tw_im[0 + p*3]; |
| double b_re = tw_re[1 + p*3], b_im = tw_im[1 + p*3]; |
| double c_re = tw_re[2 + p*3], c_im = tw_im[2 + p*3]; |
|
|
| |
| vert_re[p] = n3 * (a_re + b_re + c_re); |
| vert_im[p] = n3 * (a_im + b_im + c_im); |
|
|
| |
| double wb_re = w3_re * b_re - w3_im * b_im; |
| double wb_im = w3_re * b_im + w3_im * b_re; |
| double wc_re = w3_re * c_re + w3_im * c_im; |
| double wc_im = w3_re * c_im - w3_im * c_re; |
| vert_re[2 + p] = n3 * (a_re + wb_re + wc_re); |
| vert_im[2 + p] = n3 * (a_im + wb_im + wc_im); |
|
|
| |
| double w2b_re = w3_re * b_re + w3_im * b_im; |
| double w2b_im = w3_re * b_im - w3_im * b_re; |
| double w2c_re = w3_re * c_re - w3_im * c_im; |
| double w2c_im = w3_re * c_im + w3_im * c_re; |
| vert_re[4 + p] = n3 * (a_re + w2b_re + w2c_re); |
| vert_im[4 + p] = n3 * (a_im + w2b_im + w2c_im); |
| } |
| } |
|
|
| static void convert_view(TrialityQuhit *q, int from, int to) { |
| double *src_re = view_re(q, from), *src_im = view_im(q, from); |
| double *dst_re = view_re(q, to), *dst_im = view_im(q, to); |
|
|
| |
| if (from <= VIEW_DIAGONAL && to == VIEW_FOLDED) { |
| |
| if (from != VIEW_EDGE) { |
| triality_ensure_view(q, VIEW_EDGE); |
| src_re = q->edge_re; src_im = q->edge_im; |
| } |
| fold_forward(src_re, src_im, dst_re, dst_im); |
| triality_stats.edge_to_folded++; |
| return; |
| } |
| if (from == VIEW_FOLDED && to == VIEW_EDGE) { |
| fold_inverse(src_re, src_im, dst_re, dst_im); |
| return; |
| } |
| if (from == VIEW_FOLDED && to == VIEW_VERTEX) { |
| folded_to_vertex(src_re, src_im, dst_re, dst_im); |
| triality_stats.folded_to_vertex++; |
| return; |
| } |
| if (from == VIEW_FOLDED) { |
| |
| triality_ensure_view(q, VIEW_EDGE); |
| convert_view(q, VIEW_EDGE, to); |
| return; |
| } |
|
|
| |
| int steps = (to - from + 3) % 3; |
|
|
| if (steps == 1) { |
| dft6_forward(src_re, src_im, dst_re, dst_im); |
| } else if (steps == 2) { |
| dft6_inverse(src_re, src_im, dst_re, dst_im); |
| } |
|
|
| |
| if (from == VIEW_EDGE && to == VIEW_VERTEX) triality_stats.edge_to_vertex++; |
| if (from == VIEW_EDGE && to == VIEW_DIAGONAL) triality_stats.edge_to_diag++; |
| if (from == VIEW_VERTEX && to == VIEW_EDGE) triality_stats.vertex_to_edge++; |
| if (from == VIEW_VERTEX && to == VIEW_DIAGONAL) triality_stats.vertex_to_diag++; |
| if (from == VIEW_DIAGONAL && to == VIEW_EDGE) triality_stats.diag_to_edge++; |
| if (from == VIEW_DIAGONAL && to == VIEW_VERTEX) triality_stats.diag_to_vertex++; |
| } |
|
|
| void triality_ensure_view(TrialityQuhit *q, int view) { |
| if (!(q->dirty & view_dirty_bit(view))) return; |
|
|
| |
| |
| |
| if (!(q->dirty & DIRTY_TETRA) && view <= VIEW_DIAGONAL) { |
| triality_tetra_to_view(q, view); |
| return; |
| } |
|
|
| |
| |
| |
| |
| if (q->eigenstate_class >= 0 && view <= VIEW_DIAGONAL) { |
| |
| int source = q->primary; |
| if (source > VIEW_DIAGONAL) source = VIEW_EDGE; |
| int steps = (view - source + 3) % 3; |
| if (steps == 0) { |
| |
| memcpy(view_re(q, view), view_re(q, source), TRI_D * sizeof(double)); |
| memcpy(view_im(q, view), view_im(q, source), TRI_D * sizeof(double)); |
| } else { |
| |
| |
| static const double EV_RE[4] = {1.0, -1.0, 0.0, 0.0}; |
| static const double EV_IM[4] = {0.0, 0.0, 1.0, -1.0}; |
| double lr = EV_RE[q->eigenstate_class]; |
| double li = EV_IM[q->eigenstate_class]; |
| |
| double pr = 1.0, pi = 0.0; |
| for (int s = 0; s < steps; s++) { |
| double tr = pr * lr - pi * li; |
| double ti = pr * li + pi * lr; |
| pr = tr; pi = ti; |
| } |
| |
| const double *sr = view_re(q, source), *si = view_im(q, source); |
| double *dr = view_re(q, view), *di = view_im(q, view); |
| for (int k = 0; k < TRI_D; k++) { |
| dr[k] = pr * sr[k] - pi * si[k]; |
| di[k] = pr * si[k] + pi * sr[k]; |
| } |
| } |
| q->dirty &= ~view_dirty_bit(view); |
| triality_stats.eigenstate_skips++; |
| return; |
| } |
|
|
| |
| int source = q->primary; |
| if (q->dirty & view_dirty_bit(source)) { |
| |
| for (int v = 0; v < 4; v++) { |
| if (!(q->dirty & view_dirty_bit(v))) { |
| source = v; |
| break; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| if (source == VIEW_EDGE && view == VIEW_VERTEX) { |
| if (!(q->dirty & DIRTY_FOLDED)) { |
| |
| folded_to_vertex(q->folded_re, q->folded_im, |
| q->vertex_re, q->vertex_im); |
| q->dirty &= ~DIRTY_VERTEX; |
| triality_stats.folded_to_vertex++; |
| return; |
| } |
| |
| fold_forward(q->edge_re, q->edge_im, q->folded_re, q->folded_im); |
| q->dirty &= ~DIRTY_FOLDED; |
| triality_stats.edge_to_folded++; |
| folded_to_vertex(q->folded_re, q->folded_im, |
| q->vertex_re, q->vertex_im); |
| q->dirty &= ~DIRTY_VERTEX; |
| triality_stats.folded_to_vertex++; |
| return; |
| } |
|
|
| |
| |
| |
| if (source == VIEW_VERTEX && view == VIEW_EDGE) { |
| |
| |
| |
| |
| static const double w3_re = -0.5; |
| static const double w3_im = 0.86602540378443864676; |
| static const double n3 = 0.57735026918962576451; |
|
|
| |
| double tw_re[6], tw_im[6]; |
| for (int p = 0; p < 2; p++) { |
| double a_re = q->vertex_re[p], a_im = q->vertex_im[p]; |
| double b_re = q->vertex_re[2 + p], b_im = q->vertex_im[2 + p]; |
| double c_re = q->vertex_re[4 + p], c_im = q->vertex_im[4 + p]; |
|
|
| |
| tw_re[0 + p*3] = n3 * (a_re + b_re + c_re); |
| tw_im[0 + p*3] = n3 * (a_im + b_im + c_im); |
|
|
| |
| double wb_re = w3_re * b_re + w3_im * b_im; |
| double wb_im = w3_re * b_im - w3_im * b_re; |
| double wc_re = w3_re * c_re - w3_im * c_im; |
| double wc_im = w3_re * c_im + w3_im * c_re; |
| tw_re[1 + p*3] = n3 * (a_re + wb_re + wc_re); |
| tw_im[1 + p*3] = n3 * (a_im + wb_im + wc_im); |
|
|
| |
| double w2b_re = w3_re * b_re - w3_im * b_im; |
| double w2b_im = w3_re * b_im + w3_im * b_re; |
| double w2c_re = w3_re * c_re + w3_im * c_im; |
| double w2c_im = w3_re * c_im - w3_im * c_re; |
| tw_re[2 + p*3] = n3 * (a_re + w2b_re + w2c_re); |
| tw_im[2 + p*3] = n3 * (a_im + w2b_im + w2c_im); |
| } |
|
|
| |
| { |
| double r = tw_re[4], i = tw_im[4]; |
| tw_re[4] = W6I_RE[1] * r - W6I_IM[1] * i; |
| tw_im[4] = W6I_RE[1] * i + W6I_IM[1] * r; |
| } |
| { |
| double r = tw_re[5], i = tw_im[5]; |
| tw_re[5] = W6I_RE[2] * r - W6I_IM[2] * i; |
| tw_im[5] = W6I_RE[2] * i + W6I_IM[2] * r; |
| } |
|
|
| |
| fold_inverse(tw_re, tw_im, q->edge_re, q->edge_im); |
|
|
| q->dirty &= ~DIRTY_EDGE; |
| |
| memcpy(q->folded_re, tw_re, sizeof(tw_re)); |
| memcpy(q->folded_im, tw_im, sizeof(tw_im)); |
| q->dirty &= ~DIRTY_FOLDED; |
| triality_stats.folded_to_vertex++; |
| return; |
| } |
|
|
| convert_view(q, source, view); |
| q->dirty &= ~view_dirty_bit(view); |
| } |
|
|
| void triality_sync_all(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
| triality_ensure_view(q, VIEW_VERTEX); |
| triality_ensure_view(q, VIEW_DIAGONAL); |
| } |
|
|
| const double *triality_view_re(TrialityQuhit *q, int view) { |
| triality_ensure_view(q, view); |
| return view_re(q, view); |
| } |
|
|
| const double *triality_view_im(TrialityQuhit *q, int view) { |
| triality_ensure_view(q, view); |
| return view_im(q, view); |
| } |
|
|
| |
| |
| |
|
|
| |
| void triality_phase(TrialityQuhit *q, const double *phi_re, const double *phi_im) { |
| triality_ensure_view(q, VIEW_EDGE); |
| if (q->real_valued) { |
| |
| int all_real_phases = 1; |
| for (int k = 0; k < TRI_D; k++) |
| if (fabs(phi_im[k]) > 1e-15) { all_real_phases = 0; break; } |
| if (all_real_phases) { |
| for (int k = 0; k < TRI_D; k++) { |
| if (!(q->active_mask & (1 << k))) continue; |
| q->edge_re[k] *= phi_re[k]; |
| } |
| triality_stats.real_fast_path++; |
| triality_stats.gates_edge++; |
| q->primary = VIEW_EDGE; |
| q->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_TETRA; |
| q->delta_valid = 0; |
| return; |
| } |
| } |
| for (int k = 0; k < TRI_D; k++) { |
| if (!(q->active_mask & (1 << k))) { |
| triality_stats.mask_skips++; |
| continue; |
| } |
| double re = q->edge_re[k], im = q->edge_im[k]; |
| q->edge_re[k] = re * phi_re[k] - im * phi_im[k]; |
| q->edge_im[k] = re * phi_im[k] + im * phi_re[k]; |
| } |
| |
| q->real_valued = 0; |
| q->primary = VIEW_EDGE; |
| q->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_TETRA; |
| q->delta_valid = 0; |
| triality_stats.gates_edge++; |
| } |
|
|
| |
| void triality_phase_single(TrialityQuhit *q, int k, double phi_re, double phi_im) { |
| triality_ensure_view(q, VIEW_EDGE); |
| q->delta_valid = 0; |
| if (!(q->active_mask & (1 << k))) { |
| triality_stats.mask_skips++; |
| return; |
| } |
| double re = q->edge_re[k], im = q->edge_im[k]; |
| q->edge_re[k] = re * phi_re - im * phi_im; |
| q->edge_im[k] = re * phi_im + im * phi_re; |
| if (fabs(phi_im) > 1e-15) q->real_valued = 0; |
| q->primary = VIEW_EDGE; |
| q->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_TETRA; |
| triality_stats.gates_edge++; |
| } |
|
|
| |
| void triality_z(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
| for (int k = 0; k < TRI_D; k++) { |
| if (!(q->active_mask & (1 << k))) { |
| triality_stats.mask_skips++; |
| continue; |
| } |
| double wr = W6_RE[k], wi = W6_IM[k]; |
| double re = q->edge_re[k], im = q->edge_im[k]; |
| q->edge_re[k] = re * wr - im * wi; |
| q->edge_im[k] = re * wi + im * wr; |
| } |
| q->real_valued = 0; |
| q->primary = VIEW_EDGE; |
| q->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_TETRA; |
| q->delta_valid = 0; |
| triality_stats.gates_edge++; |
| |
| |
| q->eigenstate_class = -1; |
| } |
|
|
| |
| |
| |
| void triality_shift(TrialityQuhit *q, int delta) { |
| delta = ((delta % TRI_D) + TRI_D) % TRI_D; |
| if (delta == 0) return; |
|
|
| triality_ensure_view(q, VIEW_VERTEX); |
| for (int j = 0; j < TRI_D; j++) { |
| int idx = (delta * j) % 6; |
| double wr = W6_RE[idx], wi = W6_IM[idx]; |
| double re = q->vertex_re[j], im = q->vertex_im[j]; |
| q->vertex_re[j] = re * wr - im * wi; |
| q->vertex_im[j] = re * wi + im * wr; |
| } |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->primary = VIEW_VERTEX; |
| q->dirty |= DIRTY_EDGE | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_TETRA; |
| q->delta_valid = 0; |
| triality_stats.gates_vertex++; |
| } |
|
|
| |
| void triality_x(TrialityQuhit *q) { |
| triality_shift(q, 1); |
| } |
|
|
| |
| |
| |
| void triality_dft(TrialityQuhit *q) { |
| triality_sync_all(q); |
|
|
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| memcpy(tmp_re, q->edge_re, sizeof(tmp_re)); |
| memcpy(tmp_im, q->edge_im, sizeof(tmp_im)); |
|
|
| dft6_forward(tmp_re, tmp_im, q->edge_re, q->edge_im); |
| q->primary = VIEW_EDGE; |
| q->dirty = DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_EXOTIC | DIRTY_TETRA; |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->delta_valid = 0; |
| triality_stats.gates_edge++; |
| } |
|
|
| |
| void triality_idft(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| memcpy(tmp_re, q->edge_re, sizeof(tmp_re)); |
| memcpy(tmp_im, q->edge_im, sizeof(tmp_im)); |
| dft6_inverse(tmp_re, tmp_im, q->edge_re, q->edge_im); |
| q->primary = VIEW_EDGE; |
| q->dirty = DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_EXOTIC | DIRTY_TETRA; |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->delta_valid = 0; |
| triality_stats.gates_edge++; |
| } |
|
|
| |
| void triality_unitary(TrialityQuhit *q, int view, |
| const double *U_re, const double *U_im) { |
| triality_ensure_view(q, view); |
| double *v_re = view_re(q, view), *v_im = view_im(q, view); |
| double out_re[TRI_D] = {0}, out_im[TRI_D] = {0}; |
|
|
| for (int j = 0; j < TRI_D; j++) |
| for (int k = 0; k < TRI_D; k++) { |
| double ur = U_re[j * TRI_D + k], ui = U_im[j * TRI_D + k]; |
| out_re[j] += ur * v_re[k] - ui * v_im[k]; |
| out_im[j] += ur * v_im[k] + ui * v_re[k]; |
| } |
|
|
| memcpy(v_re, out_re, sizeof(out_re)); |
| memcpy(v_im, out_im, sizeof(out_im)); |
| q->primary = view; |
| q->dirty = DIRTY_ALL & ~view_dirty_bit(view); |
| q->eigenstate_class = -1; |
| q->delta_valid = 0; |
|
|
| |
| uint8_t mask = 0; |
| int count = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| if (out_re[k] * out_re[k] + out_im[k] * out_im[k] > 1e-30) { |
| mask |= (uint8_t)(1 << k); |
| count++; |
| } |
| } |
| q->active_mask = mask; |
| q->active_count = (uint8_t)count; |
|
|
| |
| int is_real = 1; |
| for (int k = 0; k < TRI_D; k++) { |
| if (fabs(out_im[k]) > 1e-15) { is_real = 0; break; } |
| } |
| q->real_valued = (uint8_t)is_real; |
|
|
| if (view == VIEW_EDGE) triality_stats.gates_edge++; |
| if (view == VIEW_VERTEX) triality_stats.gates_vertex++; |
| if (view == VIEW_DIAGONAL) triality_stats.gates_diag++; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| void triality_cz(TrialityQuhit *a, TrialityQuhit *b) { |
| triality_ensure_view(a, VIEW_EDGE); |
| triality_ensure_view(b, VIEW_EDGE); |
|
|
| |
| |
| |
| |
| triality_update_mask(a); |
| triality_update_mask(b); |
|
|
| |
| |
| uint8_t ma = a->active_mask, mb = b->active_mask; |
|
|
| |
| |
| |
| |
| |
| |
| static const int TRI_EVEN[3] = {0, 2, 4}; |
| static const int TRI_ODD[3] = {1, 3, 5}; |
| #define MASK_EVEN 0x15 |
| #define MASK_ODD 0x2A |
|
|
| const int *tri_a = NULL, *tri_b = NULL; |
| int na = 0, nb = 0; |
|
|
| if ((ma & ~MASK_EVEN) == 0 && ma) { tri_a = TRI_EVEN; na = __builtin_popcount(ma); } |
| else if ((ma & ~MASK_ODD) == 0 && ma) { tri_a = TRI_ODD; na = __builtin_popcount(ma); } |
|
|
| if ((mb & ~MASK_EVEN) == 0 && mb) { tri_b = TRI_EVEN; nb = __builtin_popcount(mb); } |
| else if ((mb & ~MASK_ODD) == 0 && mb) { tri_b = TRI_ODD; nb = __builtin_popcount(mb); } |
|
|
| double eff_a_re[TRI_D] = {0}, eff_a_im[TRI_D] = {0}; |
| double eff_b_re[TRI_D] = {0}, eff_b_im[TRI_D] = {0}; |
| int skipped = 0; |
|
|
| if (tri_a && tri_b) { |
| |
| for (int ti = 0; ti < 3; ti++) { |
| int j = tri_a[ti]; |
| if (!(ma & (1 << j))) continue; |
| double aprob = a->edge_re[j]*a->edge_re[j] + a->edge_im[j]*a->edge_im[j]; |
| for (int tk = 0; tk < 3; tk++) { |
| int k = tri_b[tk]; |
| if (!(mb & (1 << k))) continue; |
| int idx = (j * k) % 6; |
| double bprob = b->edge_re[k]*b->edge_re[k] + b->edge_im[k]*b->edge_im[k]; |
| eff_a_re[j] += bprob * W6_RE[idx]; |
| eff_a_im[j] += bprob * W6_IM[idx]; |
| eff_b_re[k] += aprob * W6_RE[idx]; |
| eff_b_im[k] += aprob * W6_IM[idx]; |
| } |
| } |
| for (int ti = 0; ti < 3; ti++) { |
| int j = tri_a[ti]; |
| if (!(ma & (1 << j))) continue; |
| double re = a->edge_re[j], im = a->edge_im[j]; |
| a->edge_re[j] = re * eff_a_re[j] - im * eff_a_im[j]; |
| a->edge_im[j] = re * eff_a_im[j] + im * eff_a_re[j]; |
| } |
| for (int tk = 0; tk < 3; tk++) { |
| int k = tri_b[tk]; |
| if (!(mb & (1 << k))) continue; |
| double re = b->edge_re[k], im = b->edge_im[k]; |
| b->edge_re[k] = re * eff_b_re[k] - im * eff_b_im[k]; |
| b->edge_im[k] = re * eff_b_im[k] + im * eff_b_re[k]; |
| } |
| triality_stats.mask_skips += (6 - na) + (6 - nb); |
| goto cz_renorm; |
| } |
|
|
| |
| for (int j = 0; j < TRI_D; j++) { |
| if (!(ma & (1 << j))) continue; |
| double aprob = a->edge_re[j]*a->edge_re[j] + a->edge_im[j]*a->edge_im[j]; |
| for (int k = 0; k < TRI_D; k++) { |
| if (!(mb & (1 << k))) continue; |
| int idx = (j * k) % 6; |
| double bprob = b->edge_re[k]*b->edge_re[k] + b->edge_im[k]*b->edge_im[k]; |
| eff_a_re[j] += bprob * W6_RE[idx]; |
| eff_a_im[j] += bprob * W6_IM[idx]; |
| eff_b_re[k] += aprob * W6_RE[idx]; |
| eff_b_im[k] += aprob * W6_IM[idx]; |
| } |
| } |
| |
| for (int j = 0; j < TRI_D; j++) { |
| if (!(ma & (1 << j))) { skipped++; continue; } |
| double re = a->edge_re[j], im = a->edge_im[j]; |
| a->edge_re[j] = re * eff_a_re[j] - im * eff_a_im[j]; |
| a->edge_im[j] = re * eff_a_im[j] + im * eff_a_re[j]; |
| } |
| for (int k = 0; k < TRI_D; k++) { |
| if (!(mb & (1 << k))) { skipped++; continue; } |
| double re = b->edge_re[k], im = b->edge_im[k]; |
| b->edge_re[k] = re * eff_b_re[k] - im * eff_b_im[k]; |
| b->edge_im[k] = re * eff_b_im[k] + im * eff_b_re[k]; |
| } |
| triality_stats.mask_skips += skipped; |
|
|
| |
| |
| |
| |
| |
| |
| cz_renorm: |
| { |
| double na = 0, nb = 0; |
| for (int i = 0; i < TRI_D; i++) { |
| na += a->edge_re[i]*a->edge_re[i] + a->edge_im[i]*a->edge_im[i]; |
| nb += b->edge_re[i]*b->edge_re[i] + b->edge_im[i]*b->edge_im[i]; |
| } |
| if (na > 1e-30 && fabs(na - 1.0) > 1e-15) { |
| double inv = 1.0 / sqrt(na); |
| for (int i = 0; i < TRI_D; i++) { |
| a->edge_re[i] *= inv; a->edge_im[i] *= inv; |
| } |
| } |
| if (nb > 1e-30 && fabs(nb - 1.0) > 1e-15) { |
| double inv = 1.0 / sqrt(nb); |
| for (int i = 0; i < TRI_D; i++) { |
| b->edge_re[i] *= inv; b->edge_im[i] *= inv; |
| } |
| } |
| } |
| a->real_valued = 0; b->real_valued = 0; |
| a->eigenstate_class = -1; b->eigenstate_class = -1; |
| a->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED; |
| b->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED; |
| a->delta_valid = 0; b->delta_valid = 0; |
| triality_stats.gates_edge += 2; |
| } |
|
|
| |
| |
| |
|
|
| |
| static uint64_t triality_rng_next(uint64_t *state) { |
| uint64_t x = *state; |
| x ^= x << 13; |
| x ^= x >> 7; |
| x ^= x << 17; |
| *state = x; |
| return x; |
| } |
|
|
| static double triality_rng_double(uint64_t *state) { |
| return (triality_rng_next(state) >> 11) * 0x1.0p-53; |
| } |
|
|
| void triality_probabilities(TrialityQuhit *q, int view, double *probs) { |
| triality_ensure_view(q, view); |
| const double *re = view_re(q, view), *im = view_im(q, view); |
| double total = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| probs[k] = re[k]*re[k] + im[k]*im[k]; |
| total += probs[k]; |
| } |
| if (total > 1e-30) |
| for (int k = 0; k < TRI_D; k++) probs[k] /= total; |
| } |
|
|
| int triality_measure(TrialityQuhit *q, int view, uint64_t *rng_state) { |
| double probs[TRI_D]; |
| triality_probabilities(q, view, probs); |
|
|
| |
| double r = triality_rng_double(rng_state); |
| int outcome = 0; |
| double cdf = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| cdf += probs[k]; |
| if (r < cdf) { outcome = k; break; } |
| } |
|
|
| |
| triality_ensure_view(q, view); |
| double *v_re = view_re(q, view), *v_im = view_im(q, view); |
|
|
| |
| double win_re = v_re[outcome], win_im = v_im[outcome]; |
| double norm2 = win_re*win_re + win_im*win_im; |
| double scale = (norm2 > 1e-30) ? 1.0 / sqrt(norm2) : 0.0; |
|
|
| for (int k = 0; k < TRI_D; k++) { |
| v_re[k] = 0; |
| v_im[k] = 0; |
| } |
| v_re[outcome] = win_re * scale; |
| v_im[outcome] = win_im * scale; |
|
|
| q->primary = view; |
| q->dirty = DIRTY_ALL & ~view_dirty_bit(view); |
|
|
| |
| q->active_mask = (uint8_t)(1 << outcome); |
| q->active_count = 1; |
| q->real_valued = (fabs(v_im[outcome]) < 1e-15) ? 1 : 0; |
| q->eigenstate_class = -1; |
| q->delta_valid = 0; |
|
|
| return outcome; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| void triality_rotate(TrialityQuhit *q) { |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
|
|
| |
| memcpy(tmp_re, q->diag_re, sizeof(tmp_re)); |
| memcpy(tmp_im, q->diag_im, sizeof(tmp_im)); |
|
|
| |
| memcpy(q->diag_re, q->vertex_re, sizeof(tmp_re)); |
| memcpy(q->diag_im, q->vertex_im, sizeof(tmp_im)); |
|
|
| |
| memcpy(q->vertex_re, q->edge_re, sizeof(tmp_re)); |
| memcpy(q->vertex_im, q->edge_im, sizeof(tmp_im)); |
|
|
| |
| memcpy(q->edge_re, tmp_re, sizeof(tmp_re)); |
| memcpy(q->edge_im, tmp_im, sizeof(tmp_im)); |
|
|
| |
| uint8_t d = q->dirty; |
| uint8_t lo3 = d & 0x7; |
| uint8_t folded = d & DIRTY_FOLDED; |
| q->dirty = (((lo3 & 1) << 1) | ((lo3 & 2) << 1) | ((lo3 & 4) >> 2)) | folded | DIRTY_FOLDED; |
|
|
| |
| q->primary = (q->primary + 1) % 3; |
|
|
| triality_stats.rotations++; |
| } |
|
|
| void triality_rotate_inv(TrialityQuhit *q) { |
| |
| triality_rotate(q); |
| triality_rotate(q); |
| } |
|
|
| |
| |
| |
|
|
| void triality_print(TrialityQuhit *q, const char *label) { |
| triality_sync_all(q); |
|
|
| printf("\n ββββ Triality Quhit: %s ββββ\n", label ? label : ""); |
| printf(" β View β"); |
| for (int k = 0; k < TRI_D; k++) printf(" |%dβ© ", k); |
| printf("β\n"); |
| printf(" βββββββββββββΌ"); |
| for (int k = 0; k < TRI_D; k++) printf("ββββββββββββ"); |
| printf("β€\n"); |
|
|
| const char *names[3] = {"Edge (Y)", "Vertex(C)", "Diag (M)"}; |
| double *arrays_re[3] = {q->edge_re, q->vertex_re, q->diag_re}; |
| double *arrays_im[3] = {q->edge_im, q->vertex_im, q->diag_im}; |
|
|
| for (int v = 0; v < 3; v++) { |
| printf(" β %s β", names[v]); |
| for (int k = 0; k < TRI_D; k++) { |
| double re = arrays_re[v][k], im = arrays_im[v][k]; |
| double mag = sqrt(re*re + im*im); |
| if (mag < 1e-10) |
| printf(" Β· "); |
| else if (fabs(im) < 1e-10) |
| printf(" %+.4f ", re); |
| else |
| printf(" %+.2f%+.2fi", re, im); |
| } |
| printf("β\n"); |
| } |
| printf(" | Primary: %s | Dirty: %c%c%c%c | Eigen: %d | Mask: 0x%02X (%d) | Real: %d |\n", |
| names[q->primary > 2 ? 0 : q->primary], |
| (q->dirty & DIRTY_EDGE) ? 'E' : 'Β·', |
| (q->dirty & DIRTY_VERTEX) ? 'V' : 'Β·', |
| (q->dirty & DIRTY_DIAGONAL) ? 'D' : 'Β·', |
| (q->dirty & DIRTY_FOLDED) ? 'F' : 'Β·', |
| q->eigenstate_class, |
| q->active_mask, q->active_count, |
| q->real_valued); |
| printf(" β"); |
| for (int i = 0; i < 12 + TRI_D * 12; i++) printf("β"); |
| printf("β\n"); |
| } |
|
|
|
|
| |
| |
| |
|
|
| |
|
|
| void triality_fold(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
| fold_forward(q->edge_re, q->edge_im, q->folded_re, q->folded_im); |
| q->dirty &= ~DIRTY_FOLDED; |
| triality_stats.edge_to_folded++; |
| } |
|
|
| void triality_unfold(TrialityQuhit *q) { |
| if (q->dirty & DIRTY_FOLDED) { |
| triality_fold(q); |
| } |
| fold_inverse(q->folded_re, q->folded_im, q->edge_re, q->edge_im); |
| q->dirty &= ~DIRTY_EDGE; |
| q->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL; |
| } |
|
|
| void triality_ensure_view_via_fold(TrialityQuhit *q, int target_view) { |
| if (target_view == VIEW_FOLDED) { |
| if (q->dirty & DIRTY_FOLDED) triality_fold(q); |
| return; |
| } |
| if (target_view == VIEW_VERTEX) { |
| |
| if (q->dirty & DIRTY_FOLDED) triality_fold(q); |
| folded_to_vertex(q->folded_re, q->folded_im, |
| q->vertex_re, q->vertex_im); |
| q->dirty &= ~DIRTY_VERTEX; |
| triality_stats.folded_to_vertex++; |
| return; |
| } |
| |
| triality_ensure_view(q, target_view); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| static const double TETRA_TO_EDGE_RE[36] = { |
| +0.8391210551713808, -0.0000000000000002, +0.5439447166468928, -0.0000000000000000, +0.0000000000000003, -0.0000000000000000, |
| +0.2432594724848628, +0.5405470133003926, -0.3752663441429122, +0.0843314257205145, +0.6532814824381888, -0.2705980500730983, |
| +0.2432594724848627, -0.2975766753297839, -0.3752663441429118, -0.4595632394582247, +0.2705980500730981, +0.6532814824381883, |
| +0.2432594724848627, -0.4859406759412170, -0.3752663441429117, +0.7504636274754213, -0.0000000000000005, -0.0000000000000005, |
| +0.2432594724848627, -0.2975766753297834, -0.3752663441429116, -0.4595632394582254, -0.2705980500730989, -0.6532814824381882, |
| +0.2432594724848627, +0.5405470133003922, -0.3752663441429114, +0.0843314257205145, -0.6532814824381878, +0.2705980500730987, |
| }; |
| static const double TETRA_TO_EDGE_IM[36] = { |
| +0.0000000000000000, +0.0000000000000000, +0.0000000000000000, +0.0000000000000001, +0.0000000000000002, +0.0000000000000000, |
| -0.0000000000000000, -0.0263785533033470, +0.0000000000000001, -0.0011441038385107, +0.0000000000000000, +0.0000000000000001, |
| +0.0000000000000001, +0.0145216641640333, +0.0000000000000000, +0.0062347821326423, +0.0000000000000000, +0.0000000000000000, |
| +0.0000000000000002, +0.0237137782786277, +0.0000000000000001, -0.0101813565882631, +0.0000000000000000, -0.0000000000000001, |
| +0.0000000000000002, +0.0145216641640335, +0.0000000000000001, +0.0062347821326419, +0.0000000000000000, +0.0000000000000002, |
| +0.0000000000000003, -0.0263785533033474, +0.0000000000000001, -0.0011441038385105, +0.0000000000000003, +0.0000000000000000, |
| }; |
|
|
| static const double EDGE_TO_TETRA_RE[36] = { |
| +0.8391210551713808, +0.2432594724848628, +0.2432594724848627, +0.2432594724848627, +0.2432594724848627, +0.2432594724848627, |
| -0.0000000000000002, +0.5405470133003926, -0.2975766753297839, -0.4859406759412170, -0.2975766753297834, +0.5405470133003922, |
| +0.5439447166468928, -0.3752663441429122, -0.3752663441429118, -0.3752663441429117, -0.3752663441429116, -0.3752663441429114, |
| -0.0000000000000000, +0.0843314257205145, -0.4595632394582247, +0.7504636274754213, -0.4595632394582254, +0.0843314257205145, |
| +0.0000000000000003, +0.6532814824381888, +0.2705980500730981, -0.0000000000000005, -0.2705980500730989, -0.6532814824381878, |
| -0.0000000000000000, -0.2705980500730983, +0.6532814824381883, -0.0000000000000005, -0.6532814824381882, +0.2705980500730987, |
| }; |
| static const double EDGE_TO_TETRA_IM[36] = { |
| -0.0000000000000000, +0.0000000000000000, -0.0000000000000001, -0.0000000000000002, -0.0000000000000002, -0.0000000000000003, |
| -0.0000000000000000, +0.0263785533033470, -0.0145216641640333, -0.0237137782786277, -0.0145216641640335, +0.0263785533033474, |
| -0.0000000000000000, -0.0000000000000001, -0.0000000000000000, -0.0000000000000001, -0.0000000000000001, -0.0000000000000001, |
| -0.0000000000000001, +0.0011441038385107, -0.0062347821326423, +0.0101813565882631, -0.0062347821326419, +0.0011441038385105, |
| -0.0000000000000002, -0.0000000000000000, -0.0000000000000000, -0.0000000000000000, -0.0000000000000000, -0.0000000000000003, |
| -0.0000000000000000, -0.0000000000000001, -0.0000000000000000, +0.0000000000000001, -0.0000000000000002, -0.0000000000000000, |
| }; |
|
|
| |
| static const double TETRA_EIGENVAL_RE[6] = {+1.0, +1.0, -1.0, -1.0, +0.0, -0.0}; |
| static const double TETRA_EIGENVAL_IM[6] = {+0.0, +0.0, +0.0, +0.0, +1.0, -1.0}; |
|
|
| |
| static const double TETRA_EIGENVAL_CONJ_RE[6] = {+1.0, +1.0, -1.0, -1.0, +0.0, -0.0}; |
| static const double TETRA_EIGENVAL_CONJ_IM[6] = {+0.0, +0.0, +0.0, +0.0, -1.0, +1.0}; |
|
|
| |
| static void edge_to_tetra(const double *edge_re, const double *edge_im, |
| double *tetra_re, double *tetra_im) |
| { |
| for (int j = 0; j < TRI_D; j++) { |
| double sr = 0, si = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| double tr = EDGE_TO_TETRA_RE[j * TRI_D + k]; |
| double ti = EDGE_TO_TETRA_IM[j * TRI_D + k]; |
| sr += tr * edge_re[k] - ti * edge_im[k]; |
| si += tr * edge_im[k] + ti * edge_re[k]; |
| } |
| tetra_re[j] = sr; |
| tetra_im[j] = si; |
| } |
| } |
|
|
| |
| static void tetra_to_edge_convert(const double *tetra_re, const double *tetra_im, |
| double *edge_re, double *edge_im) |
| { |
| for (int j = 0; j < TRI_D; j++) { |
| double sr = 0, si = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| double tr = TETRA_TO_EDGE_RE[j * TRI_D + k]; |
| double ti = TETRA_TO_EDGE_IM[j * TRI_D + k]; |
| sr += tr * tetra_re[k] - ti * tetra_im[k]; |
| si += tr * tetra_im[k] + ti * tetra_re[k]; |
| } |
| edge_re[j] = sr; |
| edge_im[j] = si; |
| } |
| } |
|
|
| |
|
|
| void triality_ensure_tetra(TrialityQuhit *q) { |
| if (!(q->dirty & DIRTY_TETRA)) return; |
|
|
| |
| triality_ensure_view(q, VIEW_EDGE); |
| edge_to_tetra(q->edge_re, q->edge_im, q->tetra_re, q->tetra_im); |
| q->dirty &= ~DIRTY_TETRA; |
| triality_stats.tetra_conversions++; |
| } |
|
|
| void triality_tetra_to_view(TrialityQuhit *q, int target_view) { |
| triality_ensure_tetra(q); |
|
|
| if (target_view == VIEW_EDGE || target_view == VIEW_VERTEX || |
| target_view == VIEW_DIAGONAL) |
| { |
| |
| |
| |
| |
| |
| |
| |
| int n = target_view; |
| double scaled_re[TRI_D], scaled_im[TRI_D]; |
|
|
| for (int k = 0; k < TRI_D; k++) { |
| |
| double lr = TETRA_EIGENVAL_RE[k], li = TETRA_EIGENVAL_IM[k]; |
| double pr = 1.0, pi = 0.0; |
| for (int s = 0; s < n; s++) { |
| double tr = pr * lr - pi * li; |
| double ti = pr * li + pi * lr; |
| pr = tr; pi = ti; |
| } |
| |
| scaled_re[k] = q->tetra_re[k] * pr - q->tetra_im[k] * pi; |
| scaled_im[k] = q->tetra_re[k] * pi + q->tetra_im[k] * pr; |
| } |
|
|
| |
| double *dst_re = view_re(q, target_view); |
| double *dst_im = view_im(q, target_view); |
| tetra_to_edge_convert(scaled_re, scaled_im, dst_re, dst_im); |
| q->dirty &= ~view_dirty_bit(target_view); |
| triality_stats.tetra_conversions++; |
| } |
| } |
|
|
| void triality_dft_via_tetra(TrialityQuhit *q) { |
| triality_ensure_tetra(q); |
|
|
| |
| |
| for (int k = 0; k < TRI_D; k++) { |
| double tr = q->tetra_re[k], ti = q->tetra_im[k]; |
| double lr = TETRA_EIGENVAL_RE[k], li = TETRA_EIGENVAL_IM[k]; |
| q->tetra_re[k] = tr * lr - ti * li; |
| q->tetra_im[k] = tr * li + ti * lr; |
| } |
|
|
| |
| |
| |
| q->dirty = (DIRTY_EDGE | DIRTY_VERTEX | DIRTY_DIAGONAL | |
| DIRTY_FOLDED | DIRTY_EXOTIC); |
| |
|
|
| |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->delta_valid = 0; |
| triality_stats.tetra_dft_skips++; |
| } |
|
|
| void triality_idft_via_tetra(TrialityQuhit *q) { |
| triality_ensure_tetra(q); |
|
|
| |
| for (int k = 0; k < TRI_D; k++) { |
| double tr = q->tetra_re[k], ti = q->tetra_im[k]; |
| double lr = TETRA_EIGENVAL_CONJ_RE[k], li = TETRA_EIGENVAL_CONJ_IM[k]; |
| q->tetra_re[k] = tr * lr - ti * li; |
| q->tetra_im[k] = tr * li + ti * lr; |
| } |
|
|
| q->dirty = (DIRTY_EDGE | DIRTY_VERTEX | DIRTY_DIAGONAL | |
| DIRTY_FOLDED | DIRTY_EXOTIC); |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->delta_valid = 0; |
| triality_stats.tetra_dft_skips++; |
| } |
|
|
| |
|
|
| int triality_detect_eigenstate(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
|
|
| |
| double f_re[TRI_D], f_im[TRI_D]; |
| dft6_forward(q->edge_re, q->edge_im, f_re, f_im); |
|
|
| |
| int ref = -1; |
| for (int k = 0; k < TRI_D; k++) { |
| double mag = q->edge_re[k]*q->edge_re[k] + q->edge_im[k]*q->edge_im[k]; |
| if (mag > 1e-20) { ref = k; break; } |
| } |
| if (ref < 0) { q->eigenstate_class = -1; return -1; } |
|
|
| |
| double sr = q->edge_re[ref], si = q->edge_im[ref]; |
| double fr = f_re[ref], fi = f_im[ref]; |
| double denom = sr*sr + si*si; |
| double lr = (fr*sr + fi*si) / denom; |
| double li = (fi*sr - fr*si) / denom; |
|
|
| |
| static const double EV_RE[4] = {1.0, -1.0, 0.0, 0.0}; |
| static const double EV_IM[4] = {0.0, 0.0, 1.0, -1.0}; |
| int cls = -1; |
| for (int c = 0; c < 4; c++) { |
| if (fabs(lr - EV_RE[c]) < 1e-10 && fabs(li - EV_IM[c]) < 1e-10) { |
| cls = c; break; |
| } |
| } |
| if (cls < 0) { q->eigenstate_class = -1; return -1; } |
|
|
| |
| for (int k = 0; k < TRI_D; k++) { |
| double expected_re = EV_RE[cls] * q->edge_re[k] - EV_IM[cls] * q->edge_im[k]; |
| double expected_im = EV_RE[cls] * q->edge_im[k] + EV_IM[cls] * q->edge_re[k]; |
| if (fabs(f_re[k] - expected_re) > 1e-10 || |
| fabs(f_im[k] - expected_im) > 1e-10) { |
| q->eigenstate_class = -1; |
| return -1; |
| } |
| } |
|
|
| q->eigenstate_class = (int8_t)cls; |
| return cls; |
| } |
|
|
| void triality_clear_eigenstate(TrialityQuhit *q) { |
| q->eigenstate_class = -1; |
| } |
|
|
| |
|
|
| void triality_update_mask(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
| uint8_t mask = 0; |
| int count = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| double mag2 = q->edge_re[k]*q->edge_re[k] + q->edge_im[k]*q->edge_im[k]; |
| if (mag2 > 1e-30) { |
| mask |= (uint8_t)(1 << k); |
| count++; |
| } |
| } |
| q->active_mask = mask; |
| q->active_count = (uint8_t)count; |
| } |
|
|
| |
|
|
| void triality_detect_real(TrialityQuhit *q) { |
| triality_ensure_view(q, VIEW_EDGE); |
| q->real_valued = 1; |
| for (int k = 0; k < TRI_D; k++) { |
| if (fabs(q->edge_im[k]) > 1e-15) { |
| q->real_valued = 0; |
| return; |
| } |
| } |
| } |
|
|
| |
|
|
| void triality_refresh_flags(TrialityQuhit *q) { |
| triality_update_mask(q); |
| triality_detect_real(q); |
| triality_detect_eigenstate(q); |
|
|
| |
| |
| |
| int optimal = s6_min_entropy_syntheme(q->edge_re, q->edge_im); |
| if (optimal != q->exotic_syntheme) { |
| q->exotic_syntheme = optimal; |
| q->dirty |= DIRTY_EXOTIC; |
| } |
| } |
|
|
| void triality_stats_print(void) { |
| printf("\n ββ Triality Statistics ββ\n"); |
| printf(" View conversions:\n"); |
| printf(" EdgeβVertex: %llu\n", (unsigned long long)triality_stats.edge_to_vertex); |
| printf(" EdgeβDiag: %llu\n", (unsigned long long)triality_stats.edge_to_diag); |
| printf(" VertexβEdge: %llu\n", (unsigned long long)triality_stats.vertex_to_edge); |
| printf(" VertexβDiag: %llu\n", (unsigned long long)triality_stats.vertex_to_diag); |
| printf(" DiagβEdge: %llu\n", (unsigned long long)triality_stats.diag_to_edge); |
| printf(" DiagβVertex: %llu\n", (unsigned long long)triality_stats.diag_to_vertex); |
| printf(" EdgeβFolded: %llu\n", (unsigned long long)triality_stats.edge_to_folded); |
| printf(" FoldedβVertex: %llu\n", (unsigned long long)triality_stats.folded_to_vertex); |
| printf(" Gates:\n"); |
| printf(" Edge view: %llu\n", (unsigned long long)triality_stats.gates_edge); |
| printf(" Vertex view: %llu\n", (unsigned long long)triality_stats.gates_vertex); |
| printf(" Diag view: %llu\n", (unsigned long long)triality_stats.gates_diag); |
| printf(" Rotations: %llu\n", (unsigned long long)triality_stats.rotations); |
| printf(" Enhancements:\n"); |
| printf(" Eigenstate skips: %llu\n", (unsigned long long)triality_stats.eigenstate_skips); |
| printf(" Mask skips: %llu\n", (unsigned long long)triality_stats.mask_skips); |
| printf(" Real fast path: %llu\n", (unsigned long long)triality_stats.real_fast_path); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #define DFT_ORDER 4 |
|
|
| static void ltri_diag_identity(double *re, double *im) { |
| for (int k = 0; k < TRI_D; k++) { re[k] = 1.0; im[k] = 0.0; } |
| } |
|
|
| static void ltri_diag_mul_phase(double *d_re, double *d_im, int k, |
| double pr, double pi) { |
| double re = d_re[k], im = d_im[k]; |
| d_re[k] = re * pr - im * pi; |
| d_im[k] = re * pi + im * pr; |
| } |
|
|
| static void ltri_apply_diag(const double *d_re, const double *d_im, |
| const double *in_re, const double *in_im, |
| double *out_re, double *out_im) { |
| for (int k = 0; k < TRI_D; k++) { |
| out_re[k] = d_re[k] * in_re[k] - d_im[k] * in_im[k]; |
| out_im[k] = d_re[k] * in_im[k] + d_im[k] * in_re[k]; |
| } |
| } |
|
|
| |
| static void ltri_apply_reversal(double *re, double *im) { |
| for (int k = 1; k < (TRI_D + 1) / 2; k++) { |
| int j = TRI_D - k; |
| double tr = re[k]; re[k] = re[j]; re[j] = tr; |
| double ti = im[k]; im[k] = im[j]; im[j] = ti; |
| } |
| } |
|
|
| |
| static void ltri_diag_reverse(double *d_re, double *d_im) { |
| for (int k = 1; k < (TRI_D + 1) / 2; k++) { |
| int j = TRI_D - k; |
| double tr = d_re[k]; d_re[k] = d_re[j]; d_re[j] = tr; |
| double ti = d_im[k]; d_im[k] = d_im[j]; d_im[j] = ti; |
| } |
| } |
|
|
| |
| static void ltri_diag_mul(double *a_re, double *a_im, |
| const double *b_re, const double *b_im) { |
| for (int k = 0; k < TRI_D; k++) { |
| double ar = a_re[k], ai = a_im[k]; |
| a_re[k] = ar * b_re[k] - ai * b_im[k]; |
| a_im[k] = ar * b_im[k] + ai * b_re[k]; |
| } |
| } |
|
|
| static void ltri_apply_n_dfts(double *re, double *im, int n) { |
| n = ((n % DFT_ORDER) + DFT_ORDER) % DFT_ORDER; |
| if (n == 0) return; |
| if (n == 2) { |
| |
| ltri_apply_reversal(re, im); |
| return; |
| } |
| |
| if (n == 1) { |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| dft6_forward(re, im, tmp_re, tmp_im); |
| memcpy(re, tmp_re, sizeof(tmp_re)); |
| memcpy(im, tmp_im, sizeof(tmp_im)); |
| } else { |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| dft6_inverse(re, im, tmp_re, tmp_im); |
| memcpy(re, tmp_re, sizeof(tmp_re)); |
| memcpy(im, tmp_im, sizeof(tmp_im)); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #define ORACLE_THRESHOLD 4 |
| #define D6 TRI_D |
|
|
| |
| static void mat6_identity(double R_re[D6][D6], double R_im[D6][D6]) { |
| memset(R_re, 0, sizeof(double) * D6 * D6); |
| memset(R_im, 0, sizeof(double) * D6 * D6); |
| for (int i = 0; i < D6; i++) R_re[i][i] = 1.0; |
| } |
|
|
| |
| static void mat6_mul(double C_re[D6][D6], double C_im[D6][D6], |
| const double A_re[D6][D6], const double A_im[D6][D6], |
| const double B_re[D6][D6], const double B_im[D6][D6]) { |
| double T_re[D6][D6], T_im[D6][D6]; |
| for (int i = 0; i < D6; i++) |
| for (int j = 0; j < D6; j++) { |
| double sr = 0, si = 0; |
| for (int k = 0; k < D6; k++) { |
| sr += A_re[i][k] * B_re[k][j] - A_im[i][k] * B_im[k][j]; |
| si += A_re[i][k] * B_im[k][j] + A_im[i][k] * B_re[k][j]; |
| } |
| T_re[i][j] = sr; |
| T_im[i][j] = si; |
| } |
| memcpy(C_re, T_re, sizeof(T_re)); |
| memcpy(C_im, T_im, sizeof(T_im)); |
| } |
|
|
| |
| static void mat6_pow(double R_re[D6][D6], double R_im[D6][D6], |
| const double M_re[D6][D6], const double M_im[D6][D6], |
| int n) { |
| mat6_identity(R_re, R_im); |
| if (n <= 0) return; |
| double B_re[D6][D6], B_im[D6][D6]; |
| memcpy(B_re, M_re, sizeof(B_re)); |
| memcpy(B_im, M_im, sizeof(B_im)); |
| while (n > 0) { |
| if (n & 1) |
| mat6_mul(R_re, R_im, R_re, R_im, B_re, B_im); |
| n >>= 1; |
| if (n > 0) |
| mat6_mul(B_re, B_im, B_re, B_im, B_re, B_im); |
| } |
| } |
|
|
| |
| static void mat6_vec(double out_re[D6], double out_im[D6], |
| const double M_re[D6][D6], const double M_im[D6][D6], |
| const double v_re[D6], const double v_im[D6]) { |
| for (int i = 0; i < D6; i++) { |
| double sr = 0, si = 0; |
| for (int k = 0; k < D6; k++) { |
| sr += M_re[i][k] * v_re[k] - M_im[i][k] * v_im[k]; |
| si += M_re[i][k] * v_im[k] + M_im[i][k] * v_re[k]; |
| } |
| out_re[i] = sr; |
| out_im[i] = si; |
| } |
| } |
|
|
| |
| static void mat6_build_dft(double M_re[D6][D6], double M_im[D6][D6], int n) { |
| n = ((n % DFT_ORDER) + DFT_ORDER) % DFT_ORDER; |
| mat6_identity(M_re, M_im); |
| if (n == 0) return; |
| if (n == 2) { |
| memset(M_re, 0, sizeof(double) * D6 * D6); |
| M_re[0][0] = 1.0; |
| for (int k = 1; k < D6; k++) M_re[k][D6 - k] = 1.0; |
| return; |
| } |
| const double *wr_tab = (n == 1) ? W6_RE : W6I_RE; |
| const double *wi_tab = (n == 1) ? W6_IM : W6I_IM; |
| for (int j = 0; j < D6; j++) |
| for (int k = 0; k < D6; k++) { |
| int idx = (j * k) % 6; |
| M_re[j][k] = wr_tab[idx] * INV_SQRT6; |
| M_im[j][k] = wi_tab[idx] * INV_SQRT6; |
| } |
| } |
|
|
| |
| static void mat6_build_segment(double M_re[D6][D6], double M_im[D6][D6], |
| const double *d_re, const double *d_im, |
| int pre_dfts) { |
| double F_re[D6][D6], F_im[D6][D6]; |
| mat6_build_dft(F_re, F_im, pre_dfts); |
| for (int i = 0; i < D6; i++) |
| for (int j = 0; j < D6; j++) { |
| M_re[i][j] = d_re[i] * F_re[i][j] - d_im[i] * F_im[i][j]; |
| M_im[i][j] = d_re[i] * F_im[i][j] + d_im[i] * F_re[i][j]; |
| } |
| } |
|
|
| |
| static int segments_match(const LazyTrialityQuhit *q, int a, int b) { |
| if (q->segments[a].pre_dfts != q->segments[b].pre_dfts) return 0; |
| for (int k = 0; k < D6; k++) { |
| if (q->segments[a].diag_re[k] != q->segments[b].diag_re[k]) return 0; |
| if (q->segments[a].diag_im[k] != q->segments[b].diag_im[k]) return 0; |
| } |
| return 1; |
| } |
|
|
| |
| static int detect_pattern(const LazyTrialityQuhit *q, int *start_idx) { |
| if (q->n_segments < ORACLE_THRESHOLD) return 0; |
| int all_same = 1; |
| for (int s = 2; s < q->n_segments && all_same; s++) |
| if (!segments_match(q, 1, s)) all_same = 0; |
| if (all_same && q->n_segments >= ORACLE_THRESHOLD) { |
| *start_idx = 1; |
| return 1; |
| } |
| if (q->n_segments >= ORACLE_THRESHOLD + 1) { |
| int alt_match = 1; |
| for (int s = 3; s < q->n_segments && alt_match; s++) |
| if (!segments_match(q, (s % 2 == 1) ? 1 : 2, s)) alt_match = 0; |
| if (alt_match) { |
| *start_idx = 1; |
| return 2; |
| } |
| } |
| return 0; |
| } |
|
|
| |
| |
| static void ltri_build_chain_matrix(const LazyTrialityQuhit *q, |
| double M_re[D6][D6], double M_im[D6][D6]) { |
| mat6_identity(M_re, M_im); |
| for (int s = 0; s < q->n_segments; s++) { |
| |
| double F_re[D6][D6], F_im[D6][D6]; |
| mat6_build_dft(F_re, F_im, q->segments[s].pre_dfts); |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, F_re, F_im, M_re, M_im); |
| |
| for (int i = 0; i < D6; i++) |
| for (int j = 0; j < D6; j++) { |
| double dr = q->segments[s].diag_re[i]; |
| double di = q->segments[s].diag_im[i]; |
| M_re[i][j] = dr * T_re[i][j] - di * T_im[i][j]; |
| M_im[i][j] = dr * T_im[i][j] + di * T_re[i][j]; |
| } |
| } |
| |
| if (q->trailing_dfts != 0) { |
| double F_re[D6][D6], F_im[D6][D6]; |
| mat6_build_dft(F_re, F_im, q->trailing_dfts); |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, F_re, F_im, M_re, M_im); |
| memcpy(M_re, T_re, sizeof(T_re)); |
| memcpy(M_im, T_im, sizeof(T_im)); |
| } |
| } |
|
|
| static void ltri_new_segment(LazyTrialityQuhit *q) { |
| if (q->n_segments >= MAX_LAZY_SEGMENTS) { |
| |
| |
| |
| |
| int oracle_start = 0; |
| int period = detect_pattern(q, &oracle_start); |
|
|
| if (period > 0) { |
| |
| |
| double batch_re[D6][D6], batch_im[D6][D6]; |
|
|
| if (oracle_start > 0) { |
| |
| mat6_build_segment(batch_re, batch_im, |
| q->segments[0].diag_re, q->segments[0].diag_im, |
| q->segments[0].pre_dfts); |
| } else { |
| mat6_identity(batch_re, batch_im); |
| } |
|
|
| |
| double P_re[D6][D6], P_im[D6][D6]; |
| if (period == 1) { |
| mat6_build_segment(P_re, P_im, |
| q->segments[oracle_start].diag_re, |
| q->segments[oracle_start].diag_im, |
| q->segments[oracle_start].pre_dfts); |
| } else { |
| double S1_re[D6][D6], S1_im[D6][D6]; |
| double S2_re[D6][D6], S2_im[D6][D6]; |
| mat6_build_segment(S1_re, S1_im, |
| q->segments[oracle_start].diag_re, |
| q->segments[oracle_start].diag_im, |
| q->segments[oracle_start].pre_dfts); |
| mat6_build_segment(S2_re, S2_im, |
| q->segments[oracle_start + 1].diag_re, |
| q->segments[oracle_start + 1].diag_im, |
| q->segments[oracle_start + 1].pre_dfts); |
| mat6_mul(P_re, P_im, S2_re, S2_im, S1_re, S1_im); |
| } |
|
|
| int remaining = q->n_segments - oracle_start; |
| int full_periods = remaining / period; |
|
|
| |
| double R_re[D6][D6], R_im[D6][D6]; |
| mat6_pow(R_re, R_im, P_re, P_im, full_periods); |
|
|
| |
| if (oracle_start > 0) { |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, R_re, R_im, batch_re, batch_im); |
| memcpy(batch_re, T_re, sizeof(T_re)); |
| memcpy(batch_im, T_im, sizeof(T_im)); |
| } else { |
| memcpy(batch_re, R_re, sizeof(R_re)); |
| memcpy(batch_im, R_im, sizeof(R_im)); |
| } |
|
|
| |
| int leftover_start = oracle_start + full_periods * period; |
| for (int s = leftover_start; s < q->n_segments; s++) { |
| double S_re[D6][D6], S_im[D6][D6]; |
| mat6_build_segment(S_re, S_im, |
| q->segments[s].diag_re, q->segments[s].diag_im, |
| q->segments[s].pre_dfts); |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, S_re, S_im, batch_re, batch_im); |
| memcpy(batch_re, T_re, sizeof(T_re)); |
| memcpy(batch_im, T_im, sizeof(T_im)); |
| } |
|
|
| |
| if (q->trailing_dfts != 0) { |
| double F_re[D6][D6], F_im[D6][D6]; |
| mat6_build_dft(F_re, F_im, q->trailing_dfts); |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, F_re, F_im, batch_re, batch_im); |
| memcpy(batch_re, T_re, sizeof(T_re)); |
| memcpy(batch_im, T_im, sizeof(T_im)); |
| } |
|
|
| |
| if (q->oracle_active) { |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, batch_re, batch_im, |
| q->oracle_M_re, q->oracle_M_im); |
| memcpy(q->oracle_M_re, T_re, sizeof(T_re)); |
| memcpy(q->oracle_M_im, T_im, sizeof(T_im)); |
| } else { |
| memcpy(q->oracle_M_re, batch_re, sizeof(batch_re)); |
| memcpy(q->oracle_M_im, batch_im, sizeof(batch_im)); |
| q->oracle_active = 1; |
| } |
| } else { |
| |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| ltri_materialize(q, tmp_re, tmp_im); |
| |
| } |
|
|
| q->n_segments = 0; |
| q->trailing_dfts = 0; |
| } |
| int idx = q->n_segments++; |
| ltri_diag_identity(q->segments[idx].diag_re, q->segments[idx].diag_im); |
| q->segments[idx].pre_dfts = q->trailing_dfts; |
| q->trailing_dfts = 0; |
| q->segments_created++; |
| } |
|
|
| void ltri_init(LazyTrialityQuhit *q) { |
| memset(q, 0, sizeof(*q)); |
| q->state_re[0] = 1.0; |
| } |
|
|
| void ltri_init_basis(LazyTrialityQuhit *q, int k) { |
| memset(q, 0, sizeof(*q)); |
| q->state_re[k] = 1.0; |
| } |
|
|
| static void ltri_ensure_segment(LazyTrialityQuhit *q) { |
| if (q->n_segments == 0) { |
| ltri_new_segment(q); |
| return; |
| } |
| if (q->trailing_dfts == 0) { |
| |
| return; |
| } |
| |
| ltri_new_segment(q); |
| } |
|
|
| void ltri_z(LazyTrialityQuhit *q) { |
| |
| ltri_ensure_segment(q); |
| int idx = q->n_segments - 1; |
| for (int k = 0; k < TRI_D; k++) |
| ltri_diag_mul_phase(q->segments[idx].diag_re, q->segments[idx].diag_im, |
| k, W6_RE[k], W6_IM[k]); |
| q->gates_fused++; |
| } |
|
|
| void ltri_x(LazyTrialityQuhit *q) { |
| |
| |
| |
| q->trailing_dfts = (q->trailing_dfts + 1) % DFT_ORDER; |
| ltri_ensure_segment(q); |
| int idx = q->n_segments - 1; |
| for (int k = 0; k < TRI_D; k++) |
| ltri_diag_mul_phase(q->segments[idx].diag_re, q->segments[idx].diag_im, |
| k, W6_RE[k], W6_IM[k]); |
| q->trailing_dfts = 3; |
| q->gates_fused++; |
| } |
|
|
| void ltri_shift(LazyTrialityQuhit *q, int delta) { |
| delta = ((delta % TRI_D) + TRI_D) % TRI_D; |
| if (delta == 0) return; |
| q->trailing_dfts = (q->trailing_dfts + 1) % DFT_ORDER; |
| ltri_ensure_segment(q); |
| int idx = q->n_segments - 1; |
| for (int k = 0; k < TRI_D; k++) { |
| int widx = (delta * k) % 6; |
| ltri_diag_mul_phase(q->segments[idx].diag_re, q->segments[idx].diag_im, |
| k, W6_RE[widx], W6_IM[widx]); |
| } |
| q->trailing_dfts = 3; |
| q->gates_fused++; |
| } |
|
|
| void ltri_dft(LazyTrialityQuhit *q) { |
| q->trailing_dfts = (q->trailing_dfts + 1) % DFT_ORDER; |
| q->gates_fused++; |
| } |
|
|
| void ltri_idft(LazyTrialityQuhit *q) { |
| q->trailing_dfts = (q->trailing_dfts + 3) % DFT_ORDER; |
| q->gates_fused++; |
| } |
|
|
| void ltri_phase(LazyTrialityQuhit *q, const double *phi_re, const double *phi_im) { |
| ltri_ensure_segment(q); |
| int idx = q->n_segments - 1; |
| for (int k = 0; k < TRI_D; k++) |
| ltri_diag_mul_phase(q->segments[idx].diag_re, q->segments[idx].diag_im, |
| k, phi_re[k], phi_im[k]); |
| q->gates_fused++; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| static void ltri_compact_chain(LazyTrialityQuhit *q) { |
| if (q->n_segments <= 1) return; |
| int dst = 0; |
| for (int src = 1; src < q->n_segments; src++) { |
| if (q->segments[src].pre_dfts == 0) { |
| |
| ltri_diag_mul(q->segments[dst].diag_re, q->segments[dst].diag_im, |
| q->segments[src].diag_re, q->segments[src].diag_im); |
| } else { |
| |
| dst++; |
| if (dst != src) { |
| memcpy(&q->segments[dst], &q->segments[src], sizeof(q->segments[0])); |
| } |
| } |
| } |
| q->n_segments = dst + 1; |
| } |
|
|
|
|
| |
| |
| |
|
|
| void ltri_materialize(LazyTrialityQuhit *q, double *out_re, double *out_im) { |
| |
| ltri_compact_chain(q); |
|
|
| double cur_re[TRI_D], cur_im[TRI_D]; |
| memcpy(cur_re, q->state_re, sizeof(cur_re)); |
| memcpy(cur_im, q->state_im, sizeof(cur_im)); |
|
|
| |
| if (q->oracle_active) { |
| |
| if (q->n_segments > 0 || q->trailing_dfts != 0) { |
| double tail_re[D6][D6], tail_im[D6][D6]; |
| ltri_build_chain_matrix(q, tail_re, tail_im); |
| double T_re[D6][D6], T_im[D6][D6]; |
| mat6_mul(T_re, T_im, tail_re, tail_im, |
| q->oracle_M_re, q->oracle_M_im); |
| mat6_vec(out_re, out_im, T_re, T_im, cur_re, cur_im); |
| } else { |
| mat6_vec(out_re, out_im, q->oracle_M_re, q->oracle_M_im, |
| cur_re, cur_im); |
| } |
| |
| memcpy(q->state_re, out_re, sizeof(q->state_re)); |
| memcpy(q->state_im, out_im, sizeof(q->state_im)); |
| q->oracle_active = 0; |
| q->n_segments = 0; |
| q->trailing_dfts = 0; |
| q->materializations++; |
| return; |
| } |
|
|
| |
| int oracle_start = 0; |
| int period = detect_pattern(q, &oracle_start); |
|
|
| if (period > 0 && (q->n_segments - oracle_start) >= ORACLE_THRESHOLD) { |
| |
| for (int s = 0; s < oracle_start; s++) { |
| ltri_apply_n_dfts(cur_re, cur_im, q->segments[s].pre_dfts); |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| ltri_apply_diag(q->segments[s].diag_re, q->segments[s].diag_im, |
| cur_re, cur_im, tmp_re, tmp_im); |
| memcpy(cur_re, tmp_re, sizeof(cur_re)); |
| memcpy(cur_im, tmp_im, sizeof(cur_im)); |
| } |
|
|
| |
| double P_re[D6][D6], P_im[D6][D6]; |
| if (period == 1) { |
| mat6_build_segment(P_re, P_im, |
| q->segments[oracle_start].diag_re, |
| q->segments[oracle_start].diag_im, |
| q->segments[oracle_start].pre_dfts); |
| } else { |
| double S1_re[D6][D6], S1_im[D6][D6]; |
| double S2_re[D6][D6], S2_im[D6][D6]; |
| mat6_build_segment(S1_re, S1_im, |
| q->segments[oracle_start].diag_re, |
| q->segments[oracle_start].diag_im, |
| q->segments[oracle_start].pre_dfts); |
| mat6_build_segment(S2_re, S2_im, |
| q->segments[oracle_start + 1].diag_re, |
| q->segments[oracle_start + 1].diag_im, |
| q->segments[oracle_start + 1].pre_dfts); |
| mat6_mul(P_re, P_im, S2_re, S2_im, S1_re, S1_im); |
| } |
|
|
| int remaining = q->n_segments - oracle_start; |
| int full_periods = remaining / period; |
|
|
| double R_re[D6][D6], R_im[D6][D6]; |
| mat6_pow(R_re, R_im, P_re, P_im, full_periods); |
|
|
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| mat6_vec(tmp_re, tmp_im, R_re, R_im, cur_re, cur_im); |
| memcpy(cur_re, tmp_re, sizeof(cur_re)); |
| memcpy(cur_im, tmp_im, sizeof(cur_im)); |
|
|
| int leftover_start = oracle_start + full_periods * period; |
| for (int s = leftover_start; s < q->n_segments; s++) { |
| ltri_apply_n_dfts(cur_re, cur_im, q->segments[s].pre_dfts); |
| double tmp2_re[TRI_D], tmp2_im[TRI_D]; |
| ltri_apply_diag(q->segments[s].diag_re, q->segments[s].diag_im, |
| cur_re, cur_im, tmp2_re, tmp2_im); |
| memcpy(cur_re, tmp2_re, sizeof(cur_re)); |
| memcpy(cur_im, tmp2_im, sizeof(cur_im)); |
| } |
| } else { |
| |
| for (int s = 0; s < q->n_segments; s++) { |
| ltri_apply_n_dfts(cur_re, cur_im, q->segments[s].pre_dfts); |
| double tmp_re[TRI_D], tmp_im[TRI_D]; |
| ltri_apply_diag(q->segments[s].diag_re, q->segments[s].diag_im, |
| cur_re, cur_im, tmp_re, tmp_im); |
| memcpy(cur_re, tmp_re, sizeof(cur_re)); |
| memcpy(cur_im, tmp_im, sizeof(cur_im)); |
| } |
| } |
|
|
| ltri_apply_n_dfts(cur_re, cur_im, q->trailing_dfts); |
|
|
| memcpy(out_re, cur_re, sizeof(cur_re)); |
| memcpy(out_im, cur_im, sizeof(cur_im)); |
| |
| memcpy(q->state_re, out_re, sizeof(q->state_re)); |
| memcpy(q->state_im, out_im, sizeof(q->state_im)); |
| q->n_segments = 0; |
| q->trailing_dfts = 0; |
| q->materializations++; |
| } |
|
|
| int ltri_measure(LazyTrialityQuhit *q, int view, uint64_t *rng_state) { |
| double amp_re[TRI_D], amp_im[TRI_D]; |
| ltri_materialize(q, amp_re, amp_im); |
|
|
| if (view != VIEW_EDGE) { |
| int steps = ((view - VIEW_EDGE) % DFT_ORDER + DFT_ORDER) % DFT_ORDER; |
| ltri_apply_n_dfts(amp_re, amp_im, steps); |
| } |
|
|
| double probs[TRI_D], total = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| probs[k] = amp_re[k]*amp_re[k] + amp_im[k]*amp_im[k]; |
| total += probs[k]; |
| } |
| if (total > 1e-30) |
| for (int k = 0; k < TRI_D; k++) probs[k] /= total; |
|
|
| double r = triality_rng_double(rng_state); |
| int outcome = 0; |
| double cdf = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| cdf += probs[k]; |
| if (r < cdf) { outcome = k; break; } |
| } |
|
|
| memset(q->state_re, 0, sizeof(q->state_re)); |
| memset(q->state_im, 0, sizeof(q->state_im)); |
| q->state_re[outcome] = 1.0; |
| q->n_segments = 0; |
| q->trailing_dfts = 0; |
|
|
| return outcome; |
| } |
|
|
| void ltri_stats_print(const LazyTrialityQuhit *q) { |
| printf("\n βββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n"); |
| printf(" β LAZY TRIALITY STATISTICS β\n"); |
| printf(" βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€\n"); |
| printf(" β Gates fused: %8lu β\n", (unsigned long)q->gates_fused); |
| printf(" β Segments created: %8lu β\n", (unsigned long)q->segments_created); |
| printf(" β Current segments: %8d / %d β\n", q->n_segments, MAX_LAZY_SEGMENTS); |
| printf(" β Trailing DFTs: %8d β\n", q->trailing_dfts); |
| printf(" β Materializations: %8lu β\n", (unsigned long)q->materializations); |
| double fusion_ratio = (q->segments_created > 0) ? |
| (double)q->gates_fused / q->segments_created : 0; |
| printf(" β Fusion ratio: %8.1f gates/segment β\n", fusion_ratio); |
| printf(" βββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n"); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| void triality_exotic_init(void) { |
| s6_exotic_init(); |
| } |
|
|
| void triality_set_exotic_syntheme(TrialityQuhit *q, int syntheme_idx) { |
| if (syntheme_idx < 0 || syntheme_idx >= S6_NUM_SYNTHEMES) |
| syntheme_idx = 0; |
| q->exotic_syntheme = syntheme_idx; |
| q->dirty |= DIRTY_EXOTIC; |
| } |
|
|
| |
| |
| |
|
|
| void triality_fold_syntheme(TrialityQuhit *q, int syntheme_idx) { |
| triality_ensure_view(q, VIEW_EDGE); |
| s6_fold_syntheme(q->edge_re, q->edge_im, |
| q->exotic_re, q->exotic_im, |
| syntheme_idx); |
| q->exotic_syntheme = syntheme_idx; |
| q->dirty &= ~DIRTY_EXOTIC; |
| triality_stats.exotic_folds++; |
| } |
|
|
| void triality_unfold_syntheme(TrialityQuhit *q, int syntheme_idx) { |
| |
| s6_unfold_syntheme(q->exotic_re, q->exotic_im, |
| q->edge_re, q->edge_im, |
| syntheme_idx); |
| q->primary = VIEW_EDGE; |
| q->dirty = DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_EXOTIC; |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->delta_valid = 0; |
| triality_stats.exotic_folds++; |
| } |
|
|
| |
| |
| |
|
|
| void triality_exotic_gate(TrialityQuhit *q, S6Perm sigma) { |
| triality_ensure_view(q, VIEW_EDGE); |
| double out_re[TRI_D], out_im[TRI_D]; |
| s6_apply_exotic_gate(q->edge_re, q->edge_im, |
| out_re, out_im, sigma); |
| memcpy(q->edge_re, out_re, sizeof(out_re)); |
| memcpy(q->edge_im, out_im, sizeof(out_im)); |
|
|
| q->primary = VIEW_EDGE; |
| q->dirty |= DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_EXOTIC; |
| q->real_valued = 0; |
| q->eigenstate_class = -1; |
| q->active_mask = 0x3F; q->active_count = 6; |
| q->delta_valid = 0; |
| triality_stats.exotic_gates++; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| double triality_cz_dual(TrialityQuhit *a, TrialityQuhit *b) { |
| |
| triality_cz(a, b); |
|
|
| |
| |
| |
| |
| |
| triality_ensure_view(a, VIEW_EDGE); |
| triality_ensure_view(b, VIEW_EDGE); |
|
|
| double delta_a = s6_exotic_invariant(a->edge_re, a->edge_im); |
| double delta_b = s6_exotic_invariant(b->edge_re, b->edge_im); |
|
|
| |
| a->cached_delta = delta_a; |
| a->delta_valid = 1; |
| b->cached_delta = delta_b; |
| b->delta_valid = 1; |
|
|
| return (delta_a + delta_b) / 2.0; |
| } |
|
|
| |
| |
| |
| |
|
|
| int triality_measure_exotic(TrialityQuhit *q, int syntheme_idx, uint64_t *rng_state) { |
| |
| triality_fold_syntheme(q, syntheme_idx); |
|
|
| |
| double probs[TRI_D]; |
| double total = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| probs[k] = q->exotic_re[k]*q->exotic_re[k] |
| + q->exotic_im[k]*q->exotic_im[k]; |
| total += probs[k]; |
| } |
| if (total > 1e-30) |
| for (int k = 0; k < TRI_D; k++) probs[k] /= total; |
|
|
| |
| uint64_t x = *rng_state; |
| x ^= x << 13; x ^= x >> 7; x ^= x << 17; |
| *rng_state = x; |
| double r = (x >> 11) * 0x1.0p-53; |
|
|
| int outcome = TRI_D - 1; |
| double cdf = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| cdf += probs[k]; |
| if (r < cdf) { outcome = k; break; } |
| } |
|
|
| |
| double win_re = q->exotic_re[outcome], win_im = q->exotic_im[outcome]; |
| double norm2 = win_re*win_re + win_im*win_im; |
| double scale = (norm2 > 1e-30) ? 1.0 / sqrt(norm2) : 0.0; |
|
|
| for (int k = 0; k < TRI_D; k++) { |
| q->exotic_re[k] = 0; |
| q->exotic_im[k] = 0; |
| } |
| q->exotic_re[outcome] = win_re * scale; |
| q->exotic_im[outcome] = win_im * scale; |
|
|
| |
| triality_unfold_syntheme(q, syntheme_idx); |
|
|
| triality_stats.exotic_folds++; |
| return outcome; |
| } |
|
|
| |
| |
| |
| |
|
|
| int triality_measure_dual(TrialityQuhit *q, int view, int exotic_syntheme, |
| uint64_t *rng_state, int *exotic_outcome) { |
| |
| triality_ensure_view(q, VIEW_EDGE); |
| double exo_fold_re[TRI_D], exo_fold_im[TRI_D]; |
| s6_fold_syntheme(q->edge_re, q->edge_im, |
| exo_fold_re, exo_fold_im, |
| exotic_syntheme); |
|
|
| double exo_probs[TRI_D]; |
| double total = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| exo_probs[k] = exo_fold_re[k]*exo_fold_re[k] |
| + exo_fold_im[k]*exo_fold_im[k]; |
| total += exo_probs[k]; |
| } |
| if (total > 1e-30) |
| for (int k = 0; k < TRI_D; k++) exo_probs[k] /= total; |
|
|
| |
| uint64_t rng_copy = *rng_state; |
| uint64_t x = rng_copy; |
| x ^= x << 13; x ^= x >> 7; x ^= x << 17; |
| rng_copy = x; |
| double r_exo = (x >> 11) * 0x1.0p-53; |
|
|
| int exo_out = TRI_D - 1; |
| double cdf = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| cdf += exo_probs[k]; |
| if (r_exo < cdf) { exo_out = k; break; } |
| } |
| if (exotic_outcome) *exotic_outcome = exo_out; |
|
|
| |
| int std_out = triality_measure(q, view, rng_state); |
|
|
| triality_stats.dual_measurements++; |
| return std_out; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| void triality_rotate_exotic(TrialityQuhit *q) { |
| |
| triality_rotate(q); |
|
|
| |
| int current = q->exotic_syntheme; |
|
|
| |
| if (!s6_exotic_ready) s6_exotic_init(); |
|
|
| int my_total = -1, my_pos = -1; |
| for (int t = 0; t < S6_NUM_TOTALS && my_total < 0; t++) { |
| for (int j = 0; j < 5; j++) { |
| if (s6_totals[t][j] == current) { |
| my_total = t; |
| my_pos = j; |
| break; |
| } |
| } |
| } |
|
|
| if (my_total >= 0) { |
| |
| int next_pos = (my_pos + 1) % 5; |
| q->exotic_syntheme = s6_totals[my_total][next_pos]; |
| } |
|
|
| q->dirty |= DIRTY_EXOTIC; |
| } |
|
|
| |
| |
| |
|
|
| void triality_dual_probabilities(TrialityQuhit *q, int view, |
| double *probs_std, double *probs_exo) { |
| |
| triality_probabilities(q, view, probs_std); |
|
|
| |
| triality_ensure_view(q, VIEW_EDGE); |
| double fold_re[TRI_D], fold_im[TRI_D]; |
| s6_fold_syntheme(q->edge_re, q->edge_im, |
| fold_re, fold_im, |
| q->exotic_syntheme); |
|
|
| double total = 0; |
| for (int k = 0; k < TRI_D; k++) { |
| probs_exo[k] = fold_re[k]*fold_re[k] + fold_im[k]*fold_im[k]; |
| total += probs_exo[k]; |
| } |
| if (total > 1e-30) |
| for (int k = 0; k < TRI_D; k++) probs_exo[k] /= total; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| void triality_invalidate_exotic_cache(TrialityQuhit *q) { |
| q->delta_valid = 0; |
| } |
|
|
| double triality_exotic_invariant_cached(TrialityQuhit *q) { |
| if (q->delta_valid) return q->cached_delta; |
|
|
| triality_ensure_view(q, VIEW_EDGE); |
| q->cached_delta = s6_exotic_invariant(q->edge_re, q->edge_im); |
|
|
| |
| s6_exotic_fingerprint(q->edge_re, q->edge_im, q->cached_fingerprint); |
|
|
| q->delta_valid = 1; |
| return q->cached_delta; |
| } |
|
|
| void triality_exotic_fingerprint_cached(TrialityQuhit *q, double *deltas) { |
| if (q->delta_valid) { |
| |
| memcpy(deltas, q->cached_fingerprint, 11 * sizeof(double)); |
| return; |
| } |
|
|
| triality_ensure_view(q, VIEW_EDGE); |
| s6_exotic_fingerprint(q->edge_re, q->edge_im, deltas); |
| q->cached_delta = s6_exotic_invariant(q->edge_re, q->edge_im); |
| memcpy(q->cached_fingerprint, deltas, 11 * sizeof(double)); |
| q->delta_valid = 1; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| void ltri_force_materialize(LazyTrialityQuhit *lq, TrialityQuhit *out) { |
| double edge_re[TRI_D], edge_im[TRI_D]; |
| ltri_materialize(lq, edge_re, edge_im); |
|
|
| |
| memset(out, 0, sizeof(TrialityQuhit)); |
| memcpy(out->edge_re, edge_re, sizeof(edge_re)); |
| memcpy(out->edge_im, edge_im, sizeof(edge_im)); |
| out->primary = VIEW_EDGE; |
| out->dirty = DIRTY_VERTEX | DIRTY_DIAGONAL | DIRTY_FOLDED | DIRTY_EXOTIC; |
| out->eigenstate_class = -1; |
| out->delta_valid = 0; |
|
|
| |
| uint8_t mask = 0; |
| int count = 0; |
| int is_real = 1; |
| for (int k = 0; k < TRI_D; k++) { |
| double mag2 = edge_re[k] * edge_re[k] + edge_im[k] * edge_im[k]; |
| if (mag2 > 1e-30) { |
| mask |= (uint8_t)(1 << k); |
| count++; |
| } |
| if (fabs(edge_im[k]) > 1e-15) is_real = 0; |
| } |
| out->active_mask = mask; |
| out->active_count = (uint8_t)count; |
| out->real_valued = (uint8_t)is_real; |
| } |
|
|