File size: 7,066 Bytes
faf5ff0 4e95a36 22c5fe9 197e07d 22c5fe9 faf5ff0 f4a7c39 22c5fe9 faf5ff0 cb02dd8 faf5ff0 cb02dd8 22c5fe9 9d3fe8b af62927 9d3fe8b faf5ff0 197e07d 22c5fe9 faf5ff0 7ee5c66 faf5ff0 cb02dd8 0c5d221 faf5ff0 af62927 cb02dd8 faf5ff0 7760b04 faf5ff0 4162e1c 7760b04 faf5ff0 cb02dd8 faf5ff0 af62927 faf5ff0 af62927 faf5ff0 af62927 faf5ff0 c42c20c faf5ff0 7760b04 4162e1c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# ==============================================================================
# Causal Convergence Simulator (Final Documented Version)
# ==============================================================================
# Author: Carlos R. Santos (in collaboration with a development partner)
#
# This Gradio application provides a real-time, interactive 3D simulation
# of the Causal Convergence principle. An agent (sphere) autonomously
# navigates a 3D space by learning from its immediate past ("causal echo")
# to determine the most logical next step towards a new random target.
# ==============================================================================
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
from scipy.special import comb
import json
import time
# --- Core Mathematical Functions ---
def bernstein_poly(i, n, t):
""" The Bernstein polynomial, which is the basis for Bézier curves. """
return comb(n, i) * (t**(i)) * ((1 - t)**(n - i))
def bezier_curve_3d(points, n_times=20):
""" Generates a 3D Bézier curve from a list of control points. """
n_points = len(points)
points_q = [np.array([quantize(p[0]), quantize(p[1]), quantize(p[2])]) for p in points]
x_points, y_points, z_points = np.array([p[0] for p in points_q]), np.array([p[1] for p in points_q]), np.array([p[2] for p in points_q])
t = np.linspace(0.0, 1.0, n_times)
polynomial_array = np.array([bernstein_poly(i, n_points - 1, t) for i in range(n_points)])
x_vals, y_vals, z_vals = np.dot(x_points, polynomial_array), np.dot(y_points, polynomial_array), np.dot(z_points, polynomial_array)
return x_vals, y_vals, z_vals
def learn_from_echo_3d(echo_points: list):
""" Calculates the essence of motion (the inertia vector) from the echo. """
if len(echo_points) < 2: return {"velocity_vector": np.array([0, 0, 0])}
p1, p2 = np.array(echo_points[0]), np.array(echo_points[-1])
return {"velocity_vector": p2 - p1}
def quantize(value, multiple=4):
""" Rounds a value to the nearest specified multiple. """
return multiple * round(value / multiple)
# --- Main Gradio Simulation Engine ---
def infinite_simulation_engine(camera_angle: int):
"""
A generator function that runs an infinite simulation loop, yielding
a new plot for the Gradio UI on each frame.
"""
# 1. Initialize the simulation state
start_point = np.array([quantize(v) for v in [0., 0., 0.]])
inertia_vector = np.array([quantize(v) for v in [10., 10., 10.]])
trail_history = [start_point.tolist()]
fig = plt.figure(figsize=(8, 8)); ax = fig.add_subplot(111, projection='3d')
background_color = '#0a0a0a'; fig.patch.set_facecolor(background_color); ax.set_facecolor(background_color)
cycle_num = 0
while True: # The infinite loop
cycle_num += 1
# 2. The previous target becomes the new starting point
current_point = np.array(trail_history[-1])
# 3. Generate a new random target, quantized to the grid
random_target_raw = np.random.rand(3) * 50 - 25
next_target = np.array([quantize(v) for v in random_target_raw])
# 4. Calculate the trajectory for the current cycle
control_point = current_point + inertia_vector
curve_points = [current_point, control_point, next_target]
x_cycle, y_cycle, z_cycle = bezier_curve_3d(curve_points)
# 5. Update the continuous trail history
new_trail_points = list(zip(x_cycle, y_cycle, z_cycle))
trail_history.extend(new_trail_points)
max_trail_length = 150
trail_history = trail_history[-max_trail_length:]
# 6. Learn the inertia from the end of this cycle for the *next* one
echo_size = 10
echo_points = trail_history[-echo_size:]
inertia_vector = learn_from_echo_3d(echo_points)["velocity_vector"]
trail_np = np.array(trail_history)
# 7. Render and yield each frame of the current cycle
for frame_idx in range(len(x_cycle)):
ax.cla() # Clear the plot for the new frame
ax.xaxis.pane.fill = False; ax.yaxis.pane.fill = False; ax.zaxis.pane.fill = False
ax.grid(color='#222222', linestyle='--'); ax.view_init(elev=30., azim=camera_angle)
ax.set_xlim(-30, 30); ax.set_ylim(-30, 30); ax.set_zlim(-30, 30)
ax.set_xticklabels([]); ax.set_yticklabels([]); ax.set_zticklabels([])
# Draw static elements
ax.scatter(*current_point, s=150, c='lime', alpha=0.7)
ax.scatter(*next_target, s=150, c='red', marker='X', alpha=0.9)
# Draw the gradient trail
trail_end_index = len(trail_history) - len(x_cycle) + frame_idx
trail_start_index = max(0, trail_end_index - 12)
current_trail_segment = trail_history[trail_start_index:trail_end_index+1]
if len(current_trail_segment) > 1:
for i in range(len(current_trail_segment) - 1):
p1, p2 = current_trail_segment[i], current_trail_segment[i+1]
alpha = 0.8 * (i / 12)
ax.plot([p1[0], p2[0]], [p1[1], p2[1]], [p1[2], p2[2]], color='#ff4500', linewidth=4, alpha=alpha)
# Draw the agent sphere
ax.plot([x_cycle[frame_idx]], [y_cycle[frame_idx]], [z_cycle[frame_idx]], 'o', color='#ff4500', markersize=8, markeredgecolor='white')
# Draw info text
info_text = f"Cycle: {cycle_num}\nTarget: {np.round(next_target)}"; ax.text2D(0.05, 0.95, info_text, transform=ax.transAxes, color='white')
yield fig
time.sleep(0.01) # Controls animation speed for UI responsiveness
plt.close(fig)
# --- Gradio User Interface ---
with gr.Blocks(theme=gr.themes.Base(primary_hue="purple", secondary_hue="orange")) as demo:
gr.Markdown("# ✨ Causal Convergence Simulator ✨"); gr.Markdown("### The Mathematics of the Next Step")
with gr.Tabs():
with gr.TabItem("🔬 The Simulation"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("Control the camera perspective and start the simulation. The agent (sphere) will navigate autonomously, generating new random targets and leaving a fading trail of its inertia."); camera_angle_slider = gr.Slider(-180, 180, value=25, label="Camera Angle (Azimuth)"); start_btn = gr.Button("🚀 Start Simulation", variant="primary")
with gr.Column(scale=2):
plot_output = gr.Plot(label="Real-Time Visualization")
with gr.TabItem("📜 The Theory"):
# Load the explanation from an external markdown file
with open("explanation.md", "r", encoding="utf-8") as f:
gr.Markdown(f.read())
start_btn.click(fn=infinite_simulation_engine, inputs=[camera_angle_slider], outputs=[plot_output])
if __name__ == "__main__":
demo.launch() |