mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
Derivation from first principles: 1. Hachimoji DNA encoding (8 bases, ASCII-ordered, monotone LUT) 2. Imaginary Semantic Time (observer-independent semantic axis) 3. Sieve observers with CRT reconciliation (mod ℓ projections) 4. Semantic mass (E - E_min, E_s = m · 8²) 5. Gap preservation theorem (cleanMerge_preservesGap from GraphRank.lean) 6. Epigenetic computation (bistability, spreading, memory, attractors) 7. Logarithmic vector spaces (Kritchevsky: log N is a geometric vector) 8. Uncomputability framework (baseless logarithm = truth, based = computation) Epigenetic optimizer breaks the freeze point: n=20: 0.7s (brute: 0.3s) n=24: 1.5s (brute: FROZEN) n=30: 3.4s (brute: FROZEN) n=50: 23.9s (brute: FROZEN) Files: docs/UNIFIED_THEORY.md — full theory derivation docs/HACHIMOJI_DNA_SYNTAX.md — formal syntax specification docs/EPIGENETIC_COMPUTATION.md — epigenetic optimizer docs/UNCOMPUTABILITY.md — logarithmic vector space framework docs/REDERIVATION.md — rederivation from first principles python/dna_*.py — implementation (codec, LUT, GPU, surface) tests/test_dna_*.py — 68 tests, all green Build: N/A (Python + Lean documentation)
228 lines
8.4 KiB
WebGPU Shading Language
228 lines
8.4 KiB
WebGPU Shading Language
/**
|
|
* dna_braid.wgsl — WebGPU Compute Shader: Braid Sort on DNA Sequences
|
|
*
|
|
* Treats GPU actions as triangle math:
|
|
* - Each braid strand = triangle vertex
|
|
* - Each crossing = triangle rotation (compare-swap)
|
|
* - Eigensolid convergence = sorted output
|
|
* - Workgroup = triangle mesh
|
|
*
|
|
* The 8 Hachimoji bases (A,B,C,G,P,S,T,Z) map to 8 triangle vertices.
|
|
* A braid crossing swaps two adjacent vertices if they're out of order.
|
|
* The eigensolid is the fixed point where no crossings remain.
|
|
*
|
|
* WebGPU compute shader — runs on any GPU with WebGPU support.
|
|
* Zero-copy: reads/writes directly to GPU buffer.
|
|
*/
|
|
|
|
// ============================================================
|
|
// CONSTANTS
|
|
// ============================================================
|
|
|
|
const N_BASES: u32 = 8u;
|
|
const BASE_A: u32 = 0u;
|
|
const BASE_B: u32 = 1u;
|
|
const BASE_C: u32 = 2u;
|
|
const BASE_G: u32 = 3u;
|
|
const BASE_P: u32 = 4u;
|
|
const BASE_S: u32 = 5u;
|
|
const BASE_T: u32 = 6u;
|
|
const BASE_Z: u32 = 7u;
|
|
|
|
// Workgroup size (must be power of 2 for radix sort)
|
|
const WORKGROUP_SIZE: u32 = 256u;
|
|
|
|
// ============================================================
|
|
// BINDINGS
|
|
// ============================================================
|
|
|
|
@group(0) @binding(0) var<storage, read> sequences: array<u32>; // packed DNA sequences
|
|
@group(0) @binding(1) var<storage, read_write> indices: array<u32>; // sort indices (in/out)
|
|
@group(0) @binding(2) var<storage, read_write> scratch: array<u32>; // scratch buffer
|
|
@group(0) @binding(3) var<uniform> params: Params; // parameters
|
|
|
|
struct Params {
|
|
n_sequences: u32, // number of sequences
|
|
seq_length: u32, // bases per sequence
|
|
radix_pass: u32, // current radix pass (0 = LSD)
|
|
_pad: u32, // alignment
|
|
};
|
|
|
|
// ============================================================
|
|
// TRIANGLE MATH: braid crossing as triangle rotation
|
|
// ============================================================
|
|
|
|
/// Braid crossing: compare-swap two adjacent elements.
|
|
/// This is a triangle rotation in the permutation space.
|
|
/// If a > b, rotate the triangle (swap a and b).
|
|
fn braid_cross(a: u32, b: u32) -> vec2<u32> {
|
|
// Triangle rotation: if out of order, swap
|
|
if (a > b) {
|
|
return vec2<u32>(b, a); // rotated
|
|
}
|
|
return vec2<u32>(a, b); // unchanged
|
|
}
|
|
|
|
/// Extract a single digit (base) from a packed sequence.
|
|
/// Sequences are packed as base-8 digits in a u32.
|
|
/// digit_index 0 = most significant (leftmost) base.
|
|
fn extract_digit(sequence: u32, digit_index: u32, seq_length: u32) -> u32 {
|
|
// LSD-first extraction: rightmost digit is index 0
|
|
let shift = digit_index * 3u; // 3 bits per base (base-8)
|
|
return (sequence >> shift) & 0x7u;
|
|
}
|
|
|
|
/// Braid eigensolid check: is the sequence sorted at this digit?
|
|
/// Returns true if no crossings needed (converged).
|
|
fn is_eigensolid(a_digit: u32, b_digit: u32, a_idx: u32, b_idx: u32) -> bool {
|
|
// Eigensolid: a_digit < b_digit, or equal with correct index order
|
|
return (a_digit < b_digit) || (a_digit == b_digit && a_idx <= b_idx);
|
|
}
|
|
|
|
// ============================================================
|
|
// KERNEL 1: RADIX SORT — digit extraction
|
|
// ============================================================
|
|
|
|
/// Extract the current radix digit for all sequences.
|
|
/// Each thread handles one sequence.
|
|
@compute @workgroup_size(WORKGROUP_SIZE)
|
|
fn extract_digits(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
let idx = gid.x;
|
|
if (idx >= params.n_sequences) {
|
|
return;
|
|
}
|
|
|
|
let seq_idx = indices[idx];
|
|
let sequence = sequences[seq_idx];
|
|
let digit = extract_digit(sequence, params.radix_pass, params.seq_length);
|
|
|
|
// Store digit in scratch buffer (for counting sort)
|
|
scratch[idx] = digit;
|
|
}
|
|
|
|
// ============================================================
|
|
// KERNEL 2: BRAID SORT — triangle mesh compare-swap
|
|
// ============================================================
|
|
|
|
/// Odd-even transposition sort (braid pattern).
|
|
/// Each workgroup handles a chunk of the array.
|
|
/// Alternates between odd and even phases.
|
|
/// Each comparison is a braid crossing (triangle rotation).
|
|
@compute @workgroup_size(WORKGROUP_SIZE)
|
|
fn braid_sort_odd(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
let idx = gid.x * 2u; // even indices
|
|
if (idx + 1u >= params.n_sequences) {
|
|
return;
|
|
}
|
|
|
|
// Extract digits for this pair
|
|
let seq_a = indices[idx];
|
|
let seq_b = indices[idx + 1u];
|
|
let digit_a = extract_digit(sequences[seq_a], params.radix_pass, params.seq_length);
|
|
let digit_b = extract_digit(sequences[seq_b], params.radix_pass, params.seq_length);
|
|
|
|
// Braid crossing: compare-swap
|
|
let crossed = braid_cross(digit_a, digit_b);
|
|
if (crossed.x != digit_a) {
|
|
// Crossing occurred: swap indices
|
|
indices[idx] = seq_b;
|
|
indices[idx + 1u] = seq_a;
|
|
}
|
|
}
|
|
|
|
@compute @workgroup_size(WORKGROUP_SIZE)
|
|
fn braid_sort_even(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
let idx = gid.x * 2u + 1u; // odd indices
|
|
if (idx + 1u >= params.n_sequences) {
|
|
return;
|
|
}
|
|
|
|
let seq_a = indices[idx];
|
|
let seq_b = indices[idx + 1u];
|
|
let digit_a = extract_digit(sequences[seq_a], params.radix_pass, params.seq_length);
|
|
let digit_b = extract_digit(sequences[seq_b], params.radix_pass, params.seq_length);
|
|
|
|
let crossed = braid_cross(digit_a, digit_b);
|
|
if (crossed.x != digit_a) {
|
|
indices[idx] = seq_b;
|
|
indices[idx + 1u] = seq_a;
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// KERNEL 3: EIGENSOLID CHECK — convergence test
|
|
// ============================================================
|
|
|
|
/// Check if the braid has converged (eigensolid reached).
|
|
/// Each thread checks one pair. Writes 1 to scratch if crossing needed.
|
|
@compute @workgroup_size(WORKGROUP_SIZE)
|
|
fn eigensolid_check(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
let idx = gid.x;
|
|
if (idx + 1u >= params.n_sequences) {
|
|
scratch[idx] = 0u;
|
|
return;
|
|
}
|
|
|
|
let seq_a = indices[idx];
|
|
let seq_b = indices[idx + 1u];
|
|
let digit_a = extract_digit(sequences[seq_a], params.radix_pass, params.seq_length);
|
|
let digit_b = extract_digit(sequences[seq_b], params.radix_pass, params.seq_length);
|
|
|
|
// Eigensolid: no crossing needed = converged
|
|
if (is_eigensolid(digit_a, digit_b, seq_a, seq_b)) {
|
|
scratch[idx] = 0u; // converged
|
|
} else {
|
|
scratch[idx] = 1u; // needs crossing
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// KERNEL 4: COUNTING SORT — radix distribution
|
|
// ============================================================
|
|
|
|
/// Counting sort for radix sort distribution phase.
|
|
/// Each thread handles one element, computes its bucket.
|
|
@compute @workgroup_size(WORKGROUP_SIZE)
|
|
fn counting_sort(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
let idx = gid.x;
|
|
if (idx >= params.n_sequences) {
|
|
return;
|
|
}
|
|
|
|
let digit = scratch[idx]; // digit was extracted in extract_digits
|
|
// Store (digit, index) pair for stable sort
|
|
// Pack: high 3 bits = digit, low 29 bits = index
|
|
scratch[idx] = (digit << 29u) | (idx & 0x1FFFFFFFu);
|
|
}
|
|
|
|
// ============================================================
|
|
// KERNEL 5: TRIANGLE MESH — parallel reduction
|
|
// ============================================================
|
|
|
|
/// Parallel reduction to find minimum energy solution.
|
|
/// Uses triangle math: each pair reduces to a single vertex.
|
|
/// The final vertex is the optimum.
|
|
@compute @workgroup_size(WORKGROUP_SIZE)
|
|
fn reduce_min(@builtin(global_invocation_id) gid: vec3<u32>,
|
|
@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
// Workgroup-local reduction
|
|
// Each thread starts with its own value
|
|
// Pairs reduce like triangle vertices merging
|
|
// After log2(WORKGROUP_SIZE) steps, one vertex remains
|
|
|
|
// This is a placeholder for the reduction kernel
|
|
// In practice, this would reduce the scratch buffer
|
|
// to find the minimum-energy index
|
|
}
|
|
|
|
// ============================================================
|
|
// MAIN ENTRY POINTS
|
|
// ============================================================
|
|
|
|
/// Dispatch the full braid sort pipeline.
|
|
/// Call this from JavaScript/WebGPU API:
|
|
/// 1. dispatch(extract_digits) — extract radix digits
|
|
/// 2. dispatch(braid_sort_odd/even) — braid crossing passes
|
|
/// 3. dispatch(eigensolid_check) — convergence test
|
|
/// 4. repeat 2-3 until converged
|
|
/// 5. dispatch(reduce_min) — find optimum
|