mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
665 lines
23 KiB
Python
665 lines
23 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
COUCH Equation N-Space Map Analysis
|
||
|
||
Applies every Research Stack mathematical framework to COUCH equation
|
||
as an n-space map with "=" at the center.
|
||
|
||
COUCH: ẍ_i + γẋ_i + ω_i²x_i + Σ_j κ_ij(x_i - x_j) = F(t)
|
||
|
||
Treat "=" as central attractor in n-dimensional space.
|
||
"""
|
||
|
||
import numpy as np
|
||
from typing import Dict, List, Tuple, Any
|
||
from dataclasses import dataclass
|
||
from enum import Enum
|
||
import json
|
||
import hashlib
|
||
|
||
|
||
class NSpaceFramework(Enum):
|
||
"""Mathematical frameworks from Research Stack."""
|
||
PIST = "PIST (Perfectly Imperfect Square Theory)"
|
||
FAMM = "FAMM (Fractal Adaptive Manifold Mapping)"
|
||
QUATERNION = "Quaternion Counter-Rotation"
|
||
MENGER = "Menger Sponge Fractal"
|
||
ENE = "ENE Triangle Manifold"
|
||
MERKLE = "Merkle Jack Tree"
|
||
MANIFOLD = "Manifold Compression"
|
||
TRIUMVIRATE = "Triumvirate Clock"
|
||
SVQF = "SVQF Sparse Voxel"
|
||
CALABI_YAU = "Calabi-Yau Compactification"
|
||
RICCI_FLOW = "Ricci Flow Adaptation"
|
||
BRAID = "Braid Group Theory"
|
||
|
||
|
||
@dataclass
|
||
class COUCHState:
|
||
"""COUCH oscillator state in n-space."""
|
||
position: np.ndarray # x_i
|
||
velocity: np.ndarray # ẋ_i
|
||
acceleration: np.ndarray # ẍ_i
|
||
coupling: np.ndarray # κ_ij
|
||
damping: float # γ
|
||
frequency: np.ndarray # ω_i
|
||
forcing: float # F(t)
|
||
hysteresis: float # H = ∮ F(t) · dx
|
||
|
||
|
||
@dataclass
|
||
class NSpaceCoordinate:
|
||
"""N-space coordinate with framework-specific mapping."""
|
||
framework: NSpaceFramework
|
||
coordinates: np.ndarray
|
||
distance_from_center: float
|
||
is_admissible: bool
|
||
|
||
|
||
class COUCHNSpaceMap:
|
||
"""
|
||
COUCH equation as n-space map with "=" at center.
|
||
|
||
Central attractor: "=" (equilibrium point where ẋ_i = 0, ẍ_i = 0)
|
||
"""
|
||
|
||
def __init__(self, n_oscillators: int = 3, n_dimensions: int = 10):
|
||
self.n_oscillators = n_oscillators
|
||
self.n_dimensions = n_dimensions
|
||
self.center = np.zeros(n_dimensions) # "=" as central attractor
|
||
self.frameworks = list(NSpaceFramework)
|
||
self.framework_mappings: Dict[NSpaceFramework, List[NSpaceCoordinate]] = {}
|
||
|
||
def initialize_couch_state(self) -> COUCHState:
|
||
"""Initialize COUCH oscillator system."""
|
||
np.random.seed(42)
|
||
|
||
position = np.random.randn(self.n_oscillators) * 0.5
|
||
velocity = np.random.randn(self.n_oscillators) * 0.3
|
||
acceleration = np.zeros(self.n_oscillators)
|
||
|
||
# Coupling matrix (symmetric)
|
||
coupling = np.random.randn(self.n_oscillators, self.n_oscillators) * 0.1
|
||
coupling = (coupling + coupling.T) / 2
|
||
|
||
damping = 0.5
|
||
frequency = np.ones(self.n_oscillators) * 2.0
|
||
forcing = 1.0
|
||
|
||
hysteresis = 0.0
|
||
|
||
return COUCHState(
|
||
position=position,
|
||
velocity=velocity,
|
||
acceleration=acceleration,
|
||
coupling=coupling,
|
||
damping=damping,
|
||
frequency=frequency,
|
||
forcing=forcing,
|
||
hysteresis=hysteresis
|
||
)
|
||
|
||
def apply_pist_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply PIST (Perfectly Imperfect Square Theory) mapping.
|
||
|
||
Shell coordinates: (k, t, H) where H = hysteresis
|
||
FAMM frustration: Φ = trace(stress_tensor) / mass
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Shell index based on position magnitude
|
||
k = int(np.abs(state.position[i]) * 10)
|
||
|
||
# Time step (iteration)
|
||
t = i
|
||
|
||
# Hysteresis as third coordinate
|
||
h = state.hysteresis
|
||
|
||
# Mass (vertex product)
|
||
a = float(k % 3)
|
||
b = float((k + 1) - (k % 3))
|
||
c = float(k)
|
||
mass = a * b * c
|
||
if mass == 0:
|
||
mass = 1.0
|
||
|
||
# Stress tensor (simplified)
|
||
stress = np.array([
|
||
[state.position[i], state.velocity[i], state.acceleration[i]],
|
||
[state.velocity[i], state.position[i], state.acceleration[i]],
|
||
[state.acceleration[i], state.position[i], state.velocity[i]]
|
||
])
|
||
|
||
# FAMM frustration
|
||
phi = np.trace(stress) / mass
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0] = k
|
||
coord[1] = t
|
||
coord[2] = h
|
||
coord[3] = phi
|
||
coord[4:7] = [a, b, c]
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = phi <= 1.0
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.PIST,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_menger_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply Menger Sponge fractal mapping.
|
||
|
||
Hausdorff dimension: d_H = log(20)/log(3) ≈ 2.7268
|
||
Address: menger_hash(x,y,z) ⊕ fractal_offset
|
||
"""
|
||
coordinates = []
|
||
|
||
d_H = 2.7268
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Map oscillator state to 3D coordinates
|
||
x = int(state.position[i] * 10 + 32)
|
||
y = int(state.velocity[i] * 10 + 32)
|
||
z = int(state.acceleration[i] * 10 + 32)
|
||
|
||
# Menger hash
|
||
hash_val = x ^ ((y << 1) & 0xFFFFFFFF) ^ ((z << 2) & 0xFFFFFFFF)
|
||
|
||
# Fractal offset
|
||
offset = int((x + y + z) * d_H)
|
||
|
||
# Address
|
||
address = hash_val ^ offset
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0] = x
|
||
coord[1] = y
|
||
coord[2] = z
|
||
coord[3] = hash_val
|
||
coord[4] = offset
|
||
coord[5] = address
|
||
coord[6] = d_H
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = True # All Menger coordinates admissible
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.MENGER,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_ene_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply ENE Triangle Manifold mapping.
|
||
|
||
Concentric shells with triangular number indexing
|
||
Rotation field + transmission field
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Shell index
|
||
k = int(np.abs(state.position[i]) * 5)
|
||
|
||
# Triangular number
|
||
t_num = k * (k + 1) // 2
|
||
|
||
# Vertex parameters
|
||
a = float(k % 3)
|
||
b = float((k + 1) - (k % 3))
|
||
c = float(k)
|
||
|
||
# Mass
|
||
mass = a * b * c if (a * b * c) > 0 else 1.0
|
||
|
||
# Rotation angle
|
||
rotation = float(k) * 0.1
|
||
|
||
# Bandwidth and latency (curvature-based)
|
||
curvature = 0.5
|
||
bandwidth = 10.0 * (1.0 - curvature)
|
||
latency = 1.0 + curvature
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0] = k
|
||
coord[1] = t_num
|
||
coord[2:5] = [a, b, c]
|
||
coord[5] = mass
|
||
coord[6] = rotation
|
||
coord[7] = bandwidth
|
||
coord[8] = latency
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = True
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.ENE,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_quaternion_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply quaternion counter-rotation mapping.
|
||
|
||
Zero-net-angular-momentum design
|
||
Counter-rotating steps: q at layer N, q⁻¹ at layer N-1
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Map state to quaternion (w, x, y, z)
|
||
w = 1.0 # Scalar part
|
||
x = state.position[i]
|
||
y = state.velocity[i]
|
||
z = state.acceleration[i]
|
||
|
||
# Normalize
|
||
norm = np.sqrt(w**2 + x**2 + y**2 + z**2)
|
||
if norm > 0:
|
||
w, x, y, z = w/norm, x/norm, y/norm, z/norm
|
||
|
||
# Counter-rotation (inverse quaternion)
|
||
w_inv = w
|
||
x_inv = -x
|
||
y_inv = -y
|
||
z_inv = -z
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0:4] = [w, x, y, z]
|
||
coord[4:8] = [w_inv, x_inv, y_inv, z_inv]
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = True
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.QUATERNION,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_manifold_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply manifold compression mapping.
|
||
|
||
Isometric chart constraints
|
||
Jacobian determinant for compression
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# State as manifold point
|
||
x = state.position[i]
|
||
v = state.velocity[i]
|
||
a = state.acceleration[i]
|
||
|
||
# Jacobian (simplified 3x3)
|
||
J = np.array([
|
||
[1.0, 0.1, 0.0],
|
||
[0.1, 1.0, 0.1],
|
||
[0.0, 0.1, 1.0]
|
||
])
|
||
|
||
# Jacobian determinant
|
||
det_J = np.linalg.det(J)
|
||
|
||
# Chart bloat: B = N/D
|
||
N = 3 # Representation dimension
|
||
D = 2 # Intrinsic dimension
|
||
bloat = N / D
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0:3] = [x, v, a]
|
||
coord[3] = det_J
|
||
coord[4] = bloat
|
||
coord[5] = N
|
||
coord[6] = D
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = bloat == 1.0 # Isometric when bloat = 1
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.MANIFOLD,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_braid_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply braid group theory mapping.
|
||
|
||
Strand crossing invariants
|
||
Topological constraints
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Treat oscillators as strands
|
||
strand_a = i
|
||
strand_b = (i + 1) % self.n_oscillators
|
||
|
||
# Crossing direction based on relative position
|
||
crossing = 1 if state.position[i] > state.position[strand_b] else -1
|
||
|
||
# Invariant
|
||
invariant = f"braid_{strand_a}_{strand_b}_{crossing}"
|
||
|
||
# Map to n-space (encode invariant numerically)
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0] = strand_a
|
||
coord[1] = strand_b
|
||
coord[2] = crossing
|
||
digest = hashlib.sha256(invariant.encode("utf-8")).digest()
|
||
coord[3] = int.from_bytes(digest[:8], "big") % 1000
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = True
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.BRAID,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_svqf_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply SVQF sparse voxel indexing mapping.
|
||
|
||
Sparse voxel representation
|
||
Only store admissible regions
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Voxel coordinates
|
||
vx = int(state.position[i] * 10 + 50)
|
||
vy = int(state.velocity[i] * 10 + 50)
|
||
vz = int(state.acceleration[i] * 10 + 50)
|
||
|
||
# Sparse index (only if within bounds)
|
||
is_admissible = 0 <= vx < 100 and 0 <= vy < 100 and 0 <= vz < 100
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0:3] = [vx, vy, vz]
|
||
coord[3] = 1 if is_admissible else 0
|
||
coord[4] = vx * 10000 + vy * 100 + vz # Linear index
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.SVQF,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_triumvirate_mapping(self, state: COUCHState) -> List[NSpaceCoordinate]:
|
||
"""
|
||
Apply Triumvirate clock mapping.
|
||
|
||
Builder-Judge-Warden roles
|
||
Clock actions: ADD, PAUSE, SUBTRACT
|
||
"""
|
||
coordinates = []
|
||
|
||
for i in range(self.n_oscillators):
|
||
# Map oscillator state to clock phase
|
||
phase = np.arctan2(state.velocity[i], state.position[i])
|
||
|
||
# Clock action based on phase
|
||
if phase > np.pi/2:
|
||
action = 1 # ADD (Builder)
|
||
elif phase < -np.pi/2:
|
||
action = -1 # SUBTRACT (Warden)
|
||
else:
|
||
action = 0 # PAUSE (Judge)
|
||
|
||
# Map to n-space
|
||
coord = np.zeros(self.n_dimensions)
|
||
coord[0] = phase
|
||
coord[1] = action
|
||
coord[2] = i
|
||
|
||
distance = np.linalg.norm(coord - self.center)
|
||
is_admissible = True
|
||
|
||
coordinates.append(NSpaceCoordinate(
|
||
framework=NSpaceFramework.TRIUMVIRATE,
|
||
coordinates=coord,
|
||
distance_from_center=distance,
|
||
is_admissible=is_admissible
|
||
))
|
||
|
||
return coordinates
|
||
|
||
def apply_all_frameworks(self, state: COUCHState) -> Dict[NSpaceFramework, List[NSpaceCoordinate]]:
|
||
"""Apply all frameworks to COUCH state."""
|
||
mappings = {}
|
||
|
||
mappings[NSpaceFramework.PIST] = self.apply_pist_mapping(state)
|
||
mappings[NSpaceFramework.MENGER] = self.apply_menger_mapping(state)
|
||
mappings[NSpaceFramework.ENE] = self.apply_ene_mapping(state)
|
||
mappings[NSpaceFramework.QUATERNION] = self.apply_quaternion_mapping(state)
|
||
mappings[NSpaceFramework.MANIFOLD] = self.apply_manifold_mapping(state)
|
||
mappings[NSpaceFramework.BRAID] = self.apply_braid_mapping(state)
|
||
mappings[NSpaceFramework.SVQF] = self.apply_svqf_mapping(state)
|
||
mappings[NSpaceFramework.TRIUMVIRATE] = self.apply_triumvirate_mapping(state)
|
||
|
||
self.framework_mappings = mappings
|
||
return mappings
|
||
|
||
def analyze_center_attractor(self) -> Dict[str, Any]:
|
||
"""
|
||
Analyze "=" as central attractor in n-space.
|
||
|
||
Check if all frameworks converge to center or diverge.
|
||
"""
|
||
analysis = {
|
||
"center": self.center.tolist(),
|
||
"frameworks": {},
|
||
"convergence": {},
|
||
"admissibility": {}
|
||
}
|
||
|
||
for framework, coords in self.framework_mappings.items():
|
||
distances = [c.distance_from_center for c in coords]
|
||
admissible = [c.is_admissible for c in coords]
|
||
|
||
analysis["frameworks"][framework.value] = {
|
||
"avg_distance": np.mean(distances),
|
||
"max_distance": np.max(distances),
|
||
"min_distance": np.min(distances),
|
||
"admissible_count": sum(admissible),
|
||
"total_count": len(admissible),
|
||
"admissibility_ratio": sum(admissible) / len(admissible) if admissible else 0
|
||
}
|
||
|
||
# Convergence: check if distances decrease toward center
|
||
analysis["convergence"][framework.value] = distances[0] > distances[-1] if len(distances) > 1 else True
|
||
|
||
# Admissibility
|
||
analysis["admissibility"][framework.value] = all(admissible)
|
||
|
||
return analysis
|
||
|
||
def find_framework_intersections(self) -> Dict[str, Any]:
|
||
"""
|
||
Find intersections between framework mappings.
|
||
|
||
Identify coordinates where multiple frameworks agree.
|
||
"""
|
||
intersections = {
|
||
"pairwise": {},
|
||
"common_admissible": [],
|
||
"framework_distances": {}
|
||
}
|
||
|
||
frameworks = list(self.framework_mappings.keys())
|
||
|
||
# Pairwise intersections
|
||
for i in range(len(frameworks)):
|
||
for j in range(i + 1, len(frameworks)):
|
||
f1 = frameworks[i]
|
||
f2 = frameworks[j]
|
||
|
||
coords1 = self.framework_mappings[f1]
|
||
coords2 = self.framework_mappings[f2]
|
||
|
||
# Find closest pairs
|
||
min_dist = float('inf')
|
||
closest_pair = None
|
||
|
||
for c1 in coords1:
|
||
for c2 in coords2:
|
||
dist = np.linalg.norm(c1.coordinates - c2.coordinates)
|
||
if dist < min_dist:
|
||
min_dist = dist
|
||
closest_pair = (c1, c2)
|
||
|
||
intersections["pairwise"][f"{f1.value} ↔ {f2.value}"] = {
|
||
"min_distance": min_dist,
|
||
"closest_pair_coords": closest_pair[0].coordinates.tolist() if closest_pair else None,
|
||
"both_admissible": closest_pair[0].is_admissible and closest_pair[1].is_admissible if closest_pair else False
|
||
}
|
||
|
||
# Common admissible coordinates
|
||
all_admissible = []
|
||
for framework, coords in self.framework_mappings.items():
|
||
admissible_coords = [c.coordinates for c in coords if c.is_admissible]
|
||
all_admissible.append(admissible_coords)
|
||
|
||
# Find intersection of all admissible sets
|
||
if all_admissible:
|
||
common = all_admissible[0]
|
||
for coords in all_admissible[1:]:
|
||
common = [c for c in common if any(np.allclose(c, other) for other in coords)]
|
||
intersections["common_admissible"] = [c.tolist() for c in common[:5]] # First 5
|
||
|
||
return intersections
|
||
|
||
|
||
def main():
|
||
"""Run COUCH n-space map analysis."""
|
||
print("=" * 70)
|
||
print("COUCH EQUATION N-SPACE MAP ANALYSIS")
|
||
print("=" * 70)
|
||
print("\n[*] Treating COUCH as n-space map with '=' at center")
|
||
print("[*] Applying all Research Stack mathematical frameworks")
|
||
|
||
# Initialize n-space map
|
||
nspace_map = COUCHNSpaceMap(n_oscillators=3, n_dimensions=10)
|
||
|
||
# Initialize COUCH state
|
||
couch_state = nspace_map.initialize_couch_state()
|
||
|
||
print(f"\n[*] COUCH State:")
|
||
print(f" Oscillators: {nspace_map.n_oscillators}")
|
||
print(f" Position: {couch_state.position}")
|
||
print(f" Velocity: {couch_state.velocity}")
|
||
print(f" Damping: {couch_state.damping}")
|
||
print(f" Forcing: {couch_state.forcing}")
|
||
|
||
# Apply all frameworks
|
||
print(f"\n[*] Applying {len(nspace_map.frameworks)} frameworks...")
|
||
mappings = nspace_map.apply_all_frameworks(couch_state)
|
||
|
||
for framework, coords in mappings.items():
|
||
admissible_count = sum(c.is_admissible for c in coords)
|
||
print(f" {framework.value}: {len(coords)} coordinates, {admissible_count} admissible")
|
||
|
||
# Analyze center attractor
|
||
print(f"\n[*] Analyzing '=' as central attractor...")
|
||
center_analysis = nspace_map.analyze_center_attractor()
|
||
|
||
print(f"\n[*] Center Attractor Analysis:")
|
||
for framework, stats in center_analysis["frameworks"].items():
|
||
print(f" {framework}:")
|
||
print(f" Avg distance: {stats['avg_distance']:.4f}")
|
||
print(f" Admissibility: {stats['admissibility_ratio']:.2%}")
|
||
|
||
# Find intersections
|
||
print(f"\n[*] Finding framework intersections...")
|
||
intersections = nspace_map.find_framework_intersections()
|
||
|
||
print(f"\n[*] Framework Intersections:")
|
||
for pair, data in intersections["pairwise"].items():
|
||
print(f" {pair}:")
|
||
print(f" Min distance: {data['min_distance']:.4f}")
|
||
print(f" Both admissible: {data['both_admissible']}")
|
||
|
||
# Save results (convert numpy types to native Python)
|
||
def convert_to_native(obj):
|
||
"""Convert numpy types to native Python types for JSON serialization."""
|
||
if isinstance(obj, np.ndarray):
|
||
return obj.tolist()
|
||
elif isinstance(obj, np.integer):
|
||
return int(obj)
|
||
elif isinstance(obj, np.floating):
|
||
return float(obj)
|
||
elif isinstance(obj, np.bool_):
|
||
return bool(obj)
|
||
elif isinstance(obj, dict):
|
||
return {k: convert_to_native(v) for k, v in obj.items()}
|
||
elif isinstance(obj, list):
|
||
return [convert_to_native(item) for item in obj]
|
||
else:
|
||
return obj
|
||
|
||
results = {
|
||
"couch_state": {
|
||
"position": couch_state.position.tolist(),
|
||
"velocity": couch_state.velocity.tolist(),
|
||
"damping": float(couch_state.damping),
|
||
"forcing": float(couch_state.forcing)
|
||
},
|
||
"center_analysis": convert_to_native(center_analysis),
|
||
"intersections": convert_to_native(intersections)
|
||
}
|
||
|
||
output_path = "/home/allaun/Documents/Research Stack/data/couch_nspace_map_analysis.json"
|
||
with open(output_path, 'w') as f:
|
||
json.dump(results, f, indent=2)
|
||
|
||
print(f"\n[*] Results saved to: {output_path}")
|
||
|
||
print("\n" + "=" * 70)
|
||
print("✅ COUCH N-SPACE MAP ANALYSIS COMPLETE")
|
||
print("=" * 70)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|