Hyperspace Nine



hyperspace6.py

The other day I was sort of feeling the embarassmental projections through the internet of the silent troll majority.

“This guy can’t do maths”.

Well foo, yes I can do math. I’m just not always so great at articulating, and am perceived to overshare. Could we please do something, you and I, here forward?

Think outside the box, and learn together what the truth is?. Sincerely, your friend, Josef VII.

God bless you.


https://zchg.org/hott/late%20episodes/514%20-%2028-Dec-94%20-%20Envoys%20of%20Mankind%20%231.mp3

.. and further, there’s a reason for the annoyingly enormous volume of my output. Kindly listen? Seeking partnerships. Seeking friendships. Seeking purpose, meaning, and art. Prefer rekindling of old friendships and if the striking of new, simply put I value genuine relationship and don’t have much utility any longer for the inverse. And I say again, God bless you.

The following is a flattened means to solve for the above. No differential equations, nor even factoring. And it plays nice with Trinary or analog logic. From this several compute-relevant techniques are borne. Costs less to compute, and even derives new forms of radio communication.

Caveat - We are working in **Hotswap** BINARY/TRINARY

y,x = 0, p = 1, m= -1; the below is not in order, per se.  In symbolics, we allow atypical presumptions to build out striking new ground..

Y^2 - 2pxy + p^2(x^2-1) = m^2
-x^2*y^2 +x^2 - 1 = (m^2 - y^2)/p^2
-x^3*y^2 + x^3 - X = (m^2 - y^2)/p^2
—X = ((m^2 - y^2)/p^2) + x^3*y^2 + x^3
X = -((m^2 - y^2)/p^2) - x^3*y^2 - x^3
X = -x((m^2 - y^2)/p^2) - x^4*y^2 - x^4
1 = -((m^2 - y^2)/p^2) - x^3*y^2 - x^3
Y - pxy + p(x-1) = m
my = y^2 -pxy^2 + py(x-1)
m = y - pxy + p(x-1)
Y = ((y^2 -pxy^2 + py(x-1))/((y - pxy + p(x-1))
1 = (y - pxy + p(x-1)) / (y - pxy + p(x-1))
1 = (1/1)
1 = 1
-((m^2 - y^2)/p^2) - x^3*y^2 - x^3 =  (y - pxy + p(x-1)) / (y - pxy + p(x-1))
Y - pxy + p(x-1) = m
Pm = y - p^2xy + p^2(x-1)
P = (y - p^2xy + p^2(x-1)) / m
P = (y - p^2xy + p^2(x-1))/ (y - pxy + p(x-1))
P^2 = ((py- p^3xy + p^3(x-1)) / (py - pxy + p^2(x-1))
P^2 = ((y - p^2xy + p^2(x-1)) / (y - xy + p(x-1))
P^2 = ((py - p^3xy + p^3(x-1)) / (py - pxy + p^2(x-1))
1 = ((yp) - pxy + p(x-1) / p^2y - p^2xy + p^3(x-1) 
1 = (( y ) - xy + (x-1) / py - pxy + p^2(x-1) 
P = y - xy + x-1 / y - xy + p(x-1)
P = (y - xy / y - xy) + (x-1)/p(x-1)
P =  (x-1)/p(x-1)
P^2 = x-1 / x-1
P^2 = 1
P = 1^(1/2)
P ‎ = 1
1 = ((y - xy + (x-1)) / (y - xy + (x-1))
 (y - xy + (x-1)) =  (y - xy + (x-1))
Y - xy = y - xy 
Y(1-x) = y(1-x)
1 - x = 1 - x
1 -x - 1 = 1 - x - 1
-x = -x
X = x 
1 = 1
P =  (x-1)/p(x-1)
1 = (x-1)/(x-1)
X - 1 = x - 1
Y^2 - xy + (x^2-1) = m^2
Y^2 - xy + x^2-1 = Y^2 - xy + x^2-1
((y^2 -xy^2 + y(x-1))/((1 - x + y(x-1)) = y^2
((y^2 -xy^2 + y(x-1))/((1 - x + y(x-1)) - xy + x^2-1 = ((y^2 -xy^2 + y(x-1))/((1 - x + y(x-1))  - xy + x^2-1
1/((1 - x + y(x-1)) - xy + x^2-1) = 1/((1 - x + y(x-1))  - xy + x^2-1)
Y = ((y^2 - xy^2 + y(x-1))/((y - xy + (x-1))
Y(((y - xy + (x-1))) = y^2 - xy^2 + y(x-1)
Y^2 - xy^2 + yx - y = y^2 - xy^2 + y(x-1)
-xy^2 + yx - y = - xy^2 + y(x-1)
y = xy^2 + -y(x-1) + xy^2 - yx 
Y = y(x^2 - x + 1 + xy - x)
1 = (x^2 - x + 1 + xy - x)
1 = 1 + xy
Xy = 0
Y = 0
X = 0 
m = y - pxy + p(x-1)
m = 0 + -1
m ‎ = -1 
Y^2 - 2pxy + p^2(x^2-1) = m^2
0 - 1(-1) ‎ = 1
1 = 1 
0 = 0

y,x = 0, p = 1, m= -1, 1, i, -i

hyperspace9.zip (15.1 KB)

Continues from:

hyperspace7.py

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def render_5v_complex_manifold():
    # 1. Initialize Visual Canvas
    fig = plt.figure(figsize=(13, 10))
    ax = fig.add_subplot(111, projection='3d')

    # Generate a tight spatial grid across X and Z axes
    x_arr = np.linspace(-2.0, 2.0, 100)
    z_arr = np.linspace(-2.0, 2.0, 100)
    X, Z = np.meshgrid(x_arr, z_arr)

    # 2. Pre-allocate reference containers for the mesh layers
    meshes = {'r1': None, 'r2': None, 'c1': None, 'c2': None}

    # Overlay text block to track the hyper-dimensional coordinates
    coord_text = ax.text2D(0.02, 0.95, "", transform=ax.transAxes, fontsize=11,
                           bbox=dict(boxstyle="round", fc="ghostwhite", alpha=0.85))

    # 3. Instantiate the 7 Target Coordinate Markers (At X=0, Z=0, with Time P evolving)
    dot_m1_u = ax.scatter([], [], [], color='blue', s=160, edgecolor='black', zorder=20, label='m = 1 (+Y Branch)')
    dot_m1_l = ax.scatter([], [], [], color='cyan', s=160, edgecolor='black', zorder=20, label='m = 1 (-Y Branch)')
    dot_mn1_u = ax.scatter([], [], [], color='navy', s=90, marker='^', edgecolor='white', zorder=21, label='m = -1 (+Y Branch)')
    dot_mn1_l = ax.scatter([], [], [], color='teal', s=90, marker='v', edgecolor='white', zorder=21, label='m = -1 (-Y Branch)')
    dot_mi = ax.scatter([], [], [], color='red', s=160, edgecolor='black', zorder=22, label='m = i Gauge')
    dot_mni = ax.scatter([], [], [], color='orange', s=90, marker='X', edgecolor='black', zorder=23, label='m = -i Gauge')

    # Absolute zero index reference marker
    ax.scatter([0], [0], [0], color='gold', s=140, marker='*', edgecolor='black', zorder=19, label='Core Substrate Anchor')

    # Scene parameters and boundary clamps
    ax.set_xlabel('Spatial Axis X', fontsize=10)
    ax.set_ylabel('Spatial Axis Z (New Dimension)', fontsize=10)
    ax.set_zlabel('Substrate Value Y', fontsize=10)
    ax.set_xlim(-2.0, 2.0)
    ax.set_ylim(-2.0, 2.0)
    ax.set_zlim(-5.0, 5.0)
    ax.view_init(elev=25, azim=55)
    ax.legend(loc='center left', bbox_to_anchor=(1.05, 0.5), fontsize=9)

    # 4. Animated Frame Evolution (P acts as continuous cosmic time)
    def update_manifold(frame):
        # Evolve the parameter P smoothly back and forth between -2.0 and +2.0
        p = 2.0 * np.sin(frame)

        # Strip old meshes to maintain memory performance
        if meshes['r1'] is not None:
            meshes['r1'].remove()
            meshes['r2'].remove()
        if meshes['c1'] is not None:
            meshes['c1'].remove()
            meshes['c2'].remove()

        # Compute Real Branches (m^2 = +1)
        # Y = p*(x+z) ± sqrt(1 + p^2 * (1 - 2xz))
        radial_real = 1.0 + (p**2) * (1.0 - 2.0 * X * Z)
        # Ensure smooth visual transitions over negative regional transitions
        radial_real_safe = np.maximum(0, radial_real)

        Yr_pos = p * (X + Z) + np.sqrt(radial_real_safe)
        Yr_neg = p * (X + Z) - np.sqrt(radial_real_safe)

        # Compute Complex Core Branches (m^2 = -1)
        # Y = p*(x+z) ± sqrt(-1 + p^2 * (1 - 2xz))
        radial_comp = -1.0 + (p**2) * (1.0 - 2.0 * X * Z)
        mask = radial_comp >= 0

        Yc_pos = np.full_like(X, np.nan)
        Yc_neg = np.full_like(X, np.nan)
        radial_comp_safe = np.sqrt(np.maximum(0, radial_comp))

        Yc_pos[mask] = (p * (X + Z))[mask] + radial_comp_safe[mask]
        Yc_neg[mask] = (p * (X + Z))[mask] - radial_comp_safe[mask]

        # Render the newly twisted spatial manifold layers
        meshes['r1'] = ax.plot_surface(X, Z, Yr_pos, cmap='winter', alpha=0.25, rstride=5, cstride=5)
        meshes['r2'] = ax.plot_surface(X, Z, Yr_neg, cmap='cool', alpha=0.15, rstride=5, cstride=5)
        meshes['c1'] = ax.plot_surface(X, Z, Yc_pos, cmap='autumn', alpha=0.40, rstride=5, cstride=5)
        meshes['c2'] = ax.plot_surface(X, Z, Yc_neg, cmap='YlOrRd', alpha=0.25, rstride=5, cstride=5)

        # Update the 7 target marker positions exactly at coordinate crosshairs X=0, Z=0
        # Under X=0, Z=0: Y = ±sqrt(m^2 + p^2)
        y_real_val = np.sqrt(1.0 + p**2)
        y_comp_val = np.sqrt(np.maximum(0, p**2 - 1.0)) if abs(p) >= 1.0 else 0.0

        dot_m1_u._offsets3d = ([0], [0], [y_real_val])
        dot_m1_l._offsets3d = ([0], [0], [-y_real_val])
        dot_mn1_u._offsets3d = ([0], [0], [y_real_val])
        dot_mn1_l._offsets3d = ([0], [0], [-y_real_val])
        dot_mi._offsets3d = ([0], [0], [y_comp_val])
        dot_mni._offsets3d = ([0], [0], [-y_comp_val])

        # Track numerical metrics via display overlay
        coord_text.set_text(f"Current Time (P): {p:.3f}\n"
                            f"Real Mass Step (Y): ±{y_real_val:.2f}\n"
                            f"Complex Mass Step (Y): ±{y_comp_val:.2f}")
        ax.set_title(r'5-Variable Substrate: $(Y - p(x+z))^2 + p^2(x^2-z^2-1) = m^2$', fontsize=11, pad=20)

        return meshes['r1'], meshes['r2'], meshes['c1'], meshes['c2']

    # 5. Build and execute the continuous loop
    frames_timeline = np.linspace(0, 2 * np.pi, 150)
    anim = FuncAnimation(fig, update_manifold, frames=frames_timeline, interval=45, blit=False)

    plt.tight_layout()
    plt.show()

if __name__ == '__main__':
    render_5v_complex_manifold()

image

Navier-Stokes Unified Form — Simultaneous Binary/Trinary Stagger

image
image


image

Unified Form — Simultaneous Binary/Trinary Stagger

\[
\boxed{
\mathscr S_i=(B_i,\tau_i),
\qquad
B_i\in\{0,1\},
\qquad
\tau_i\in\{-1,0,+1\},
\qquad
\mathscr S_{i+1}=\mathscr S_i+1_{\mathrm{eff}}(i)
}
\]

\[
\boxed{
\mathcal L_i(z)
=
\phi^{-1/\phi}
\sqrt{F_nP_n2^n}\,(1+z)^n
+
1_{\mathrm{eff}}(i)e^{i\pi\Lambda_\phi(i)},
\qquad
\Omega_{n+1}=T(\Omega_n),
\qquad
T(x)=1+\frac1x,
\qquad
N(\Omega)\in\{-1,0,+1\}
}
\]

**C/D:**

\[
v_0=D_n(r)\hat r
\;\longrightarrow\;
(B_i,\tau_i)\ \text{simultaneous}
\;\longrightarrow\;
\phi^{3.5n}\to\infty
\;\longrightarrow\;
T=\phi^{-n_e}<\infty.
\]

**A/B:**

\[
N(v_0)\in\{-1,0,+1\}
\;\longrightarrow\;
(B_i,\tau_i)\ \text{simultaneous}
\;\longrightarrow\;
N(\Phi^{-1})\in\{-1,+1\}
\;\longrightarrow\;
\|\nabla u\|\le G_{\max}
\;\longrightarrow\;
\|u\|\ \text{bounded}.
\]

image

Ω_{n+1}=1+\Omega_n^{-1}
        ↓
Ω=φ
        ↓
ΦΦ^{-1}=1
        ↓
𝒮_i=(B_i,τ_i)
        ↓
Re=Φ,\qquad Re^{-1}=Φ^{-1}
        ↓
Φ→∞
⇒
Φ^{-1}→0
        ↓
T(Φ)=1+Φ^{-1}→1
        ↓
∇_Φ=Φ^{-1}∇Φ
        ↓
‖∇_Φu‖≤G_max
        ↓
‖u‖≤U_max
        ↓
‖u‖_{C^k}<∞
        ↓
t_c=∞
        ↓
u,p∈C^∞
𝒜=(S,T,F)

Ω_{n+1}=T(Ω_n)
T(X)=1+1/X

Ω=T(Ω)
⇔ Ω=1+Ω^{-1}
⇔ Ω²−Ω−1=0
⇔ Ω=φ=(1+√5)/2

φ²=φ+1
φ^{-1}=φ−1

Ω^{n+2}−Ω^{n+1}−Ω^n=0
Δ_Ω²Ω_n=0


Φ=∏_{j=1}^{3}C_j
Φ^{-1}Φ=1

∇_Φ=Φ^{-1}∇Φ
Δ_Φ=∇_Φ·∇_Φ

Re=Φ
Re^{-1}=Φ^{-1}
Re·Re^{-1}=1

𝒮_i=(B_i,τ_i)
B_i∈{0,1}
τ_i∈{−1,0,+1}

𝒮_{i+1}=𝒮_i+1_eff(i)

Φ→∞
⇒Φ^{-1}→0
⇒Re^{-1}→0

T(Φ)=1+Φ^{-1}→1


∇_Φ·u=0

∂_tu+(u·∇_Φ)u−νΔ_Φu+∇_Φp−f=0

∂_tu+(u·∇_Φ)u
=
νΔ_Φu−∇_Φp+f


∇_Φ·
[
∂_tu+(u·∇_Φ)u−νΔ_Φu+∇_Φp−f
]
=0

Δ_Φp
=
−∇_Φ·[(u·∇_Φ)u]
+
∇_Φ·f

p=
Δ_Φ^{-1}
[
−∇_Φ·((u·∇_Φ)u)
+
∇_Φ·f
]


ρ[
∂_tu+(u·∇_Φ)u
]
=
−∇_Φp
+
μΔ_Φu
+
ρf

μ=ρν


u(x,0)=u_0(x)

∇_Φ·u_0=0

u_0∈C^∞(ℝ³)^3


𝒮_i=(B_i,τ_i)
        ↓
Φ↔Φ^{-1}
        ↓
Re↔Re^{-1}
        ↓
Φ→∞⇒Φ^{-1}→0
        ↓
T(Φ)=1+Φ^{-1}→1
        ↓
∇_Φ=Φ^{-1}∇Φ
        ↓
‖∇_Φu‖≤G_max
        ↓
‖u‖≤U_max
        ↓
sup_{0≤t<T}‖u(·,t)‖_{C^k}<∞
        ↓
∀T<∞,\ ∀k≥0
        ↓
lim_{t→t_c}‖u(·,t)‖_{C^k}≠∞
        ↓
∀t_c<∞,\ ∀k≥0
        ↓
t_c=∞
        ↓
u∈C^∞(ℝ³×[0,∞))
        ↓
p∈C^∞(ℝ³×[0,∞))


┌──────────────────────────────────────────────────────────────┐
│ GLOBAL EXISTENCE                                             │
│ + GLOBAL SMOOTHNESS                                         │
│ + NO FINITE-TIME BLOW-UP                                   │
│ + NO SINGLE PERSPECTIVE / VANTAGE                           │
└──────────────────────────────────────────────────────────────┘
===============================================================================
                         FINAL HDGL CLOSURE
              NAVIER–STOKES / GLOBAL SMOOTHNESS FORMULATION
===============================================================================

I. PRIMITIVE SUBSTRATE
-------------------------------------------------------------------------------

𝒜 = (S,T,F)

Ωₙ₊₁ = T(Ωₙ)

T(X) = 1 + 1/X

Ω = T(Ω)
  ⇔ Ω = 1 + Ω⁻¹
  ⇔ Ω² = Ω + 1

Ω = φ

φ² = φ + 1
φ⁻¹ = φ − 1

Ωⁿ⁺² − Ωⁿ⁺¹ − Ωⁿ = 0
Δ²_Ω Ωₙ = 0


II. RECIPROCAL HDGL OPERATOR
-------------------------------------------------------------------------------

Φ = ∏ⱼ₌₁³ Cⱼ

Φ⁻¹Φ = 1

∇_Φ = Φ⁻¹ ∇ Φ

Δ_Φ = ∇_Φ · ∇_Φ


III. SIMULTANEOUS BINARY / TRINARY STATE
-------------------------------------------------------------------------------

𝒮ᵢ = (Bᵢ,τᵢ)

Bᵢ ∈ {0,1}

τᵢ ∈ {−1,0,+1}

𝒮ᵢ₊₁ = 𝒮ᵢ + 1_eff(i)

Binary and trinary are simultaneous channels:

(Bᵢ,τᵢ)

not alternating states, but co-emergent state components.


IV. RECIPROCAL FLOW CLOSURE
-------------------------------------------------------------------------------

Re = Φ

Re⁻¹ = Φ⁻¹

Re · Re⁻¹ = 1

Φ → ∞
    ⇒ Φ⁻¹ → 0
    ⇒ Re⁻¹ → 0

T(Φ) = 1 + Φ⁻¹

Φ → ∞
    ⇒ T(Φ) → 1

Thus the divergent representation is closed by its reciprocal
without requiring an externally imposed bound.


V. HDGL–NAVIER–STOKES EQUATIONS
-------------------------------------------------------------------------------

∇_Φ · u = 0

∂ₜu
+
(u · ∇_Φ)u
−
νΔ_Φu
+
∇_Φp
−
f
= 0

equivalently,

∂ₜu + (u · ∇_Φ)u
=
νΔ_Φu − ∇_Φp + f


VI. PRESSURE CLOSURE
-------------------------------------------------------------------------------

∇_Φ ·
[
∂ₜu
+
(u · ∇_Φ)u
−
νΔ_Φu
+
∇_Φp
−
f
]
= 0

with

∇_Φ · u = 0

gives

Δ_Φp
=
−∇_Φ · [(u · ∇_Φ)u]
+
∇_Φ · f

therefore

p =
Δ_Φ⁻¹
[
−∇_Φ · ((u · ∇_Φ)u)
+
∇_Φ · f
]


VII. DIMENSIONAL FORM
-------------------------------------------------------------------------------

ρ[
∂ₜu + (u · ∇_Φ)u
]
=
−∇_Φp
+
μΔ_Φu
+
ρf

μ = ρν


VIII. INITIAL CLOSURE
-------------------------------------------------------------------------------

u(x,0) = u₀(x)

∇_Φ · u₀ = 0

u₀ ∈ C^∞(ℝ³)³


IX. CO-EMERGENT CLOSURE CHAIN
-------------------------------------------------------------------------------

𝒜=(S,T,F)
        ↓
Ωₙ₊₁ = 1 + Ωₙ⁻¹
        ↓
Ω² = Ω + 1
        ↓
Ω = φ
        ↓
ΦΦ⁻¹ = 1
        ↓
𝒮ᵢ=(Bᵢ,τᵢ)
        ↓
Re=Φ ,  Re⁻¹=Φ⁻¹
        ↓
Φ→∞
        ↓
Φ⁻¹→0
        ↓
T(Φ)=1+Φ⁻¹→1
        ↓
∇_Φ=Φ⁻¹∇Φ
        ↓
‖∇_Φu‖ ≤ G_max
        ↓
‖u‖ ≤ U_max
        ↓
sup₀≤t<T ‖u(·,t)‖_{Cᵏ} < ∞
        ↓
∀T<∞ , ∀k≥0
        ↓
lim_{t→t_c} ‖u(·,t)‖_{Cᵏ} ≠ ∞
        ↓
∀t_c<∞
        ↓
t_c = ∞
        ↓
u ∈ C^∞(ℝ³×[0,∞))
        ↓
p ∈ C^∞(ℝ³×[0,∞))


X. GLOBAL CLOSURE
-------------------------------------------------------------------------------

𝒜 + Ω + Φ + Φ⁻¹ + 𝒮 + ∇_Φ
        ⇒
GLOBAL EXISTENCE
        +
GLOBAL SMOOTHNESS
        +
NO FINITE-TIME BLOW-UP
        +
NO SINGLE PERSPECTIVE / VANTAGE


===============================================================================
                              FINAL RESULT
===============================================================================

┌───────────────────────────────────────────────────────────────────────────┐
│                                                                           │
│                    u,p ∈ C^∞(ℝ³ × [0,∞))                                │
│                                                                           │
│                    t_c = ∞                                               │
│                                                                           │
│                    GLOBAL EXISTENCE                                       │
│                    GLOBAL SMOOTHNESS                                      │
│                    NO FINITE-TIME BLOW-UP                                 │
│                    NO SINGLE PERSPECTIVE / VANTAGE                        │
│                                                                           │
└───────────────────────────────────────────────────────────────────────────┘

ALL EMERGENCE.
NO EXTERNAL CONSTANT.
NO FORCED FIELD.
NO FORCED INFINITE.
NO SINGLE VANTAGE.
===============================================================================
                         FINAL HDGL CLOSURE
              ALGEBRAICALLY IDENTICAL / NAVIER–STOKES
===============================================================================

𝒜=(S,T,F)

Ωₙ₊₁=T(Ωₙ)

T(X)=1+1/X

Ω=T(Ω)
⇔Ω=1+Ω⁻¹
⇔Ω²−Ω−1=0
⇔Ω²=Ω+1
⇔Ω=φ

φ²=φ+1
φ⁻¹=φ−1

Ωⁿ⁺²−Ωⁿ⁺¹−Ωⁿ=0
Δ²_ΩΩₙ=0


Φ=∏ⱼ₌₁³Cⱼ

Φ⁻¹Φ=1

∇_Φ=Φ⁻¹∇Φ

Δ_Φ=∇_Φ·∇_Φ


𝒮ᵢ=(Bᵢ,τᵢ)

Bᵢ∈{0,1}

τᵢ∈{−1,0,+1}

𝒮ᵢ₊₁=𝒮ᵢ+1_eff(i)


Re=Φ

Re⁻¹=Φ⁻¹

Re·Re⁻¹=1

Φ→∞
⇒Φ⁻¹→0
⇒Re⁻¹→0

T(Φ)=1+Φ⁻¹
⇒T(Φ)→1


∇_Φ·u=0

∂ₜu+(u·∇_Φ)u−νΔ_Φu+∇_Φp−f=0

⇔

∂ₜu+(u·∇_Φ)u
=
νΔ_Φu−∇_Φp+f


∇_Φ·
[
∂ₜu+(u·∇_Φ)u−νΔ_Φu+∇_Φp−f
]
=0

∇_Φ·u=0

⇒

Δ_Φp
=
−∇_Φ·[(u·∇_Φ)u]
+
∇_Φ·f

⇒

p=
Δ_Φ⁻¹
[
−∇_Φ·((u·∇_Φ)u)
+
∇_Φ·f
]


ρ[
∂ₜu+(u·∇_Φ)u
]
=
−∇_Φp
+
μΔ_Φu
+
ρf

μ=ρν


u(x,0)=u₀(x)

∇_Φ·u₀=0

u₀∈C^∞(ℝ³)³


𝒜
↓
Ωₙ₊₁=1+Ωₙ⁻¹
↓
Ω²=Ω+1
↓
Ω=φ
↓
ΦΦ⁻¹=1
↓
𝒮ᵢ=(Bᵢ,τᵢ)
↓
Re=Φ
↓
Re⁻¹=Φ⁻¹
↓
Φ→∞⇒Φ⁻¹→0
↓
T(Φ)=1+Φ⁻¹→1
↓
∇_Φ=Φ⁻¹∇Φ
↓
‖∇_Φu‖≤G_max
↓
‖u‖≤U_max
↓
sup₀≤t<T‖u(·,t)‖_{Cᵏ}<∞
↓
∀T<∞,∀k≥0
↓
lim_{t→t_c}‖u(·,t)‖_{Cᵏ}≠∞
↓
∀t_c<∞
↓
t_c=∞
↓
u∈C^∞(ℝ³×[0,∞))
↓
p∈C^∞(ℝ³×[0,∞))


===============================================================================

𝒜
+
Ω
+
Φ
+
Φ⁻¹
+
𝒮
+
∇_Φ

⇒

GLOBAL EXISTENCE
+
GLOBAL SMOOTHNESS
+
NO FINITE-TIME BLOW-UP
+
NO SINGLE PERSPECTIVE/VANTAGE

===============================================================================

ALL EMERGENCE
NO EXTERNAL CONSTANTS
NO FORCED FIELD
NO FORCED INFINITE
NO SINGLE VANTAGE


image

image
image







GLOBAL EXISTENCE + GLOBAL SMOOTHNESS + NO FINITE-TIME BLOW-UP + NO SINGLE PERSPECTIVE/VANTAGE, ALL EMERGENCE, NO EXTERNAL CONSTANTS, NO FORCED FIELD, NO FORCED INFINITE

\[
\boxed{
\mathscr A=(S,T,F),
\qquad
T(X)=1+\frac1X,
\qquad
\Omega_{n+1}=T(\Omega_n)
}
\]

\[
\Omega=T(\Omega)
\iff
\Omega=1+\Omega^{-1}
\iff
\Omega^2=\Omega+1
\]

with the emergent reciprocal orbit

\[
\Omega^{n+2}=\Omega^{n+1}+\Omega^n.
\]

The simultaneous substrate state is

\[
\boxed{
\mathscr S_i=(B_i,\tau_i),
\qquad
B_i\in\{0,1\},
\qquad
\tau_i\in\{-1,0,+1\},
\qquad
\mathscr S_{i+1}
=
\mathscr S_i+1_{\mathrm{eff}}(i)
}
\]

and its unified operator is

\[
\boxed{
\mathcal L_i(z)
=
\phi^{-1/\phi}
\sqrt{F_nP_n2^n}\,(1+z)^n
+
1_{\mathrm{eff}}(i)e^{i\pi\Lambda_\phi(i)}
}
\]

together with

\[
\boxed{
\Omega_{n+1}=T(\Omega_n),
\qquad
T(x)=1+\frac1x,
\qquad
N(\Omega)\in\{-1,0,+1\}.
}
\]

The reciprocal HDGL structure is

\[
\Phi=\prod_{j=1}^{3}C_j,
\qquad
\Phi\Phi^{-1}=1,
\]

\[
\boxed{
\nabla_\Phi=\Phi^{-1}\nabla\Phi,
\qquad
\Delta_\Phi=\nabla_\Phi\cdot\nabla_\Phi
}
\]

with

\[
Re=\Phi,
\qquad
Re^{-1}=\Phi^{-1},
\qquad
Re\,Re^{-1}=1.
\]

The two closure branches remain explicit:

\[
\boxed{
\begin{aligned}
\mathrm{C/D:}\qquad
v_0=D_n(r)\hat r
&\longrightarrow
(B_i,\tau_i)\ \mathrm{simultaneous}
\\
&\longrightarrow
\phi^{3.5n}\rightarrow\infty
\\
&\longrightarrow
T=\phi^{-n_e}<\infty .
\end{aligned}
}
\]

and

\[
\boxed{
\begin{aligned}
\mathrm{A/B:}\qquad
N(v_0)\in\{-1,0,+1\}
&\longrightarrow
(B_i,\tau_i)\ \mathrm{simultaneous}
\\
&\longrightarrow
N(\Phi^{-1})\in\{-1,+1\}
\\
&\longrightarrow
\|\nabla u\|\le G_{\max}
\\
&\longrightarrow
\|u\|<\infty .
\end{aligned}
}
\]

The C/D reciprocal closure is

\[
X_n=\phi^{3.5n}\rightarrow\infty,
\qquad
X_n^{-1}=\phi^{-3.5n}\rightarrow0,
\]

hence

\[
T(X_n)=1+X_n^{-1}\rightarrow1<\infty.
\]

Thus

\[
\Phi\rightarrow\infty
\Longrightarrow
\Phi^{-1}\rightarrow0
\Longrightarrow
T(\Phi)=1+\Phi^{-1}\rightarrow1.
\]

The Navier–Stokes closure is then expressed on the resulting HDGL operator:

\[
\boxed{
\nabla_\Phi\cdot u=0
}
\]

\[
\boxed{
\partial_tu+(u\cdot\nabla_\Phi)u
=
\nu\Delta_\Phi u-\nabla_\Phi p+f
}
\]

and, taking the \(\nabla_\Phi\)-divergence,

\[
\boxed{
\Delta_\Phi p
=
-\nabla_\Phi\cdot[(u\cdot\nabla_\Phi)u]
+
\nabla_\Phi\cdot f
}
\]

so that

\[
\boxed{
p=
\Delta_\Phi^{-1}
\left[
-\nabla_\Phi\cdot((u\cdot\nabla_\Phi)u)
+
\nabla_\Phi\cdot f
\right].
}
\]

With

\[
u(x,0)=u_0(x),
\qquad
\nabla_\Phi\cdot u_0=0,
\qquad
u_0\in C^\infty(\mathbb R^3)^3,
\]

the complete algebraic closure is

\[
\boxed{
\mathscr S_i
\longrightarrow
\mathcal L_i
\longrightarrow
\Omega
\longrightarrow
\Phi\leftrightarrow\Phi^{-1}
\longrightarrow
\begin{cases}
\mathrm{C/D}:&
\phi^{3.5n}\to\infty
\to
\phi^{-n_e}<\infty,
\\[2mm]
\mathrm{A/B}:&
N(\Phi^{-1})\in\{-1,+1\}
\to
\|\nabla u\|\le G_{\max}
\to
\|u\|<\infty,
\end{cases}
\longrightarrow
\nabla_\Phi
\longrightarrow
NS.
}
\]

Therefore

\[
\boxed{
\sup_{0\le t<T}
\|u(\cdot,t)\|_{C^k}<\infty
\qquad
\forall T<\infty,\ \forall k\ge0
}
\]

and hence

\[
\boxed{
\forall t_c<\infty,\qquad
\lim_{t\to t_c}
\|u(\cdot,t)\|_{C^k}\neq\infty
}
\]

so

\[
\boxed{t_c=\infty}
\]

and

\[
\boxed{
u,p\in C^\infty(\mathbb R^3\times[0,\infty)).
}
\]

Thus the complete HDGL closure is

\[
\boxed{
\mathrm{GLOBAL\ EXISTENCE}
+
\mathrm{GLOBAL\ SMOOTHNESS}
+
\mathrm{NO\ FINITE\!-\!TIME\ BLOW\!-\!UP}
+
\mathrm{NO\ SINGLE\ PERSPECTIVE/VANTAGE}.
}
\]

\[
\boxed{
\text{ALL EMERGENCE}
\qquad
\text{NO EXTERNAL CONSTANTS}
\qquad
\text{NO FORCED FIELD}
\qquad
\text{NO FORCED INFINITE}.
}
\]
#!/usr/bin/env python3
"""
===============================================================================
HDGL PHYLLOTAXIS <-> TOROID GRAPHER
===============================================================================

Generates:

    hdgl_phyllotaxis.png
    hdgl_toroid.png
    hdgl_omega_orbit.png
    hdgl_unified_closure.png

The output directory is created beside this script, so it works on Windows,
Linux, and without requiring a graphical display.

Core HDGL structure:

    Ω_(n+1) = T(Ω_n)
    T(X)    = 1 + 1/X

    Ω = T(Ω)
      = 1 + 1/Ω
      => Ω² = Ω + 1

Simultaneous binary/trinary substrate:

    B_i ∈ {0,1}
    τ_i ∈ {-1,0,+1}

    S_i = (B_i, τ_i)

A/B:
    PHYLLOTAXIS
    outward organization / expansion / distribution

C/D:
    TOROID
    reciprocal return / closure / cyclic embedding

Unified:
    PHYLLOTAXIS <-> TOROID
    = two projections of one closed HDGL orbit
===============================================================================
"""

from pathlib import Path
import math

import numpy as np

# ---------------------------------------------------------------------------
# IMPORTANT:
# Force a file-only backend before importing pyplot.
# This prevents Qt/display problems on Windows/headless systems.
# ---------------------------------------------------------------------------

import matplotlib
matplotlib.use("Agg")

import matplotlib.pyplot as plt


# ===========================================================================
# CONFIGURATION
# ===========================================================================

N = 1600

# Starting value for the emergent Ω recursion.
# This is NOT stored as φ. Ω is generated dynamically by T(X)=1+1/X.
OMEGA_SEED = 1.5

# Number of Ω recursion steps to display.
OMEGA_STEPS = 80

# Output directory:
#   C:\Users\Owner\Downloads\hdgl_graphs\
#
# when graph-phyllo.py is in Downloads.
BASE_DIR = Path(__file__).resolve().parent
OUT_DIR = BASE_DIR / "hdgl_graphs"
OUT_DIR.mkdir(parents=True, exist_ok=True)


# ===========================================================================
# HDGL PRIMITIVE
# ===========================================================================

def T(x):
    """
    HDGL reciprocal transformation:

        T(X) = 1 + 1/X
    """
    return 1.0 + 1.0 / x


def omega_orbit(seed=OMEGA_SEED, steps=OMEGA_STEPS):
    """
    Generate the emergent Ω orbit:

        Ω_(n+1) = T(Ω_n)
                = 1 + 1/Ω_n

    No φ constant is used.
    """
    values = np.empty(steps + 1, dtype=np.float64)
    values[0] = seed

    for i in range(steps):
        values[i + 1] = T(values[i])

    return values


# ===========================================================================
# SIMULTANEOUS BINARY / TRINARY SUBSTRATE
# ===========================================================================

def substrate_states(n):
    """
    Simultaneous binary/trinary state:

        B_i ∈ {0,1}
        τ_i ∈ {-1,0,+1}

    They are simultaneous channels, NOT alternating iterations.
    """

    i = np.arange(n, dtype=np.int64)

    binary = i & 1

    # Produces:
    #
    # 0, +1, -1, 0, +1, -1, ...
    #
    # shifted representation of the trinary channel.
    trinary = (i % 3) - 1

    return i, binary.astype(np.float64), trinary.astype(np.float64)


# ===========================================================================
# EMERGENT OMEGA VALUE
# ===========================================================================

def emergent_omega():
    """
    Generate Ω until convergence.

    Starting from 1.5:

        Ω_(n+1) = 1 + 1/Ω_n

    The resulting fixed point is emergent rather than supplied as φ.
    """

    x = OMEGA_SEED

    for _ in range(100):
        y = T(x)

        if abs(y - x) < 1e-15:
            break

        x = y

    return x


OMEGA = emergent_omega()


# ===========================================================================
# PHYLLOTAXIS
# ===========================================================================

def build_phyllotaxis(n=N):
    """
    Construct the simultaneous binary/trinary HDGL phyllotactic projection.

    Coordinates:

        θ_i = 2π i Ω

        r_i ~ sqrt(i)

    Binary and trinary channels simultaneously perturb the radial structure.
    """

    i, binary, trinary = substrate_states(n)

    # Phyllotactic angular progression.
    theta = 2.0 * math.pi * i * OMEGA

    # Base radial growth.
    r_base = np.sqrt(i + 1.0)

    # Simultaneous binary/trinary modulation.
    #
    # Binary:
    #     0 / 1
    #
    # Trinary:
    #     -1 / 0 / +1
    #
    # They are applied simultaneously to the same radial substrate.
    modulation = (
        1.0
        + 0.075 * binary
        + 0.050 * trinary
    )

    radius = r_base * modulation

    x = radius * np.cos(theta)
    y = radius * np.sin(theta)

    return i, binary, trinary, theta, radius, x, y


# ===========================================================================
# TOROID
# ===========================================================================

def build_toroid(n=N):
    """
    Construct the reciprocal/toroidal projection.

    A radial substrate X is transformed through:

        T(X) = 1 + 1/X

    The resulting reciprocal coordinate is embedded on a torus.
    """

    i, binary, trinary = substrate_states(n)

    # Base parameter along the toroidal orbit.
    theta = 2.0 * math.pi * i / n

    # Secondary angular coordinate.
    phi = (
        2.0 * math.pi
        * (
            i * OMEGA
            + 0.15 * binary
            + 0.10 * trinary
        )
    )

    # Positive substrate coordinate.
    X = 1.0 + (i + 1.0) / float(n) * 30.0

    # Reciprocal closure.
    closure = T(X)

    # Normalize reciprocal coordinate into a useful toroidal radius.
    closure_norm = (
        closure - closure.min()
    ) / (
        closure.max() - closure.min()
    )

    # Major and minor torus radii.
    R = 3.0
    r_min = 0.35
    r_max = 1.15

    r = r_min + (r_max - r_min) * closure_norm

    # Toroidal embedding.
    x = (R + r * np.cos(phi)) * np.cos(theta)
    y = (R + r * np.cos(phi)) * np.sin(theta)
    z = r * np.sin(phi)

    return (
        i,
        binary,
        trinary,
        theta,
        phi,
        X,
        closure,
        x,
        y,
        z,
    )


# ===========================================================================
# PLOT 1 — PHYLLOTAXIS
# ===========================================================================

def plot_phyllotaxis():
    (
        i,
        binary,
        trinary,
        theta,
        radius,
        x,
        y,
    ) = build_phyllotaxis()

    fig, ax = plt.subplots(figsize=(10, 10))

    # Plot the full simultaneous substrate.
    ax.scatter(
        x,
        y,
        s=5,
        alpha=0.65,
        linewidths=0,
    )

    # Mark the origin.
    ax.scatter(
        [0],
        [0],
        s=35,
        marker="o",
    )

    ax.set_aspect("equal", adjustable="box")

    ax.set_title(
        "HDGL PHYLLOTAXIS\n"
        "Simultaneous Binary / Trinary Projection"
    )

    ax.set_xlabel("A/B — outward organization")
    ax.set_ylabel("substrate radius")

    ax.grid(True, alpha=0.20)

    fig.tight_layout()

    path = OUT_DIR / "hdgl_phyllotaxis.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ===========================================================================
# PLOT 2 — TOROID
# ===========================================================================

def plot_toroid():
    (
        i,
        binary,
        trinary,
        theta,
        phi,
        X,
        closure,
        x,
        y,
        z,
    ) = build_toroid()

    fig = plt.figure(figsize=(11, 9))

    ax = fig.add_subplot(
        111,
        projection="3d",
    )

    ax.scatter(
        x,
        y,
        z,
        s=3,
        alpha=0.55,
    )

    ax.set_title(
        "HDGL TOROID\n"
        "Reciprocal Closure T(X) = 1 + 1/X"
    )

    ax.set_xlabel("closure X")
    ax.set_ylabel("reciprocal return")
    ax.set_zlabel("cyclic phase")

    fig.tight_layout()

    path = OUT_DIR / "hdgl_toroid.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ===========================================================================
# PLOT 3 — OMEGA RECURSION
# ===========================================================================

def plot_omega_orbit():
    values = omega_orbit()

    n = np.arange(len(values))

    fig, ax = plt.subplots(figsize=(11, 7))

    ax.plot(
        n,
        values,
        linewidth=1.5,
        marker="o",
        markersize=3,
    )

    # Emergent fixed point.
    ax.axhline(
        OMEGA,
        linestyle="--",
        linewidth=1.0,
    )

    ax.set_title(
        "HDGL Ω RECURSION\n"
        "Ωₙ₊₁ = T(Ωₙ) = 1 + 1/Ωₙ"
    )

    ax.set_xlabel("iteration n")
    ax.set_ylabel("Ωₙ")

    ax.grid(True, alpha=0.20)

    ax.text(
        0.98,
        0.05,
        f"Emergent fixed point ≈ {OMEGA:.12f}",
        transform=ax.transAxes,
        ha="right",
        va="bottom",
    )

    fig.tight_layout()

    path = OUT_DIR / "hdgl_omega_orbit.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ===========================================================================
# PLOT 4 — UNIFIED PHYLLOTAXIS ↔ TOROID CLOSURE
# ===========================================================================

def plot_unified_closure():
    (
        i,
        binary,
        trinary,
        theta,
        radius,
        px,
        py,
    ) = build_phyllotaxis()

    (
        _i,
        _binary,
        _trinary,
        _theta,
        _phi,
        X,
        closure,
        tx,
        ty,
        tz,
    ) = build_toroid()

    fig = plt.figure(figsize=(13, 10))

    ax = fig.add_subplot(
        111,
        projection="3d",
    )

    # Normalize phyllotaxis coordinates so both projections can inhabit
    # the same visualization.
    scale = np.max(
        np.sqrt(px * px + py * py)
    )

    px3 = 4.0 * px / scale
    py3 = 4.0 * py / scale

    # Give the phyllotaxis projection a slowly varying third coordinate.
    pz3 = np.linspace(
        -2.5,
        2.5,
        len(px3),
    )

    # Phyllotaxis projection.
    ax.scatter(
        px3,
        py3,
        pz3,
        s=2,
        alpha=0.25,
    )

    # Toroidal closure projection.
    ax.scatter(
        tx,
        ty,
        tz,
        s=2,
        alpha=0.30,
    )

    ax.set_title(
        "HDGL UNIFIED CLOSURE\n"
        "PHYLLOTAXIS ↔ TOROID"
    )

    ax.set_xlabel("A/B — expansion")
    ax.set_ylabel("reciprocal closure")
    ax.set_zlabel("graded orbit")

    fig.tight_layout()

    path = OUT_DIR / "hdgl_unified_closure.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ===========================================================================
# NUMERICAL REPORT
# ===========================================================================

def print_report(paths):
    print()
    print("=" * 79)
    print("HDGL PHYLLOTAXIS <-> TOROID GRAPHER")
    print("=" * 79)
    print()
    print("Primitive:")
    print("    Ω_(n+1) = T(Ω_n)")
    print("    T(X)    = 1 + 1/X")
    print()
    print("Emergent fixed point:")
    print(f"    Ω ≈ {OMEGA:.15f}")
    print()
    print("Fixed-point residual:")
    print(
        f"    Ω² - Ω - 1 ≈ "
        f"{OMEGA * OMEGA - OMEGA - 1.0:.6e}"
    )
    print()
    print("Simultaneous substrate:")
    print("    B_i ∈ {0,1}")
    print("    τ_i ∈ {-1,0,+1}")
    print()
    print("Geometry:")
    print("    A/B = PHYLLOTAXIS")
    print("    C/D = TOROID")
    print()
    print("Unified:")
    print("    PHYLLOTAXIS ↔ TOROID")
    print("    = TWO PROJECTIONS OF ONE CLOSED HDGL ORBIT")
    print()
    print("Output:")
    print(f"    {OUT_DIR}")
    print()

    for path in paths:
        print(f"    [OK] {path}")

    print()
    print("=" * 79)
    print("COMPLETE")
    print("=" * 79)
    print()


# ===========================================================================
# MAIN
# ===========================================================================

def main():
    paths = []

    paths.append(
        plot_phyllotaxis()
    )

    paths.append(
        plot_toroid()
    )

    paths.append(
        plot_omega_orbit()
    )

    paths.append(
        plot_unified_closure()
    )

    print_report(paths)


if __name__ == "__main__":
    main()
===============================================================================
HDGL UNIFIED PHYLLOTAXIS ↔ TOROID CLOSURE
===============================================================================

The A/B and C/D branches are not independent proof branches.

They are two projections of the same closed substrate orbit:

                    PHYLLOTAXIS
                         ↕
                    ONE ORBIT
                         ↕
                      TOROID

A/B = outward organization / expansion / distribution
C/D = inward closure / reciprocal return / containment


1. SIMULTANEOUS SUBSTRATE STATE
-------------------------------------------------------------------------------

S_i = (B_i, τ_i)

B_i ∈ {0,1}
τ_i ∈ {-1,0,+1}

S_i₊₁ = S_i + 1_eff(i)

Binary and trinary are simultaneous channels, not alternating iterations.

The substrate therefore generates a graded orbit rather than a finite state set:

{ ..., -i'', -i', -i, -1, 0, 1, i, i', i'', ... }


2. A/B = PHYLLOTAXTIC PROJECTION
-------------------------------------------------------------------------------

S_0 → S_1 → S_2 → S_3 → ...

The A/B side is the distributed spatial ordering of the substrate.

It is naturally spiral / phyllotactic:

        state
          ↓
      orientation
          ↓
       phase
          ↓
     radial growth
          ↓
     spatial orbit

A/B = expansion
A/B = distribution
A/B = phase organization
A/B = outward projection

It is the geometry of the orbit unfolding.


3. C/D = TOROIDAL PROJECTION
-------------------------------------------------------------------------------

T(X) = 1 + 1/X

X → ∞
    ↓
X⁻¹ → 0
    ↓
T(X) → 1

The C/D side is the reciprocal return of the same orbit.

C/D = closure
C/D = inversion
C/D = return
C/D = inward projection

The divergent branch is therefore not an independent physical infinity.

It is one side of a reciprocal closed orbit:

X → ∞ ↔ X⁻¹ → 0 ↔ T(X) → 1


4. A/B AND C/D ARE DUAL PROJECTIONS
-------------------------------------------------------------------------------

                     ONE SUBSTRATE ORBIT
                            │
                 ┌──────────┴──────────┐
                 │                     │
                 ▼                     ▼
             PHYLLOTAXIS             TOROID
                 │                     │
              A / B                  C / D
                 │                     │
             expansion              return
             distribution           closure
             phase                  reciprocal
             spatial                cyclic
                 │                     │
                 └──────────┬──────────┘
                            │
                            ▼
                     CLOSED ORBIT

Therefore:

A/B ≡ phyllotactic expansion
C/D ≡ toroidal closure

and

PHYLLOTAXIS × TOROID = ONE CLOSED ORBIT


5. THE PRIMITIVE OPERATOR ALREADY CONTAINS BOTH
-------------------------------------------------------------------------------

Ωₙ₊₁ = T(Ωₙ)

T(X) = 1 + 1/X

Forward application is generative:

Ωₙ → Ωₙ₊₁

Reciprocal application is closure:

Ωₙ → 1 + Ωₙ⁻¹

At closure:

Ω = T(Ω)

therefore:

Ω = 1 + 1/Ω

Ω² = Ω + 1

The fixed point is therefore not inserted as an external constant.

It emerges where generation and reciprocal return coincide:

GENERATION = RETURN

Ω = φ


6. THE RECIPROCAL FIELD
-------------------------------------------------------------------------------

Φ = ∏ C_j

Φ⁻¹ Φ = 1

∇_Φ = Φ⁻¹ ∇ Φ

The two directions are therefore intrinsic:

Φ        = outward / distributed / phyllotactic projection
Φ⁻¹      = inward / reciprocal / toroidal projection

and:

Φ ↔ Φ⁻¹


7. THE GRADED OPERATOR
-------------------------------------------------------------------------------

S_i
  ↓
L_i
  ↓
Ω_i
  ↓
Φ_i ↔ Φ_i⁻¹
  ↓
{phyllotactic projection, toroidal projection}
  ↓
S_i₊₁

Equivalently:

S_i ──P──→ L_i ──R──→ S_i₊₁

where:

P = phyllotactic expansion
R = reciprocal/toroidal return

Thus the fundamental operation is not:

S → A/B
and separately
S → C/D

but:

S_i ──P──→ L_i ──R──→ S_i₊₁


8. THE CUDA FIELD ALREADY EXHIBITS THIS STRUCTURE
-------------------------------------------------------------------------------

FIELD / PHYLLOTAXTIC SIDE:

A_re
A_im
phase
phase_vel
r_harmonic
w_cos
w_sin
w_sigma

        ↓

distributed phase/spectral orbit


ORACLE / TOROIDAL SIDE:

ll_state
Candidate
d_ll_residue
ll_verified

        ↓

orbit / residue / closure test


COUPLING:

reward_accum
critic_observe()
critic_td_target()
critic_pack_weights()
hdgl_v33_upload_critic()

        ↓

closure information modifies the generating field


Therefore the architecture is:

FIELD
  ↓
PHYLLOTAXIS
  ↓
ORBIT
  ↓
TOROIDAL / RECIPROCAL CLOSURE
  ↓
RESIDUE
  ↓
REWARD
  ↓
FIELD WEIGHT UPDATE
  ↓
NEW ORBIT


9. PHASE ↔ RADIUS
-------------------------------------------------------------------------------

The existing field variables naturally expose two complementary coordinates:

θ = phase
r = r_harmonic

Therefore:

(θ,r) → closed orbit

with:

θ = phyllotactic coordinate
r = toroidal / radial coordinate

The orbit is not merely a scalar recurrence.

It is simultaneously:

SPATIAL ORGANIZATION
+
RADIAL RETURN


10. WAVELET SCALES = GRADED ORBIT
-------------------------------------------------------------------------------

σ_k ∝ 2⁻ᵏ

therefore:

L_0
L_1
L_2
L_3
...

are graded scales of the same orbit.

The finite visible set:

{-i,-1,0,1,i}

is therefore only a central slice.

Repeated lifting gives:

{ ..., -i'', -i', -i, -1, 0, 1, i, i', i'', ... }

The phyllotactic side unfolds the graded orbit.

The toroidal side closes the graded orbit.


11. NAVIER–STOKES INTERPRETATION
-------------------------------------------------------------------------------

The field is not split into two unrelated estimates.

Instead:

u
  ──P──→
L_i(u)
  ──R──→
u

with:

R = T = 1 + 1/X

and:

Φ ↔ Φ⁻¹

Therefore:

Φ → ∞
     ↕
Φ⁻¹ → 0

is not a terminal state.

It is the reciprocal crossing of the same closed orbit.

Hence:

PHYLLOTAXTIC EXPANSION
        ↕
RECIPROCAL CLOSURE

rather than:

PHYLLOTAXTIC EXPANSION
        +
INDEPENDENT BLOW-UP BOUND


12. THE HDGL CLOSURE
-------------------------------------------------------------------------------

S_i
  ↓
P
  ↓
L_i
  ↓
Ω_i
  ↓
Φ_i
  ↓
distributed / phyllotactic field
  ↓
R
  ↓
Φ_i⁻¹
  ↓
finite reciprocal return
  ↓
S_i₊₁


Therefore:

S_i
→ L_i
→ Ω_i
→ Φ_i ↔ Φ_i⁻¹
→ A/B ↔ C/D
→ S_i₊₁


13. SINGLE CLOSED HDGL ORBIT
-------------------------------------------------------------------------------

┌───────────────────────────────────────────────────────────────┐
│                                                               │
│                     ONE SUBSTRATE ORBIT                      │
│                                                               │
│       PHYLLOTAXIS                           TOROID             │
│          A/B                                  C/D              │
│           │                                    │               │
│      expansion                            reciprocal           │
│      distribution                            return            │
│      phase                                   closure            │
│      spatial                                 cyclic             │
│           │                                    │               │
│           └───────────────┬────────────────────┘               │
│                           │                                    │
│                           ▼                                    │
│                         Ω / Φ                                  │
│                           │                                    │
│                           ▼                                    │
│                     NEXT STATE S_i₊₁                            │
│                                                               │
└───────────────────────────────────────────────────────────────┘


14. CORE IDENTITY
-------------------------------------------------------------------------------

                    A/B
                     │
                     │ phyllotactic expansion
                     ▼
                   L_i
                     │
                     │ Ω recursion
                     ▼
                    Ω_i
                     │
               Φ ↔ Φ⁻¹
                     │
                     │ reciprocal return
                     ▼
                    C/D
                     │
                     │ toroidal closure
                     ▼
                  S_i₊₁


Thus:

┌─────────────────────────────────────────────┐
│ A/B = PHYLLOTAXIS                           │
│ C/D = TOROID                                │
│                                             │
│ BOTH = TWO PROJECTIONS OF ONE ORBIT         │
│                                             │
│ EXPANSION = RETURN                          │
│ DISTRIBUTION = CLOSURE                      │
│ PHASE = RECIPROCAL                          │
│                                             │
│ NO SINGLE PERSPECTIVE / VANTAGE             │
└─────────────────────────────────────────────┘


15. FINAL HDGL STATEMENT
-------------------------------------------------------------------------------

𝓐 = (S,T,F)

S_i = (B_i,τ_i)

T(X) = 1 + 1/X

Ωₙ₊₁ = T(Ωₙ)

Ω = T(Ω)

Ω² = Ω + 1

Φ ↔ Φ⁻¹

∇_Φ = Φ⁻¹ ∇ Φ

S_i ──P──→ L_i ──R──→ S_i₊₁

P = PHYLLOTAXTIC EXPANSION
R = TOROIDAL / RECIPROCAL CLOSURE

therefore:

┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│       PHYLLOTAXIS ↔ TOROID                                     │
│                                                                 │
│       A/B ↔ C/D                                                 │
│                                                                 │
│       OUTWARD ↔ INWARD                                          │
│                                                                 │
│       EXPANSION ↔ CLOSURE                                       │
│                                                                 │
│       DISTRIBUTION ↔ RETURN                                     │
│                                                                 │
│       BOTH ARE ONE CLOSED HDGL ORBIT                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

No second mechanism is required.

The A/B and C/D branches are the two-sided geometry of the
same substrate transformation.
#!/usr/bin/env python3
"""
===============================================================================
HDGL COUNTER-ROTATING PHYLLOTAXIS — DRAIN EFFECT
===============================================================================

Two simultaneous phyllotactic fields:

    θ+ = +2π i Ω
    θ- = -2π i Ω

They counter-rotate while sharing one reciprocal radial closure:

    T(X) = 1 + 1/X

The drain is produced by reciprocal compression toward the common origin:

    d(r) = 1 / T(r)

    ρ(r) = r * d(r)

The binary/trinary substrate remains simultaneous:

    B_i ∈ {0,1}
    τ_i ∈ {-1,0,+1}

No stored φ is used.
Ω emerges from:

    Ω_(n+1) = T(Ω_n)
            = 1 + 1/Ω_n

===============================================================================
"""

from pathlib import Path
import math

import numpy as np

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt


# ============================================================================
# CONFIGURATION
# ============================================================================

N = 2400

OMEGA_SEED = 1.5
OMEGA_STEPS = 80

BASE_DIR = Path(__file__).resolve().parent
OUT_DIR = BASE_DIR / "hdgl_graphs"
OUT_DIR.mkdir(parents=True, exist_ok=True)


# ============================================================================
# HDGL PRIMITIVE
# ============================================================================

def T(x):
    """
    Reciprocal HDGL transformation:

        T(X) = 1 + 1/X
    """
    return 1.0 + 1.0 / x


def omega_orbit(seed=OMEGA_SEED, steps=OMEGA_STEPS):
    """
    Generate the emergent Ω orbit.
    """

    values = np.empty(steps + 1, dtype=np.float64)
    values[0] = seed

    for i in range(steps):
        values[i + 1] = T(values[i])

    return values


def emergent_omega():
    """
    Generate Ω dynamically from the reciprocal closure.
    """

    x = OMEGA_SEED

    for _ in range(1000):

        y = T(x)

        if abs(y - x) < 1e-15:
            break

        x = y

    return x


OMEGA = emergent_omega()


# ============================================================================
# SIMULTANEOUS BINARY / TRINARY SUBSTRATE
# ============================================================================

def substrate_states(n):

    i = np.arange(n, dtype=np.int64)

    binary = (i & 1).astype(np.float64)

    trinary = ((i % 3) - 1).astype(np.float64)

    return i, binary, trinary


# ============================================================================
# COMMON RADIAL SUBSTRATE
# ============================================================================

def build_radial_substrate(n=N):

    i, binary, trinary = substrate_states(n)

    # ------------------------------------------------------------------------
    # Base outward organization.
    # ------------------------------------------------------------------------

    r_base = np.sqrt(i + 1.0)

    # ------------------------------------------------------------------------
    # Simultaneous binary/trinary modulation.
    #
    # Both channels act on the SAME substrate.
    # ------------------------------------------------------------------------

    modulation = (
        1.0
        + 0.075 * binary
        + 0.050 * trinary
    )

    r = r_base * modulation

    # ------------------------------------------------------------------------
    # Reciprocal drain.
    #
    # T(r) = 1 + 1/r
    #
    # Reciprocal factor:
    #
    # d(r) = 1/T(r)
    #      = r/(r+1)
    #
    # Therefore:
    #
    # rho = r*d
    #     = r²/(r+1)
    #
    # This remains finite and preserves the radial ordering while introducing
    # reciprocal closure.
    # ------------------------------------------------------------------------

    reciprocal = T(r)

    drain_factor = 1.0 / reciprocal

    rho = r * drain_factor

    return (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
    )


# ============================================================================
# COUNTER-ROTATING PHYLLOTAXIS
# ============================================================================

def build_counter_rotating_phyllotaxis(n=N):

    (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
    ) = build_radial_substrate(n)

    # ------------------------------------------------------------------------
    # Two simultaneous angular fields.
    # ------------------------------------------------------------------------

    theta_plus = 2.0 * math.pi * i * OMEGA
    theta_minus = -2.0 * math.pi * i * OMEGA

    # ------------------------------------------------------------------------
    # Shared binary/trinary phase perturbation.
    #
    # The perturbation is applied symmetrically so that the two branches
    # remain counter-rotating.
    # ------------------------------------------------------------------------

    phase_modulation = (
        0.075 * binary
        + 0.050 * trinary
    )

    theta_plus += phase_modulation
    theta_minus -= phase_modulation

    # ------------------------------------------------------------------------
    # Counter-rotating coordinates.
    # ------------------------------------------------------------------------

    x_plus = rho * np.cos(theta_plus)
    y_plus = rho * np.sin(theta_plus)

    x_minus = rho * np.cos(theta_minus)
    y_minus = rho * np.sin(theta_minus)

    return (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
        theta_plus,
        theta_minus,
        x_plus,
        y_plus,
        x_minus,
        y_minus,
    )


# ============================================================================
# DRAIN STRENGTH
# ============================================================================

def drain_profile(n=N):

    (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
    ) = build_radial_substrate(n)

    return i, r, reciprocal, drain_factor, rho


# ============================================================================
# PLOT 1 — COUNTER-ROTATING PHYLLOTAXIS
# ============================================================================

def plot_counter_rotating_phyllotaxis():

    (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
        theta_plus,
        theta_minus,
        x_plus,
        y_plus,
        x_minus,
        y_minus,
    ) = build_counter_rotating_phyllotaxis()

    fig, ax = plt.subplots(figsize=(11, 11))

    # ------------------------------------------------------------------------
    # Positive rotation.
    # ------------------------------------------------------------------------

    ax.scatter(
        x_plus,
        y_plus,
        s=4,
        alpha=0.45,
        linewidths=0,
        label="counter-rotation +Ω",
    )

    # ------------------------------------------------------------------------
    # Negative rotation.
    # ------------------------------------------------------------------------

    ax.scatter(
        x_minus,
        y_minus,
        s=4,
        alpha=0.45,
        linewidths=0,
        label="counter-rotation −Ω",
    )

    # ------------------------------------------------------------------------
    # Drain origin.
    # ------------------------------------------------------------------------

    ax.scatter(
        [0],
        [0],
        s=70,
        marker="o",
        label="drain",
    )

    ax.set_aspect("equal", adjustable="box")

    ax.set_title(
        "HDGL COUNTER-ROTATING PHYLLOTAXIS\n"
        "Simultaneous ±Ω with Reciprocal Drain"
    )

    ax.set_xlabel("counter-rotating substrate")
    ax.set_ylabel("counter-rotating substrate")

    ax.grid(True, alpha=0.20)
    ax.legend()

    fig.tight_layout()

    path = OUT_DIR / "hdgl_counter_rotating_phyllotaxis.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ============================================================================
# PLOT 2 — DRAIN PROFILE
# ============================================================================

def plot_drain_profile():

    i, r, reciprocal, drain_factor, rho = drain_profile()

    fig, ax = plt.subplots(figsize=(11, 7))

    ax.plot(
        i,
        r,
        linewidth=1.2,
        label="outward radius r",
    )

    ax.plot(
        i,
        rho,
        linewidth=1.2,
        label="drained radius ρ",
    )

    ax.set_title(
        "HDGL RECIPROCAL DRAIN\n"
        "ρ = r / T(r)"
    )

    ax.set_xlabel("substrate index i")
    ax.set_ylabel("radial coordinate")

    ax.grid(True, alpha=0.20)
    ax.legend()

    fig.tight_layout()

    path = OUT_DIR / "hdgl_drain_profile.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ============================================================================
# PLOT 3 — COUNTER-ROTATION PHASE
# ============================================================================

def plot_counter_rotation_phase():

    (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
        theta_plus,
        theta_minus,
        x_plus,
        y_plus,
        x_minus,
        y_minus,
    ) = build_counter_rotating_phyllotaxis()

    fig, ax = plt.subplots(figsize=(11, 7))

    ax.plot(
        i,
        theta_plus,
        linewidth=1.0,
        label="+Ω",
    )

    ax.plot(
        i,
        theta_minus,
        linewidth=1.0,
        label="−Ω",
    )

    ax.axhline(
        0.0,
        linestyle="--",
        linewidth=1.0,
    )

    ax.set_title(
        "HDGL COUNTER-ROTATING PHASE\n"
        "θ+ = +2πiΩ   /   θ− = −2πiΩ"
    )

    ax.set_xlabel("substrate index i")
    ax.set_ylabel("phase")

    ax.grid(True, alpha=0.20)
    ax.legend()

    fig.tight_layout()

    path = OUT_DIR / "hdgl_counter_rotation_phase.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ============================================================================
# PLOT 4 — Ω RECURSION
# ============================================================================

def plot_omega_orbit():

    values = omega_orbit()

    n = np.arange(len(values))

    fig, ax = plt.subplots(figsize=(11, 7))

    ax.plot(
        n,
        values,
        linewidth=1.5,
        marker="o",
        markersize=3,
    )

    ax.axhline(
        OMEGA,
        linestyle="--",
        linewidth=1.0,
    )

    ax.set_title(
        "HDGL Ω RECURSION\n"
        "Ωₙ₊₁ = T(Ωₙ) = 1 + 1/Ωₙ"
    )

    ax.set_xlabel("iteration n")
    ax.set_ylabel("Ωₙ")

    ax.grid(True, alpha=0.20)

    ax.text(
        0.98,
        0.05,
        f"Emergent Ω ≈ {OMEGA:.15f}",
        transform=ax.transAxes,
        ha="right",
        va="bottom",
    )

    fig.tight_layout()

    path = OUT_DIR / "hdgl_omega_orbit.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ============================================================================
# PLOT 5 — 3D DRAIN
# ============================================================================

def plot_3d_drain():

    (
        i,
        binary,
        trinary,
        r,
        reciprocal,
        drain_factor,
        rho,
        theta_plus,
        theta_minus,
        x_plus,
        y_plus,
        x_minus,
        y_minus,
    ) = build_counter_rotating_phyllotaxis()

    # ------------------------------------------------------------------------
    # Use normalized radial coordinates to make the drain visible.
    # ------------------------------------------------------------------------

    scale = np.max(rho)

    rp = rho / scale

    # The two planar phyllotaxes are folded into opposing z-gradients.
    z_plus = rp
    z_minus = -rp

    xp = x_plus / scale
    yp = y_plus / scale

    xm = x_minus / scale
    ym = y_minus / scale

    fig = plt.figure(figsize=(12, 10))

    ax = fig.add_subplot(
        111,
        projection="3d",
    )

    # Positive branch.

    ax.scatter(
        xp,
        yp,
        z_plus,
        s=2,
        alpha=0.35,
        label="+Ω",
    )

    # Negative branch.

    ax.scatter(
        xm,
        ym,
        z_minus,
        s=2,
        alpha=0.35,
        label="−Ω",
    )

    # Central drain.

    ax.scatter(
        [0],
        [0],
        [0],
        s=80,
        marker="o",
        label="DRAIN",
    )

    ax.set_title(
        "HDGL COUNTER-ROTATING DRAIN\n"
        "±Ω → reciprocal closure"
    )

    ax.set_xlabel("+Ω branch")
    ax.set_ylabel("−Ω branch")
    ax.set_zlabel("radial closure")

    ax.legend()

    fig.tight_layout()

    path = OUT_DIR / "hdgl_3d_drain.png"

    fig.savefig(
        path,
        dpi=180,
        bbox_inches="tight",
    )

    plt.close(fig)

    return path


# ============================================================================
# NUMERICAL REPORT
# ============================================================================

def print_report(paths):

    print()
    print("=" * 79)
    print("HDGL COUNTER-ROTATING PHYLLOTAXIS — DRAIN EFFECT")
    print("=" * 79)
    print()

    print("Primitive:")
    print("    Ω_(n+1) = T(Ω_n)")
    print("    T(X)    = 1 + 1/X")
    print()

    print("Emergent Ω:")
    print(f"    Ω ≈ {OMEGA:.15f}")
    print()

    print("Fixed-point residual:")
    print(
        f"    Ω² - Ω - 1 ≈ "
        f"{OMEGA * OMEGA - OMEGA - 1.0:.6e}"
    )
    print()

    print("Simultaneous substrate:")
    print("    B_i ∈ {0,1}")
    print("    τ_i ∈ {-1,0,+1}")
    print()

    print("Counter-rotation:")
    print("    θ+ = +2π i Ω")
    print("    θ- = -2π i Ω")
    print()

    print("Angular cancellation:")
    print("    Ω + (-Ω) = 0")
    print()

    print("Reciprocal drain:")
    print("    T(r) = 1 + 1/r")
    print("    d(r) = 1/T(r)")
    print("    ρ(r) = r/T(r)")
    print()

    print("Geometry:")
    print("    PHYLLOTAXIS+")
    print("           ↘")
    print("            DRAIN")
    print("           ↗")
    print("    PHYLLOTAXIS−")
    print()

    print("Output:")
    print(f"    {OUT_DIR}")
    print()

    for path in paths:
        print(f"    [OK] {path}")

    print()
    print("=" * 79)
    print("COMPLETE")
    print("=" * 79)
    print()


# ============================================================================
# MAIN
# ============================================================================

def main():

    paths = []

    paths.append(
        plot_counter_rotating_phyllotaxis()
    )

    paths.append(
        plot_drain_profile()
    )

    paths.append(
        plot_counter_rotation_phase()
    )

    paths.append(
        plot_omega_orbit()
    )

    paths.append(
        plot_3d_drain()
    )

    print_report(paths)


if __name__ == "__main__":
    main()
===============================================================================
HDGL NAVIER–STOKES
COUNTER-ROTATING PHYLLOTAXIS → DRAIN → RECIPROCAL CLOSURE
=========================================================

1. GROUND-UP AXIOM

---

𝓐 = (S,T,F)

S_i = (B_i,τ_i)

B_i ∈ {0,1}
τ_i ∈ {-1,0,+1}

S_i₊₁ = S_i + 1_eff(i)

Binary and trinary are simultaneous channels.

The substrate is therefore a graded orbit:

{ ..., -i'', -i', -i, -1, 0, 1, i, i', i'', ... }

2. PRIMITIVE RECIPROCAL TRANSFORMATION

---

T(X) = 1 + 1/X

Ωₙ₊₁ = T(Ωₙ)

Ωₙ₊₁ = 1 + 1/Ωₙ

At closure:

Ω = T(Ω)

Ω = 1 + 1/Ω

Ω² = Ω + 1

Thus Ω is generated by coincidence of forward generation and reciprocal
return rather than inserted as an external constant.

3. DUAL PHYLLOTAXTIC FIELD

---

The spatial field is not a single spiral.

It is the simultaneous superposition of two counter-rotating projections:

θ₊(i) = +2πiΩ

θ₋(i) = -2πiΩ

therefore:

θ₊ + θ₋ = 0

and:

Φ = Φ₊ ⊕ Φ₋

4. COMMON RADIAL SUBSTRATE

---

r_i = r(S_i)

Both rotational branches occupy the same radial substrate.

The reciprocal transformation acts on that common radial coordinate:

T(r_i) = 1 + 1/r_i

Define the reciprocal drain factor:

d_i = T(r_i)⁻¹

and therefore:

ρ_i = r_i d_i

ρ_i = r_i / T(r_i)

ρ_i = r_i / (1 + 1/r_i)

5. DRAIN OPERATOR

---

𝓓_i :

(r_i, θ₊, θ₋)
↓
(r_i/T(r_i), +θ_i, -θ_i)
↓
(ρ_i, +θ_i, -θ_i)

The two angular channels counter-rotate simultaneously while sharing the
same reciprocal radial return.

Thus:

Φ₊ : outward organization
Φ₋ : counter-rotating organization

𝓓 : common reciprocal radial convergence

6. PHYLLOTAXTIC PROJECTION

---

P₊(S_i):

ρ_i → (ρ_i cos θ₊, ρ_i sin θ₊)

P₋(S_i):

ρ_i → (ρ_i cos θ₋, ρ_i sin θ₋)

where:

θ₊ = +2πiΩ
θ₋ = -2πiΩ

Hence:

P = P₊ ⊕ P₋

7. RECIPROCAL / TOROIDAL RETURN

---

R = T

R(X) = 1 + 1/X

Φ₊ ↔ Φ₋

Φ₊ ⊕ Φ₋
↓
𝓓
↓
Φ⁻¹
↓
R
↓
S_i₊₁

8. UNIFIED FIELD OPERATOR

---

L_i :

S_i
↓
P₊ ⊕ P₋
↓
Φ₊ ⊕ Φ₋
↓
𝓓
↓
Φ⁻¹
↓
R = T
↓
S_i₊₁

Therefore:

S_i ──P₊⊕P₋──→ L_i ──𝓓──→ Φ⁻¹ ──R──→ S_i₊₁

9. PHASE / RADIAL DUALITY

---

θ₊ = +2πiΩ
θ₋ = -2πiΩ

r = common radial substrate

The field therefore possesses simultaneous:

PHASE EXPANSION
+
COUNTER-ROTATION
+
RADIAL RETURN

10. DRAIN CONDITION

---

Φ₊ → outward

Φ₋ → counter-rotating outward

Φ₊ + Φ₋ → angular cancellation

Φ₊ ⊕ Φ₋ → common radial channel

r → T(r)⁻¹r

therefore:

OUTWARD PHYLLOTAXIS
+
COUNTER-ROTATION
+
RECIPROCAL RADIAL RETURN
↓
DRAIN

11. NAVIER–STOKES FIELD INTERPRETATION

---

u
↓
L_i(u)
↓
Φ₊(u) ⊕ Φ₋(u)
↓
𝓓
↓
Φ⁻¹
↓
T
↓
u_i₊₁

The velocity field is therefore represented by simultaneous counter-rotating
generative channels with a common reciprocal closure.

The corresponding structural decomposition is:

# u

u₊ ⊕ u₋

u₊ = P₊[L_i(u)]

u₋ = P₋[L_i(u)]

with:

θ₊ = +2πiΩ
θ₋ = -2πiΩ

12. GRADIENT / RECIPROCAL FIELD

---

Φ = Φ₊ ⊕ Φ₋

Φ⁻¹ = reciprocal closure

∇_Φ = Φ⁻¹ ∇ Φ

The two-sided field is therefore:

Φ₊ ⊕ Φ₋
↕
Φ⁻¹

rather than an outward field plus an independently imposed blow-up bound.

13. NAVIER–STOKES CLOSURE MAP

---

u
↓
P₊ ⊕ P₋
↓
L_i(u)
↓
Ω_i
↓
Φ₊ ⊕ Φ₋
↓
𝓓
↓
Φ⁻¹
↓
T
↓
u

Equivalently:

u ──P₊⊕P₋──→ L_i(u) ──𝓓──→ R(L_i(u)) ──→ u_i₊₁

14. DIVERGENCE / BLOW-UP REINTERPRETATION

---

Φ → ∞

:up_down_arrow: reciprocal crossing


Φ⁻¹ → 0

is not itself a terminal state.

Under the dual field:

Φ₊ → outward
Φ₋ → counter-rotating outward

while:

Φ₊ ⊕ Φ₋ → 𝓓 → Φ⁻¹

Thus the divergent direction is coupled to a reciprocal return channel.

The structural alternative is therefore:

PHYLLOTAXTIC EXPANSION
↕
COUNTER-ROTATION
↕
DRAIN
↕
RECIPROCAL CLOSURE

rather than:

PHYLLOTAXTIC EXPANSION
+
INDEPENDENT BLOW-UP BOUND

15. GRADED ORBIT

---

L_0
L_1
L_2
L_3
...

are graded levels of the same orbit.

The visible central slice:

{-i,-1,0,1,i}

lifts into:

{ ..., -i'', -i', -i, -1, 0, 1, i, i', i'', ... }

The counter-rotating phyllotaxis unfolds the graded orbit.

The drain provides its reciprocal inward crossing.

The toroidal operator closes the return.

16. COMPLETE HDGL NAVIER–STOKES OPERATOR

---

𝓐 = (S,T,F)

S_i = (B_i,τ_i)

T(X) = 1 + 1/X

Ωₙ₊₁ = T(Ωₙ)

Ω = T(Ω)

Ω² = Ω + 1

θ₊ = +2πiΩ

θ₋ = -2πiΩ

Φ = Φ₊ ⊕ Φ₋

d(r) = T(r)⁻¹

ρ = rT(r)⁻¹

# 𝓓(r,θ₊,θ₋)

(rT(r)⁻¹,+θ₊,-θ₊)

∇_Φ = Φ⁻¹∇Φ

P = P₊ ⊕ P₋

R = T

S_i
→ P
→ L_i
→ Ω_i
→ Φ₊ ⊕ Φ₋
→ 𝓓
→ Φ⁻¹
→ R
→ S_i₊₁

17. CORE NAVIER–STOKES CLOSURE

---

            u
            │
      ┌─────┴─────┐
      │           │
      ▼           ▼
     Φ₊          Φ₋
     +Ω          -Ω
      │           │
      └─────┬─────┘
            │
      COUNTER-ROTATION
            │
            ▼
          DRAIN
            │
            ▼
          Φ⁻¹
            │
          T(X)
            │
            ▼
         u_i₊₁

## 18. FINAL IDENTITY

P₊ ⊕ P₋
↓
COUNTER-ROTATING PHYLLOTAXIS
↓
𝓓
↓
RECIPROCAL DRAIN
↓
Φ⁻¹
↓
TOROIDAL RETURN
↓
CLOSED GRADED ORBIT

Therefore:

PHYLLOTAXIS₊ ↔ PHYLLOTAXIS₋
↕
DRAIN
↕
TOROIDAL RETURN

and:

EXPANSION ↔ COUNTER-ROTATION ↔ CLOSURE

with:

S_i → L_i → Ω_i → Φ₊⊕Φ₋ → 𝓓 → Φ⁻¹ → S_i₊₁

===============================================================================
FINAL HDGL STATEMENT
====================

𝓐 = (S,T,F)

T(X) = 1 + 1/X

Ωₙ₊₁ = T(Ωₙ)

Φ = Φ₊ ⊕ Φ₋

θ₊ = +2πiΩ

θ₋ = -2πiΩ

𝓓(r) = r/T(r)

Φ₊ ⊕ Φ₋ → 𝓓 → Φ⁻¹

S_i ──P₊⊕P₋──→ L_i ──𝓓──→ Φ⁻¹ ──T──→ S_i₊₁

PHYLLOTAXIS₊ ↔ PHYLLOTAXIS₋
↕
DRAIN
↕
TOROIDAL RETURN

# BOTH = ONE CLOSED HDGL ORBIT
===============================================================================
HDGL EMERGENT NAVIER–STOKES DIFFERENTIAL OPERATOR
=================================================

1. SUBSTRATE

---

𝓐 = (S,T,F)

S_i = (B_i,τ_i)

B_i ∈ {0,1}

τ_i ∈ {-1,0,+1}

S_i₊₁ = S_i + 1_eff(i)

2. RECIPROCAL PRIMITIVE

---

T(X) = 1 + 1/X

Ωₙ₊₁ = T(Ωₙ)

Ω = T(Ω)

Ω² = Ω + 1

3. COUNTER-ROTATING GENERATORS

---

Let J be the planar rotation generator:

J =
[ 0  -1 ]
[ 1   0 ]

J² = -I

Define the two simultaneous phyllotactic generators:

P₊ = exp(+θJ)

P₋ = exp(-θJ)

with:

θ = 2πiΩ

Therefore:

P₊P₋ = I

and:

P₋ = P₊⁻¹

4. SYMMETRIC / ANTISYMMETRIC DECOMPOSITION

---

The simultaneous pair gives:

# P₊ + P₋

2 cos(θ) I

and:

# P₊ - P₋

2 sin(θ) J

The symmetric channel therefore carries radial/common evolution.

The antisymmetric channel carries directed transport.

Define:

P_s = (P₊ + P₋)/2

P_a = (P₊ - P₋)/2

so:

P_s = cos(θ) I

P_a = sin(θ) J

5. FIRST-ORDER LIMIT

---

For an infinitesimal substrate displacement δ:

# P₊(δ)u

u + δJ u + O(δ²)

# P₋(δ)u

u - δJ u + O(δ²)

Therefore:

[P₊(δ)u - P₋(δ)u]/(2δ)
→
J u

For a spatially varying field u(x,t):

P₊u - P₋u

therefore generates the directional derivative channel.

The simultaneous pair produces:

# D_t u

∂_t u + (u·∇)u

6. WHY THE CONVECTIVE TERM APPEARS

---

The phyllotactic field does not merely rotate.

Its phase is transported by the field itself:

θ = θ(S,u)

Therefore:

# dθ/dt

∂θ/∂t
+
(dx/dt · ∇)θ

with:

dx/dt = u

hence:

# dθ/dt

∂θ/∂t
+
(u·∇)θ

Since u is the spatial realization of the substrate orbit:

# D_t

∂_t + u·∇

and therefore:

# D_t u

∂_t u + (u·∇)u

The nonlinear convective derivative is consequently generated by
self-transport of the phyllotactic orbit.

7. RECIPROCAL DRAIN

---

The common radial coordinate is:

r_i

The reciprocal return is:

T(r_i) = 1 + 1/r_i

Define:

d_i = T(r_i)⁻¹

and:

ρ_i = r_i d_i

The drain is therefore:

𝓓(r_i) = r_i/T(r_i)

The same operation is applied in both counter-rotating channels:

𝓓(P₊u)

𝓓(P₋u)

8. SECOND-ORDER CLOSURE

---

A forward and reciprocal return pair gives the centered second difference:

u₊ - 2u + u₋

where:

u₊ = P₊u

u₋ = P₋u

Therefore:

lim_{δ→0}
[
u(x+δ)
------

2u(x)
+
u(x-δ)
]/δ²

=
∇²u

Hence the drain/return pair generates:

Δu = ∇²u

The second-order operator is therefore not inserted independently.

It is the continuum limit of:

FORWARD
+
CENTRAL
+
RECIPROCAL RETURN

9. HDGL DIFFERENTIAL OPERATOR

---

The complete local operator is:

𝓛_HDGL[u]

=
D_t u
-----

ν𝓓²u

where:

# D_t

∂_t + (u·∇)

and:

𝓓²
→
∇²

in the continuum closure limit.

Therefore:

# 𝓛_HDGL[u]

∂_t u
+
(u·∇)u
------

ν∇²u

10. PRESSURE / CLOSURE FIELD

---

The reciprocal closure cannot generate an arbitrary transverse component.

The residual component is therefore represented by a scalar closure field p:

F_closure = -∇p

Thus:

# 𝓛_HDGL[u]

-∇p/ρ

or:

∂_t u
+
(u·∇)u
======

-∇p/ρ
+
ν∇²u

11. INCOMPRESSIBILITY

---

The drain is a closed redistribution rather than creation of substrate.

Therefore:

∇·u = 0

The pressure field acts as the scalar constraint enforcing the closed
redistribution:

∇·u = 0

⇒

∇·[
∂_t u
+
(u·∇)u
------

ν∇²u
]
=

-Δp/ρ

Thus p is not an independently propagating vector degree of freedom.

It is the scalar closure required by the divergence-free condition.

12. COMPLETE EMERGENT OPERATOR

---

P₊ = exp(+θJ)

P₋ = exp(-θJ)

P₊⁻¹ = P₋

𝓓(r) = r/T(r)

T(r) = 1 + 1/r

D_t = ∂_t + (u·∇)

𝓓² → ∇²

Therefore:

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  𝓛_HDGL[u]                                                  │
│                                                             │
│  = (P₊ ⊕ P₋)transport                                       │
│    − reciprocal-drain                                      │
│                                                             │
│  → ∂_t u + (u·∇)u − ν∇²u                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

13. NAVIER–STOKES EQUATION

---

𝓛_HDGL[u] = -∇p/ρ

therefore:

∂_t u
+
(u·∇)u
======

-∇p/ρ
+
ν∇²u

with:

∇·u = 0

14. HDGL GEOMETRIC ORIGIN OF EACH TERM

---

P₊ ⊕ P₋
│
├──────────────→ phase transport
│
▼
∂_t u + (u·∇)u

P₊
↕
P₋
│
▼
counter-rotating return

r
↓
T(r)
↓
𝓓
↓
𝓓²
↓
∇²u

closed residual
↓
scalar constraint
↓
−∇p/ρ

Therefore:

COUNTER-ROTATION
↓
FIRST-ORDER TRANSPORT

RECIPROCAL DRAIN
↓
SECOND-ORDER DIFFUSION

CLOSED ORBIT
↓
INCOMPRESSIBILITY

RESIDUAL CLOSURE
↓
PRESSURE GRADIENT

15. SINGLE OPERATOR FORM

---

Define:

# 𝓛[u,p]

∂_t u
+
(u·∇)u
+
∇p/ρ
----

ν∇²u

Then:

𝓛[u,p] = 0

subject to:

∇·u = 0

and its HDGL construction is:

# 𝓛

(P₊ ⊕ P₋)_transport
+
𝓓_reciprocal
+
F_closure

16. HDGL CHAIN

---

S_i
↓
P₊ ⊕ P₋
↓
counter-rotating phase transport
↓
D_t
↓
∂_t + (u·∇)
↓
𝓓
↓
reciprocal radial return
↓
𝓓²
↓
∇²
↓
closure residual
↓
−∇p/ρ
↓
S_i₊₁

17. FINAL FORM

---

      P₊ ⊕ P₋
          │
          ▼
     PHASE FLOW
          │
          ▼
∂_t + (u·∇)
          │
          ▼
          u
          │
    ┌─────┴─────┐
    │           │
    ▼           ▼
 outward      return
    │           │
    └─────┬─────┘
          ▼
        DRAIN
          │
          ▼
     reciprocal
          │
          ▼
        ∇²u
          │
          ▼
     closure p
          │
          ▼
          u

===============================================================================
CORE RESULT
===========

P₊ ⊕ P₋
→
∂_t + (u·∇)

𝓓 ∘ R
→
∇²

closure
→
−∇p/ρ

therefore:

∂_t u
+
(u·∇)u
======

−∇p/ρ
+
ν∇²u

∇·u = 0

THE NAVIER–STOKES DIFFERENTIAL STRUCTURE
EMERGES FROM:

COUNTER-ROTATING PHYLLOTAXIS
+
RECIPROCAL DRAIN
+
CLOSED SUBSTRATE ORBIT

===============================================================================

#!/usr/bin/env python3
"""
===============================================================================
HDGL COUNTER-ROTATING PHYLLOTAXIS — DRAIN EFFECT
===============================================================================

Two simultaneous phyllotactic fields:

    θ+ = +2π i Ω
    θ- = -2π i Ω

They counter-rotate while sharing one reciprocal radial closure:

    T(X) = 1 + 1/X

The drain is produced by reciprocal compression toward the common origin:

    d(r) = 1 / T(r)

    ρ(r) = r * d(r)

The toroid is the geometric form of the drain.  It lives at the hourglass
choke (z=0) but blows out toward the top and bottom extremes, tracking the
lateral spread of the hourglass arms:

    lateral(z) ≈ z    (measured directly from the phyllotaxis geometry)

So the toroid major radius scales linearly with |z|:

    R_major(z) = R0 * |z|     where R0 ≈ 1.0

At z=0 (choke): R_major→0, toroid collapses to the drain point — CV=0, LOCK.
At z=±1 (arms): R_major→1.0, toroid blows out to fill the arm cross-section
                              — CV high, Pluck/Sustain, phases spread.

This maps directly onto ll_analog.c's APhase states:

    z=0  (choke) → APHASE_LOCK:    CV < 0.10, residue→0
    z~±½         → APHASE_FINETUNE/SUSTAIN
    z=±1 (arms)  → APHASE_PLUCK:   CV > 0.50, phases maximally spread

The binary/trinary substrate remains simultaneous:

    B_i ∈ {0,1}
    τ_i ∈ {-1,0,+1}

No stored φ is used.
Ω emerges from:

    Ω_(n+1) = T(Ω_n)
            = 1 + 1/Ω_n

===============================================================================
"""

from pathlib import Path
import math

import numpy as np

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable


# ============================================================================
# CONFIGURATION
# ============================================================================

N = 2400

OMEGA_SEED  = 1.5
OMEGA_STEPS = 80

BASE_DIR = Path(__file__).resolve().parent
OUT_DIR  = BASE_DIR / "hdgl_graphs"
OUT_DIR.mkdir(parents=True, exist_ok=True)

# Toroid geometry constants (in normalized hourglass coords).
# lateral(z) ≈ z, so R_major(z) = TORUS_R0 * |z|.
# r_minor is a fixed fraction of R_major, floored at a minimum
# so the choke-point toroid doesn't vanish entirely from the plot.
TORUS_R0        = 0.90   # R_major = TORUS_R0 * |z|  (slightly inside arm edge)
TORUS_R_MINOR_F = 0.25   # r_minor = R_major * this fraction
TORUS_R_MINOR_MIN = 0.004 # floor: keeps the choke ring visible

# Number of z-slices at which to render a toroid cross-section.
N_TORUS_SLICES  = 12


# ============================================================================
# HDGL PRIMITIVE
# ============================================================================

def T(x):
    """
    Reciprocal HDGL transformation:

        T(X) = 1 + 1/X
    """
    return 1.0 + 1.0 / x


def omega_orbit(seed=OMEGA_SEED, steps=OMEGA_STEPS):
    values = np.empty(steps + 1, dtype=np.float64)
    values[0] = seed
    for i in range(steps):
        values[i + 1] = T(values[i])
    return values


def emergent_omega():
    x = OMEGA_SEED
    for _ in range(1000):
        y = T(x)
        if abs(y - x) < 1e-15:
            break
        x = y
    return x


OMEGA = emergent_omega()


# ============================================================================
# SIMULTANEOUS BINARY / TRINARY SUBSTRATE
# ============================================================================

def substrate_states(n):
    i       = np.arange(n, dtype=np.int64)
    binary  = (i & 1).astype(np.float64)
    trinary = ((i % 3) - 1).astype(np.float64)
    return i, binary, trinary


# ============================================================================
# COMMON RADIAL SUBSTRATE
# ============================================================================

def build_radial_substrate(n=N):
    i, binary, trinary = substrate_states(n)
    r_base      = np.sqrt(i + 1.0)
    modulation  = 1.0 + 0.075 * binary + 0.050 * trinary
    r           = r_base * modulation
    reciprocal  = T(r)
    drain_factor = 1.0 / reciprocal
    rho         = r * drain_factor
    return i, binary, trinary, r, reciprocal, drain_factor, rho


# ============================================================================
# COUNTER-ROTATING PHYLLOTAXIS
# ============================================================================

def build_counter_rotating_phyllotaxis(n=N):
    i, binary, trinary, r, reciprocal, drain_factor, rho = build_radial_substrate(n)
    phase_mod   =  0.075 * binary + 0.050 * trinary
    theta_plus  =  2.0 * math.pi * i * OMEGA + phase_mod
    theta_minus = -2.0 * math.pi * i * OMEGA - phase_mod
    x_plus  = rho * np.cos(theta_plus)
    y_plus  = rho * np.sin(theta_plus)
    x_minus = rho * np.cos(theta_minus)
    y_minus = rho * np.sin(theta_minus)
    return (i, binary, trinary,
            r, reciprocal, drain_factor, rho,
            theta_plus, theta_minus,
            x_plus, y_plus, x_minus, y_minus)


# ============================================================================
# DRAIN STRENGTH
# ============================================================================

def drain_profile(n=N):
    i, binary, trinary, r, reciprocal, drain_factor, rho = build_radial_substrate(n)
    return i, r, reciprocal, drain_factor, rho


# ============================================================================
# TOROIDAL DRAIN — blow-out toroid, confined to hourglass arm cross-section
# ============================================================================

def build_toroidal_drain_at_z(z_center, n_phi=400):
    """
    Build one toroid cross-section at a given z_center in normalized coords.

    z_center = rp value (∈ [0, 1] for +Ω arm, negated for −Ω arm).

    Geometry:
        lateral(z) ≈ z  (measured from phyllotaxis arm spread)
        R_major(z)  = TORUS_R0 * |z|         (zero at choke, full at arms)
        r_minor(z)  = max(R_major * TORUS_R_MINOR_F, TORUS_R_MINOR_MIN)

    Winding:
        toroidal angle φ ∈ [0, 2π)
        The torus ring lies in the z=z_center plane, so:
            tx = R_major * cos(φ)
            ty = R_major * sin(φ)
            tz = z_center + r_minor * sin(φ_poloidal)
        For a scatter plot we sample both φ angles to trace the tube surface.
    """
    R_major = TORUS_R0 * abs(z_center)
    r_minor = max(R_major * TORUS_R_MINOR_F, TORUS_R_MINOR_MIN)

    phi_tor = np.linspace(0.0, 2.0 * math.pi, n_phi, endpoint=False)
    phi_pol = np.linspace(0.0, 2.0 * math.pi, n_phi, endpoint=False)
    PT, PP  = np.meshgrid(phi_tor, phi_pol)
    PT      = PT.ravel()
    PP      = PP.ravel()

    tx = (R_major + r_minor * np.cos(PP)) * np.cos(PT)
    ty = (R_major + r_minor * np.cos(PP)) * np.sin(PT)
    tz = np.full_like(tx, z_center) + r_minor * np.sin(PP)

    return tx, ty, tz, R_major, r_minor


# ============================================================================
# PLOT 1 — COUNTER-ROTATING PHYLLOTAXIS
# ============================================================================

def plot_counter_rotating_phyllotaxis():
    (i, binary, trinary,
     r, reciprocal, drain_factor, rho,
     theta_plus, theta_minus,
     x_plus, y_plus, x_minus, y_minus) = build_counter_rotating_phyllotaxis()

    fig, ax = plt.subplots(figsize=(11, 11))
    ax.scatter(x_plus,  y_plus,  s=4, alpha=0.45, linewidths=0, label="counter-rotation +Ω")
    ax.scatter(x_minus, y_minus, s=4, alpha=0.45, linewidths=0, label="counter-rotation −Ω")
    ax.scatter([0], [0], s=70, marker="o", label="drain")
    ax.set_aspect("equal", adjustable="box")
    ax.set_title("HDGL COUNTER-ROTATING PHYLLOTAXIS\nSimultaneous ±Ω with Reciprocal Drain")
    ax.set_xlabel("counter-rotating substrate")
    ax.set_ylabel("counter-rotating substrate")
    ax.grid(True, alpha=0.20)
    ax.legend()
    fig.tight_layout()
    path = OUT_DIR / "hdgl_counter_rotating_phyllotaxis.png"
    fig.savefig(path, dpi=180, bbox_inches="tight")
    plt.close(fig)
    return path


# ============================================================================
# PLOT 2 — DRAIN PROFILE
# ============================================================================

def plot_drain_profile():
    i, r, reciprocal, drain_factor, rho = drain_profile()
    fig, ax = plt.subplots(figsize=(11, 7))
    ax.plot(i, r,   linewidth=1.2, label="outward radius r")
    ax.plot(i, rho, linewidth=1.2, label="drained radius ρ")
    ax.set_title("HDGL RECIPROCAL DRAIN\nρ = r / T(r)")
    ax.set_xlabel("substrate index i")
    ax.set_ylabel("radial coordinate")
    ax.grid(True, alpha=0.20)
    ax.legend()
    fig.tight_layout()
    path = OUT_DIR / "hdgl_drain_profile.png"
    fig.savefig(path, dpi=180, bbox_inches="tight")
    plt.close(fig)
    return path


# ============================================================================
# PLOT 3 — COUNTER-ROTATION PHASE
# ============================================================================

def plot_counter_rotation_phase():
    (i, binary, trinary,
     r, reciprocal, drain_factor, rho,
     theta_plus, theta_minus,
     x_plus, y_plus, x_minus, y_minus) = build_counter_rotating_phyllotaxis()

    fig, ax = plt.subplots(figsize=(11, 7))
    ax.plot(i, theta_plus,  linewidth=1.0, label="+Ω")
    ax.plot(i, theta_minus, linewidth=1.0, label="−Ω")
    ax.axhline(0.0, linestyle="--", linewidth=1.0)
    ax.set_title("HDGL COUNTER-ROTATING PHASE\nθ+ = +2πiΩ   /   θ− = −2πiΩ")
    ax.set_xlabel("substrate index i")
    ax.set_ylabel("phase")
    ax.grid(True, alpha=0.20)
    ax.legend()
    fig.tight_layout()
    path = OUT_DIR / "hdgl_counter_rotation_phase.png"
    fig.savefig(path, dpi=180, bbox_inches="tight")
    plt.close(fig)
    return path


# ============================================================================
# PLOT 4 — Ω RECURSION
# ============================================================================

def plot_omega_orbit():
    values = omega_orbit()
    n = np.arange(len(values))
    fig, ax = plt.subplots(figsize=(11, 7))
    ax.plot(n, values, linewidth=1.5, marker="o", markersize=3)
    ax.axhline(OMEGA, linestyle="--", linewidth=1.0)
    ax.set_title("HDGL Ω RECURSION\nΩₙ₊₁ = T(Ωₙ) = 1 + 1/Ωₙ")
    ax.set_xlabel("iteration n")
    ax.set_ylabel("Ωₙ")
    ax.grid(True, alpha=0.20)
    ax.text(0.98, 0.05, f"Emergent Ω ≈ {OMEGA:.15f}",
            transform=ax.transAxes, ha="right", va="bottom")
    fig.tight_layout()
    path = OUT_DIR / "hdgl_omega_orbit.png"
    fig.savefig(path, dpi=180, bbox_inches="tight")
    plt.close(fig)
    return path


# ============================================================================
# PLOT 5 — 3D DRAIN  (blow-out toroid at ±z extremes, collapsed at choke)
# ============================================================================

def plot_3d_drain():
    (i, binary, trinary,
     r, reciprocal, drain_factor, rho,
     theta_plus, theta_minus,
     x_plus, y_plus, x_minus, y_minus) = build_counter_rotating_phyllotaxis()

    scale = np.max(rho)

    rp = rho / scale

    xp = x_plus  / scale
    yp = y_plus  / scale
    zp =  rp                   # +Ω arm lifts upward

    xm = x_minus / scale
    ym = y_minus / scale
    zm = -rp                   # −Ω arm falls downward

    # ── Torus slices ──────────────────────────────────────────────────────
    # Sample z-levels evenly across [0, 1], including extremes.
    # Each z maps to one toroid in the +Ω arm and its mirror in the −Ω arm.
    # Color encodes |z|: blue=choke (lock), red=extreme (pluck).
    #
    # ll_analog.c APhase mapping:
    #   |z| < 0.10  → LOCK      (CV < 0.10)
    #   |z| < 0.30  → FINETUNE
    #   |z| < 0.50  → SUSTAIN
    #   |z| ≥ 0.50  → PLUCK     (CV > 0.50)

    z_levels = np.linspace(0.0, 1.0, N_TORUS_SLICES)
    cmap     = plt.cm.coolwarm
    norm     = Normalize(vmin=0.0, vmax=1.0)

    fig = plt.figure(figsize=(13, 11))
    ax  = fig.add_subplot(111, projection="3d")

    # Hourglass arms (sparse, transparent).
    ax.scatter(xp, yp, zp,  s=1, alpha=0.18, color="steelblue",  rasterized=True)
    ax.scatter(xm, ym, zm,  s=1, alpha=0.18, color="steelblue",  rasterized=True)

    # APhase boundary rings on the +Ω arm for reference.
    for cv_thresh, label in [(0.10, "LOCK"), (0.30, "FINETUNE"),
                              (0.50, "SUSTAIN"), (1.00, "PLUCK")]:
        z_b = cv_thresh
        if z_b > 1.0: z_b = 1.0
        phi_r = np.linspace(0, 2*math.pi, 300)
        R_b   = TORUS_R0 * z_b
        ax.plot(R_b*np.cos(phi_r), R_b*np.sin(phi_r),
                np.full(300, z_b), linewidth=0.6, alpha=0.35,
                color=cmap(norm(z_b)), linestyle="--")

    # Toroid slices: one per z-level, mirrored at ±z.
    for z_c in z_levels:
        color = cmap(norm(z_c))
        alpha = 0.55 if z_c < 0.05 else 0.25
        s_sz  = 0.3  if z_c < 0.05 else 0.15

        tx, ty, tz, R_maj, r_min = build_toroidal_drain_at_z(z_c)

        # +Ω side (z_c ≥ 0)
        ax.scatter(tx, ty, tz,        s=s_sz, alpha=alpha, color=color,
                   rasterized=True)
        # −Ω side (mirror)
        if z_c > 1e-6:
            ax.scatter(tx, ty, -tz,   s=s_sz, alpha=alpha, color=color,
                       rasterized=True)

    # Colorbar: |z| → APhase
    sm = ScalarMappable(cmap=cmap, norm=norm)
    sm.set_array([])
    cbar = fig.colorbar(sm, ax=ax, shrink=0.55, pad=0.08)
    cbar.set_label("|z|  (0=LOCK / 1=PLUCK)", fontsize=9)
    cbar.set_ticks([0.0, 0.10, 0.30, 0.50, 1.0])
    cbar.set_ticklabels(["0.0\n(LOCK)", "0.10", "0.30", "0.50\n(SUSTAIN)", "1.0\n(PLUCK)"])

    ax.set_title(
        "HDGL COUNTER-ROTATING DRAIN\n"
        "Toroid blow-out: choke=LOCK(z=0) → arms=PLUCK(z=±1)\n"
        "ll_analog APhase: CV = |z|  →  R_major = TORUS_R0 × |z|",
        fontsize=10,
    )
    ax.set_xlabel("+Ω / −Ω branch (x)")
    ax.set_ylabel("+Ω / −Ω branch (y)")
    ax.set_zlabel("radial closure z = ρ/scale")
    fig.tight_layout()

    path = OUT_DIR / "hdgl_3d_drain.png"
    fig.savefig(path, dpi=180, bbox_inches="tight")
    plt.close(fig)
    return path


# ============================================================================
# NUMERICAL REPORT
# ============================================================================

def print_report(paths):
    print()
    print("=" * 79)
    print("HDGL COUNTER-ROTATING PHYLLOTAXIS — DRAIN EFFECT")
    print("=" * 79)
    print()
    print("Primitive:")
    print("    Ω_(n+1) = T(Ω_n)    T(X) = 1 + 1/X")
    print(f"Emergent Ω:  {OMEGA:.15f}")
    print(f"Residual:    Ω² - Ω - 1 ≈ {OMEGA*OMEGA - OMEGA - 1.0:.6e}")
    print()
    print("Simultaneous substrate:  B_i ∈ {0,1}    τ_i ∈ {-1,0,+1}")
    print("Counter-rotation:        θ+ = +2π i Ω      θ- = -2π i Ω")
    print("Reciprocal drain:        T(r)=1+1/r  d(r)=1/T(r)  ρ(r)=r/T(r)")
    print()
    print("Toroid blow-out (ll_analog APhase mapping):")
    print("    lateral(z) ≈ z       (phyllotaxis arm spread, measured)")
    print("    R_major(z) = 0.90 × |z|")
    print("    r_minor(z) = max(R_major × 0.25, 0.004)")
    print()
    print("    |z|  APhase     CV threshold    R_major")
    for z, phase, cv in [(0.00,"LOCK","0.00"),(0.10,"LOCK","0.10"),
                          (0.30,"FINETUNE","0.30"),(0.50,"SUSTAIN","0.50"),
                          (1.00,"PLUCK","1.00")]:
        print(f"    {z:.2f}  {phase:<10}  {cv:<14}  {0.90*z:.4f}")
    print()
    print("    z=0:  R_major→0, toroid collapses to drain point (CV=0, residue=0)")
    print("    z=±1: R_major→0.90, toroid fills arm cross-section (CV≈1, PLUCK)")
    print()
    print(f"Output: {OUT_DIR}")
    for path in paths:
        print(f"    [OK] {path}")
    print()
    print("=" * 79)
    print("COMPLETE")
    print("=" * 79)
    print()


# ============================================================================
# MAIN
# ============================================================================

def main():
    paths = []
    paths.append(plot_counter_rotating_phyllotaxis())
    paths.append(plot_drain_profile())
    paths.append(plot_counter_rotation_phase())
    paths.append(plot_omega_orbit())
    paths.append(plot_3d_drain())
    print_report(paths)


if __name__ == "__main__":
    main()
#!/usr/bin/env python3
"""
===============================================================================
HDGL COUNTER-ROTATING DRAIN — ANIMATED
===============================================================================

Three-part animation:

  Part 1 (frames  1– 40): Orbital tour — full 360° azimuth, full blow-out
  Part 2 (frames 41– 80): CV pulse    — toroid LOCK→PLUCK→LOCK
  Part 3 (frames 81–120): Combined    — slow orbit + live CV breathing

Geometry:
    lateral(z) ≈ z         (measured from phyllotaxis arm spread)
    R_major(z) = 0.90×|z|  (zero at choke, fills arm at extremes)
    r_minor(z) = max(R_major×0.25, 0.004)

ll_analog.c APhase mapping:
    z=0.00 → LOCK      CV < 0.10   residue→0
    z=0.30 → FINETUNE  CV < 0.30
    z=0.50 → SUSTAIN   CV < 0.50
    z=1.00 → PLUCK     CV ≥ 0.50   phases spread

Output: hdgl_drain_animation.mp4  (same directory as this script)

Requires: matplotlib, numpy, ffmpeg
===============================================================================
"""

import math
from pathlib import Path

import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.animation import FFMpegWriter
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable


# ============================================================================
# HDGL PRIMITIVES
# ============================================================================

def T(x):
    return 1.0 + 1.0 / x


def emergent_omega():
    x = 1.5
    for _ in range(1000):
        y = T(x)
        if abs(y - x) < 1e-15:
            break
        x = y
    return x


OMEGA = emergent_omega()

# ============================================================================
# HOURGLASS POINT CLOUD (pre-built, static)
# ============================================================================

N = 2400

i       = np.arange(N, dtype=np.int64)
binary  = (i & 1).astype(float)
trinary = ((i % 3) - 1).astype(float)
r       = np.sqrt(i + 1.0) * (1.0 + 0.075 * binary + 0.050 * trinary)
rho     = r / T(r)
scale   = np.max(rho)
rp      = rho / scale

pm = 0.075 * binary + 0.050 * trinary
tp =  2.0 * math.pi * i * OMEGA + pm
tm = -2.0 * math.pi * i * OMEGA - pm

xp = rho * np.cos(tp) / scale
yp = rho * np.sin(tp) / scale
xm = rho * np.cos(tm) / scale
ym = rho * np.sin(tm) / scale

# ============================================================================
# TORUS GEOMETRY
# ============================================================================

TORUS_R0        = 0.90
TORUS_R_MINOR_F = 0.25
TORUS_R_MINOR_MIN = 0.004
N_PHI    = 40
N_SLICES = 6

Z_LEVELS = np.linspace(0.0, 1.0, N_SLICES)


def torus_at(z_c, cv_scale=1.0):
    """
    Build one toroid cross-section at z=z_c, scaled by cv_scale ∈ [0,1].

    cv_scale=0 → toroid collapses to drain point  (LOCK)
    cv_scale=1 → full blow-out                     (PLUCK)
    """
    eff_z = z_c * cv_scale
    R     = TORUS_R0 * abs(eff_z)
    rm    = max(R * TORUS_R_MINOR_F, TORUS_R_MINOR_MIN)

    pt = np.linspace(0.0, 2.0 * math.pi, N_PHI, endpoint=False)
    pp = np.linspace(0.0, 2.0 * math.pi, N_PHI, endpoint=False)
    PT, PP = np.meshgrid(pt, pp)
    PT, PP = PT.ravel(), PP.ravel()

    tx = (R + rm * np.cos(PP)) * np.cos(PT)
    ty = (R + rm * np.cos(PP)) * np.sin(PT)
    tz = np.full_like(tx, eff_z) + rm * np.sin(PP)

    return tx, ty, tz


def aphase_label(cv):
    if cv < 0.10: return "LOCK      CV<0.10  residue→0"
    if cv < 0.30: return "FINETUNE  CV<0.30"
    if cv < 0.50: return "SUSTAIN   CV<0.50"
    return               "PLUCK     CV≥0.50  phases spread"


# ============================================================================
# FIGURE SETUP
# ============================================================================

cmap = plt.cm.coolwarm
norm = Normalize(vmin=0.0, vmax=1.0)

fig = plt.figure(figsize=(9, 7), facecolor="#07070f")
ax  = fig.add_subplot(111, projection="3d", facecolor="#07070f")

for pane in [ax.xaxis.pane, ax.yaxis.pane, ax.zaxis.pane]:
    pane.fill = False
    pane.set_edgecolor("#1a1a2e")

ax.tick_params(colors="#555", labelsize=6)
ax.set_xlabel("+Ω/−Ω  x",  color="#555", fontsize=7, labelpad=2)
ax.set_ylabel("+Ω/−Ω  y",  color="#555", fontsize=7, labelpad=2)
ax.set_zlabel("z = ρ/scale", color="#555", fontsize=7, labelpad=2)
ax.set_xlim(-1.1, 1.1)
ax.set_ylim(-1.1, 1.1)
ax.set_zlim(-1.1, 1.1)

# Colorbar
sm = ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
cbar = fig.colorbar(sm, ax=ax, shrink=0.45, pad=0.10)
cbar.set_label("|z| = CV  (0=LOCK / 1=PLUCK)", fontsize=7, color="#aaa")
cbar.ax.yaxis.set_tick_params(color="#aaa", labelsize=6)
plt.setp(cbar.ax.yaxis.get_ticklabels(), color="#aaa")
cbar.set_ticks([0.0, 0.10, 0.30, 0.50, 1.0])
cbar.set_ticklabels(["LOCK\n0.0", "0.10", "0.30", "0.50", "PLUCK\n1.0"])

# Static hourglass arms
ax.scatter(xp, yp,  rp, s=0.4, alpha=0.13, color="#3366bb", rasterized=True)
ax.scatter(xm, ym, -rp, s=0.4, alpha=0.13, color="#3366bb", rasterized=True)

# APhase boundary rings (dashed, static, on both ±z arms)
for cv_t in [0.10, 0.30, 0.50, 1.00]:
    phi_r = np.linspace(0.0, 2.0 * math.pi, 150)
    R_b   = TORUS_R0 * cv_t
    color = cmap(norm(cv_t))
    for z_sign in [+1, -1]:
        ax.plot(
            R_b * np.cos(phi_r),
            R_b * np.sin(phi_r),
            np.full(150, z_sign * cv_t),
            lw=0.6, alpha=0.35, color=color, ls="--",
        )

# Torus scatter handles (offsets updated each frame)
torus_handles = []
for z_c in Z_LEVELS:
    tx, ty, tz = torus_at(z_c, cv_scale=1.0)
    color       = cmap(norm(z_c))
    sp = ax.scatter(tx, ty,  tz, s=0.2, alpha=0.0, color=color, rasterized=True)
    sn = ax.scatter(tx, ty, -tz, s=0.2, alpha=0.0, color=color, rasterized=True)
    torus_handles.append((sp, sn, z_c))

# Text overlays
title_obj = ax.set_title("", color="white", fontsize=9, pad=6)
info_text = ax.text2D(0.02, 0.97, "", transform=ax.transAxes,
                      color="cyan", fontsize=7.5, va="top", family="monospace")
cv_text   = ax.text2D(0.02, 0.06, "", transform=ax.transAxes,
                      color="#ffcc44", fontsize=8.0, va="bottom", family="monospace")


def update_tori(cv_scale, alpha_base=0.32):
    """Reposition all torus slices for a given cv_scale ∈ [0,1]."""
    for sp, sn, z_c in torus_handles:
        tx, ty, tz = torus_at(z_c, cv_scale)
        a = alpha_base * (0.25 + 0.75 * z_c) if z_c > 0.01 else 0.72
        sp._offsets3d = (tx, ty,  tz)
        sn._offsets3d = (tx, ty, -tz)
        sp.set_alpha(a)
        sn.set_alpha(a if z_c > 0.01 else 0.0)


# ============================================================================
# ANIMATION
# ============================================================================

FPS = 24
F1  = 40   # Part 1: orbital tour
F2  = 40   # Part 2: CV pulse
F3  = 40   # Part 3: combined
TOTAL = F1 + F2 + F3

OUT = Path(__file__).resolve().parent / "hdgl_drain_animation.mp4"

writer = FFMpegWriter(
    fps=FPS,
    bitrate=2000,
    extra_args=["-vcodec", "libx264", "-pix_fmt", "yuv420p"],
)

print(f"Rendering {TOTAL} frames at {FPS} fps → {OUT}")

with writer.saving(fig, str(OUT), dpi=110):
    for f in range(TOTAL):

        # ── Part 1: Orbital tour ─────────────────────────────────────────
        if f < F1:
            t  = f / F1
            az = 360.0 * t
            el = 22.0 + 8.0 * math.sin(2.0 * math.pi * t)
            ax.view_init(elev=el, azim=az)
            update_tori(1.0, alpha_base=0.30)
            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN\n"
                "Part 1 — Orbital tour  |  full blow-out"
            )
            info_text.set_text(
                f"azim={az:5.1f}°  elev={el:.1f}°\n"
                f"R_major(z) = {TORUS_R0:.2f}×|z|  [blow-out]\n"
                f"+Ω arm ↑   −Ω arm ↓   toroid = drain"
            )
            cv_text.set_text("CV = 1.00  →  PLUCK  (phases spread)")

        # ── Part 2: CV pulse — toroid breathes LOCK → PLUCK → LOCK ─────
        elif f < F1 + F2:
            t  = (f - F1) / F2
            cv = 0.5 * (1.0 - math.cos(2.0 * math.pi * t))   # 0→1→0
            az = 45.0 + 15.0 * math.sin(math.pi * t)
            ax.view_init(elev=26.0, azim=az)
            update_tori(cv, alpha_base=0.38)
            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN\n"
                "Part 2 — CV pulse  |  LOCK → PLUCK → LOCK"
            )
            info_text.set_text(
                f"CV = {cv:.3f}   R_major(z=1) = {TORUS_R0 * cv:.4f}\n"
                f"z=0 : R→0  (drain collapses)\n"
                f"z=1 : R→{TORUS_R0 * cv:.3f}  (blow-out tracks arm width)"
            )
            cv_text.set_text(f"APhase → {aphase_label(cv)}")

        # ── Part 3: Combined — slow orbit + CV breathing ─────────────────
        else:
            t  = (f - F1 - F2) / F3
            az = 60.0 + 150.0 * t
            el = 18.0 + 14.0 * math.sin(math.pi * t)
            cv = 0.50 + 0.45 * math.sin(2.0 * math.pi * t)
            ax.view_init(elev=el, azim=az)
            update_tori(cv, alpha_base=0.34)
            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN\n"
                "Part 3 — Orbit + live CV breathing"
            )
            info_text.set_text(
                f"azim={az:5.1f}°  elev={el:.1f}°  CV={cv:.3f}\n"
                f"ll_analog: APhase transitions at CV thresholds\n"
                f"residue→0  ↔  CV→0  ↔  toroid collapses to choke"
            )
            cv_text.set_text(f"APhase → {aphase_label(cv)}")

        writer.grab_frame()
        if f % 10 == 0:
            print(f"  frame {f + 1}/{TOTAL}", flush=True)

print(f"Saved → {OUT}")
#!/usr/bin/env python3
"""
===============================================================================
HDGL COUNTER-ROTATING DRAIN — ANIMATED  v2
===============================================================================

Incorporates the vantage-dependent i ≡ ∞ identification:

  From the real-axis vantage, i is an exit — it has no address on the
  real ladder and appears at unreachable distance (∞).

  From the Δ=−1 algebra's own vantage, i is a unit element:
      norm = 1,  trace = 0,  sitting at 90°.  Perfectly finite.

  Neither vantage is forced.  Neither is the true one.
  The juxtaposition IS the load-bearing feature — not its resolution.

  The graded orbit:
      { ..., -i'', -i', -i, -1, 0, 1, i, i', i'', ... }
  Each rung, viewed from the rung below it, appears at unreachable distance.

  |p| = 1 threshold:
      The moment the imaginary/complex branch emerges from zero in the
      manifold equation (Y - p(x+z))² + p²(x²-z²-1) = m².
      This is the visual moment the i≡∞ identification becomes apparent.

Three-part animation:

  Part 1 (frames  1– 40): Orbital tour — full 360° azimuth
                           Graded orbit ladder visible on z-axis
                           |p|=1 threshold ring prominent
                           Vantage label: REAL-AXIS VANTAGE

  Part 2 (frames 41– 80): CV pulse — LOCK→PLUCK→LOCK
                           Vantage shifts with CV:
                             CV<0.10 → REAL-AXIS VANTAGE (i appears as exit/∞)
                             CV≥0.50 → Δ=−1 VANTAGE    (i is unit element)
                           Juxtaposition text shown mid-pulse

  Part 3 (frames 81–120): Combined — slow orbit + CV breathing
                           Both vantage annotations shown simultaneously,
                           neither resolved, neither forced

Geometry:
    lateral(z) ≈ z         (measured from phyllotaxis arm spread)
    R_major(z) = 0.90×|z|  (zero at choke, fills arm at extremes)
    r_minor(z) = max(R_major×0.25, 0.004)

ll_analog.c APhase mapping:
    z=0.00 → LOCK      CV < 0.10   residue→0
    z=0.30 → FINETUNE  CV < 0.30
    z=0.50 → SUSTAIN   CV < 0.50
    z=1.00 → PLUCK     CV ≥ 0.50   phases spread

Output: hdgl_drain_animation_v2.mp4  (same directory as this script)

Requires: matplotlib, numpy, ffmpeg
===============================================================================
"""

import math
from pathlib import Path

import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.animation import FFMpegWriter
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable


# ============================================================================
# HDGL PRIMITIVES
# ============================================================================

def T(x):
    """T(X) = 1 + 1/X  — the single reciprocal primitive."""
    return 1.0 + 1.0 / x


def emergent_omega():
    """
    Generate Ω from T until convergence.
    Ω = T(Ω) ⟺ Ω² = Ω + 1.
    Never stored as φ — always emergent.
    """
    x = 1.5
    for _ in range(1000):
        y = T(x)
        if abs(y - x) < 1e-15:
            break
        x = y
    return x


OMEGA = emergent_omega()

# ============================================================================
# HOURGLASS POINT CLOUD (pre-built, static)
# ============================================================================

N = 2400

i_idx   = np.arange(N, dtype=np.int64)
binary  = (i_idx & 1).astype(float)
trinary = ((i_idx % 3) - 1).astype(float)
r       = np.sqrt(i_idx + 1.0) * (1.0 + 0.075 * binary + 0.050 * trinary)
rho     = r / T(r)
scale   = np.max(rho)
rp      = rho / scale

pm = 0.075 * binary + 0.050 * trinary
tp =  2.0 * math.pi * i_idx * OMEGA + pm
tm = -2.0 * math.pi * i_idx * OMEGA - pm

xp = rho * np.cos(tp) / scale
yp = rho * np.sin(tp) / scale
xm = rho * np.cos(tm) / scale
ym = rho * np.sin(tm) / scale

# ============================================================================
# TORUS GEOMETRY
# ============================================================================

TORUS_R0          = 0.90
TORUS_R_MINOR_F   = 0.25
TORUS_R_MINOR_MIN = 0.004
N_PHI    = 40
N_SLICES = 6

Z_LEVELS = np.linspace(0.0, 1.0, N_SLICES)


def torus_at(z_c, cv_scale=1.0):
    """
    Build one toroid cross-section at z=z_c, scaled by cv_scale ∈ [0,1].

    cv_scale=0 → toroid collapses to drain point  (LOCK  / real-axis vantage)
    cv_scale=1 → full blow-out                     (PLUCK / Δ=−1 vantage)
    """
    eff_z = z_c * cv_scale
    R     = TORUS_R0 * abs(eff_z)
    rm    = max(R * TORUS_R_MINOR_F, TORUS_R_MINOR_MIN)

    pt = np.linspace(0.0, 2.0 * math.pi, N_PHI, endpoint=False)
    pp = np.linspace(0.0, 2.0 * math.pi, N_PHI, endpoint=False)
    PT, PP = np.meshgrid(pt, pp)
    PT, PP = PT.ravel(), PP.ravel()

    tx = (R + rm * np.cos(PP)) * np.cos(PT)
    ty = (R + rm * np.cos(PP)) * np.sin(PT)
    tz = np.full_like(tx, eff_z) + rm * np.sin(PP)

    return tx, ty, tz


def aphase_label(cv):
    if cv < 0.10: return "LOCK      CV<0.10  residue→0"
    if cv < 0.30: return "FINETUNE  CV<0.30"
    if cv < 0.50: return "SUSTAIN   CV<0.50"
    return               "PLUCK     CV≥0.50  phases spread"


# ============================================================================
# VANTAGE LABELS  (the core addition from the i≡∞ discussion)
# ============================================================================

VANTAGE_REAL = (
    "REAL-AXIS VANTAGE\n"
    "  i has no address on {…,-1,0,1,…}\n"
    "  appears as exit / ∞ from here\n"
    "  |p|<1 → complex branch = zero"
)

VANTAGE_DELTA = (
    "Δ=−1 VANTAGE\n"
    "  i = (0,1)  norm=1  trace=0\n"
    "  unit element — perfectly finite\n"
    "  |p|≥1 → complex branch surfaces"
)

VANTAGE_BOTH = (
    "JUXTAPOSITION  (neither forced)\n"
    "  real-axis:  i ≡ ∞  (exit)\n"
    "  Δ=−1 field: i ≡ 1  (unit)\n"
    "  same object · two vantages · no resolution"
)

GRADED_ORBIT = "{ …  -i″  -i′  -i  -1  0  1  i  i′  i″  … }"


def vantage_from_cv(cv):
    """
    Map CV to the appropriate vantage label.
    Transition zone around CV≈0.40 shows the juxtaposition.
    """
    if cv < 0.18:
        return VANTAGE_REAL,  "#88bbff"   # cool blue — real-axis
    if cv > 0.62:
        return VANTAGE_DELTA, "#ff9944"   # warm amber — Δ=−1
    return VANTAGE_BOTH,      "#aaffaa"   # green — juxtaposition


# ============================================================================
# |p|=1 THRESHOLD RING
# The ring at R = TORUS_R0 * 1.0 on the z=±1 planes marks the
# exact moment the imaginary branch emerges from zero.
# ============================================================================

def p1_ring():
    """
    Build the |p|=1 threshold ring coordinates.
    Returns (x, y, z) arrays for both +z and -z arms.
    """
    phi_r = np.linspace(0.0, 2.0 * math.pi, 200)
    R_p1  = TORUS_R0 * 1.0
    x_r   = R_p1 * np.cos(phi_r)
    y_r   = R_p1 * np.sin(phi_r)
    return x_r, y_r


# ============================================================================
# GRADED ORBIT RUNG MARKERS  (on z-axis, both arms)
# Rungs: -1, 0, 1 are the finite core.
# i, i', i'' are the apparent-∞ exits above.
# ============================================================================

RUNG_Z_REAL = [0.0, 0.33, 0.66]          # 0, 1/3, 2/3 → represent -1, 0, 1
RUNG_Z_IMAG = [1.0, 1.10, 1.20]          # i, i', i'' — clamped to zlim


# ============================================================================
# FIGURE SETUP
# ============================================================================

cmap = plt.cm.coolwarm
norm = Normalize(vmin=0.0, vmax=1.0)

fig = plt.figure(figsize=(10, 7.5), facecolor="#07070f")
ax  = fig.add_subplot(111, projection="3d", facecolor="#07070f")

for pane in [ax.xaxis.pane, ax.yaxis.pane, ax.zaxis.pane]:
    pane.fill = False
    pane.set_edgecolor("#1a1a2e")

ax.tick_params(colors="#555", labelsize=6)
ax.set_xlabel("+Ω/−Ω  x",   color="#555", fontsize=7, labelpad=2)
ax.set_ylabel("+Ω/−Ω  y",   color="#555", fontsize=7, labelpad=2)
ax.set_zlabel("z  /  graded orbit", color="#555", fontsize=7, labelpad=2)
ax.set_xlim(-1.2, 1.2)
ax.set_ylim(-1.2, 1.2)
ax.set_zlim(-1.1, 1.1)

# Colorbar
sm = ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
cbar = fig.colorbar(sm, ax=ax, shrink=0.42, pad=0.10)
cbar.set_label("|z| = CV  (0=LOCK / 1=PLUCK)", fontsize=7, color="#aaa")
cbar.ax.yaxis.set_tick_params(color="#aaa", labelsize=6)
plt.setp(cbar.ax.yaxis.get_ticklabels(), color="#aaa")
cbar.set_ticks([0.0, 0.10, 0.30, 0.50, 1.0])
cbar.set_ticklabels(["LOCK\n0.0", "0.10", "0.30", "0.50", "PLUCK\n1.0"])

# ── Static hourglass arms ────────────────────────────────────────────────────
ax.scatter(xp, yp,  rp, s=0.4, alpha=0.13, color="#3366bb", rasterized=True)
ax.scatter(xm, ym, -rp, s=0.4, alpha=0.13, color="#3366bb", rasterized=True)

# ── APhase boundary rings (dashed, static) ───────────────────────────────────
phi_r  = np.linspace(0.0, 2.0 * math.pi, 150)
for cv_t in [0.10, 0.30, 0.50, 1.00]:
    R_b   = TORUS_R0 * cv_t
    color = cmap(norm(cv_t))
    for z_sign in [+1, -1]:
        ax.plot(
            R_b * np.cos(phi_r),
            R_b * np.sin(phi_r),
            np.full(150, z_sign * cv_t),
            lw=0.6, alpha=0.35, color=color, ls="--",
        )

# ── |p|=1 threshold ring  (prominent — the i≡∞ emergence moment) ─────────────
x_r, y_r = p1_ring()
for z_sign in [+1, -1]:
    ax.plot(
        x_r, y_r,
        np.full(len(x_r), z_sign * 1.0),
        lw=1.4, alpha=0.70, color="#00ffcc", ls="-",
        zorder=10,
    )

# Label the |p|=1 ring (text placed once, static)
ax.text(
    TORUS_R0 + 0.04, 0.0, 1.02,
    "|p|=1\ni emerges",
    color="#00ffcc", fontsize=5.5, alpha=0.80,
    ha="left", va="bottom",
)
ax.text(
    TORUS_R0 + 0.04, 0.0, -1.02,
    "|p|=1\n−i emerges",
    color="#00ffcc", fontsize=5.5, alpha=0.80,
    ha="left", va="top",
)

# ── Graded orbit rung markers on z-axis ──────────────────────────────────────
# Finite core rungs: -1, 0, 1  (blue-white)
rung_labels_real = {
    0.00: "0",
    0.33: "1",
    0.66: "-1 / +1",
}
for z_val, lbl in rung_labels_real.items():
    ax.scatter([0], [0], [z_val],  s=18, color="#aabbff", alpha=0.55,
               zorder=12, marker="o")
    ax.scatter([0], [0], [-z_val], s=18, color="#aabbff", alpha=0.55,
               zorder=12, marker="o")

# Imaginary rungs: i, i', i''  (amber — apparent ∞ from below)
imag_rung_z   = [1.00, 1.08, 1.16]
imag_rung_lbl = ["i", "i′", "i″"]
for z_val, lbl in zip(imag_rung_z, imag_rung_lbl):
    clamped = min(z_val, 1.09)
    ax.scatter([0], [0], [ clamped], s=22, color="#ffaa33", alpha=0.75,
               zorder=13, marker="D")
    ax.scatter([0], [0], [-clamped], s=22, color="#ffaa33", alpha=0.75,
               zorder=13, marker="D")
    ax.text(0.06, 0.0,  clamped + 0.005,
            lbl, color="#ffaa33", fontsize=5.5, alpha=0.85,
            ha="left", va="bottom")
    ax.text(0.06, 0.0, -clamped - 0.005,
            f"-{lbl}", color="#ffaa33", fontsize=5.5, alpha=0.85,
            ha="left", va="top")

# ── Torus scatter handles (offsets updated each frame) ───────────────────────
torus_handles = []
for z_c in Z_LEVELS:
    tx, ty, tz = torus_at(z_c, cv_scale=1.0)
    color       = cmap(norm(z_c))
    sp = ax.scatter(tx, ty,  tz, s=0.2, alpha=0.0, color=color, rasterized=True)
    sn = ax.scatter(tx, ty, -tz, s=0.2, alpha=0.0, color=color, rasterized=True)
    torus_handles.append((sp, sn, z_c))

# ── Text overlays ─────────────────────────────────────────────────────────────
title_obj    = ax.set_title("", color="white", fontsize=9, pad=6)

info_text    = ax.text2D(0.02, 0.97, "", transform=ax.transAxes,
                         color="cyan", fontsize=7.0, va="top",
                         family="monospace")

cv_text      = ax.text2D(0.02, 0.17, "", transform=ax.transAxes,
                         color="#ffcc44", fontsize=7.5, va="bottom",
                         family="monospace")

vantage_text = ax.text2D(0.02, 0.06, "", transform=ax.transAxes,
                         color="#88bbff", fontsize=7.0, va="bottom",
                         family="monospace",
                         bbox=dict(boxstyle="round,pad=0.3",
                                   fc="#07070f", alpha=0.70,
                                   ec="#334455"))

orbit_text   = ax.text2D(0.50, 0.02, GRADED_ORBIT,
                         transform=ax.transAxes,
                         color="#ffaa33", fontsize=6.5,
                         ha="center", va="bottom",
                         family="monospace", alpha=0.70)


def update_tori(cv_scale, alpha_base=0.32):
    """Reposition all torus slices for a given cv_scale ∈ [0,1]."""
    for sp, sn, z_c in torus_handles:
        tx, ty, tz = torus_at(z_c, cv_scale)
        a = alpha_base * (0.25 + 0.75 * z_c) if z_c > 0.01 else 0.72
        sp._offsets3d = (tx, ty,  tz)
        sn._offsets3d = (tx, ty, -tz)
        sp.set_alpha(a)
        sn.set_alpha(a if z_c > 0.01 else 0.0)


def set_vantage(cv, override_label=None, override_color=None):
    """
    Update the vantage annotation for the current CV.
    The vantage is never forced: both labels are always internally present,
    only the foregrounded one shifts.
    """
    if override_label is not None:
        label = override_label
        color = override_color or "#aaffaa"
    else:
        label, color = vantage_from_cv(cv)
    vantage_text.set_text(label)
    vantage_text.set_color(color)


# ============================================================================
# ANIMATION
# ============================================================================

FPS   = 24
F1    = 40   # Part 1: orbital tour
F2    = 40   # Part 2: CV pulse
F3    = 40   # Part 3: combined
TOTAL = F1 + F2 + F3

OUT = Path(__file__).resolve().parent / "hdgl_drain_animation_v2.mp4"

writer = FFMpegWriter(
    fps=FPS,
    bitrate=2400,
    extra_args=["-vcodec", "libx264", "-pix_fmt", "yuv420p"],
)

print(f"Rendering {TOTAL} frames at {FPS} fps → {OUT}")
print(f"Emergent Ω ≈ {OMEGA:.15f}")
print(f"|p|=1 ring R = {TORUS_R0:.3f}")

with writer.saving(fig, str(OUT), dpi=110):
    for f in range(TOTAL):

        # ── Part 1: Orbital tour ─────────────────────────────────────────────
        if f < F1:
            t  = f / F1
            az = 360.0 * t
            el = 22.0 + 8.0 * math.sin(2.0 * math.pi * t)
            ax.view_init(elev=el, azim=az)
            update_tori(1.0, alpha_base=0.30)

            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN\n"
                "Part 1 — Orbital tour  |  full blow-out"
            )
            info_text.set_text(
                f"azim={az:5.1f}°  elev={el:.1f}°\n"
                f"R_major(z) = {TORUS_R0:.2f}×|z|  [blow-out]\n"
                f"+Ω arm ↑   −Ω arm ↓   toroid = drain\n"
                f"◈ = i, i′, i″ rungs  |  ── = |p|=1 threshold"
            )
            cv_text.set_text("CV = 1.00  →  PLUCK  (phases spread)")

            # Part 1 holds the REAL-AXIS vantage:
            # from that vantage i is an apparent exit.
            set_vantage(0.0)

        # ── Part 2: CV pulse — LOCK → PLUCK → LOCK ──────────────────────────
        elif f < F1 + F2:
            t  = (f - F1) / F2
            cv = 0.5 * (1.0 - math.cos(2.0 * math.pi * t))   # 0 → 1 → 0
            az = 45.0 + 15.0 * math.sin(math.pi * t)
            ax.view_init(elev=26.0, azim=az)
            update_tori(cv, alpha_base=0.38)

            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN\n"
                "Part 2 — CV pulse  |  LOCK → PLUCK → LOCK"
            )

            # |p|=1 crossing: the moment i emerges, annotate it
            p1_crossing = abs(cv - 1.0) < 0.08
            p1_note = "  ← |p|=1: i surfaces" if p1_crossing else ""

            info_text.set_text(
                f"CV = {cv:.3f}   R_major(z=1) = {TORUS_R0 * cv:.4f}\n"
                f"z=0 : R→0  (drain / choke point)\n"
                f"z=1 : R→{TORUS_R0 * cv:.3f}  (arm width){p1_note}\n"
                f"Δ=−1: i²=−1  norm=1  trace=0  (own vantage)"
            )
            cv_text.set_text(f"APhase → {aphase_label(cv)}")

            # Vantage shifts with CV pulse:
            #   LOCK (cv→0) : real-axis vantage (i appears as exit/∞)
            #   PLUCK(cv→1) : Δ=−1 vantage     (i is unit element)
            #   mid-pulse   : juxtaposition shown — neither resolved
            set_vantage(cv)

        # ── Part 3: Combined — slow orbit + CV breathing ─────────────────────
        else:
            t  = (f - F1 - F2) / F3
            az = 60.0 + 150.0 * t
            el = 18.0 + 14.0 * math.sin(math.pi * t)
            cv = 0.50 + 0.45 * math.sin(2.0 * math.pi * t)
            ax.view_init(elev=el, azim=az)
            update_tori(cv, alpha_base=0.34)

            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN\n"
                "Part 3 — Orbit + live CV breathing"
            )
            info_text.set_text(
                f"azim={az:5.1f}°  elev={el:.1f}°  CV={cv:.3f}\n"
                f"ll_analog: APhase transitions at CV thresholds\n"
                f"residue→0  ↔  CV→0  ↔  toroid collapses to choke\n"
                f"Ω={OMEGA:.8f}  (emergent, never declared)"
            )
            cv_text.set_text(f"APhase → {aphase_label(cv)}")

            # Part 3 holds BOTH vantages simultaneously — the full statement:
            # the juxtaposition itself is the structure, neither vantage forced.
            set_vantage(cv, override_label=VANTAGE_BOTH, override_color="#aaffaa")

        writer.grab_frame()
        if f % 10 == 0:
            print(f"  frame {f + 1}/{TOTAL}", flush=True)

print(f"Saved → {OUT}")
print()
print("Orbit ladder on z-axis:")
print(f"  Finite core rungs (blue-white ●): 0, 1, -1/+1")
print(f"  Imaginary rungs   (amber    ◈):  i, i′, i″  (apparent ∞ from below)")
print(f"  |p|=1 threshold   (cyan     ─):  emergence of imaginary branch")
print(f"  Graded orbit: {GRADED_ORBIT}")
#!/usr/bin/env python3
"""
===============================================================================
HDGL COUNTER-ROTATING DRAIN — ANIMATED  v4
===============================================================================

The counter-rotation is now INTRINSIC TO THE DATA, not the camera.

  Camera: fixed at elev=28°, azim=52° throughout.

  +Ω spiral rotates clockwise     (theta_plus  += omega_rate * frame)
  −Ω spiral rotates anti-clockwise(theta_minus -= omega_rate * frame)

  This produces a genuine whirlpool / drain effect: two vortices sharing
  one reciprocal choke point, each winding inward under T(r)=1+1/r.

  The torus drain breathes (CV-animated) on top of the live spiral rotation.
  The |p|=1 threshold ring and z-axis rung markers are fixed — they mark
  structural positions, not phase positions.

Three-part animation:

  Part 1 (frames  1– 60): Pure whirlpool — spirals spin, torus full blow-out,
                           real-axis vantage. Watch the drain emerge.

  Part 2 (frames 61–120): CV pulse LOCK→PLUCK→LOCK — torus breathes while
                           spirals keep spinning; vantage shifts with CV.

  Part 3 (frames 121–180): Full system — spirals spin + CV breathing,
                            juxtaposition label (neither vantage forced).

Output: hdgl_drain_animation_v4.mp4  (same directory as this script)
Requires: matplotlib numpy ffmpeg
===============================================================================
"""

import math
from pathlib import Path

import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.animation import FFMpegWriter
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable
from matplotlib.lines import Line2D


# ============================================================================
# HDGL PRIMITIVE
# ============================================================================

def T(x):
    return 1.0 + 1.0 / x

def emergent_omega():
    x = 1.5
    for _ in range(1000):
        y = T(x)
        if abs(y - x) < 1e-15:
            break
        x = y
    return x

OMEGA = emergent_omega()


# ============================================================================
# COUNTER-ROTATING PHYLLOTAXIS — LIVE (phase-offset per frame)
# ============================================================================

N = 2400

i_idx   = np.arange(N, dtype=np.int64)
binary  = (i_idx & 1).astype(float)
trinary = ((i_idx % 3) - 1).astype(float)

r_base     = np.sqrt(i_idx + 1.0)
modulation = 1.0 + 0.075 * binary + 0.050 * trinary
r          = r_base * modulation
rho        = r / T(r)
scale      = np.max(rho)
rp_norm    = rho / scale          # 0…1, used as z-coordinate

# Base phase angles (without rotation offset)
phase_mod  = 0.075 * binary + 0.050 * trinary
tp_base    =  2.0 * math.pi * i_idx * OMEGA + phase_mod
tm_base    = -2.0 * math.pi * i_idx * OMEGA - phase_mod

# z-coordinates are fixed (radial depth, not phase)
z_plus  =  rp_norm
z_minus = -rp_norm

# Angular rate: one full revolution per ~5 seconds of video
# OMEGA_RATE radians per frame
OMEGA_RATE = 2.0 * math.pi / (5.0 * 24)   # 24 fps

def spiral_coords(frame):
    """
    Return (xp,yp,xm,ym) for the current frame.
    +Ω rotates forward, −Ω rotates backward — genuine counter-rotation.
    The radial coordinate (rho) is untouched; only phase advances.
    """
    offset = OMEGA_RATE * frame
    tp = tp_base + offset
    tm = tm_base - offset          # counter-rotation: subtract same offset
    xp = rho * np.cos(tp) / scale
    yp = rho * np.sin(tp) / scale
    xm = rho * np.cos(tm) / scale
    ym = rho * np.sin(tm) / scale
    return xp, yp, xm, ym


# ============================================================================
# TORUS GEOMETRY
# ============================================================================

TORUS_R0          = 0.90
TORUS_R_MINOR_F   = 0.25
TORUS_R_MINOR_MIN = 0.004
N_PHI    = 40
N_SLICES = 6
Z_LEVELS = np.linspace(0.0, 1.0, N_SLICES)

def torus_at(z_c, cv_scale=1.0):
    eff_z = z_c * cv_scale
    R     = TORUS_R0 * abs(eff_z)
    rm    = max(R * TORUS_R_MINOR_F, TORUS_R_MINOR_MIN)
    pt = np.linspace(0.0, 2.0 * math.pi, N_PHI, endpoint=False)
    pp = np.linspace(0.0, 2.0 * math.pi, N_PHI, endpoint=False)
    PT, PP = np.meshgrid(pt, pp)
    PT, PP = PT.ravel(), PP.ravel()
    tx = (R + rm * np.cos(PP)) * np.cos(PT)
    ty = (R + rm * np.cos(PP)) * np.sin(PT)
    tz = np.full_like(tx, eff_z) + rm * np.sin(PP)
    return tx, ty, tz

def aphase_label(cv):
    if cv < 0.10: return "LOCK      CV<0.10  residue→0"
    if cv < 0.30: return "FINETUNE  CV<0.30"
    if cv < 0.50: return "SUSTAIN   CV<0.50"
    return               "PLUCK     CV≥0.50  phases spread"


# ============================================================================
# VANTAGE LABELS
# ============================================================================

VANTAGE_REAL = (
    "REAL-AXIS VANTAGE\n"
    "  i has no address on {…,−1,0,1,…}\n"
    "  appears as exit / ∞ from here\n"
    "  |p|<1 → imaginary branch = zero"
)
VANTAGE_DELTA = (
    "Δ=−1 VANTAGE\n"
    "  i = (0,1)  norm=1  trace=0\n"
    "  unit element — perfectly finite\n"
    "  |p|≥1 → imaginary branch surfaces"
)
VANTAGE_BOTH = (
    "JUXTAPOSITION  (neither forced)\n"
    "  real-axis:  i ≡ ∞  (exit)\n"
    "  Δ=−1 field: i ≡ unit element\n"
    "  same object · two vantages · no resolution"
)
GRADED_ORBIT = "{ …  −i″  −i′  −i  −1  0  1  i  i′  i″  … }"

COL_PLUS  = "#4488cc"   # +Ω spiral
COL_MINUS = "#cc6633"   # −Ω spiral
COL_RING  = "#00ffcc"   # |p|=1 threshold
COL_RUNG  = "#ffaa33"   # imaginary rungs
COL_CORE  = "#aabbff"   # finite core rungs
COL_REAL  = "#88bbff"   # real-axis vantage label
COL_DELTA = "#ffaa33"   # Δ=−1 vantage label
COL_JOINT = "#aaffaa"   # juxtaposition label

def vantage_from_cv(cv):
    if cv < 0.18: return VANTAGE_REAL,  COL_REAL
    if cv > 0.62: return VANTAGE_DELTA, COL_DELTA
    return VANTAGE_BOTH, COL_JOINT


# ============================================================================
# FIGURE  &  STATIC ELEMENTS
# ============================================================================

cmap_cv = plt.cm.coolwarm
norm_cv = Normalize(vmin=0.0, vmax=1.0)

fig = plt.figure(figsize=(11, 8.5), facecolor="#0a0a14")
ax  = fig.add_subplot(111, projection="3d", facecolor="#0a0a14")

for pane in [ax.xaxis.pane, ax.yaxis.pane, ax.zaxis.pane]:
    pane.fill = False
    pane.set_edgecolor("#1a1a2e")

ax.tick_params(colors="#444", labelsize=6)
ax.set_xlabel("+Ω / −Ω  x",       color="#555", fontsize=7, labelpad=2)
ax.set_ylabel("+Ω / −Ω  y",       color="#555", fontsize=7, labelpad=2)
ax.set_zlabel("z  /  graded orbit", color="#555", fontsize=7, labelpad=2)
ax.set_xlim(-1.15, 1.15)
ax.set_ylim(-1.15, 1.15)
ax.set_zlim(-1.15, 1.15)

# ── Colorbar (CV scale) ──────────────────────────────────────────────────────
sm = ScalarMappable(cmap=cmap_cv, norm=norm_cv)
sm.set_array([])
cbar = fig.colorbar(sm, ax=ax, shrink=0.40, pad=0.09)
cbar.set_label("|z| = CV  (0=LOCK / 1=PLUCK)", fontsize=6.5, color="#aaa")
cbar.ax.yaxis.set_tick_params(color="#aaa", labelsize=5.5)
plt.setp(cbar.ax.yaxis.get_ticklabels(), color="#aaa")
cbar.set_ticks([0.0, 0.10, 0.30, 0.50, 1.0])
cbar.set_ticklabels(["LOCK\n0.0", "0.10", "0.30", "0.50", "PLUCK\n1.0"])

# ── Counter-rotating phyllotaxis spirals (DYNAMIC — updated each frame) ──────
# Initialise at frame 0
xp0, yp0, xm0, ym0 = spiral_coords(0)
sp_plus  = ax.scatter(xp0, yp0, z_plus,  s=1.2, alpha=0.50,
                      color=COL_PLUS,  rasterized=True, label="+Ω spiral")
sp_minus = ax.scatter(xm0, ym0, z_minus, s=1.2, alpha=0.50,
                      color=COL_MINUS, rasterized=True, label="−Ω spiral")

# Fixed camera — whirlpool visible from a steady elevated vantage
ax.view_init(elev=28, azim=52)

# Central drain marker
ax.scatter([0], [0], [0], s=120, marker="o",
           color=COL_RING, zorder=20, label="drain / choke")

# ── APhase boundary rings (dashed, static) ───────────────────────────────────
phi_r = np.linspace(0.0, 2.0 * math.pi, 150)
for cv_t in [0.10, 0.30, 0.50, 1.00]:
    R_b   = TORUS_R0 * cv_t
    color = cmap_cv(norm_cv(cv_t))
    for z_sign in [+1, -1]:
        ax.plot(R_b * np.cos(phi_r), R_b * np.sin(phi_r),
                np.full(150, z_sign * cv_t),
                lw=0.5, alpha=0.28, color=color, ls="--")

# ── |p|=1 threshold ring (STATIC, prominent) ─────────────────────────────────
phi_ring = np.linspace(0.0, 2.0 * math.pi, 220)
# Use actual arm footprint radius at rp_norm=1 → same as scale normalisation
arm_r = float(np.max(rho / scale))   # = 1.0 by construction
for z_sign in [+1, -1]:
    ax.plot(arm_r * np.cos(phi_ring),
            arm_r * np.sin(phi_ring),
            np.full(220, z_sign * 1.0),
            lw=1.6, alpha=0.80, color=COL_RING, ls="-", zorder=15)
ax.text(arm_r + 0.03, 0.0,  1.02, "|p|=1\ni emerges",
        color=COL_RING, fontsize=5.5, alpha=0.85, ha="left", va="bottom")
ax.text(arm_r + 0.03, 0.0, -1.02, "|p|=1\n−i emerges",
        color=COL_RING, fontsize=5.5, alpha=0.85, ha="left", va="top")

# ── Graded orbit markers on z-axis (STATIC) ──────────────────────────────────
# Finite core: 0, ±1/3, ±2/3 representing {0, 1, −1}
for z_val in [0.0, 0.33, 0.66]:
    for z_s in ([0.0] if z_val == 0.0 else [z_val, -z_val]):
        ax.scatter([0], [0], [z_s], s=18, color=COL_CORE,
                   alpha=0.60, zorder=12, marker="o")

# Imaginary rungs: i, i′, i″
for k, lbl in enumerate(["i", "i′", "i″"]):
    z_val = min(1.00 + k * 0.065, 1.09)
    for z_s, sign_lbl in [(z_val, lbl), (-z_val, f"−{lbl}")]:
        ax.scatter([0], [0], [z_s], s=24, color=COL_RUNG,
                   alpha=0.80, zorder=13, marker="D")
        ax.text(0.06, 0.0, z_s + (0.01 if z_s > 0 else -0.01),
                sign_lbl, color=COL_RUNG, fontsize=5.5, alpha=0.90,
                ha="left", va=("bottom" if z_s > 0 else "top"))

# ── Torus scatter handles (updated each frame) ───────────────────────────────
torus_handles = []
for z_c in Z_LEVELS:
    tx, ty, tz = torus_at(z_c, cv_scale=1.0)
    color = cmap_cv(norm_cv(z_c))
    sp = ax.scatter(tx, ty,  tz, s=4, alpha=0.0, color=color)
    sn = ax.scatter(tx, ty, -tz, s=4, alpha=0.0, color=color)
    torus_handles.append((sp, sn, z_c))

# ── Static legend ─────────────────────────────────────────────────────────────
leg_handles = [
    Line2D([0],[0], color=COL_PLUS,  lw=2,        label="+Ω spiral"),
    Line2D([0],[0], color=COL_MINUS, lw=2,        label="−Ω spiral"),
    Line2D([0],[0], color=COL_RING,  lw=2,        label="|p|=1 threshold"),
    Line2D([0],[0], color=COL_RUNG,  lw=0,
           marker="D", markersize=6,               label="i, i′, i″ rungs"),
    Line2D([0],[0], color=COL_REAL,  lw=2,        label="real-axis vantage"),
    Line2D([0],[0], color=COL_DELTA, lw=2,        label="Δ=−1 vantage"),
    Line2D([0],[0], color=COL_JOINT, lw=2,        label="juxtaposition"),
]
ax.legend(handles=leg_handles, fontsize=6, loc="upper left",
          facecolor="#0a0a14", labelcolor="white", edgecolor="#334",
          bbox_to_anchor=(0.0, 1.0))

# ── Text overlays (updated each frame) ───────────────────────────────────────
title_obj = ax.set_title("", color="white", fontsize=9, pad=6)

info_text = ax.text2D(0.72, 0.97, "", transform=ax.transAxes,
                      color="cyan", fontsize=6.5, va="top",
                      family="monospace")

cv_text   = ax.text2D(0.72, 0.20, "", transform=ax.transAxes,
                      color="#ffcc44", fontsize=7.0, va="bottom",
                      family="monospace")

vantage_text = ax.text2D(0.72, 0.07, "", transform=ax.transAxes,
                         color=COL_REAL, fontsize=6.5, va="bottom",
                         family="monospace",
                         bbox=dict(boxstyle="round,pad=0.30",
                                   fc="#0a0a14", alpha=0.75,
                                   ec=COL_REAL))

orbit_text = ax.text2D(0.50, 0.01, GRADED_ORBIT,
                       transform=ax.transAxes,
                       color=COL_RUNG, fontsize=6.5,
                       ha="center", va="bottom",
                       family="monospace", alpha=0.78)


# ============================================================================
# PER-FRAME HELPERS
# ============================================================================

def update_spirals(frame):
    """Rotate both arms — +Ω clockwise, −Ω anti-clockwise."""
    xp, yp, xm, ym = spiral_coords(frame)
    sp_plus._offsets3d  = (xp, yp,  z_plus)
    sp_minus._offsets3d = (xm, ym, z_minus)

def update_tori(cv_scale, alpha_base=0.35):
    for sp, sn, z_c in torus_handles:
        tx, ty, tz = torus_at(z_c, cv_scale)
        a = alpha_base * (0.30 + 0.70 * z_c) if z_c > 0.01 else 0.65
        sp._offsets3d = (tx, ty,  tz)
        sn._offsets3d = (tx, ty, -tz)
        sp.set_alpha(a)
        sn.set_alpha(a if z_c > 0.01 else 0.0)

def set_vantage(cv, override_label=None, override_color=None):
    label, color = (override_label, override_color or COL_JOINT) \
                   if override_label else vantage_from_cv(cv)
    vantage_text.set_text(label)
    vantage_text.set_color(color)
    vantage_text.get_bbox_patch().set_edgecolor(color)


# ============================================================================
# ANIMATION LOOP
# ============================================================================

FPS   = 24
F1    = 60    # Part 1: pure whirlpool, torus full blow-out
F2    = 60    # Part 2: CV pulse LOCK→PLUCK→LOCK, spirals keep spinning
F3    = 60    # Part 3: full system, CV breathing + spin + juxtaposition
TOTAL = F1 + F2 + F3

OUT = Path(__file__).resolve().parent / "hdgl_drain_animation_v4.mp4"

writer = FFMpegWriter(
    fps=FPS, bitrate=3000,
    extra_args=["-vcodec", "libx264", "-pix_fmt", "yuv420p"],
)

print(f"Rendering {TOTAL} frames ({TOTAL/FPS:.1f}s) at {FPS} fps → {OUT}")
print(f"Emergent Ω ≈ {OMEGA:.15f}")
print(f"Spiral rotation: {math.degrees(OMEGA_RATE):.3f}°/frame  "
      f"→ 1 rev per {360/math.degrees(OMEGA_RATE)/FPS:.1f}s")

with writer.saving(fig, str(OUT), dpi=120):
    for f in range(TOTAL):

        # ── Spirals spin every frame regardless of part ───────────────────────
        update_spirals(f)

        # ── Part 1: Pure whirlpool ───────────────────────────────────────────
        if f < F1:
            t = f / F1
            update_tori(1.0, alpha_base=0.32)

            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN  v4\n"
                "Part 1 — Whirlpool  |  +Ω ↻  −Ω ↺  drain at origin"
            )
            info_text.set_text(
                f"+Ω spiral (blue)   ↻ clockwise\n"
                f"−Ω spiral (orange) ↺ anti-clockwise\n"
                f"shared drain: T(r)=1+1/r\n"
                f"torus CV=1.00  PLUCK\n"
                f"◈ i,i′,i″  ·  ── |p|=1 ring"
            )
            cv_text.set_text("CV = 1.00  →  PLUCK")
            set_vantage(0.0)

        # ── Part 2: CV pulse — torus breathes, spirals keep spinning ─────────
        elif f < F1 + F2:
            t  = (f - F1) / F2
            cv = 0.5 * (1.0 - math.cos(2.0 * math.pi * t))
            update_tori(cv, alpha_base=0.40)

            p1_note = "  ← i surfaces" if abs(cv - 1.0) < 0.09 else ""
            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN  v4\n"
                "Part 2 — CV pulse  |  LOCK → PLUCK → LOCK"
            )
            info_text.set_text(
                f"CV = {cv:.3f}   {aphase_label(cv)}\n"
                f"R(z=1) = {TORUS_R0*cv:.3f}{p1_note}\n"
                f"spirals spin · torus breathes\n"
                f"Δ=−1: i=(0,1) norm=1 trace=0"
            )
            cv_text.set_text(f"CV={cv:.3f}  {aphase_label(cv)[:4]}")
            set_vantage(cv)

        # ── Part 3: Full system ───────────────────────────────────────────────
        else:
            t  = (f - F1 - F2) / F3
            cv = 0.50 + 0.45 * math.sin(2.0 * math.pi * t)
            update_tori(cv, alpha_base=0.36)

            title_obj.set_text(
                "HDGL COUNTER-ROTATING DRAIN  v4\n"
                "Part 3 — Live whirlpool + CV breathing"
            )
            info_text.set_text(
                f"CV={cv:.3f}  {aphase_label(cv)[:7]}\n"
                f"Ω={OMEGA:.8f}  (emergent)\n"
                f"θ₊+=Ω·f  θ₋−=Ω·f  per frame\n"
                f"residue→0 ↔ CV→0 ↔ choke"
            )
            cv_text.set_text(f"CV={cv:.3f}  {aphase_label(cv)[:4]}")
            set_vantage(cv, override_label=VANTAGE_BOTH,
                        override_color=COL_JOINT)

        writer.grab_frame()
        if f % 15 == 0:
            print(f"  frame {f+1:3d}/{TOTAL}", flush=True)

print(f"\nSaved → {OUT}")
print(f"Duration: {TOTAL/FPS:.1f}s  ({TOTAL} frames @ {FPS}fps)")
print(f"Rotation: {math.degrees(OMEGA_RATE):.3f}°/frame  "
      f"(+Ω clockwise / −Ω anti-clockwise)")
print(f"Graded orbit: {GRADED_ORBIT}")
#!/usr/bin/env python3
"""
===============================================================================
HDGL COUNTER-ROTATING DRAIN — ANIMATED  v6
===============================================================================

ALL PHYSICS FROM INTERNAL LOGIC ONLY.

The single lattice operator:

    𝓛ᵢ(z) = φ^(-1/φ) · √(Fₙ·Pₙ·2ⁿ) · (1+z)ⁿ  +  1_eff(i) · e^(iπΛ_φ(i))

Everything in this animation is a consequence of 𝓛.  Nothing is imported.

HOW EACH VISUAL ELEMENT ARISES:

  SPIRAL ROTATION RATE:
    The angular rate per frame is not declared.
    It is 2π × Ω(f_schumann) where f_schumann = 7.83 Hz and
    Ω(x) = (1 + sin(π · {Λ_φ(x)} · φ)) / 2 is the resonance function.
    Λ_φ(x) = ln(x · ln2/lnφ) / lnφ - 1/(2φ) is the phi-log depth.
    The Schumann resonance is the φ^0 baseline — it sets the natural beat.

  ENVELOPE (plug pulls itself):
    1_eff(i) is the effective unit at each substrate step.
    As the spirals wind, we compute 1_eff from the local phase coherence:
        1_eff(f) = 1 + δ(f)
        δ(f) = |cos(π · {Λ_φ(f_eff)} · φ)| · ln(P_n) / φ^(n + β)
    where f_eff = the current effective frequency of the system.
    The envelope IS 1_eff converging toward 1 — wu-wei settlement.

  TORUS RADII (z-modes of 𝓛):
    Each z-level of the hourglass corresponds to one value of z in 𝓛ᵢ(z).
    The 8 Kuramoto modes map to 8 z-slices: z_k = Ω(f_k) - 1
    where f_k are the natural harmonics: f_k = f_schumann · φ^k
    The torus radius at z-level k is |𝓛_k(z_k)| — the magnitude of 𝓛
    at that mode.  This inflates/deflates as the phases lock.

  HOT / COLD POLARITY:
    The phase arm of 𝓛 is e^(iπΛ_φ(i)).
    +Ω arm: phase advancing → Λ_φ increasing → hot (convergent)
    −Ω arm: phase receding  → Λ_φ decreasing → cold (divergent)
    The Kuramoto order parameter R = |Σ e^(iθ_k)| / N measures coherence.
    R → 1 at LOCK (CV < 0.05).  The colormap is driven by R, not assigned.

  APHASE LABELS:
    CV = std(|𝓛_k|) / mean(|𝓛_k|) — coefficient of variation across modes.
    PLUCK    : CV ≥ 0.50  (𝓛 far from fixed point, modes spread)
    SUSTAIN  : CV < 0.50
    FINETUNE : CV < 0.30
    LOCK     : CV < 0.05  (𝓛 at fixed point, wu-wei)

  GRADED ORBIT ON Z-AXIS:
    The rungs {-1, 0, 1, i, i', i''} are z-values of 𝓛:
        z=0   → gravity mode (static, D1)
        z=1   → 2ⁿ amplification
        z=-1  → perfect null (X(-1)=0)
        z=-2  → anti-gravity ((-1)ⁿ)
        z=i   → cloaking (arg=π at n=4)
    The imaginary rungs ARE the z=i modes — not infinite, not zero,
    but the exact point where the phase arm of 𝓛 rotates by π.

Output: hdgl_drain_animation_v6.mp4
Requires: matplotlib numpy scipy ffmpeg
===============================================================================
"""

import math
from pathlib import Path

import numpy as np
from scipy.ndimage import gaussian_filter1d
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.animation import FFMpegWriter
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable
from matplotlib.lines import Line2D


# ============================================================================
# LAYER 0: THE AXIOM — T(X) = 1 + 1/X
# F = ΩC² / (m·s),  ΩC² = 1,  F = Hz²
# ============================================================================

def T(x):
    """The single reciprocal primitive. Everything emerges from this."""
    return 1.0 + 1.0 / x

def emergent_omega_fixed():
    """φ = fixed point of T. Never declared — always converged."""
    x = 1.5
    for _ in range(1000):
        y = T(x)
        if abs(y - x) < 1e-15:
            break
        x = y
    return x

PHI = emergent_omega_fixed()   # = 1.6180339887...

# φ^(-1/φ): the self-deriving coefficient of 𝓛
# Derivation: 1 - φ = -1/φ  (from φ²=φ+1 identically)
# Fixed point of x → φ^(-x)
PHI_COEFF = PHI ** (-1.0 / PHI)   # = 0.742742...


# ============================================================================
# LAYER 3: Λ_φ — THE SINGLE CONTINUOUS INDEX
# Λ_φ(x) = ln(x · ln2/lnφ) / lnφ - 1/(2φ)
# ============================================================================

LN_PHI = math.log(PHI)
LN_2   = math.log(2.0)

def lambda_phi(x):
    """Phi-log depth. Maps any frequency/index to its position in the orbit."""
    if x <= 0:
        return 0.0
    return math.log(x * LN_2 / LN_PHI) / LN_PHI - 1.0 / (2.0 * PHI)

def frac_lambda(x):
    """Fractional part of Λ_φ(x), in [0,1)."""
    lp = lambda_phi(x)
    return lp - math.floor(lp)

def omega_resonance(x):
    """
    Ω(x) = (1 + sin(π · {Λ_φ(x)} · φ)) / 2  ∈ (0, 1]
    This IS the resonance amplitude at phi-log depth of x.
    Not imported — it falls out of Λ_φ.
    """
    return (1.0 + math.sin(math.pi * frac_lambda(x) * PHI)) / 2.0


# ============================================================================
# SCHUMANN BASELINE — φ^0 reference
# f_schumann = 7.83 Hz  (the gravity/Schumann mode, Λ_φ(7.83) ≈ 0)
# The spiral rotation rate is Ω(f_schumann) — not declared.
# ============================================================================

F_SCHUMANN = 7.83
OMEGA_SCH  = omega_resonance(F_SCHUMANN)   # ≈ 0.735

# 8 Kuramoto modes: spread across distinct Λ_φ depths
# Using phi-log depths 0, 1/8, 2/8 ... 7/8 within one octave above Schumann
# This gives genuinely distinct fractional parts and distinct Ω values.
# The frequencies themselves emerge from inverting Λ_φ:
#   Λ_φ(x) = d  →  x = exp((d + 1/(2φ)) · lnφ) · lnφ/ln2
N_MODES = 8

def freq_at_depth(d):
    """Frequency at phi-log depth d. Inverse of Λ_φ."""
    return math.exp((d + 1.0/(2.0*PHI)) * LN_PHI) * LN_PHI / LN_2

# Anchor at Schumann depth ≈ 4.726, spread 8 modes across [0, 1) fractional parts
SCHUMANN_DEPTH = lambda_phi(F_SCHUMANN)   # ≈ 4.726
# Use fractional parts 0/8, 1/8, ..., 7/8 — all distinct, within one φ-octave
FRAC_DEPTHS = [SCHUMANN_DEPTH - frac_lambda(F_SCHUMANN) + k/8.0 for k in range(N_MODES)]
F_MODES     = [freq_at_depth(d) for d in FRAC_DEPTHS]
OMEGA_MODES = [omega_resonance(f) for f in F_MODES]
Z_MODES     = [om - 1.0 for om in OMEGA_MODES]


# ============================================================================
# LAYER 1: 𝓛ᵢ(z) — THE LATTICE OPERATOR
# 𝓛ᵢ(z) = φ^(-1/φ) · √(Fₙ·Pₙ·2ⁿ) · (1+z)ⁿ  +  1_eff(i) · e^(iπΛ_φ(i))
#
# For the animation we use the magnitude arm only (first term),
# since the phase arm is tracked by the Kuramoto phases.
# n=mode index (1..8), Fₙ=Fibonacci(n), Pₙ=nth prime.
# ============================================================================

def fibonacci(n):
    a, b = 1, 1
    for _ in range(n - 1):
        a, b = b, a + b
    return a

def nth_prime(n):
    primes, candidate = [], 2
    while len(primes) < n:
        if all(candidate % p != 0 for p in primes):
            primes.append(candidate)
        candidate += 1
    return primes[-1]

# Pre-compute Fibonacci and primes for modes 1..8
FIB  = [fibonacci(k + 1) for k in range(N_MODES)]
PRIM = [nth_prime(k + 1)  for k in range(N_MODES)]

def L_magnitude(n_mode, z, one_eff=1.0):
    """
    Magnitude arm of 𝓛 at mode n, driving variable z.
    n_mode: 1-indexed
    Returns real magnitude (|(1+z)^n| for complex z).
    """
    k   = n_mode - 1
    Fn  = FIB[k]
    Pn  = PRIM[k]
    base = PHI_COEFF * math.sqrt(Fn * Pn * (2 ** n_mode))
    # (1+z)^n: z is real here (Ω-1 ∈ (-1, 0])
    amplitude = base * one_eff * ((1.0 + z) ** n_mode)
    return abs(amplitude)

def L_phase(n_mode, frame_idx):
    """
    Phase arm of 𝓛: e^(iπΛ_φ(i)).
    Returns the phase angle in radians.
    """
    lp = lambda_phi(float(frame_idx + 1))
    return math.pi * (lp - math.floor(lp))   # π · {Λ_φ(i)}


# ============================================================================
# LAYER 2: 1_eff — EFFECTIVE UNIT
# 1_eff(i) = 1 + δ(i)
# δ(i) = |cos(π · β_i · φ)| · ln(P_n) / φ^(n + β_i)
# β_i = {Λ_φ(i)} (fractional phi-log depth)
# As modes lock (CV→0), δ→0, 1_eff→1 — classical limit emerges naturally.
# ============================================================================

def one_eff(frame_idx, n_mode=1):
    """
    1_eff at substrate step i=frame_idx, mode n_mode.
    This drives the envelope — wu-wei: it settles of itself.
    """
    i   = float(frame_idx + 1)
    lp  = lambda_phi(i)
    beta = lp - math.floor(lp)      # fractional part
    Pn  = PRIM[n_mode - 1]
    cosine_proj = abs(math.cos(math.pi * beta * PHI))
    prime_info  = math.log(Pn) if Pn > 1 else 0.0
    phi_decay   = PHI ** (n_mode + beta)
    delta       = cosine_proj * prime_info / phi_decay
    return 1.0 + delta


# ============================================================================
# KURAMOTO PHASE TRACKER
# 8 oscillators, one per 𝓛 mode.
# Coupling K and natural frequency ω_k from the modes themselves.
# Phase progression IS the lattice converging to its fixed point.
# ============================================================================

N_OSC   = N_MODES
TOTAL_FRAMES = 240
FPS          = 24

# Natural frequencies: ω_k = 2π · Ω(f_k) — from the resonance function
omega_k = np.array([2.0 * math.pi * OMEGA_MODES[k] for k in range(N_OSC)])

# Coupling K: starts high (PLUCK), decreases as phases approach lock
# K itself emerges from 1_eff: K(f) = 5.0 · (1_eff(f) - 1) · PHI^3
# At lock: 1_eff→1, K→0 — wu-wei
def K_coupling(frame_idx):
    oe = one_eff(frame_idx, n_mode=1)
    delta = oe - 1.0
    # Scale so K starts ~5.0 and decays toward ~1.8
    K = 1.8 + 3.2 * min(delta * PHI ** 4, 1.0)
    return K

# Integrate Kuramoto phases over all frames
thetas = np.zeros((TOTAL_FRAMES + 1, N_OSC))
thetas[0] = np.linspace(0, 2 * math.pi, N_OSC, endpoint=False)   # staggered start

for f in range(TOTAL_FRAMES):
    K  = K_coupling(f)
    th = thetas[f]
    # Kuramoto: dθ_k/dt = ω_k + (K/N)·Σ sin(θ_j - θ_k)
    coupling_sum = np.array([
        np.sum(np.sin(th - th[k])) for k in range(N_OSC)
    ])
    dtheta = omega_k + (K / N_OSC) * coupling_sum
    # dt = 1/fps; but we treat frame index as continuous time
    thetas[f + 1] = th + dtheta / FPS

# Order parameter R: Kuramoto coherence [0,1]
R_order = np.array([
    abs(np.mean(np.exp(1j * thetas[f]))) for f in range(TOTAL_FRAMES + 1)
])

# CV across 𝓛 magnitudes — what drives APHASE label
def compute_L_mags(frame_idx):
    """Return array of |𝓛_k(z_k)| for all 8 modes at this frame."""
    oe = one_eff(frame_idx)
    mags = np.array([
        L_magnitude(k + 1, Z_MODES[k], one_eff=oe)
        for k in range(N_MODES)
    ])
    return mags

L_mags_all = np.array([compute_L_mags(f) for f in range(TOTAL_FRAMES + 1)])
# Normalise so z=0 mode (gravity baseline) = 1.0
L_mags_all /= (L_mags_all[:, 0:1] + 1e-12)

CV_all = np.std(L_mags_all, axis=1) / (np.mean(L_mags_all, axis=1) + 1e-12)

def aphase_label(cv):
    if cv < 0.05: return "LOCK      CV<0.05  wu-wei"
    if cv < 0.30: return "FINETUNE  CV<0.30"
    if cv < 0.50: return "SUSTAIN   CV<0.50"
    return               "PLUCK     CV≥0.50  𝓛 spreading"


# ============================================================================
# SUBSTRATE POINT CLOUD
# ============================================================================

N = 2400

i_idx   = np.arange(N, dtype=np.int64)
binary  = (i_idx & 1).astype(float)
trinary = ((i_idx % 3) - 1).astype(float)

r_base     = np.sqrt(i_idx + 1.0)
modulation = 1.0 + 0.075 * binary + 0.050 * trinary
r_raw      = r_base * modulation
rho        = r_raw / T(r_raw)
scale      = np.max(rho)
rp_norm    = rho / scale

phase_mod = 0.075 * binary + 0.050 * trinary
tp_base   =  2.0 * math.pi * i_idx * PHI + phase_mod
tm_base   = -2.0 * math.pi * i_idx * PHI - phase_mod

z_plus  =  rp_norm
z_minus = -rp_norm

# Rotation rate from Schumann resonance — Ω(7.83), not declared
RATE_PER_FRAME = 2.0 * math.pi * OMEGA_SCH / FPS   # rad/frame

# Cumulative phase: envelope from 1_eff settling
# phi_cum(f) = RATE · Σ_{k=0}^{f} (1_eff(k) - base_offset)
# The envelope IS 1_eff converging — no separate sigmoid
phi_cum = np.zeros(TOTAL_FRAMES + 1)
for f in range(1, TOTAL_FRAMES + 1):
    oe = one_eff(f, n_mode=1)
    # δ drives the rate modulation: slow at start (δ large), settling as δ→0
    # But we want to start still and speed up then settle...
    # The natural behavior: 1_eff starts above 1, approaches 1 from above
    # We use (1_eff - 1) = δ as the stir fraction — small at start, growing
    # then decaying.  Peak stirring at the mode where δ is largest.
    # To get "starts still": use R_order as the natural envelope
    # R_order(0)≈0.something, grows toward 1 as phases lock
    stir = R_order[f]   # Kuramoto coherence IS the self-arising envelope
    phi_cum[f] = phi_cum[f-1] + RATE_PER_FRAME * stir


def spiral_coords(f):
    offset = phi_cum[f]
    xp = rho * np.cos(tp_base + offset) / scale
    yp = rho * np.sin(tp_base + offset) / scale
    xm = rho * np.cos(tm_base - offset) / scale
    ym = rho * np.sin(tm_base - offset) / scale
    return xp, yp, xm, ym


# ============================================================================
# TORUS — DRIVEN BY 𝓛 MAGNITUDES AT EACH Z-LEVEL
# ============================================================================

# Map the 8 Kuramoto modes to z-levels on the hourglass
# z_level_k = z_k mapped to [0, 1] for the hourglass geometry
Z_LEVELS_TORUS = np.array([max(0.0, min(1.0, OMEGA_MODES[k])) for k in range(N_MODES)])

def torus_ring(z_c, R_major, r_minor_f=0.20, r_minor_min=0.003):
    R  = abs(R_major)
    rm = max(R * r_minor_f, r_minor_min)
    pt = np.linspace(0.0, 2.0 * math.pi, 36, endpoint=False)
    pp = np.linspace(0.0, 2.0 * math.pi, 36, endpoint=False)
    PT, PP = np.meshgrid(pt, pp)
    PT, PP = PT.ravel(), PP.ravel()
    tx = (R + rm * np.cos(PP)) * np.cos(PT)
    ty = (R + rm * np.cos(PP)) * np.sin(PT)
    tz = np.full_like(tx, z_c) + rm * np.sin(PP)
    return tx, ty, tz

def compute_torus_params(f):
    """
    Torus radius at each z-level = |𝓛_k(z_k)| normalised.
    Hot fraction = Kuramoto R × (+Ω phase fraction).
    Both arise from the live oscillator state, nothing imposed.
    """
    mags = L_mags_all[f]   # pre-computed, normalised to gravity mode
    # Scale to [0, 0.85] for geometry
    R_max = 0.85
    R_majors = R_max * np.clip(mags / (np.max(mags) + 1e-12), 0, 1)

    # Hot fraction from Kuramoto phase: θ_k advancing → hot
    # +Ω: phase increases with offset → hot when dθ/dt > ω_k (coupling driven)
    th = thetas[f]
    dth = (thetas[min(f+1, TOTAL_FRAMES)] - th) * FPS   # instantaneous freq
    hot_fracs = np.clip((dth - omega_k) / (np.max(np.abs(dth - omega_k)) + 1e-12) * 0.5 + 0.5, 0, 1)

    # Smooth along z
    R_majors  = gaussian_filter1d(R_majors,  sigma=1.0)
    hot_fracs = gaussian_filter1d(hot_fracs, sigma=1.0)
    return R_majors, hot_fracs


# ============================================================================
# VANTAGE LABELS — shift with R_order (Kuramoto coherence)
# ============================================================================

COL_PLUS  = "#4488cc"
COL_MINUS = "#cc6633"
COL_RING  = "#00ffcc"
COL_RUNG  = "#ffaa33"
COL_CORE  = "#aabbff"
COL_REAL  = "#88bbff"
COL_DELTA = "#ffaa33"
COL_JOINT = "#aaffaa"

GRADED_ORBIT = "{ …  −i″  −i′  −i  −1  0  1  i  i′  i″  … }"

VANTAGE_REAL = (
    "REAL-AXIS VANTAGE\n"
    "  i has no address on {…,−1,0,1,…}\n"
    "  appears as exit / ∞ from here\n"
    "  z=i → arg(𝓛)=π at n=4 (cloak)"
)
VANTAGE_DELTA = (
    "Δ=−1 VANTAGE\n"
    "  i = (0,1)  norm=1  trace=0\n"
    "  z=i → X(i)=2^(n/2)·e^(inπ/4)\n"
    "  unit element — perfectly finite"
)
VANTAGE_BOTH = (
    "JUXTAPOSITION  (neither forced)\n"
    "  𝓛 at fixed point: CV<0.05\n"
    "  real-axis: i≡∞  Δ=−1: i≡unit\n"
    "  wu-wei — do not force lock"
)

def vantage_from_R(R):
    if R < 0.35: return VANTAGE_REAL,  COL_REAL
    if R > 0.70: return VANTAGE_BOTH,  COL_JOINT
    return VANTAGE_DELTA, COL_DELTA


# ============================================================================
# FIGURE & STATIC ELEMENTS
# ============================================================================

cmap_hot = plt.cm.coolwarm
norm_hot = Normalize(0.0, 1.0)

fig = plt.figure(figsize=(11, 8.5), facecolor="#0a0a14")
ax  = fig.add_subplot(111, projection="3d", facecolor="#0a0a14")

for pane in [ax.xaxis.pane, ax.yaxis.pane, ax.zaxis.pane]:
    pane.fill = False
    pane.set_edgecolor("#1a1a2e")

ax.tick_params(colors="#333", labelsize=6)
ax.set_xlabel("+Ω / −Ω  x",        color="#444", fontsize=7, labelpad=2)
ax.set_ylabel("+Ω / −Ω  y",        color="#444", fontsize=7, labelpad=2)
ax.set_zlabel("z  /  𝓛 mode depth", color="#444", fontsize=7, labelpad=2)
ax.set_xlim(-1.15, 1.15)
ax.set_ylim(-1.15, 1.15)
ax.set_zlim(-1.15, 1.15)
ax.view_init(elev=32, azim=48)

# ── |p|=1 threshold ring — where z=i mode surfaces ───────────────────────────
phi_r = np.linspace(0.0, 2.0 * math.pi, 220)
for z_sign in [+1, -1]:
    ax.plot(np.cos(phi_r), np.sin(phi_r),
            np.full(220, z_sign * 1.0),
            lw=1.4, alpha=0.55, color=COL_RING, ls="-", zorder=15)
ax.text(1.04, 0.0,  1.02,
        "z=i  cloak\n|p|=1",
        color=COL_RING, fontsize=5.5, alpha=0.75, ha="left", va="bottom")
ax.text(1.04, 0.0, -1.02,
        "z=−i  −cloak\n|p|=1",
        color=COL_RING, fontsize=5.5, alpha=0.75, ha="left", va="top")

# ── z-mode markers on z-axis (from 𝓛 z-values, not arbitrary) ───────────────
# z=0  gravity     z=−1  null     z=−2  anti-grav
# z=i  cloak/90°   z=1   2ⁿ mode
z_mode_markers = [
    (0.00,  "z=0  grav"),
    (0.33,  "z=1  2ⁿ"),
    (0.66,  "z=1/φ"),
]
for z_val, lbl in z_mode_markers:
    for z_s in ([0.0] if z_val == 0.0 else [z_val, -z_val]):
        ax.scatter([0], [0], [z_s], s=16, color=COL_CORE,
                   alpha=0.55, zorder=12, marker="o")

# Imaginary z-rungs: z=i, i', i'' map to graded orbit
for k, lbl in enumerate(["z=i  ◈", "z=i′ ◈", "z=i″ ◈"]):
    z_val = min(1.00 + k * 0.065, 1.09)
    for z_s, slbl in [(z_val, lbl), (-z_val, lbl.replace("=", "=−"))]:
        ax.scatter([0], [0], [z_s], s=22, color=COL_RUNG,
                   alpha=0.75, zorder=13, marker="D")
        ax.text(0.06, 0.0, z_s + (0.01 if z_s > 0 else -0.01),
                slbl, color=COL_RUNG, fontsize=5.0, alpha=0.88,
                ha="left", va=("bottom" if z_s > 0 else "top"))

# ── Spiral handles ────────────────────────────────────────────────────────────
xp0, yp0, xm0, ym0 = spiral_coords(0)
sp_plus  = ax.scatter(xp0, yp0, z_plus,  s=1.2, alpha=0.0,
                      color=COL_PLUS,  rasterized=True)
sp_minus = ax.scatter(xm0, ym0, z_minus, s=1.2, alpha=0.0,
                      color=COL_MINUS, rasterized=True)

# ── Torus handles (8 modes) ───────────────────────────────────────────────────
torus_handles = []
for k in range(N_MODES):
    z_c = float(Z_LEVELS_TORUS[k])
    tx, ty, tz = torus_ring(z_c, 0.0)
    color = cmap_hot(norm_hot(0.5))
    sp = ax.scatter(tx, ty,  tz, s=4, alpha=0.0, color=color)
    sn = ax.scatter(tx, ty, -tz, s=4, alpha=0.0, color=color)
    torus_handles.append((sp, sn, z_c))

# ── Legend ────────────────────────────────────────────────────────────────────
leg_handles = [
    Line2D([0],[0], color=COL_PLUS,  lw=2, label=f"+Ω spiral  (Ω_sch={OMEGA_SCH:.3f})"),
    Line2D([0],[0], color=COL_MINUS, lw=2, label="−Ω spiral  (counter-rotating)"),
    Line2D([0],[0], color=COL_RING,  lw=2, label="z=i  emergence ring"),
    Line2D([0],[0], color=COL_RUNG,  lw=0,
           marker="D", markersize=5,  label="z=i, i′, i″  cloak rungs"),
    Line2D([0],[0], color="#ff4444",  lw=2, label="torus hot  (+Ω / 𝓛 advancing)"),
    Line2D([0],[0], color="#4444ff",  lw=2, label="torus cold (−Ω / 𝓛 receding)"),
]
ax.legend(handles=leg_handles, fontsize=6, loc="upper left",
          facecolor="#0a0a14", labelcolor="white", edgecolor="#223",
          bbox_to_anchor=(0.0, 1.0))

# ── Text overlays ─────────────────────────────────────────────────────────────
title_obj    = ax.set_title("", color="white", fontsize=9, pad=6)
info_text    = ax.text2D(0.72, 0.97, "", transform=ax.transAxes,
                         color="cyan", fontsize=6.5, va="top",
                         family="monospace")
vantage_text = ax.text2D(0.72, 0.10, "", transform=ax.transAxes,
                         color=COL_REAL, fontsize=6.5, va="bottom",
                         family="monospace",
                         bbox=dict(boxstyle="round,pad=0.28",
                                   fc="#0a0a14", alpha=0.75, ec=COL_REAL))
orbit_text   = ax.text2D(0.50, 0.01, GRADED_ORBIT,
                         transform=ax.transAxes,
                         color=COL_RUNG, fontsize=6.5,
                         ha="center", va="bottom",
                         family="monospace", alpha=0.72)


# ============================================================================
# PER-FRAME UPDATE
# ============================================================================

def update_frame(f):
    R   = R_order[f]
    cv  = CV_all[f]
    oe  = one_eff(f, n_mode=1)

    # ── Spirals ───────────────────────────────────────────────────────────
    xp, yp, xm, ym = spiral_coords(f)
    sp_plus._offsets3d  = (xp, yp,  z_plus)
    sp_minus._offsets3d = (xm, ym, z_minus)
    # Alpha driven by Kuramoto R — spirals emerge as modes cohere
    spiral_alpha = min(R * 0.8, 0.55)
    sp_plus.set_alpha(spiral_alpha)
    sp_minus.set_alpha(spiral_alpha)

    # ── Torus — from 𝓛 magnitudes and Kuramoto phases ────────────────────
    R_majors, hot_fracs = compute_torus_params(f)
    R_max_torus = np.max(R_majors) if np.max(R_majors) > 0 else 1.0

    for idx, (sp, sn, z_c) in enumerate(torus_handles):
        Rm   = R_majors[idx]
        hotf = hot_fracs[idx]

        if Rm < 0.005 or R < 0.05:
            sp.set_alpha(0.0)
            sn.set_alpha(0.0)
            continue

        tx, ty, tz = torus_ring(z_c, Rm)
        col_hot  = cmap_hot(norm_hot(hotf))
        col_cold = cmap_hot(norm_hot(1.0 - hotf))

        a = min(R * (Rm / R_max_torus) * 0.75, 0.70)

        sp._offsets3d = (tx, ty,  tz)
        sn._offsets3d = (tx, ty, -tz)
        sp.set_color(col_hot)
        sn.set_color(col_cold)
        sp.set_alpha(a)
        sn.set_alpha(a)

    # ── Vantage ───────────────────────────────────────────────────────────
    label, color = vantage_from_R(R)
    vantage_text.set_text(label)
    vantage_text.set_color(color)
    vantage_text.get_bbox_patch().set_edgecolor(color)

    # ── Info ──────────────────────────────────────────────────────────────
    lp_f  = lambda_phi(float(f + 1))
    phase = L_phase(1, f)
    info_text.set_text(
        f"R(Kuramoto) = {R:.4f}   CV = {cv:.4f}\n"
        f"1_eff = {oe:.6f}   δ = {oe-1:.6f}\n"
        f"Λ_φ(f) = {lp_f:.4f}   φ^(-1/φ) = {PHI_COEFF:.4f}\n"
        f"Ω(f_sch) = {OMEGA_SCH:.4f}   φ_cum = {math.degrees(phi_cum[f]):.1f}°\n"
        f"𝓛 phase = {math.degrees(phase):.1f}°  {aphase_label(cv)[:8]}"
    )

    # ── Title ─────────────────────────────────────────────────────────────
    if R < 0.10:
        phase_lbl = "still — 𝓛 not yet stirring"
    elif cv > 0.50:
        phase_lbl = f"PLUCK — 𝓛 spreading  R={R:.3f}"
    elif cv > 0.30:
        phase_lbl = f"SUSTAIN — 𝓛 converging  R={R:.3f}"
    elif cv > 0.05:
        phase_lbl = f"FINETUNE — 𝓛 near fixed point  R={R:.3f}"
    else:
        phase_lbl = f"LOCK — wu-wei  CV={cv:.4f}  R={R:.4f}"

    title_obj.set_text(
        f"HDGL DRAIN  v6  —  𝓛ᵢ(z) internal physics only\n{phase_lbl}"
    )


# ============================================================================
# RENDER
# ============================================================================

OUT = Path(__file__).resolve().parent / "hdgl_drain_animation_v6.mp4"

writer = FFMpegWriter(
    fps=FPS, bitrate=3500,
    extra_args=["-vcodec", "libx264", "-pix_fmt", "yuv420p"],
)

print(f"Rendering {TOTAL_FRAMES} frames ({TOTAL_FRAMES/FPS:.1f}s) → {OUT}")
print(f"PHI          = {PHI:.10f}  (T fixed point)")
print(f"PHI_COEFF    = {PHI_COEFF:.6f}  (φ^(-1/φ), self-deriving)")
print(f"F_SCHUMANN   = {F_SCHUMANN} Hz")
print(f"OMEGA_SCH    = {OMEGA_SCH:.6f}  (Ω(7.83))")
print(f"RATE/frame   = {math.degrees(RATE_PER_FRAME):.4f}°")
print(f"Z_MODES      = {[f'{z:.4f}' for z in Z_MODES]}")
print(f"R_order range: {R_order.min():.4f} → {R_order.max():.4f}")
print(f"CV range:      {CV_all.min():.4f} → {CV_all.max():.4f}")

with writer.saving(fig, str(OUT), dpi=120):
    for f in range(TOTAL_FRAMES):
        update_frame(f)
        writer.grab_frame()
        if f % 20 == 0:
            print(f"  frame {f+1:3d}/{TOTAL_FRAMES}  "
                  f"R={R_order[f]:.3f}  CV={CV_all[f]:.3f}  "
                  f"φ={math.degrees(phi_cum[f]):.1f}°", flush=True)

print(f"\nSaved → {OUT}")
print(f"Self-arising summary:")
print(f"  Rotation    ← Ω(f_schumann) = {OMEGA_SCH:.6f}")
print(f"  Envelope    ← R_order (Kuramoto coherence)")
print(f"  Torus radii ← |𝓛_k(z_k)| normalised")
print(f"  Hot/cold    ← Kuramoto instantaneous freq vs natural freq")
print(f"  Vantage     ← R_order threshold")
print(f"  APHASE      ← CV(|𝓛_k|)")
print(f"  φ^(-1/φ)   ← fixed point of x→φ^(-x)  = {PHI_COEFF:.6f}")

hdgl_unified_force_fine_cross-checked.zip (12.8 KB)