Research-Stack/docs/experiment_geodesic_search.md
Allaun Silverfox 13a1683b8e experiment(radial): 5-domain expert design — self-finding on S⁷
The experiment: use the Φ-corkscrew system to search its own manifold
for the direction that maximizes compression ratio. 5 domain experts
designed their components in parallel.

EXPERIMENT: EXPERIMENT_RADIAL_SELF_FIND.md
  - Hypothesis: ∃ d* on S⁷: walking γ_{d*} monotonically increases C(n)
  - Method: Self-referential geodesic search with radial exploration
  - Predictions: gradient exists, ascent converges, self-encoding helps

AGENT 1 — GeometricPhysicist: experiment_geodesic_search.md
  - Geodesic: γ_d(t) = cos(t)·x + sin(t)·d (great circles on S⁷)
  - Gradient ascent: exponential map + parallel transport
  - Direction sampling: uniform, Φ-guided, gradient-biased
  - 3 core functions: geodesic_search, gradient_ascent_step, sample_directions

AGENT 2 — InformationTheorist: experiment_compression_metric.md
  - C(n) = L_S / |RLE(DNA(phinary(n)))|
  - Bounds: Ω(L_S/log n) ≤ C(n) ≤ O(L_S/log log n)
  - Key insight: phinary constraint inherently favors compressibility
  - Entropy H(n), Kolmogorov K(n), spectral radius analysis

AGENT 3 — SystemsEngineer: experiment_feedback_loop.md (2,033 lines!)
  - 12-state, 15-transition state machine
  - 3-layer strange loop containment (bounded, contractive, depth cap)
  - Radial exploration: OUTWARD/INWARD/OSCILLATE modes
  - Full FAMM-DAG integration with meltdown recovery
  - 7 convergence criteria

AGENT 4 — FormalVerifier: experiment_formal_verification.md
  - 8 Lean 4 theorems + master theorem
  - Key: Bijection Preservation (search transform preserves injectivity)
  - Paradox Prevention theorem (self-referential safety)
  - 10 invariants, 5 verification conditions
  - Integrates with ChentsovFinite.lean, quine.py proofs

AGENT 5 — MetaMathematician: experiment_meta_analysis.md
  - Strange loop converges (C(n) is Lyapunov function, S⁷ compact)
  - Fixed points exist (Brouwer + Kleene recursion theorem)
  - Gödel boundary is epistemological, not ontological
  - System finds itself but cannot prove global optimality
  - 12 formal theorems

Total: 6 files, ~6,000 lines of experiment design

Refs: PHI_CORKSCREW_PERFECT_RECOVERY.md, PROOF_SELFSIGHT.md,
ChentsovFinite.lean, GoldenSpiralManifold.lean
2026-06-23 02:13:42 -05:00

980 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

