Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -6,7 +6,6 @@ import random
|
|
| 6 |
from fastapi import FastAPI
|
| 7 |
from fastapi.responses import HTMLResponse, FileResponse
|
| 8 |
from fastapi.middleware.cors import CORSMiddleware
|
| 9 |
-
from pydantic import BaseModel
|
| 10 |
|
| 11 |
app = FastAPI()
|
| 12 |
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
|
|
@@ -16,30 +15,25 @@ class SimEngine:
|
|
| 16 |
self.nodes = {}
|
| 17 |
self.running = False
|
| 18 |
self.mode = 'inference'
|
| 19 |
-
self.
|
| 20 |
-
self.
|
| 21 |
self.batch_queue = collections.deque()
|
| 22 |
-
self.logs =
|
| 23 |
self.iteration = 0
|
| 24 |
self.current_error = 0.0
|
| 25 |
self.reset()
|
| 26 |
|
| 27 |
def reset(self):
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
# Generate Multicellular Mesh between A->C and B->C
|
| 35 |
-
for i in range(self.mesh_depth):
|
| 36 |
-
self.nodes[f'H_AC_{i}'] = {'x': random.uniform(0, 1), 'y': 1.0, 'anchored': False, 'k': random.uniform(0.1, 1.0)}
|
| 37 |
-
self.nodes[f'H_BC_{i}'] = {'x': random.uniform(0, 1), 'y': -1.0, 'anchored': False, 'k': random.uniform(0.1, 1.0)}
|
| 38 |
-
|
| 39 |
self.batch_queue.clear()
|
| 40 |
-
self.logs =
|
| 41 |
self.iteration = 0
|
| 42 |
-
self.
|
| 43 |
|
| 44 |
def add_log(self, msg):
|
| 45 |
self.logs.insert(0, f"[{self.iteration}]: {msg}")
|
|
@@ -53,23 +47,21 @@ class SimEngine:
|
|
| 53 |
self.nodes['C']['anchored'] = True
|
| 54 |
else:
|
| 55 |
self.nodes['C']['anchored'] = False
|
| 56 |
-
|
|
|
|
| 57 |
|
| 58 |
def physics_step(self):
|
| 59 |
-
|
| 60 |
-
# We simulate the "Law" as a chain of K-stiffness through the hidden cells
|
| 61 |
-
val_ac = self.nodes['A']['x']
|
| 62 |
-
for i in range(self.mesh_depth):
|
| 63 |
-
val_ac *= self.nodes[f'H_AC_{i}']['k']
|
| 64 |
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
|
|
|
|
|
|
| 68 |
|
| 69 |
-
|
| 70 |
-
prediction = val_ac + val_bc
|
| 71 |
-
self.current_error = prediction - self.nodes['C']['x']
|
| 72 |
|
|
|
|
| 73 |
if abs(self.current_error) < 0.05:
|
| 74 |
if self.batch_queue:
|
| 75 |
p = self.batch_queue.popleft()
|
|
@@ -79,16 +71,23 @@ class SimEngine:
|
|
| 79 |
self.running = False
|
| 80 |
return False
|
| 81 |
|
| 82 |
-
# 2.
|
| 83 |
if self.mode == 'inference':
|
| 84 |
-
#
|
| 85 |
-
|
|
|
|
| 86 |
elif self.mode == 'training':
|
| 87 |
-
#
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
self.iteration += 1
|
| 94 |
return True
|
|
@@ -112,24 +111,31 @@ async def get_state():
|
|
| 112 |
@app.post("/config")
|
| 113 |
async def config(data: dict):
|
| 114 |
engine.mode = data['mode']
|
| 115 |
-
engine.
|
| 116 |
-
engine.
|
| 117 |
engine.running = False
|
| 118 |
engine.reset()
|
|
|
|
| 119 |
return {"ok": True}
|
| 120 |
|
| 121 |
@app.post("/generate")
|
| 122 |
async def generate(data: dict):
|
| 123 |
engine.batch_queue.clear()
|
| 124 |
-
for _ in range(
|
| 125 |
-
a = random.uniform(
|
| 126 |
-
b = random.uniform(
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
engine.batch_queue.append({'a': a, 'b': b, 'c': c})
|
|
|
|
| 133 |
p = engine.batch_queue.popleft()
|
| 134 |
engine.set_problem(p['a'], p['b'], p['c'])
|
| 135 |
engine.running = True
|
|
|
|
| 6 |
from fastapi import FastAPI
|
| 7 |
from fastapi.responses import HTMLResponse, FileResponse
|
| 8 |
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
| 9 |
|
| 10 |
app = FastAPI()
|
| 11 |
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
|
|
|
|
| 15 |
self.nodes = {}
|
| 16 |
self.running = False
|
| 17 |
self.mode = 'inference'
|
| 18 |
+
self.architecture = 'additive' # How the mesh physically works
|
| 19 |
+
self.dataset_type = 'housing' # What data we are forcing into it
|
| 20 |
self.batch_queue = collections.deque()
|
| 21 |
+
self.logs =[]
|
| 22 |
self.iteration = 0
|
| 23 |
self.current_error = 0.0
|
| 24 |
self.reset()
|
| 25 |
|
| 26 |
def reset(self):
|
| 27 |
+
# A & B are inputs, C is output. K-factors are the elasticity of the connections.
|
| 28 |
+
self.nodes = {
|
| 29 |
+
'A': {'x': 2.0, 'y': 2.0, 'anchored': True, 'k': random.uniform(0.1, 1.0)},
|
| 30 |
+
'B': {'x': 3.0, 'y': -2.0, 'anchored': True, 'k': random.uniform(0.1, 1.0)},
|
| 31 |
+
'C': {'x': 5.0, 'y': 0.0, 'anchored': False, 'k': 1.0}
|
| 32 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
self.batch_queue.clear()
|
| 34 |
+
self.logs =[]
|
| 35 |
self.iteration = 0
|
| 36 |
+
self.current_error = 0.0
|
| 37 |
|
| 38 |
def add_log(self, msg):
|
| 39 |
self.logs.insert(0, f"[{self.iteration}]: {msg}")
|
|
|
|
| 47 |
self.nodes['C']['anchored'] = True
|
| 48 |
else:
|
| 49 |
self.nodes['C']['anchored'] = False
|
| 50 |
+
# Start C at zero to watch it drift to the answer
|
| 51 |
+
self.nodes['C']['x'] = 0.0
|
| 52 |
|
| 53 |
def physics_step(self):
|
| 54 |
+
na, nb, nc = self.nodes['A'], self.nodes['B'], self.nodes['C']
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
+
# 1. CORE ARCHITECTURE LOGIC (Completely blind to the dataset)
|
| 57 |
+
if self.architecture == 'additive':
|
| 58 |
+
prediction = (na['x'] * na['k']) + (nb['x'] * nb['k'])
|
| 59 |
+
else: # multiplicative
|
| 60 |
+
prediction = (na['x'] * na['k']) * (nb['x'] * nb['k'])
|
| 61 |
|
| 62 |
+
self.current_error = prediction - nc['x']
|
|
|
|
|
|
|
| 63 |
|
| 64 |
+
# Check for convergence
|
| 65 |
if abs(self.current_error) < 0.05:
|
| 66 |
if self.batch_queue:
|
| 67 |
p = self.batch_queue.popleft()
|
|
|
|
| 71 |
self.running = False
|
| 72 |
return False
|
| 73 |
|
| 74 |
+
# 2. RESOLVING TENSION (Push / Pull)
|
| 75 |
if self.mode == 'inference':
|
| 76 |
+
# Shift the output node C until tension reaches zero
|
| 77 |
+
nc['x'] += self.current_error * 0.1
|
| 78 |
+
|
| 79 |
elif self.mode == 'training':
|
| 80 |
+
# The structure is locked. Tension deforms the K (Stiffness) factors.
|
| 81 |
+
lr = 0.01 # Learning elasticity rate
|
| 82 |
+
|
| 83 |
+
if self.architecture == 'additive':
|
| 84 |
+
# Force distributes proportionally based on node input value
|
| 85 |
+
na['k'] -= self.current_error * na['x'] * lr
|
| 86 |
+
nb['k'] -= self.current_error * nb['x'] * lr
|
| 87 |
+
else:
|
| 88 |
+
# Chain rule tension for multiplication
|
| 89 |
+
na['k'] -= self.current_error * (nb['x'] * nb['k']) * na['x'] * (lr * 0.01)
|
| 90 |
+
nb['k'] -= self.current_error * (na['x'] * na['k']) * nb['x'] * (lr * 0.01)
|
| 91 |
|
| 92 |
self.iteration += 1
|
| 93 |
return True
|
|
|
|
| 111 |
@app.post("/config")
|
| 112 |
async def config(data: dict):
|
| 113 |
engine.mode = data['mode']
|
| 114 |
+
engine.architecture = data['architecture']
|
| 115 |
+
engine.dataset_type = data['dataset']
|
| 116 |
engine.running = False
|
| 117 |
engine.reset()
|
| 118 |
+
engine.add_log(f"Arch: {engine.architecture} | Data: {engine.dataset_type}")
|
| 119 |
return {"ok": True}
|
| 120 |
|
| 121 |
@app.post("/generate")
|
| 122 |
async def generate(data: dict):
|
| 123 |
engine.batch_queue.clear()
|
| 124 |
+
for _ in range(30):
|
| 125 |
+
a = random.uniform(2, 10)
|
| 126 |
+
b = random.uniform(2, 10)
|
| 127 |
+
|
| 128 |
+
# This is the dataset environment. The mesh DOES NOT know these rules.
|
| 129 |
+
# It must learn them by adjusting K_a and K_b.
|
| 130 |
+
if engine.dataset_type == 'housing':
|
| 131 |
+
c = (a * 2.5) + (b * 1.2) # Hidden weights: 2.5 and 1.2
|
| 132 |
+
elif engine.dataset_type == 'subtraction':
|
| 133 |
+
c = (a * 1.0) + (b * -1.0) # Hidden weights: 1.0 and -1.0
|
| 134 |
+
elif engine.dataset_type == 'multiplication':
|
| 135 |
+
c = a * b
|
| 136 |
+
|
| 137 |
engine.batch_queue.append({'a': a, 'b': b, 'c': c})
|
| 138 |
+
|
| 139 |
p = engine.batch_queue.popleft()
|
| 140 |
engine.set_problem(p['a'], p['b'], p['c'])
|
| 141 |
engine.running = True
|