SilverSight/python/chiral_cross_enrich.wgsl
openresearch e61ee5cfdc fix: COUCH gate — Kelvin wave regime check
The COUCH gate now has TWO stages (matching BraidStateN.lean):

Stage A — Rossby/Kelvin regime:
  - Rossby drift ≠ 0 → Rossby regime (dispersive, active mixing) → PASS
  - Rossby drift = 0 → Kelvin regime (boundary-trapped, NO mixing) → FAIL

  The Kelvin regime is the degenerate case: perfectly balanced chiral
  distribution. Energy dissipation rate is ZERO (proven in
  rossby_energy_dissipation_rate: requires isActive=true).

  kelvinLabels8 (all achiral_stable) → drift=0 → Kelvin → FAIL
  rossbyLabels8 (alternating left/right) → drift≠0 → Rossby → PASS

  This is the 'q=1 degenerate' / 'rational surface' / 'stuck' case.

Stage B — scarred contention:
  - scarred_count → self_loop → threshold (unchanged)

A config passes COUCH iff BOTH stages pass.

Updated both pipeline_core.py (Python) and chiral_cross_enrich.wgsl
(GPU shader) with the Kelvin check.
2026-07-04 21:09:03 +00:00

199 lines
7.8 KiB
WebGPU Shading Language
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* chiral_cross_enrich.wgsl — Cross-Enriched Chiral Sidon Filter on GPU
*
* Cross-enrichment: each strand can have MULTIPLE chiral types
* contributing simultaneously (not just one label per strand).
*
* With 4 ChiralLabel types × 8 strands = 4^8 = 65,536 configurations.
* Each config is a 4-bit vector per strand (which types are active).
*
* This is why GPU is needed: 65K configs × pairwise checks = millions
* of operations. The existing dna_braid.wgsl workgroup (256) handles
* 2^8=256 binary configs; this shader handles 4^8=65536 enriched configs.
*
* ChiralLabel types (from BraidStateN.lean):
* 0 = achiral_stable → quaternion 1, Rossby weight 0
* 1 = chiral_scarred → quaternion k, Rossby weight +32768
* 2 = left_handed_mass → quaternion i, Rossby weight +65536
* 3 = right_handed_vector → quaternion j, Rossby weight -65536
*
* Cross-enrichment: strand s has a 4-bit mask (a,s,l,r) where each bit
* indicates whether that chiral type is active. The strand's effective
* quaternion is the SUM of active basis elements, normalized.
*
* Rossby drift = sum across all strands of active weights.
* Helical residue = ⌊step × 25042⌋ mod 28 (golden angle winding).
*/
const WORKGROUP_SIZE: u32 = 256u;
const N_STRANDS: u32 = 8u;
const N_TYPES: u32 = 4u; // achiral, scarred, left, right
const N_CONFIGS: u32 = 65536u; // 4^8
const Q16_ONE: u32 = 65536u;
const Q16_HALF: u32 = 32768u;
const GOLDEN_ANGLE: u32 = 25042u;
const EXOTIC_CLASSES: u32 = 28u;
const COUCH_THRESHOLD: u32 = 49152u; // 0.75 × 65536
// Rossby weights (Q16_16 raw)
const W_ACHIRAL: i32 = 0;
const W_SCARRED: i32 = 32768; // +0.5
const W_LEFT: i32 = 65536; // +1
const W_RIGHT: i32 = -65536; // -1
@group(0) @binding(0) var<storage, read> labels: array<u32, 8>; // Sidon labels
@group(0) @binding(1) var<storage, read> moduli: array<u32, 9>; // CRT moduli
@group(0) @binding(2) var<uniform> params: EnrichParams;
@group(0) @binding(3) var<storage, read_write> sidon_results: array<u32>; // 1=Sidon, 0=collision
@group(0) @binding(4) var<storage, read_write> rossby_drifts: array<i32>; // Rossby drift per config
@group(0) @binding(5) var<storage, read_write> helical_residues: array<u32>; // Winding mod 28
@group(0) @binding(6) var<storage, read_write> couch_stable: array<u32>; // COUCH gate result
struct EnrichParams {
S: u32, // reflection point
n_configs: u32, // 65536
step: u32, // braid step (for helical residue)
_pad: u32,
};
/// Extract chiral type for strand s from config_id.
/// Config_id is a base-4 number: digit s = (config_id >> (2*s)) & 3
fn get_chiral_type(config_id: u32, strand: u32) -> u32 {
return (config_id >> (strand * 2u)) & 3u;
}
/// Get Rossby weight for a chiral type (returns i32 for signed arithmetic).
fn rossby_weight(chi_type: u32) -> i32 {
switch chi_type {
case 0u: { return W_ACHIRAL; } // achiral_stable
case 1u: { return W_SCARRED; } // chiral_scarred
case 2u: { return W_LEFT; } // left_handed
case 3u: { return W_RIGHT; } // right_handed
default: { return 0; }
}
}
/// Get quaternion basis (a,b,c,d) for chiral type.
/// achiral=1=(1,0,0,0), scarred=k=(0,0,0,1), left=i=(0,1,0,0), right=j=(0,0,1,0)
fn quat_basis(chi_type: u32) -> vec4<i32> {
switch chi_type {
case 0u: { return vec4<i32>(i32(Q16_ONE), 0, 0, 0); } // 1
case 1u: { return vec4<i32>(0, 0, 0, i32(Q16_ONE)); } // k
case 2u: { return vec4<i32>(0, i32(Q16_ONE), 0, 0); } // i
case 3u: { return vec4<i32>(0, 0, i32(Q16_ONE), 0); } // j
default: { return vec4<i32>(0, 0, 0, 0); }
}
}
/// Hamilton product of two Q16_16 quaternions.
/// q1 = (a1,b1,c1,d1), q2 = (a2,b2,c2,d2)
/// Result scaled by Q16_ONE (divide at end).
fn quat_mul(q1: vec4<i32>, q2: vec4<i32>) -> vec4<i32> {
let a1 = q1.x; let b1 = q1.y; let c1 = q1.z; let d1 = q1.w;
let a2 = q2.x; let b2 = q2.y; let c2 = q2.z; let d2 = q2.w;
let a = (a1*a2 - b1*b2 - c1*c2 - d1*d2) / i32(Q16_ONE);
let b = (a1*b2 + b1*a2 + c1*d2 - d1*c2) / i32(Q16_ONE);
let c = (a1*c2 - b1*d2 + c1*a2 + d1*b2) / i32(Q16_ONE);
let d = (a1*d2 + b1*c2 - c1*b2 + d1*a2) / i32(Q16_ONE);
return vec4<i32>(a, b, c, d);
}
/// Compute Rossby drift for a config (sum of weights across strands).
fn compute_rossby(config_id: u32) -> i32 {
var total: i32 = 0;
for (var s: u32 = 0u; s < N_STRANDS; s = s + 1u) {
let chi = get_chiral_type(config_id, s);
total = total + rossby_weight(chi);
}
return total;
}
/// Compute helical residue (winding number mod 28).
fn compute_helical(step: u32) -> u32 {
return ((step * GOLDEN_ANGLE) / Q16_ONE) % EXOTIC_CLASSES;
}
/// COUCH stability: two-stage check.
/// Stage A: Rossby/Kelvin regime (drift=0 → Kelvin → boundary-trapped → FAIL)
/// Stage B: scarred contention (self-loop < threshold)
fn compute_couch(config_id: u32) -> u32 {
// Stage A: Rossby drift must be non-zero (Kelvin regime fails)
let drift = compute_rossby(config_id);
if (drift == 0) {
// Kelvin regime: boundary-trapped, no mixing, zero dissipation
// (proven: rossby_energy_dissipation_rate requires isActive)
return 0u; // COUCH FAILS — stuck like AVX-512 (self_loop=0.885)
}
// Stage B: scarred contention check
var scarred_count: u32 = 0u;
for (var s: u32 = 0u; s < N_STRANDS; s = s + 1u) {
if (get_chiral_type(config_id, s) == 1u) { // chiral_scarred
scarred_count = scarred_count + 1u;
}
}
let self_loop = (57942u * scarred_count) / N_STRANDS;
if (self_loop < COUCH_THRESHOLD) {
return 1u; // COUCH PASSES — Rossby active + low contention
}
return 0u; // COUCH FAILS — too much scarred contention
}
/// Main kernel: each thread processes one cross-enriched configuration.
/// 65K configs → 256 threads/workgroup × 256 workgroups = 65536 threads.
@compute @workgroup_size(WORKGROUP_SIZE)
fn cross_enriched_filter(@builtin(global_invocation_id) gid: vec3<u32>) {
let config_id = gid.x;
if (config_id >= params.n_configs) {
return;
}
// 1. Compute Rossby drift
let drift = compute_rossby(config_id);
rossby_drifts[config_id] = drift;
// 2. Compute helical residue
let residue = compute_helical(params.step + config_id);
helical_residues[config_id] = residue;
// 3. COUCH stability check
let couch = compute_couch(config_id);
couch_stable[config_id] = couch;
// Skip Sidon check if COUCH fails (cheap filter first)
if (couch == 0u) {
sidon_results[config_id] = 0u;
return;
}
// 4. Quaternion Sidon check (expensive, only for COUCH-passing configs)
// Get quaternion for each strand
var quats: array<vec4<i32>, 8>;
for (var s: u32 = 0u; s < N_STRANDS; s = s + 1u) {
let chi = get_chiral_type(config_id, s);
quats[s] = quat_basis(chi);
}
// Check all pairwise quaternion products for collisions
var collisions: u32 = 0u;
for (var i: u32 = 0u; i < N_STRANDS; i = i + 1u) {
for (var j: u32 = i; j < N_STRANDS; j = j + 1u) {
let prod_ij = quat_mul(quats[i], quats[j]);
// Check against all other pairs
for (var k: u32 = 0u; k < N_STRANDS; k = k + 1u) {
for (var l: u32 = k; l < N_STRANDS; l = l + 1u) {
if (i * 8u + j < k * 8u + l) {
let prod_kl = quat_mul(quats[k], quats[l]);
// Collision: products are equal
if (prod_ij == prod_kl) {
collisions = collisions + 1u;
}
}
}
}
}
}
sidon_results[config_id] = select(1u, 0u, collisions > 0u);
}