File size: 21,483 Bytes
07b428c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
/*
 * quhit_hexagram.c β€” The Hexagram Quhit Implementation
 *
 * Edge-dual of the triality quhit. Amplitudes on hexagram line segments.
 *
 * The H₆ transform is derived from the body-diagonal projection of the
 * cube's face diagonals. Each hexagram line β„“β‚– corresponds to specific
 * face diagonals that project onto that line when viewed from (1,1,1).
 *
 * Cube vertex labels (Cubeee.html convention):
 *   0:(-1,-1,-1)  1:(+1,-1,-1)  2:(+1,+1,-1)  3:(-1,+1,-1)
 *   4:(-1,-1,+1)  5:(+1,-1,+1)  6:(+1,+1,+1)  7:(-1,+1,+1)
 *
 * Body-diagonal projection from (1,1,1), projected positions:
 *   0,6 β†’ center (body diagonal endpoints)
 *   1 β†’ (√2, 0)          β‰ˆ right
 *   2 β†’ (1/√2, √(3/2))   β‰ˆ upper-right
 *   3 β†’ (-1/√2, √(3/2))  β‰ˆ upper-left
 *   4 β†’ (-√2, 0)          β‰ˆ left
 *   5 β†’ (-1/√2, -√(3/2)) β‰ˆ lower-left  (wasn't this wrong? No...)
 *   ... Wait, let me use the quhit basis states directly.
 *
 * ── Mapping from quhit basis states to hexagram lines ──
 *
 * The 6 basis states |0⟩...|5⟩ map to the CMY channel structure:
 *   C: {|0⟩, |1⟩} = ±X face pair
 *   M: {|2⟩, |3⟩} = ±Y face pair
 *   Y: {|4⟩, |5⟩} = ±Z face pair
 *
 * Each face has 2 diagonals. Under body-diagonal projection:
 *   Face diagonals within channel k map to hexagram lines.
 *   The specific mapping depends on which cube vertices the
 *   face diagonals connect and how they project.
 *
 * The H₆ matrix encodes: for each hexagram line β„“β‚–, which
 * superposition of basis states |j⟩ contributes amplitude.
 *
 * ── Derivation of H₆ ──
 *
 * The 6 hexagram lines alternate: diameter, outer, diameter, outer, ...
 *
 * A DIAMETER line passes through the center. In the cube, this
 * corresponds to two face diagonals from opposite faces of the same
 * axis that project onto the same line through center. These combine
 * the vesica (sum) and wave (difference) of the antipodal pair.
 *
 * An OUTER line connects two adjacent hexagram vertices. This
 * corresponds to a single face diagonal from a different axis that
 * connects the projected positions of two non-antipodal vertices.
 *
 * For each hexagram line β„“β‚–, H₆[k][j] gives the contribution of
 * vertex basis state |j⟩. The matrix is constructed so that:
 *
 *   Diameters:  β„“β‚€ combines C-channel pair {|0⟩,|1⟩} antisymmetrically
 *               β„“β‚‚ combines M-channel pair {|2⟩,|3⟩} antisymmetrically
 *               β„“β‚„ combines Y-channel pair {|4⟩,|5⟩} antisymmetrically
 *
 *   Outers:     ℓ₁ combines a cross-channel pair from Y and M
 *               ℓ₃ combines a cross-channel pair from C and Y
 *               β„“β‚… combines a cross-channel pair from M and C
 *
 * The specific coefficients ensure unitarity and encode the 120Β°
 * rotational symmetry of the body-diagonal view (C→M→Y→C cycling).
 *
 * The eigenbasis structure: diameters are channel-internal (sum/diff
 * within a pair), outers are channel-crossing (linking adjacent
 * channels). This 3+3 partition mirrors the unicursal path's
 * alternating diameter/outer structure.
 */

#include <string.h>
#include <math.h>
#include <stdio.h>
#include "quhit_hexagram.h"

/* ═══════════════════════════════════════════════════════════════════════
 * CONSTANTS
 * ═══════════════════════════════════════════════════════════════════════ */

