#version 300 es

// @secao     2. M2 — o espaço de Hilbert π-primo
// @titulo    Espaço de Hilbert π-primo
// @subtitulo |ψ⟩ = Σ αᵢ|eᵢ⟩, com ‖ψ‖ = 1
// @fonte     PsiQRH · benchmark M2 (branch pure_physics_PsiQRH)
// @doi       10.5281/zenodo.17171112
// @status    EXACT
// @param1    Fase α | 0.0 | 6.2832 | 1.5708
// @param2    Dimensão d | 2 | 24 | 8

// @leitura   Cada ponto do plano é um estado |ψ⟩ escrito na base {|eᵢ⟩}. O raio é
//            o módulo antes da normalização; a cor é a fase. A esfera de raio 1
//            é onde ‖ψ‖ = 1 vive: nada aqui pode sair dela sem ser rencomposto
//            para dentro. Gire o α e todo o campo roda em bloco; mude d e o número
//            de eixos da base muda.
//
// @honesto   O que é exato é a norma: normalizar e depois medir ‖ψ‖ devolve 1
//            dentro do erro de float da GPU (~1e-7). Isso eu verifico. O que
//            NÃO está provado é que essa representação seja melhor que um
//            embedding denso comum — o M2 mede conservação de norma, não ganho
//            de qualidade. A comutatividade e a composição de fluxo também são
//            exatas, mas não aparecem nesta imagem.
//
// @custo     Uma normalização e uma rotação de fase por pixel. O(d) por pixel
//            para montar o vetor; nada de FFT.

precision highp float;

uniform vec2  uRes;
uniform float uTime;
uniform float uParam1;   // α — fase global
uniform float uParam2;   // d — dimensão da base

out vec4 fragColor;

const float PI = 3.14159265359;
const float TAU = 6.28318530718;

// ─────────────────────────────────────────────────────────────
// M2 — ESPAÇO DE HILBERT π-PRIMO
//
//   |ψ_w⟩ = Σ_i α_i |e_i⟩ ,   ‖ψ_w‖ = 1
//
// O estado é um vetor complexo de norma unitária. A evolução é
// unitária: ρ' = U ρ U†, e a norma se conserva por construção.
//
// Aqui cada pixel é um estado candidato. Montamos o vetor em
// coordenadas polares (raio, ângulo) na base de dimensão d,
// normalizamos, e mostramos:
//   - raio   → proximidade da esfera unitária
//   - matiz  → fase acumulada
//   - anéis  → iso-norma ‖ψ‖ = 1
// ─────────────────────────────────────────────────────────────

// Hash determinístico para dar "textura" à base sem ruído branco.
float hash21(vec2 p) {
    p = fract(p * vec2(123.34, 456.21));
    p += dot(p, p + 45.32);
    return fract(p.x * p.y);
}

void main() {
    vec2 uv = (gl_FragCoord.xy - 0.5 * uRes) / uRes.y;
    float r = length(uv);
    float theta = atan(uv.y, uv.x);

    // Ângulo de fase global
    float alpha = uParam1;

    // Dimensão inteira da base, de 2 a 24 (Λ₂₄ tem 24 eixos)
    float d = floor(uParam2 + 0.5);
    d = clamp(d, 2.0, 24.0);

    // ── Monta as amplitudes α_i do estado ────────────────────
    // Cada eixo |e_i⟩ recebe uma amplitude com fase própria.
    // A soma dos módulos ao quadrado é o que normalizamos.
    float soma2 = 0.0;
    float faseAcum = 0.0;
    for (int i = 0; i < 24; i++) {
        if (float(i) >= d) break;
        float fi = float(i);

        // amplitude: decai com o índice, modulada pela posição
        float ai = 1.0 / (1.0 + fi * 0.35);
        ai *= 0.55 + 0.45 * sin(fi * 2.399963 + r * 6.0);

        // fase de cada componente: α na dimensão i
        float phi = alpha * (fi + 1.0) * 0.5 + theta * (fi * 0.13);

        soma2   += ai * ai;
        faseAcum += ai * ai * phi;
    }

    // ‖ψ‖ antes da normalização
    float norma = sqrt(max(soma2, 1e-8));

    // Normalizado: este é o estado físico
    // |ψ⟩ / ‖ψ‖  →  cada amplitude dividida por norma
    float escalaNorma = 1.0 / norma;

    // ── Visualização ────────────────────────────────────────
    // Fase média ponderada pelas amplitudes (módulo 2π)
    float faseMedia = faseAcum / max(soma2, 1e-8);

    // Redemoinho: a fase cresce com o número de eixos da base
    float ang = faseMedia + uTime * 0.25 + log(r + 0.06) * d * 0.35;

    // Iso-norma: anéis onde a esfera unitária cruza o plano.
    // O raio 1 marca ‖ψ‖ = 1; o resto mostra o campo em volta.
    float anel = abs(r - 1.0);
    float esfera = smoothstep(0.055, 0.0, anel);

    // Fora da esfera o estado não é físico; escurecemos.
    float dentro = smoothstep(1.12, 0.98, r);

    vec3 cor;
    cor.r = 0.5 + 0.5 * cos(ang);
    cor.g = 0.5 + 0.5 * cos(ang - 2.0944);
    cor.b = 0.5 + 0.5 * cos(ang - 4.1888);

    // O raio é "quão longe da esfera unitária" está o estado cru
    float intensidade = 0.30 + 0.55 * dentro + 0.75 * esfera;

    // Contorno da esfera unitária: a afirmação central do M2
    intensidade += 0.55 * esfera;

    // Malha de eixos da base: d retas radiais
    float passo = TAU / d;
    float eixo = abs(mod(theta + passo * 0.5, passo) - passo * 0.5);
    float eixoLinha = smoothstep(0.012, 0.0, eixo / max(r, 0.1));
    intensidade += 0.35 * eixoLinha * dentro;

    fragColor = vec4(cor * intensidade * escalaNorma * 0.9, 1.0);
}
