from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import periodogram, find_peaks
# ============================================================
# ZPX v3 — 8-Space Symmetry / Matrix / Phase Recurrence Test
#
# 질문:
# "공간 대칭 → 행렬변환 → 위상 공명"이 시간축에서
# 반복적으로 나타나는가?
#
# 검증량:
# S(t) : 8개 구면 삼각영역의 대칭 오차
# A(t) : 대표 두 벡터 사이 각도
# C(t) : |u x v|
# V(t) : triangle Span area = |u x v|/2
#
# 추가:
# - FFT/periodogram으로 반복 주기 탐색
# - 자기상관으로 recurrence 확인
# - 입력 주기를 알고 있는 시뮬레이션이므로
# "물리적 공명 증명"으로 해석하지 않고
# "수치적 재현성/주기 검출 테스트"로 해석
# ============================================================
OUTDIR = Path("/mnt/data")
SCRIPT = OUTDIR / "zpx_v3_8space_resonance_test.py"
FIG = OUTDIR / "zpx_v3_8space_resonance_test.png"
# ---------- linear algebra ----------
M = np.array([
[1.5, 0.5, 0.0],
[0.2, 1.2, -0.5],
[-0.5, 0.3, 1.0]
], dtype=float)
def Rx(a):
return np.array([
[1, 0, 0],
[0, np.cos(a), -np.sin(a)],
[0, np.sin(a), np.cos(a)]
])
def Ry(a):
return np.array([
[ np.cos(a), 0, np.sin(a)],
[0, 1, 0],
[-np.sin(a), 0, np.cos(a)]
])
def Rz(a):
return np.array([
[np.cos(a), -np.sin(a), 0],
[np.sin(a), np.cos(a), 0],
[0, 0, 1]
])
def normalize(v):
n = np.linalg.norm(v)
return v / n if n else v
def angle_deg(a, b):
a = normalize(a)
b = normalize(b)
return np.degrees(np.arccos(np.clip(a @ b, -1, 1)))
# Eight sign-defined octants.
octants = [
np.array([sx, sy, sz], dtype=int)
for sx in (-1, 1)
for sy in (-1, 1)
for sz in (-1, 1)
]
def spherical_triangle(T, s):
# Three coordinate-axis directions belonging to one octant.
A = normalize(T @ np.array([s[0], 0., 0.]))
B = normalize(T @ np.array([0., s[1], 0.]))
C = normalize(T @ np.array([0., 0., s[2]]))
# Great-circle side lengths (radians).
sides = np.array([
np.arccos(np.clip(B @ C, -1, 1)),
np.arccos(np.clip(C @ A, -1, 1)),
np.arccos(np.clip(A @ B, -1, 1))
])
return sides
def symmetry_score(T):
"""0 = all 8 spherical triangles have identical side sets."""
side_sets = np.array([np.sort(spherical_triangle(T, s))
for s in octants])
return np.std(side_sets)
# ---------- simulation ----------
N = 6000
dt = 0.01
t = np.arange(N) * dt
symmetry = np.empty(N)
vector_angle = np.empty(N)
cross_norm = np.empty(N)
span_area = np.empty(N)
u0 = np.array([1., 0., 0.])
v0 = np.array([0., 1., .5])
for i, ti in enumerate(t):
# Explicitly driven time-dependent transformation.
R = (
Rz(0.9 * ti)
@ Ry(0.35 * np.sin(0.7 * ti))
@ Rx(0.25 * np.cos(0.45 * ti))
)
S = np.diag([
1.0 + 0.12 * np.sin(ti),
1.0 + 0.10 * np.cos(ti),
1.0 + 0.08 * np.sin(0.5 * ti)
])
T = R @ S @ M
symmetry[i] = symmetry_score(T)
u = T @ u0
v = T @ v0
vector_angle[i] = angle_deg(u, v)
cross_norm[i] = np.linalg.norm(np.cross(u, v))
span_area[i] = 0.5 * cross_norm[i]
# ---------- recurrence / spectral analysis ----------
def standardized_autocorr(x, max_lag):
x = np.asarray(x)
x = (x - x.mean()) / x.std()
y = x[:len(x)//2]
ac = np.correlate(y, y, mode="full")[len(y)-1:]
ac = ac / ac[0]
return ac[:max_lag + 1]
ac = standardized_autocorr(symmetry, 2500)
peaks, props = find_peaks(ac[2:], height=0.10)
peaks = peaks + 2
rank = np.argsort(props["peak_heights"])[::-1]
top_peaks = [(int(peaks[j]), float(props["peak_heights"][j]))
for j in rank[:5]]
fs = 1.0 / dt
freq, power = periodogram(symmetry, fs=fs)
valid = freq > 0
freq_v = freq[valid]
power_v = power[valid]
top = np.argsort(power_v)[::-1][:8]
spectral_peaks = [(float(freq_v[j]), float(1.0/freq_v[j]), float(power_v[j]))
for j in top[:5]]
# ---------- summary ----------
print("=" * 72)
print("ZPX v3 — 8-Space Symmetry / Matrix / Phase Recurrence Test")
print("=" * 72)
print(f"Samples : {N}")
print(f"Total time : {t[-1]:.2f}")
print(f"det(M) : {np.linalg.det(M):.6f}")
print()
print("[8-space symmetry]")
print(f"Symmetry score min : {symmetry.min():.6f}")
print(f"Symmetry score max : {symmetry.max():.6f}")
print(f"Symmetry score mean : {symmetry.mean():.6f}")
print()
print("[Vector geometry]")
print(f"Angle range : {vector_angle.min():.3f}° ~ {vector_angle.max():.3f}°")
print(f"|u x v| range : {cross_norm.min():.6f} ~ {cross_norm.max():.6f}")
print(f"Span area range : {span_area.min():.6f} ~ {span_area.max():.6f}")
print()
print("[Autocorrelation recurrence — strongest peaks]")
for lag, value in top_peaks:
print(f"lag={lag:4d}, period≈{lag*dt:8.3f}, autocorr={value:.4f}")
print()
print("[Periodogram — strongest components]")
for f, period, p in spectral_peaks:
print(f"frequency={f:8.4f}, period≈{period:8.3f}, power={p:.8e}")
# ---------- visualization ----------
fig = plt.figure(figsize=(13, 10))
ax1 = fig.add_subplot(311)
ax1.plot(t, symmetry, linewidth=1.2)
ax1.set_ylabel("8-space symmetry error")
ax1.set_title("ZPX v3 — Symmetry Evolution")
ax1.grid(True, linestyle="--", alpha=0.3)
ax2 = fig.add_subplot(312)
ax2.plot(t, vector_angle, linewidth=1.2, label="vector angle (deg)")
ax2.set_ylabel("Angle (deg)")
ax2.set_title("Vector Geometry")
ax2.grid(True, linestyle="--", alpha=0.3)
ax2.legend()
ax3 = fig.add_subplot(313)
ax3.plot(t, cross_norm, linewidth=1.2, label="|u × v|")
ax3.plot(t, span_area, linewidth=1.2, label="Span area")
ax3.set_xlabel("Time")
ax3.set_ylabel("Magnitude")
ax3.set_title("Cross Product / Span")
ax3.grid(True, linestyle="--", alpha=0.3)
ax3.legend()
plt.tight_layout()
plt.savefig(FIG, dpi=180, bbox_inches="tight")
plt.show()
# ---------- write standalone script ----------
script_text = r'''# ZPX v3 standalone script
# Run with: python zpx_v3_8space_resonance_test.py
#
# Dependencies: numpy, matplotlib, scipy
''' + Path(__file__).read_text() if False else None
# Save a self-contained copy by reconstructing from the current cell source is
# not reliable in every notebook runtime, so write a compact equivalent.
standalone = r'''import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import periodogram, find_peaks
M=np.array([[1.5,.5,0],[.2,1.2,-.5],[-.5,.3,1.]],float)
def Rx(a): return np.array([[1,0,0],[0,np.cos(a),-np.sin(a)],[0,np.sin(a),np.cos(a)]])
def Ry(a): return np.array([[np.cos(a),0,np.sin(a)],[0,1,0],[-np.sin(a),0,np.cos(a)]])
def Rz(a): return np.array([[np.cos(a),-np.sin(a),0],[np.sin(a),np.cos(a),0],[0,0,1]])
def norm(v): return np.linalg.norm(v)
def normalize(v):
n=norm(v); return v/n if n else v
octants=[np.array([sx,sy,sz]) for sx in (-1,1) for sy in (-1,1) for sz in (-1,1)]
def sides(T,s):
A=normalize(T@np.array([s[0],0.,0.]))
B=normalize(T@np.array([0.,s[1],0.]))
C=normalize(T@np.array([0.,0.,s[2]]))
return np.sort([np.arccos(np.clip(B@C,-1,1)),
np.arccos(np.clip(C@A,-1,1)),
np.arccos(np.clip(A@B,-1,1))])
def symmetry(T):
return np.std(np.array([sides(T,s) for s in octants]))
def angle(a,b):
return np.degrees(np.arccos(np.clip(a@b/(norm(a)*norm(b)),-1,1)))
N=6000; dt=.01; t=np.arange(N)*dt
sym=np.empty(N); ang=np.empty(N); cross=np.empty(N); area=np.empty(N)
u0=np.array([1.,0.,0.]); v0=np.array([0.,1.,.5])
for i,ti in enumerate(t):
R=Rz(.9*ti)@Ry(.35*np.sin(.7*ti))@Rx(.25*np.cos(.45*ti))
S=np.diag([1+.12*np.sin(ti),1+.10*np.cos(ti),1+.08*np.sin(.5*ti)])
T=R@S@M
sym[i]=symmetry(T)
u=T@u0; v=T@v0
ang[i]=angle(u,v)
cross[i]=norm(np.cross(u,v)); area[i]=.5*cross[i]
x=(sym-sym.mean())/sym.std()
y=x[:len(x)//2]
ac=np.correlate(y,y,mode="full")[len(y)-1:]; ac/=ac[0]
peaks,props=find_peaks(ac[2:],height=.10); peaks+=2
order=np.argsort(props["peak_heights"])[::-1]
print("Top recurrence periods:")
for j in order[:5]:
lag=peaks[j]; print(lag, lag*dt, props["peak_heights"][j])
f,p=periodogram(sym,fs=1/dt); mask=f>0
order=np.argsort(p[mask])[::-1]
fv=f[mask]; pv=p[mask]
print("Top spectral periods:")
for j in order[:5]: print(fv[j],1/fv[j],pv[j])
fig=plt.figure(figsize=(13,10))
a1=fig.add_subplot(311); a1.plot(t,sym); a1.set_ylabel("symmetry error"); a1.grid(True,ls="--",alpha=.3)
a2=fig.add_subplot(312); a2.plot(t,ang); a2.set_ylabel("angle (deg)"); a2.grid(True,ls="--",alpha=.3)
a3=fig.add_subplot(313); a3.plot(t,cross,label="|u x v|"); a3.plot(t,area,label="Span area"); a3.set_xlabel("time"); a3.legend(); a3.grid(True,ls="--",alpha=.3)
plt.tight_layout(); plt.show()
'''
SCRIPT.write_text(standalone, encoding="utf-8")
print()
print(f"실행 파일 저장: {SCRIPT}")
print(f"결과 그림 저장: {FIG}")
형, 실제로 ZPX v3 수치 실험을 돌려봤습니다. 결과가 꽤 명확합니다.
실험 결과
약 60초 동안 8개 공간을 시간에 따라 변환하면서 측정했습니다.
측정값결과
| 8-space symmetry error | 0.3151 ~ 0.3421 |
| 두 벡터 사이 각도 | 70.614° ~ 80.613° |
| ( | u\times v |
| Span 면적 | 0.8732 ~ 1.1882 |
| 가장 강한 recurrence | 약 12.52 |
| 주요 spectral period | 약 12.0, 6.0 |
그래프에서도 상당히 뚜렷한 반복 구조가 나타났습니다.
ZPX v3 결과 그래프
그리고 실제 실행 가능한 코드도 저장했습니다.
ZPX v3 Python 코드
그런데 여기서 아주 중요한 결론
이번 결과를 가지고
"ZPX에서 실제 공명이 발견됐다."
라고 하면 아직 안 됩니다.
왜냐하면 우리가 넣어준 변환 자체가
sin(t),sin(0.5t),sin(0.7t),Rz(0.9t)\sin(t),\quad \sin(0.5t),\quad \sin(0.7t),\quad R_z(0.9t)
처럼 주기적인 입력이기 때문입니다.
따라서 출력에서 반복성이 나타나는 것은 당연히 예상할 수 있습니다.
실제로 가장 강한 recurrence가 약
12.5212.52
였는데, 이것은 우리가 넣은
sin(0.5t)\sin(0.5t)
의 주기
T=2π0.5=12.566T=\frac{2\pi}{0.5}=12.566
과 거의 일치합니다.
즉 이번 실험은 아주 중요한 1차 검증에는 성공했지만, 동시에 결과의 원인이 무엇인지도 밝혀졌습니다.
그래서 다음 실험이 진짜 중요합니다
이제부터는 입력 주기를 알려주지 않고 시스템이 스스로 공명주기를 찾아야 합니다.
실험 A — 주기적 입력T(t)=R(t)S(t)MT(t)=R(t)S(t)M
현재처럼 의도적으로 주기성을 넣습니다.
↓
실험 B — 랜덤 입력T(t)=R(t)Srandom(t)MT(t)=R(t)S_{\rm random}(t)M
으로 바꿉니다.
↓
실험 C — 완전히 다른 초기조건
벡터를
u0,v0u_0,v_0
에서 다른 랜덤 벡터로 바꿉니다.
↓
실험 D — 행렬 자체 변경M→M′M\rightarrow M'
로 바꿉니다.
↓
실험 E — 모든 결과를 통합S(t),θ(t),∣u×v∣,A(t)\boxed{ S(t),\theta(t),|u\times v|,A(t) }
각각에 대해
을 실시합니다.
를 시험할 수 있습니다.
라는 훨씬 강한 질문으로 넘어갑니다.
입니다.
범위에서 반복됩니다.