static const double INV_SQRT2 = 0.70710678118654752440;
static const double INV_SQRT3 = 0.57735026918962576451;
static const double INV_SQRT6 = 0.40824829046386301637;

/* ω₃ = e^{2Ο€i/3} = -1/2 + i√3/2 */
static const double W3_RE = -0.5;
static const double W3_IM =  0.86602540378443864676;

/* ω₆ = e^{2Ο€i/6} = 1/2 + i√3/2 */
static const double W6_RE =  0.5;
static const double W6_IM =  0.86602540378443864676;

/* Line metadata (static) */
static const int LINE_TYPES[6] = {
    LINE_DIAMETER, LINE_OUTER,
    LINE_DIAMETER, LINE_OUTER,
    LINE_DIAMETER, LINE_OUTER
};

/* CMY color assignment per line:
 * β„“β‚€=C(0), ℓ₁=Y(2), β„“β‚‚=M(1), ℓ₃=C(0), β„“β‚„=Y(2), β„“β‚…=M(1)
 * Pattern: C, Y, M, C, Y, M β€” triality cycling with 120Β° offset */
static const int LINE_COLORS[6] = { 0, 2, 1, 0, 2, 1 };

static const char *LINE_NAMES[6] = {
    "l0 diam C", "l1 outr Y", "l2 diam M",
    "l3 outr C", "l4 diam Y", "l5 outr M"
};

/* ═══════════════════════════════════════════════════════════════════════
 * H₆ TRANSFORM MATRICES
 *
 * H₆ maps vertex basis |j⟩ β†’ hexagram line basis |β„“β‚–βŸ©.
 *
 * Structure (6Γ—6 unitary):
 *
 *   Diameters (rows 0,2,4) = channel-pair DIFFERENCES (wave):
 *     β„“β‚€ = (|0⟩ - |1⟩)/√2     [C channel difference]
 *     β„“β‚‚ = (|2⟩ - |3⟩)/√2     [M channel difference]
 *     β„“β‚„ = (|4⟩ - |5⟩)/√2     [Y channel difference]
 *
 *   Outers (rows 1,3,5) = DFT₃-weighted channel SUMS (vesica):
 *     Let s_c = (|2c⟩ + |2c+1⟩)/√2 for channel c ∈ {0,1,2}
 *     Then:
 *     ℓ₁ = (sβ‚€ + s₁ + sβ‚‚)/√3         = (1,1,1,1,1,1)/√6
 *     ℓ₃ = (sβ‚€ + ω₃·s₁ + ω₃²·sβ‚‚)/√3
 *     β„“β‚… = (sβ‚€ + ω₃²·s₁ + ω₃·sβ‚‚)/√3
 *
 * Orthogonality proof:
 *   Diameter βŠ₯ Outer: within each channel pair (2c, 2c+1),
 *     diameter has (+1,-1)/√2, outer has (+x,+x)/√2.
 *     Inner product per pair: x - x = 0. βœ“
 *   Outer βŠ₯ Outer: DFT₃ rows are orthogonal (1+ω₃+ω₃²=0). βœ“
 *   Diameter βŠ₯ Diameter: non-overlapping channel pairs. βœ“
 *
 * This is the Cooley-Tukey DFT₆ = DFTβ‚‚ βŠ— DFT₃:
 *   DFTβ‚‚ within each channel β†’ difference (diameter) + sum (outer)
 *   DFT₃ across the 3 sums β†’ the 3 outer lines with ω₃ phases
 * ═══════════════════════════════════════════════════════════════════════ */

double H6_re[HEX_D][HEX_D];
double H6_im[HEX_D][HEX_D];
double H6_adj_re[HEX_D][HEX_D];
double H6_adj_im[HEX_D][HEX_D];