# GEODESIC SEARCH on S^7 — Algorithm Specification
## Component: Radial Self-Finding Experiment — Geodesic Search Engine
**Author**: Geometric Physicist (Information Geometry)
**Status**: DESIGN_PHASE
**Dependencies**: `EXPERIMENT_RADIAL_SELF_FIND.md`
---
## 1. Mathematical Preliminaries
### 1.1 The Manifold: S^7 (Fisher Sphere)
The state space is the 7-sphere embedded in R^8:
```
S^7 = {x ∈ R^8 : ||x||² = 1, x_i ≥ 0}
```
In √p-coordinates, each point x corresponds to a probability distribution
p ∈ Δ_7 (the 7-simplex) via:
```
x = (√p_1, √p_2, ..., √p_8), where Σ_i p_i = 1, p_i ≥ 0
```
The **Fisher-Rao metric** on Δ_7:
```
g_ij = δ_ij / p_i + 1/p_8 (for i,j = 1,...,7)
```
In √p-coordinates, this becomes the **round metric** on S^7 (the metric
induced from the Euclidean metric on R^8). This is the Chentsov theorem:
the Fisher-Rao metric on the simplex is isometric to the round sphere.
### 1.2 Tangent Space
At a point x ∈ S^7, the tangent space is:
```
T_x S^7 = {v ∈ R^8 : ⟨v, x⟩ = 0}
```
A **direction** d at x is a unit vector in T_x S^7:
```
d ∈ T_x S^7, ||d|| = 1
```
The set of all directions at x forms a 6-sphere S^6 ⊂ T_x S^7.
**Projection to tangent space** (for any vector v ∈ R^8):
```
Proj_{T_x}(v) = v - ⟨v, x⟩ · x
```
### 1.3 Geodesics on S^7
Geodesics on the round sphere are **great circles**. The geodesic
starting at x in direction d with arc-length parameter t is:
```
γ_d(t) = cos(t) · x + sin(t) · d (G1)
```
**Properties:**
- γ_d(0) = x
- γ_d'(0) = d
- ||γ_d(t)|| = 1 for all t (stays on S^7)
- Arc-length parameter: ||γ_d'(t)|| = 1
**Range restriction**: Since x_i ≥ 0 (probability simplex), geodesics
may leave the valid region. The maximal valid step is:
```
t_max(d) = min_i { arctan(-x_i / d_i) : d_i < 0 } (G2)
```
If all d_i ≥ 0, then t_max = +∞ (stays in positive orthant).
### 1.4 Exponential Map
The exponential map at x ∈ S^7 is the geodesic flow:
```
exp_x(v) = cos(||v||) · x + sin(||v||) · (v / ||v||) (EM)
```
for v ∈ T_x S^7, v ≠ 0. For v = 0, exp_x(0) = x.
**Inverse (logarithm map)**: For y ∈ S^7 not antipodal to x:
```
log_x(y) = arccos(⟨x, y⟩) · (y - ⟨x, y⟩ x) / ||y - ⟨x, y⟩ x|| (LM)
```
### 1.5 Parallel Transport
To transport a tangent vector v ∈ T_x S^7 along the geodesic from x to
y = γ_d(t), use the standard formula for parallel transport on the sphere:
```
P_{x→y}(v) = v - (⟨v, y⟩ / (1 + ⟨x, y⟩)) · (x + y) (PT)
```
**Properties:**
- P_{x→y}(v) ∈ T_y S^7 (remains tangent)
- Isometric: ||P_{x→y}(v)|| = ||v||
- Inner-product preserving: ⟨P(v), P(w)⟩ = ⟨v, w⟩
---
## 2. Direction Representation
### 2.1 Defining a Direction
A direction d at point S_0 ∈ S^7 is represented as:
```
struct Direction {
d: R^8, // unit vector
constraints: {
⟨d, S_0⟩ = 0, // tangent to S^7
||d|| = 1, // unit length
}
}
```
### 2.2 Creating a Direction from an Arbitrary Vector
Given v ∈ R^8, construct a valid direction at S_0:
```
function make_direction(S_0: S^7, v: R^8) → Direction:
v_tangent = v - ⟨v, S_0⟩ · S_0 // Project to T_{S_0} S^7
if ||v_tangent|| < ε:
return null // v is parallel to S_0, no valid direction
d = v_tangent / ||v_tangent|| // Normalize
return Direction{d}
```
### 2.3 Direction ↔ Spiral Correspondence
Each direction d corresponds to a family of probability distributions
along the geodesic. The spiral index function maps these back to N:
```
n(d, t) = spiral_index(γ_d(t)) = argmin_n ||f(n) - γ_d(t)||²
```
where f(n) = (√n · cos(nψ), √n · sin(nψ)) is the Φ-corkscrew.
The **compression ratio** along direction d is:
```
C(d, t) = compression_ratio(n(d, t))
= original_size / |RLE(phinary(n(d, t)))|
```
---
## 3. Core Algorithm: `geodesic_search`
### 3.1 Pseudocode
```
function geodesic_search(
S_0: S^7, // Starting point on Fisher sphere
N_directions: int, // Number of directions to explore
T_steps: int, // Number of steps along each geodesic
t_max: float = π/2, // Maximum geodesic distance
step_pattern: str = "geometric" // "uniform", "geometric", "adaptive"
) → (d*, t*, S*, C*):
// ---- Step 1: Sample directions ----
D = sample_directions(S_0, N_directions)
// ---- Step 2: Define step sizes ----
if step_pattern == "uniform":
T = linspace(0, t_max, T_steps)
elif step_pattern == "geometric":
T = t_max * (1 - exp(-3 * linspace(0, 1, T_steps))) / (1 - e^{-3})
elif step_pattern == "adaptive":
T = golden_section_steps(0, t_max, T_steps)
// ---- Step 3: Evaluate all (direction, step) pairs ----
best_C = -∞
best_triple = null
for i = 1 to N_directions:
d_i = D[i]
// Compute t_max for this direction (boundary of simplex)
t_boundary = compute_boundary_limit(S_0, d_i)
T_eff = T ∩ [0, t_boundary] // Clip to valid range
for j = 1 to |T_eff|:
t_j = T_eff[j]
S_ij = γ_{d_i}(t_j) = cos(t_j)·S_0 + sin(t_j)·d_i // (G1)
// Map to probability simplex
p_ij = S_ij ⊙ S_ij // element-wise square: p_k = (S_ij,k)²
p_ij = p_ij / Σ_k p_ij,k // renormalize (numerical safety)
// Encode and measure compression
n_ij = spiral_index(S_ij)
C_ij = compression_ratio(n_ij)
// Update best
if C_ij > best_C:
best_C = C_ij
best_triple = (d_i, t_j, S_ij, C_ij)
// ---- Step 4: Return best ----
(d*, t*, S*, C*) = best_triple
return (d*, t*, S*, C*)
```
### 3.2 Step Size Patterns
**Uniform**: `t_j = j · t_max / T_steps`
Good for: Initial broad exploration.
**Geometric** (default): `t_j = t_max · (1 - e^{-3j/T_steps}) / (1 - e^{-3})`
Good for: More samples near S_0 where changes are smaller.
**Adaptive (Golden Section)**: Uses golden-ratio spacing to concentrate
samples where compression changes most rapidly.
### 3.3 Boundary Computation
```
function compute_boundary_limit(S_0: S^7, d: Direction) → float:
"""
Compute the maximum geodesic distance before leaving
the positive orthant (p_i ≥ 0 for all i).
"""
t_max_valid = +∞
for i = 1 to 8:
if d_i < 0 and S_0,i > 0:
// Solve: cos(t)·S_0,i + sin(t)·d_i = 0
// => tan(t) = -S_0,i / d_i
t_i = arctan(-S_0,i / d_i)
if t_i > 0:
t_max_valid = min(t_max_valid, t_i)
return t_max_valid
```
---
## 4. Gradient Computation: `compute_gradient`
### 4.1 Problem Statement
We need the Riemannian gradient of the compression ratio C with respect
to position on S^7. Since C is evaluated through the discrete
`spiral_index` function (argmin), it is piecewise constant with
jumps at boundaries. We use **finite differences on the sphere**.
### 4.2 Finite Difference Gradient
```
function compute_gradient(
S: S^7, // Current point
f: S^7 → R, // Objective function (here: f(x) = C(spiral_index(x)))
ε: float = 1e-4, // Finite difference step
method: str = "central" // "forward", "central", "complex"
) → ∇f ∈ T_S S^7:
// Build orthonormal basis for T_S S^7
B = build_tangent_basis(S) // Returns {e_1, ..., e_7} ⊂ R^8
// Compute directional derivatives
∇f = 0 ∈ R^8
for k = 1 to 7:
e_k = B[k]
if method == "central":
S_plus = exp_S(ε · e_k) = cos(ε)·S + sin(ε)·e_k
S_minus = exp_S(-ε · e_k) = cos(ε)·S - sin(ε)·e_k
∂f/∂e_k = (f(S_plus) - f(S_minus)) / (2ε)
elif method == "forward":
S_plus = exp_S(ε · e_k)
∂f/∂e_k = (f(S_plus) - f(S)) / ε
∇f += (∂f/∂e_k) · e_k
return ∇f // Lives in T_S S^7 by construction
```
### 4.3 Tangent Basis Construction (Gram-Schmidt)
```
function build_tangent_basis(S: S^7) → List[R^8]:
"""
Build orthonormal basis for T_S S^7 using modified Gram-Schmidt.
"""
basis = []
for i = 1 to 8:
e = standard_basis_vector(i) // (0,...,1,...,0)
// Project to tangent space
e = e - ⟨e, S⟩ · S
// Orthogonalize against existing basis vectors
for b in basis:
e = e - ⟨e, b⟩ · b
// Normalize (skip if numerically zero)
if ||e|| > ε_machine:
e = e / ||e||
basis.append(e)
// Verify: should have exactly 7 basis vectors
assert len(basis) == 7
return basis
```
### 4.4 Gradient via Automatic Differentiation (Alternative)
If the spiral_index function is differentiable (e.g., using a smooth
relaxation), we can use automatic differentiation:
```
// Smooth relaxation of spiral_index:
// Instead of argmin, use soft-argmin:
n_smooth(x) = Σ_n n · softmax(-β·||f(n) - x||²)_n
// Where β > 0 is an inverse temperature parameter.
// As β → ∞, n_smooth → argmin.
// Typical values: β ∈ [10, 1000]
// Chain rule:
∇_x C = (∂C/∂n) · (∂n_smooth/∂x)
// Project to tangent space:
∇_S C = Proj_{T_S}(∇_x C)
```
### 4.5 Gradient with Respect to Direction
When optimizing over directions d ∈ S^6 (the direction sphere at S_0):
```
function compute_direction_gradient(
S_0: S^7, // Fixed starting point
d: Direction, // Current direction
f: S^7 → R, // f(x) = C(spiral_index(x))
ε: float = 1e-4
) → ∇_d F ∈ T_d S^6:
// Define F(d) = max_t f(γ_d(t)) [or f(γ_d(t*)) for fixed t*]
// Build basis for T_d S^6 = {v ∈ T_{S_0} S^7 : ⟨v, d⟩ = 0}
B = build_direction_basis(S_0, d) // Returns 6 orthonormal vectors
// Finite differences on the direction sphere
∇F = 0 ∈ R^8
for k = 1 to 6:
b_k = B[k]
// Exponential map on S^6 (embedded in T_{S_0} S^7):
d_plus = cos(ε)·d + sin(ε)·b_k
d_minus = cos(ε)·d - sin(ε)·b_k
F_plus = evaluate_along_geodesic(S_0, d_plus, f)
F_minus = evaluate_along_geodesic(S_0, d_minus, f)
∂F/∂b_k = (F_plus - F_minus) / (2ε)
∇F += (∂F/∂b_k) · b_k
return ∇F
function build_direction_basis(S_0: S^7, d: Direction) → List[R^8]:
"""
Build orthonormal basis for T_d S^6, which is the subspace of
T_{S_0} S^7 orthogonal to d.
"""
// Start with full tangent basis at S_0
B_full = build_tangent_basis(S_0) // 7 vectors
// Remove component along d
basis = []
for b in B_full:
b_orth = b - ⟨b, d⟩ · d
if ||b_orth|| > ε_machine:
b_orth = b_orth / ||b_orth||
basis.append(b_orth)
// Should now have 6 vectors
assert len(basis) == 6
return basis
```
---
## 5. Core Algorithm: `gradient_ascent_step`
### 5.1 Standard Riemannian Gradient Ascent
```
function gradient_ascent_step(
S_current: S^7, // Current point
f: S^7 → R, // Objective: compression ratio
learning_rate: float, // Step size η
grad_method: str = "fd" // "fd" or "smooth"
) → S_next:
// Compute Riemannian gradient
if grad_method == "fd":
∇f = compute_gradient(S_current, f, ε=1e-4, method="central")
elif grad_method == "smooth":
∇f = compute_smooth_gradient(S_current, f, β=100)
// Check for stationarity
if ||∇f|| < ε_stationary:
return S_current // Local maximum reached
// Normalize for unit-step control (optional)
// ∇f = ∇f / ||∇f||
// Riemannian gradient ascent via exponential map:
v = learning_rate · ∇f
S_next = exp_{S_current}(v)
= cos(||v||) · S_current + sin(||v||) · (v / ||v||) // (EM)
// Ensure we stay in the positive orthant
if any(S_next,i < 0):
// Project to nearest valid point on S^7 ∩ {x_i ≥ 0}
S_next = project_to_simplex_sphere(S_next)
return S_next
```
### 5.2 Adaptive Step Size (Line Search)
```
function gradient_ascent_step_adaptive(
S_current: S^7,
f: S^7 → R,
η_init: float = 0.1,
α: float = 0.5, // Backtracking factor
c: float = 1e-4, // Armijo constant
max_backtrack: int = 10
) → S_next:
∇f = compute_gradient(S_current, f)
grad_norm = ||∇f||
if grad_norm < ε_stationary:
return S_current
// Unit-norm gradient direction
g = ∇f / grad_norm
η = η_init
f_current = f(S_current)
for step = 1 to max_backtrack:
S_trial = cos(η·grad_norm)·S_current + sin(η·grad_norm)·g
S_trial = project_to_simplex_sphere(S_trial)
f_trial = f(S_trial)
// Armijo condition: sufficient increase
if f_trial ≥ f_current + c · η · grad_norm²:
return S_trial
η = α · η // Backtrack
// No improvement found — return current point
return S_current
```
### 5.3 Projection to Valid Simplex Sphere
```
function project_to_simplex_sphere(y: R^8) → S^7:
"""
Project y to the nearest point on S^7 ∩ {x_i ≥ 0}.
Uses alternating projection: sphere → orthant → sphere → ...
"""
x = y / ||y|| // Project to sphere
for iter = 1 to max_proj_iter:
// Clip negative components
x_clipped = max(x, 0) // element-wise
// If already in orthant, done
if ||x_clipped - x|| < ε:
return x_clipped / ||x_clipped||
// Project back to sphere
x = x_clipped / ||x_clipped||
return x
```
### 5.4 Momentum-Based Gradient Ascent on Manifold
For faster convergence, use Riemannian momentum:
```
function gradient_ascent_momentum(
S_current: S^7,
v_prev: T_{S_prev} S^7, // Previous velocity (in old tangent space)
S_prev: S^7, // Previous point
f: S^7 → R,
η: float, // Learning rate
μ: float = 0.9 // Momentum coefficient
) → (S_next, v_next):
// Compute gradient at current point
∇f = compute_gradient(S_current, f)
// Transport previous velocity to current tangent space
if v_prev is not null:
v_transport = P_{S_prev → S_current}(v_prev) // (PT)
else:
v_transport = 0
// Update velocity: v = μ · v_transport + ∇f
v = μ · v_transport + ∇f // in T_{S_current} S^7
// Riemannian gradient step with momentum
S_next = exp_{S_current}(η · v)
= cos(η·||v||)·S_current + sin(η·||v||)·(v/||v||)
S_next = project_to_simplex_sphere(S_next)
return (S_next, v)
```
---
## 6. Core Algorithm: `sample_directions`
### 6.1 Uniform Sampling on T_{S_0} S^7
```
function sample_directions(
S_0: S^7,
N: int,
distribution: str = "uniform" // "uniform", "golden", "gradient_biased"
) → List[Direction]:
if distribution == "uniform":
return sample_uniform_directions(S_0, N)
elif distribution == "golden":
return sample_golden_directions(S_0, N)
elif distribution == "gradient_biased":
∇f = compute_gradient(S_0, f)
return sample_gradient_biased(S_0, N, ∇f)
```
### 6.2 Uniform Random Directions
```
function sample_uniform_directions(S_0: S^7, N: int) → List[Direction]:
"""
Sample N i.i.d. uniformly distributed directions on the
unit sphere S^6 ⊂ T_{S_0} S^7.
Algorithm: Sample standard Gaussian in R^8, project to tangent
space, normalize. This gives uniform distribution on S^6.
"""
directions = []
for _ = 1 to N:
v = randn(8) // N(0, I_8)
v_tangent = v - ⟨v, S_0⟩ · S_0
d = v_tangent / ||v_tangent||
directions.append(Direction{d})
return directions
```
### 6.3 Golden-Angle Directions (Φ-Quasi-Monte Carlo)
```
function sample_golden_directions(S_0: S^7, N: int) → List[Direction]:
"""
Generate N directions using the generalized golden angle on S^6.
Provides low-discrepancy coverage of the direction sphere.
Uses the Fibonacci lattice generalized to 7 dimensions with
the golden ratio φ = (1+√5)/2.
"""
φ = (1 + √5) / 2
// Build tangent basis
B = build_tangent_basis(S_0) // {e_1, ..., e_7}
directions = []
for n = 1 to N:
// Generalized Fibonacci angles in 7D
// Use the first 7 powers of φ modulo 1
angles = []
for k = 1 to 7:
α_k = 2π · fractional_part(n · φ^{-k})
angles.append(α_k)
// Convert angles to direction in the 7D tangent space
// Use hyperspherical coordinates
d_local = angles_to_unit_vector_7d(angles)
// Map from local 7D coordinates to R^8 via basis
d = Σ_{k=1}^7 d_local,k · e_k
directions.append(Direction{d})
return directions
```
**Hyperspherical coordinate mapping (7D → unit vector)**:
```
function angles_to_unit_vector_7d(angles: [θ_1,...,θ_7]) → R^7:
"""
Convert 7 angles to unit vector in R^7.
x_1 = cos(θ_1)
x_2 = sin(θ_1)·cos(θ_2)
x_3 = sin(θ_1)·sin(θ_2)·cos(θ_3)
...
x_7 = sin(θ_1)·...·sin(θ_6)·cos(θ_7)
x_8 = sin(θ_1)·...·sin(θ_6)·sin(θ_7)
(We use 7 angles for S^6, embedded in R^7 ~ T_{S_0} S^7)
"""
x = zeros(7)
sin_prod = 1.0
for k = 1 to 6:
x[k] = sin_prod · cos(angles[k])
sin_prod = sin_prod · sin(angles[k])
x[7] = sin_prod · cos(angles[7])
// Note: for S^6 in R^7, we need 6 angles, not 7
// The above gives 7D; for S^6 we use 6 angles
```
*Correction*: S^6 requires 6 angles in the hyperspherical coordinate system.
The generalized Fibonacci sequence on S^d uses d angles.
```
function sample_golden_directions_v2(S_0: S^7, N: int) → List[Direction]:
φ = (1 + √5) / 2
B = build_tangent_basis(S_0)
directions = []
for n = 1 to N:
// 6D generalized Fibonacci point
t = n / N
// Use 6 angular coordinates
coords = zeros(7)
for k = 1 to 7:
// Coordinate k = fractional part of n * φ^k, mapped to [-1, 1]
coords[k] = 2 · fractional_part(n · φ^{(k-1)/7}) - 1
// Project to unit sphere in the tangent space
d_local = coords / ||coords||
d = Σ_k d_local,k · B[k]
directions.append(Direction{d})
return directions
```
### 6.4 Gradient-Biased Direction Sampling
```
function sample_gradient_biased(
S_0: S^7,
N: int,
∇f: T_{S_0} S^7,
concentration: float = 5.0
) → List[Direction]:
"""
Sample directions biased toward the gradient direction.
Uses a von Mises-Fisher distribution on S^6 with mean
direction ∇f/||∇f|| and concentration parameter κ.
"""
μ = ∇f / ||∇f|| // Mean direction
κ = concentration // Concentration
directions = []
for _ = 1 to N:
// Rejection sampling for von Mises-Fisher
// or: sample from N(κ·μ, I), project to tangent space, normalize
v = randn(8) + κ · μ
v_tangent = v - ⟨v, S_0⟩ · S_0
d = v_tangent / ||v_tangent||
directions.append(Direction{d})
return directions
```
---
## 7. Complete Self-Finding Loop Integration
### 7.1 Main Loop (from experiment spec)
```
function self_finding_loop(
S_0: S^7, // Initial state
max_iter: int = 100, // Maximum iterations
N_directions: int = 32, // Directions per search
T_steps: int = 16, // Steps per geodesic
η: float = 0.05, // Learning rate
ε_converge: float = 1e-6 // Convergence threshold
) → (S_opt, history):
S = S_0
history = []
for iter = 1 to max_iter:
// ---- Phase 1: Direction Search ----
(d*, t*, S_candidate, C*) = geodesic_search(
S, N_directions, T_steps
)
C_current = compression_ratio(spiral_index(S))
// ---- Phase 2: Gradient Ascent Step ----
if C* > C_current:
// Move toward candidate
f(x) = compression_ratio(spiral_index(x))
S = gradient_ascent_step(S, f, η, grad_method="fd")
else:
// Local maximum reached
break
// ---- Phase 3: Self-Reference (Strange Loop) ----
// Encode the search trajectory itself
trajectory = history + [(d*, t*, C*)]
n_exp = encode_trajectory(trajectory)
// ---- Phase 4: Meta-Update ----
// Optionally: use the experiment encoding as next starting point
// S_meta = spiral_to_sphere_point(n_exp)
// This closes the strange loop
history.append({
'iteration': iter,
'S': S,
'C': C_current,
'd_best': d*,
't_best': t*,
'n_exp': n_exp
})
// Convergence check
if len(history) > 1:
C_prev = history[-2]['C']
if |C_current - C_prev| / C_prev < ε_converge:
break
return (S, history)
```
### 7.2 Encoding the Trajectory
```
function encode_trajectory(trajectory: List[(d, t, C)]) → int:
"""
Encode the search trajectory as a spiral index.
This creates the 'strange loop' — the search encodes itself.
The trajectory is a sequence of (direction, step, compression) tuples.
We serialize this and encode as a DNA sequence via the Φ-corkscrew.
"""
// Serialize trajectory to a bit string
bits = serialize(trajectory) // e.g., using IEEE 754 floats
// Convert bit string to integer
n_trajectory = bit_string_to_int(bits)
// Map to spiral index
n_exp = spiral_index_from_int(n_trajectory)
return n_exp
```
---
## 8. Convergence Analysis
### 8.1 Convergence of Geodesic Search
**Theorem** (Local convergence). Let C: S^7 → R be the compression
ratio function. If C is L-smooth on S^7 (Riemannian gradient is
L-Lipschitz) and bounded above, then gradient ascent with step size
η ∈ (0, 2/L) converges to a stationary point.
**Proof sketch**:
1. The exponential map exp_x is the standard geodesic flow on S^7
2. The sectional curvature of S^7 is constant K = 1 > 0
3. For positively curved manifolds, gradient ascent with appropriate
step size decreases the objective gradient norm to zero
4. By compactness of S^7 and continuity (of the smooth relaxation),
the sequence has a convergent subsequence
5. The limit point satisfies ∇C = 0 (stationary point)
### 8.2 Rate of Convergence
For gradient ascent on S^7 with constant step size η:
```
C(S_{k+1}) - C(S*) ≤ (1 - η·m) · (C(S_k) - C(S*)) [if m-strongly convex]
```
where m is the strong convexity parameter (lower bound on Hessian
eigenvalues in the tangent space).
For non-convex C (the general case):
```
min_{0≤k≤K} ||∇C(S_k)||² ≤ (C(S_0) - C(S*)) / (η·K)
```
O(1/√K) rate for gradient norm, O(1/K) for strongly convex regions.
### 8.3 Effect of Self-Reference
When the trajectory encoding is used as the next starting point:
```
S_{k+1} = f(S_k, trajectory(S_0, ..., S_k))
```
This creates a **non-Markovian** dynamical system. The convergence
properties depend on the encoding map. Empirically, self-reference
acts as a form of momentum: the encoded trajectory contains
information about the "shape" of the compression landscape, which
guides future searches.
---
## 9. Computational Complexity
| Operation | Complexity | Notes |
|-----------|-----------|-------|
| `sample_directions` | O(N · d) | d=8, N directions |
| `γ_d(t)` (geodesic) | O(d) | One evaluation |
| `geodesic_search` | O(N · T · (d + T_spiral)) | T_spiral = spiral_index cost |
| `compute_gradient` | O(2d · T_spiral) | 2·7 = 14 function evals |
| `gradient_ascent_step` | O(2d · T_spiral) | Same as gradient |
| `parallel_transport` | O(d) | Negligible |
| Full iteration | O(N·T·T_spiral) | Dominated by spiral_index |
Where `T_spiral` = cost of `spiral_index(x)` = O(N_spiral) for a
search over N_spiral spiral points (can be accelerated with KD-trees
to O(log N_spiral)).
---
## 10. Summary of Key Formulas
| Formula | Equation | Description |
|---------|----------|-------------|
| Geodesic | γ_d(t) = cos(t)·x + sin(t)·d | (G1) Great circle on S^7 |
| Exponential Map | exp_x(v) = cos(||v||)·x + sin(||v||)·(v/||v||) | (EM) Geodesic flow |
| Logarithm Map | log_x(y) = arccos(⟨x,y⟩)·(y-⟨x,y⟩x)/||...|| | (LM) Inverse exponential |
| Parallel Transport | P_{x→y}(v) = v - (⟨v,y⟩/(1+⟨x,y⟩))·(x+y) | (PT) Along geodesic |
| Tangent Projection | Proj_{T_x}(v) = v - ⟨v,x⟩·x | Project to tangent space |
| Boundary Limit | t_max = min_i arctan(-x_i/d_i) for d_i < 0 | (G2) Simplex boundary |
| Gradient (FD) | f = Σ_k [f(exp(ε·e_k)) - f(exp(·e_k))]/() · e_k | Central differences |
| Gradient Step | S_{next} = exp_S(η·∇f) | Riemannian ascent |
---
## 11. Interface Specification
### 11.1 Function Signatures
```python
def geodesic_search(
S_0: np.ndarray, # shape (8,), unit vector, S_0 >= 0
N_directions: int, # number of directions to sample
T_steps: int, # number of steps per geodesic
t_max: float = np.pi/2, # maximum geodesic distance
step_pattern: str = "geometric",
f: Callable = compression_ratio_at_point # f: S^7 -> R
) -> Tuple[np.ndarray, float, np.ndarray, float]:
"""Returns (d_best, t_best, S_best, C_best)"""
def gradient_ascent_step(
S_current: np.ndarray, # shape (8,), current point
f: Callable, # objective function f: S^7 -> R
learning_rate: float, # step size η
grad_method: str = "fd", # "fd" or "smooth"
ε: float = 1e-4 # finite difference step
) -> np.ndarray:
"""Returns S_next (shape (8,))"""
def sample_directions(
S_0: np.ndarray, # shape (8,), anchor point
N: int, # number of directions
distribution: str = "uniform" # "uniform", "golden", "gradient_biased"
) -> np.ndarray:
"""Returns directions (shape (N, 8)), each row is a unit tangent vector"""
def compute_gradient(
S: np.ndarray, # shape (8,), evaluation point
f: Callable, # f: S^7 -> R
ε: float = 1e-4, # FD step size
method: str = "central" # "central", "forward"
) -> np.ndarray:
"""Returns gradient (shape (8,)), in T_S S^7"""
def parallel_transport(
v: np.ndarray, # shape (8,), tangent vector at x
x: np.ndarray, # shape (8,), source point
y: np.ndarray # shape (8,), target point
) -> np.ndarray:
"""Returns transported vector (shape (8,)), in T_y S^7"""
```
### 11.2 Type Definitions
```python
S7Point = np.ndarray # shape (8,), ||x|| = 1, x_i >= 0
Direction = np.ndarray # shape (8,), ||d|| = 1, <d, x> = 0
TangentV = np.ndarray # shape (8,), <v, x> = 0
ScalarFn = Callable[[S7Point], float]
```
---
## 12. Testing Strategy
### 12.1 Unit Tests
1. **Geodesic stays on sphere**: For random x, d, t: verify ||γ_d(t)|| = 1
2. **Tangent constraint**: Verify d, S_0 = 0 for all sampled directions
3. **Unit norm**: Verify ||d|| = 1 for all directions
4. **Gradient is tangent**: Verify ⟨∇f, S = 0
5. **Gradient ascent increases f**: For a known function, verify f(S_next) > f(S)
6. **Parallel transport is isometric**: Verify ||P(v)|| = ||v||
7. **Exponential and log are inverses**: Verify log_x(exp_x(v)) ≈ v
### 12.2 Integration Tests
1. **Known optimum**: Test on a function with known maximum on S^7
2. **Symmetry**: Verify gradient is zero at symmetric points for symmetric functions
3. **Convergence**: Verify ||∇f|| → 0 as iterations increase
4. **Boundary handling**: Verify geodesics don't leave the simplex
### 12.3 End-to-End Test
```
S_0 = uniform point on S^7 ∩ {x_i >= 0}
(d*, t*, S*, C*) = geodesic_search(S_0, N=64, T=32)
assert C* >= compression_ratio(spiral_index(S_0))
assert ||S*|| ≈ 1
assert all(S* >= 0)
```
---
## 13. References
1. Amari, S.-I. (2016). *Information Geometry and Its Applications*. Springer.
2. Chentsov, N.N. (1982). *Statistical Decision Rules and Optimal Inference*.
3. Absil, P.-A., Mahony, R., & Sepulchre, R. (2008). *Optimization Algorithms
on Matrix Manifolds*. Princeton University Press.
4. Boumal, N. (2023). *An Introduction to Optimization on Smooth Manifolds*.
Cambridge University Press.
5. Audet, C. & Dennis, J.E. (2006). "Mesh Adaptive Direct Search Algorithms
for Constrained Optimization*. SIAM Journal on Optimization.
---
*End of Geodesic Search Algorithm Specification*