void hexagram_init_tables(void) {
    memset(H6_re, 0, sizeof(H6_re));
    memset(H6_im, 0, sizeof(H6_im));

    /* ω₃ powers: ω₃^0=1, ω₃^1=(-1+i√3)/2, ω₃^2=(-1-i√3)/2 */
    const double w3r[3] = { 1.0,  W3_RE,  W3_RE };
    const double w3i[3] = { 0.0,  W3_IM, -W3_IM };

    /* ── Diameter rows: (|2c⟩ - |2c+1⟩)/√2 ── */
    for (int d = 0; d < 3; d++) {
        int row = 2 * d;        /* rows 0, 2, 4 */
        int c0 = 2 * d;         /* first column of channel pair */
        H6_re[row][c0]     =  INV_SQRT2;
        H6_re[row][c0 + 1] = -INV_SQRT2;
    }

    /* ── Outer rows: Ξ£_c ω₃^(rΒ·c) Β· (|2c⟩ + |2c+1⟩) / √6 ── */
    for (int r = 0; r < 3; r++) {
        int row = 2 * r + 1;    /* rows 1, 3, 5 */
        for (int c = 0; c < 3; c++) {
            int idx = (r * c) % 3;      /* ω₃ exponent */
            double wr = w3r[idx] * INV_SQRT6;
            double wi = w3i[idx] * INV_SQRT6;
            /* Both elements of channel c get the same coefficient */
            H6_re[row][2*c]     = wr;  H6_im[row][2*c]     = wi;
            H6_re[row][2*c + 1] = wr;  H6_im[row][2*c + 1] = wi;
        }
    }

    /* Compute H₆† (conjugate transpose) */
    for (int i = 0; i < HEX_D; i++) {
        for (int j = 0; j < HEX_D; j++) {
            H6_adj_re[i][j] =  H6_re[j][i];
            H6_adj_im[i][j] = -H6_im[j][i];
        }
    }
}

/* ═══════════════════════════════════════════════════════════════════════
 * TRANSFORM PRIMITIVES
 * ═══════════════════════════════════════════════════════════════════════ */

/* Apply H₆: vertex β†’ hexagram */
static void apply_H6(const double *in_re, const double *in_im,
                     double *out_re, double *out_im)
{
    for (int k = 0; k < HEX_D; k++) {
        double sr = 0, si = 0;
        for (int j = 0; j < HEX_D; j++) {
            double hr = H6_re[k][j], hi = H6_im[k][j];
            sr += hr * in_re[j] - hi * in_im[j];
            si += hr * in_im[j] + hi * in_re[j];
        }
        out_re[k] = sr;
        out_im[k] = si;
    }
}

/* Apply H₆†: hexagram β†’ vertex */
static void apply_H6_adj(const double *in_re, const double *in_im,
                          double *out_re, double *out_im)
{
    for (int j = 0; j < HEX_D; j++) {
        double sr = 0, si = 0;
        for (int k = 0; k < HEX_D; k++) {
            double hr = H6_adj_re[j][k], hi = H6_adj_im[j][k];
            sr += hr * in_re[k] - hi * in_im[k];
            si += hr * in_im[k] + hi * in_re[k];
        }
        out_re[j] = sr;
        out_im[j] = si;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
 * LIFECYCLE
 * ═══════════════════════════════════════════════════════════════════════ */

void hexagram_init(HexagramQuhit *q) {
    memset(q, 0, sizeof(HexagramQuhit));
    q->line_re[0] = 1.0;  /* |β„“β‚€βŸ© */
    q->chirality = CHIRALITY_POS;
    q->vertex_dirty = 1;
}

void hexagram_init_from_vertex(HexagramQuhit *q,
                               const double *vert_re, const double *vert_im,
                               int chirality)
{
    memset(q, 0, sizeof(HexagramQuhit));
    q->chirality = chirality;

    /* Apply H₆ to convert vertex β†’ hexagram */
    apply_H6(vert_re, vert_im, q->line_re, q->line_im);

    /* Cache the vertex representation */
    memcpy(q->vertex_re, vert_re, HEX_D * sizeof(double));
    memcpy(q->vertex_im, vert_im, HEX_D * sizeof(double));
    q->vertex_dirty = 0;
}

void hexagram_init_line(HexagramQuhit *q, int k, int chirality) {
    memset(q, 0, sizeof(HexagramQuhit));
    q->line_re[k] = 1.0;
    q->chirality = chirality;
    q->vertex_dirty = 1;
}

/* ═══════════════════════════════════════════════════════════════════════
 * NATIVE HEXAGRAM GATES
 * ═══════════════════════════════════════════════════════════════════════ */

void hexagram_path_shift(HexagramQuhit *q, int delta) {
    delta = ((delta % HEX_D) + HEX_D) % HEX_D;
    if (delta == 0) return;

    /* Cyclic permutation of line amplitudes */
    double tmp_re[HEX_D], tmp_im[HEX_D];
    for (int k = 0; k < HEX_D; k++) {
        int src = (k - delta + HEX_D) % HEX_D;
        tmp_re[k] = q->line_re[src];
        tmp_im[k] = q->line_im[src];
    }
    memcpy(q->line_re, tmp_re, sizeof(tmp_re));
    memcpy(q->line_im, tmp_im, sizeof(tmp_im));
    q->vertex_dirty = 1;
}

void hexagram_phase(HexagramQuhit *q, const double *phi_re, const double *phi_im) {
    for (int k = 0; k < HEX_D; k++) {
        double re = q->line_re[k], im = q->line_im[k];
        q->line_re[k] = re * phi_re[k] - im * phi_im[k];
        q->line_im[k] = re * phi_im[k] + im * phi_re[k];
    }
    q->vertex_dirty = 1;
}

void hexagram_diameter_phase(HexagramQuhit *q, double phi_re, double phi_im) {
    /* Apply phase only to diameter lines: β„“β‚€, β„“β‚‚, β„“β‚„ */
    for (int k = 0; k < HEX_D; k += 2) {
        double re = q->line_re[k], im = q->line_im[k];
        q->line_re[k] = re * phi_re - im * phi_im;
        q->line_im[k] = re * phi_im + im * phi_re;
    }
    q->vertex_dirty = 1;
}

void hexagram_outer_phase(HexagramQuhit *q, double phi_re, double phi_im) {
    /* Apply phase only to outer lines: ℓ₁, ℓ₃, β„“β‚… */
    for (int k = 1; k < HEX_D; k += 2) {
        double re = q->line_re[k], im = q->line_im[k];
        q->line_re[k] = re * phi_re - im * phi_im;
        q->line_im[k] = re * phi_im + im * phi_re;
    }
    q->vertex_dirty = 1;
}

void hexagram_flip(HexagramQuhit *q) {
    /* Chirality flip: reverse path orientation.
     * |β„“β‚–, +⟩ β†’ |β„“_{5-k}, -⟩
     * Also complex-conjugates amplitudes (time reversal). */
    double tmp_re[HEX_D], tmp_im[HEX_D];
    for (int k = 0; k < HEX_D; k++) {
        tmp_re[k] =  q->line_re[5 - k];
        tmp_im[k] = -q->line_im[5 - k];  /* conjugation */
    }
    memcpy(q->line_re, tmp_re, sizeof(tmp_re));
    memcpy(q->line_im, tmp_im, sizeof(tmp_im));
    q->chirality = -q->chirality;
    q->vertex_dirty = 1;
}

void hexagram_triad(HexagramQuhit *q) {
    /* Triad gate: cyclic permutation of the 3 diameter/outer pairs.
     * ℓ₀→ℓ₂→ℓ₄→ℓ₀ (diameters: C→M→Y→C)
     * ℓ₁→ℓ₃→ℓ₅→ℓ₁ (outers: Yβ†’Cβ†’Mβ†’Y)
     * This is the Ο†-image of triality_rotate. */
    double d0_re = q->line_re[0], d0_im = q->line_im[0];
    double o0_re = q->line_re[1], o0_im = q->line_im[1];

    q->line_re[0] = q->line_re[4]; q->line_im[0] = q->line_im[4];
    q->line_re[1] = q->line_re[5]; q->line_im[1] = q->line_im[5];
    q->line_re[4] = q->line_re[2]; q->line_im[4] = q->line_im[2];
    q->line_re[5] = q->line_re[3]; q->line_im[5] = q->line_im[3];
    q->line_re[2] = d0_re;         q->line_im[2] = d0_im;
    q->line_re[3] = o0_re;         q->line_im[3] = o0_im;

    q->vertex_dirty = 1;
}

void hexagram_triad_inv(HexagramQuhit *q) {
    /* Inverse: β„“β‚€β†’β„“β‚„β†’β„“β‚‚β†’β„“β‚€, ℓ₁→ℓ₅→ℓ₃→ℓ₁ */
    double d0_re = q->line_re[0], d0_im = q->line_im[0];
    double o0_re = q->line_re[1], o0_im = q->line_im[1];

    q->line_re[0] = q->line_re[2]; q->line_im[0] = q->line_im[2];
    q->line_re[1] = q->line_re[3]; q->line_im[1] = q->line_im[3];
    q->line_re[2] = q->line_re[4]; q->line_im[2] = q->line_im[4];
    q->line_re[3] = q->line_re[5]; q->line_im[3] = q->line_im[5];
    q->line_re[4] = d0_re;         q->line_im[4] = d0_im;
    q->line_re[5] = o0_re;         q->line_im[5] = o0_im;

    q->vertex_dirty = 1;
}

/* ═══════════════════════════════════════════════════════════════════════
 * ENTANGLEMENT β€” Center-crossing interaction
 *
 * The hexagrammatic CZ: diameters (β„“β‚€,β„“β‚‚,β„“β‚„) all pass through center.
 * When two hexagram quhits have diameter amplitude, they interfere
 * at the center crossing. The phase coupling is:
 *
 *   Ο‰^(d_a Β· d_b)  where d_a, d_b ∈ {0,1,2} are the diameter indices
 *
 * Outer lines (ℓ₁,ℓ₃,β„“β‚…) do not pass through center β†’ no coupling.
 * ═══════════════════════════════════════════════════════════════════════ */

void hexagram_cross(HexagramQuhit *a, HexagramQuhit *b) {
    /* ω₃ roots: ω₃^0=1, ω₃^1=(-1+i√3)/2, ω₃^2=(-1-i√3)/2 */
    static const double W3R[3] = {1.0, -0.5, -0.5};
    static const double W3I[3] = {0.0, 0.86602540378443864676, -0.86602540378443864676};

    /* Diameter indices: β„“β‚€β†’d0, β„“β‚‚β†’d1, β„“β‚„β†’d2 */
    /* Map line index to diameter index: k/2 for even k */

    /* Compute effective phases from partner's diameter amplitudes */
    /* For each diameter d_a of qubit a, the effective phase is:
     * eff_a[d_a] = Ξ£_{d_b} |b[2Β·d_b]|Β² Β· ω₃^(d_a Β· d_b) */
    for (int da = 0; da < 3; da++) {
        int ka = 2 * da;  /* line index */
        double eff_re = 0, eff_im = 0;
        for (int db = 0; db < 3; db++) {
            int kb = 2 * db;
            double bprob = b->line_re[kb]*b->line_re[kb] + b->line_im[kb]*b->line_im[kb];
            int idx = (da * db) % 3;
            eff_re += bprob * W3R[idx];
            eff_im += bprob * W3I[idx];
        }
        /* Apply effective phase to a's diameter amplitude */
        double re = a->line_re[ka], im = a->line_im[ka];
        a->line_re[ka] = re * eff_re - im * eff_im;
        a->line_im[ka] = re * eff_im + im * eff_re;
    }

    /* Same for qubit b */
    for (int db = 0; db < 3; db++) {
        int kb = 2 * db;
        double eff_re = 0, eff_im = 0;
        for (int da = 0; da < 3; da++) {
            int ka = 2 * da;
            double aprob = a->line_re[ka]*a->line_re[ka] + a->line_im[ka]*a->line_im[ka];
            int idx = (da * db) % 3;
            eff_re += aprob * W3R[idx];
            eff_im += aprob * W3I[idx];
        }
        double re = b->line_re[kb], im = b->line_im[kb];
        b->line_re[kb] = re * eff_re - im * eff_im;
        b->line_im[kb] = re * eff_im + im * eff_re;
    }

    /* Renormalize both quhits */
    for (int qi = 0; qi < 2; qi++) {
        HexagramQuhit *q = (qi == 0) ? a : b;
        double norm = 0;
        for (int k = 0; k < HEX_D; k++)
            norm += q->line_re[k]*q->line_re[k] + q->line_im[k]*q->line_im[k];
        if (norm > 1e-30 && fabs(norm - 1.0) > 1e-15) {
            double inv = 1.0 / sqrt(norm);
            for (int k = 0; k < HEX_D; k++) {
                q->line_re[k] *= inv;
                q->line_im[k] *= inv;
            }
        }
    }

    a->vertex_dirty = 1;
    b->vertex_dirty = 1;
}

/* ═══════════════════════════════════════════════════════════════════════
 * MEASUREMENT
 * ═══════════════════════════════════════════════════════════════════════ */

static uint64_t xorshift64(uint64_t *s) {
    uint64_t x = *s;
    x ^= x << 13; x ^= x >> 7; x ^= x << 17;
    return *s = x;
}

void hexagram_probabilities(const HexagramQuhit *q, double *probs) {
    for (int k = 0; k < HEX_D; k++)
        probs[k] = q->line_re[k]*q->line_re[k] + q->line_im[k]*q->line_im[k];
}

int hexagram_measure(HexagramQuhit *q, uint64_t *rng_state) {
    double probs[HEX_D];
    hexagram_probabilities(q, probs);

    /* Born rule sampling */
    double r = (double)(xorshift64(rng_state) & 0xFFFFFFFFFFFFF) / (double)0x10000000000000;
    double cumul = 0;
    int outcome = HEX_D - 1;
    for (int k = 0; k < HEX_D; k++) {
        cumul += probs[k];
        if (r < cumul) { outcome = k; break; }
    }

    /* Collapse */
    memset(q->line_re, 0, sizeof(q->line_re));
    memset(q->line_im, 0, sizeof(q->line_im));
    q->line_re[outcome] = 1.0;
    q->vertex_dirty = 1;

    return outcome;
}

/* ═══════════════════════════════════════════════════════════════════════
 * INTERCONVERSION
 * ═══════════════════════════════════════════════════════════════════════ */

void hexagram_ensure_vertex(HexagramQuhit *q) {
    if (!q->vertex_dirty) return;
    apply_H6_adj(q->line_re, q->line_im, q->vertex_re, q->vertex_im);
    q->vertex_dirty = 0;
}

const double *hexagram_vertex_re(HexagramQuhit *q) {
    hexagram_ensure_vertex(q);
    return q->vertex_re;
}

const double *hexagram_vertex_im(HexagramQuhit *q) {
    hexagram_ensure_vertex(q);
    return q->vertex_im;
}

/* ═══════════════════════════════════════════════════════════════════════
 * DIAGNOSTICS
 * ═══════════════════════════════════════════════════════════════════════ */

int hexagram_line_type(int k) { return LINE_TYPES[k]; }
int hexagram_line_color(int k) { return LINE_COLORS[k]; }
const char *hexagram_line_name(int k) { return LINE_NAMES[k]; }

void hexagram_print(const HexagramQuhit *q, const char *label) {
    const char *chir = (q->chirality == CHIRALITY_POS) ? "+" : "-";
    printf("HexagramQuhit [%s] chirality=%s\n", label ? label : "", chir);
    for (int k = 0; k < HEX_D; k++) {
        double p = q->line_re[k]*q->line_re[k] + q->line_im[k]*q->line_im[k];
        printf("  |%s>: (%+.6f %+.6fi)  P=%.4f\n",
               LINE_NAMES[k], q->line_re[k], q->line_im[k], p);
    }
    double total = 0;
    for (int k = 0; k < HEX_D; k++)
        total += q->line_re[k]*q->line_re[k] + q->line_im[k]*q->line_im[k];
    printf("  ||psi||^2 = %.10f\n", total);
}