Atomic-VSA / app_python_backup.py
marshad180's picture
Fix: Docker+Julia HTTP server
12e5518 verified
"""
Atomic VSA Interactive Demo
A Gradio-based demonstration of Vector Symbolic Architecture for clinical triage.
"""
import gradio as gr
import numpy as np
from typing import Dict, List, Tuple
# ============================================================================
# VSA Core Implementation (Python port of Julia logic)
# ============================================================================
D = 2048 # Dimensionality for demo (production uses 10,048)
np.random.seed(42)
class AtomRegistry:
"""Registry of atomic vectors (symbols)."""
def __init__(self, dim: int = D):
self.dim = dim
self.atoms: Dict[str, np.ndarray] = {}
def get_or_create(self, name: str) -> np.ndarray:
if name not in self.atoms:
# Create bipolar random vector {-1, +1}^D
self.atoms[name] = np.random.choice([-1, 1], size=self.dim).astype(np.float32)
return self.atoms[name]
def __getitem__(self, name: str) -> np.ndarray:
return self.get_or_create(name)
# Global registry
registry = AtomRegistry()
def bind(a: np.ndarray, b: np.ndarray) -> np.ndarray:
"""BIND operation: Element-wise multiplication (⊗)."""
return a * b
def bundle(vectors: List[np.ndarray]) -> np.ndarray:
"""BUNDLE operation: Element-wise addition (⊕)."""
return np.sum(vectors, axis=0)
def similarity(a: np.ndarray, b: np.ndarray) -> float:
"""Cosine similarity between vectors."""
norm_a = np.linalg.norm(a)
norm_b = np.linalg.norm(b)
if norm_a == 0 or norm_b == 0:
return 0.0
return float(np.dot(a, b) / (norm_a * norm_b))
def thermometer_encode(value: float, min_val: float, max_val: float, levels: int = 20) -> np.ndarray:
"""Thermometer encoding for continuous values."""
level_atoms = [registry.get_or_create(f"_level_{i}") for i in range(levels)]
active_levels = int((value - min_val) / (max_val - min_val) * levels)
active_levels = max(0, min(levels, active_levels))
if active_levels == 0:
return np.zeros(D, dtype=np.float32)
return bundle(level_atoms[:active_levels])
# ============================================================================
# Clinical Triage System
# ============================================================================
SYMPTOMS = [
"chest_pain", "shortness_of_breath", "fever", "cough",
"headache", "fatigue", "nausea", "dizziness",
"abdominal_pain", "back_pain", "joint_pain", "rash",
"sore_throat", "runny_nose", "muscle_ache", "chills"
]
TRIAGE_CATEGORIES = {
"Emergency - Cardiac": ["chest_pain", "shortness_of_breath", "dizziness"],
"Urgent - Respiratory": ["shortness_of_breath", "cough", "fever", "chills"],
"Urgent - Infection": ["fever", "chills", "fatigue", "muscle_ache"],
"Standard - Flu-like": ["fever", "cough", "sore_throat", "runny_nose", "muscle_ache"],
"Standard - GI": ["nausea", "abdominal_pain", "fever"],
"Standard - Musculoskeletal": ["back_pain", "joint_pain", "muscle_ache"],
"Low Priority - Minor": ["headache", "fatigue", "runny_nose"],
}
# Pre-build prototype vectors for each triage category
PROTOTYPES: Dict[str, np.ndarray] = {}
for category, symptom_list in TRIAGE_CATEGORIES.items():
molecules = []
for symptom in symptom_list:
field_atom = registry[f"symptom_field"]
value_atom = registry[symptom]
molecules.append(bind(field_atom, value_atom))
PROTOTYPES[category] = bundle(molecules)
def create_patient_vector(symptoms: List[str], vitals: Dict[str, float]) -> np.ndarray:
"""Create a patient record as a bundled molecule."""
molecules = []
# Encode symptoms
for symptom in symptoms:
if symptom in SYMPTOMS:
field_atom = registry["symptom_field"]
value_atom = registry[symptom]
molecules.append(bind(field_atom, value_atom))
# Encode vitals with thermometer encoding
if "heart_rate" in vitals:
hr_encoded = thermometer_encode(vitals["heart_rate"], 40, 180)
molecules.append(bind(registry["heart_rate_field"], hr_encoded))
if "temperature" in vitals:
temp_encoded = thermometer_encode(vitals["temperature"], 35, 42)
molecules.append(bind(registry["temperature_field"], temp_encoded))
if "blood_pressure_sys" in vitals:
bp_encoded = thermometer_encode(vitals["blood_pressure_sys"], 80, 200)
molecules.append(bind(registry["bp_field"], bp_encoded))
if not molecules:
return np.zeros(D, dtype=np.float32)
return bundle(molecules)
def triage_patient(patient_vector: np.ndarray) -> List[Tuple[str, float]]:
"""Classify patient against triage prototypes."""
scores = []
for category, prototype in PROTOTYPES.items():
sim = similarity(patient_vector, prototype)
scores.append((category, sim))
# Sort by similarity descending
scores.sort(key=lambda x: x[1], reverse=True)
return scores
# ============================================================================
# Gradio Interface
# ============================================================================
def process_triage(
chest_pain: bool, shortness_of_breath: bool, fever: bool, cough: bool,
headache: bool, fatigue: bool, nausea: bool, dizziness: bool,
abdominal_pain: bool, back_pain: bool, joint_pain: bool, rash: bool,
sore_throat: bool, runny_nose: bool, muscle_ache: bool, chills: bool,
heart_rate: float, temperature: float, blood_pressure: float
) -> Tuple[str, str, str]:
"""Process symptoms and return triage classification."""
# Collect selected symptoms
symptom_map = {
"chest_pain": chest_pain, "shortness_of_breath": shortness_of_breath,
"fever": fever, "cough": cough, "headache": headache, "fatigue": fatigue,
"nausea": nausea, "dizziness": dizziness, "abdominal_pain": abdominal_pain,
"back_pain": back_pain, "joint_pain": joint_pain, "rash": rash,
"sore_throat": sore_throat, "runny_nose": runny_nose,
"muscle_ache": muscle_ache, "chills": chills
}
selected_symptoms = [s for s, v in symptom_map.items() if v]
if not selected_symptoms:
return "No symptoms selected", "", ""
# Create patient vector
vitals = {
"heart_rate": heart_rate,
"temperature": temperature,
"blood_pressure_sys": blood_pressure
}
patient_vec = create_patient_vector(selected_symptoms, vitals)
# Get triage scores
scores = triage_patient(patient_vec)
# Format results
primary = scores[0]
primary_result = f"**{primary[0]}**\nSimilarity: {primary[1]:.4f}"
# All scores
all_scores = "\n".join([f"{cat}: {sim:.4f}" for cat, sim in scores])
# Explanation
explanation = f"""
**VSA Explanation:**
- Patient encoded as {D}-dimensional bipolar vector
- Symptoms: {', '.join(selected_symptoms)}
- Heart Rate: {heart_rate} bpm → Thermometer encoded
- Temperature: {temperature}°C → Thermometer encoded
- Blood Pressure: {blood_pressure} mmHg → Thermometer encoded
**How it works:**
1. Each symptom is BOUND (⊗) with a field identifier
2. All bound pairs are BUNDLED (⊕) into a superposition
3. Cosine similarity computed against {len(PROTOTYPES)} prototypes
4. Classification is deterministic and fully explainable
"""
return primary_result, all_scores, explanation
def demo_bind_operation(concept_a: str, concept_b: str) -> str:
"""Demonstrate BIND operation."""
if not concept_a or not concept_b:
return "Enter two concepts"
vec_a = registry[concept_a]
vec_b = registry[concept_b]
bound = bind(vec_a, vec_b)
# Verify self-inverse property
unbound = bind(bound, vec_b)
recovery_sim = similarity(unbound, vec_a)
return f"""
**BIND Operation: {concept_a}{concept_b}**
Vector A (first 10 dims): {vec_a[:10].astype(int).tolist()}
Vector B (first 10 dims): {vec_b[:10].astype(int).tolist()}
Bound (first 10 dims): {bound[:10].astype(int).tolist()}
**Self-Inverse Property:**
(A ⊗ B) ⊗ B = A
Recovery similarity: {recovery_sim:.6f} (should be 1.0)
**Orthogonality:**
Sim(A, B): {similarity(vec_a, vec_b):.4f} (random vectors ≈ 0)
Sim(A, Bound): {similarity(vec_a, bound):.4f} (bound dissimilar to inputs)
"""
def demo_bundle_operation(concepts: str) -> str:
"""Demonstrate BUNDLE operation."""
if not concepts:
return "Enter comma-separated concepts"
concept_list = [c.strip() for c in concepts.split(",") if c.strip()]
if len(concept_list) < 2:
return "Enter at least 2 concepts"
vectors = [registry[c] for c in concept_list]
bundled = bundle(vectors)
# Show similarity to each component
sims = [(c, similarity(bundled, registry[c])) for c in concept_list]
sim_report = "\n".join([f" Sim(Bundle, {c}): {s:.4f}" for c, s in sims])
return f"""
**BUNDLE Operation: {' ⊕ '.join(concept_list)}**
Bundled {len(concept_list)} vectors into superposition.
**Holographic Property - Bundle is similar to ALL inputs:**
{sim_report}
Unlike classical storage, the bundle simultaneously represents
all {len(concept_list)} concepts in the same {D}-dimensional space!
"""
# Build the Gradio app
with gr.Blocks(title="Atomic VSA Demo", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# ⚛️ Atomic VSA: Interactive Demo
**Physics-Inspired Hyperdimensional Computing for Explainable Clinical AI**
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.18650281.svg)](https://doi.org/10.5281/zenodo.18650281)
[![GitHub](https://img.shields.io/badge/GitHub-atomic--vsa--research-blue)](https://github.com/muhammadarshad/atomic-vsa-research)
This demo showcases the Atomic Vector Symbolic Architecture (Atomic VSA) —
a deterministic, interpretable AI framework achieving **92.5% F1** on clinical triage.
""")
with gr.Tabs():
# Tab 1: Clinical Triage Demo
with gr.TabItem("🏥 Clinical Triage"):
gr.Markdown("### Enter Patient Symptoms & Vitals")
with gr.Row():
with gr.Column():
gr.Markdown("**Symptoms:**")
chest_pain = gr.Checkbox(label="Chest Pain")
shortness_of_breath = gr.Checkbox(label="Shortness of Breath")
fever = gr.Checkbox(label="Fever")
cough = gr.Checkbox(label="Cough")
headache = gr.Checkbox(label="Headache")
fatigue = gr.Checkbox(label="Fatigue")
nausea = gr.Checkbox(label="Nausea")
dizziness = gr.Checkbox(label="Dizziness")
with gr.Column():
gr.Markdown("**More Symptoms:**")
abdominal_pain = gr.Checkbox(label="Abdominal Pain")
back_pain = gr.Checkbox(label="Back Pain")
joint_pain = gr.Checkbox(label="Joint Pain")
rash = gr.Checkbox(label="Rash")
sore_throat = gr.Checkbox(label="Sore Throat")
runny_nose = gr.Checkbox(label="Runny Nose")
muscle_ache = gr.Checkbox(label="Muscle Ache")
chills = gr.Checkbox(label="Chills")
with gr.Column():
gr.Markdown("**Vitals:**")
heart_rate = gr.Slider(40, 180, value=75, label="Heart Rate (bpm)")
temperature = gr.Slider(35.0, 42.0, value=37.0, step=0.1, label="Temperature (°C)")
blood_pressure = gr.Slider(80, 200, value=120, label="Systolic BP (mmHg)")
triage_btn = gr.Button("🔬 Run Triage", variant="primary")
with gr.Row():
primary_output = gr.Markdown(label="Primary Classification")
scores_output = gr.Textbox(label="All Scores", lines=7)
explanation_output = gr.Markdown(label="VSA Explanation")
triage_btn.click(
process_triage,
inputs=[
chest_pain, shortness_of_breath, fever, cough,
headache, fatigue, nausea, dizziness,
abdominal_pain, back_pain, joint_pain, rash,
sore_throat, runny_nose, muscle_ache, chills,
heart_rate, temperature, blood_pressure
],
outputs=[primary_output, scores_output, explanation_output]
)
# Tab 2: VSA Operations
with gr.TabItem("🧮 VSA Operations"):
gr.Markdown("""
### Explore the Algebraic Operations
Atomic VSA uses two fundamental operations:
- **BIND (⊗)**: Creates relational structures (self-inverse)
- **BUNDLE (⊕)**: Creates holographic superpositions
""")
with gr.Row():
with gr.Column():
gr.Markdown("#### BIND Operation")
bind_a = gr.Textbox(label="Concept A", value="HeartRate")
bind_b = gr.Textbox(label="Concept B", value="115bpm")
bind_btn = gr.Button("Compute BIND")
bind_output = gr.Markdown()
bind_btn.click(demo_bind_operation, [bind_a, bind_b], bind_output)
with gr.Column():
gr.Markdown("#### BUNDLE Operation")
bundle_input = gr.Textbox(
label="Concepts (comma-separated)",
value="fever, cough, fatigue"
)
bundle_btn = gr.Button("Compute BUNDLE")
bundle_output = gr.Markdown()
bundle_btn.click(demo_bundle_operation, [bundle_input], bundle_output)
# Tab 3: About
with gr.TabItem("📄 About"):
gr.Markdown("""
## Atomic Vector Symbolic Architecture
### Key Innovation
Atomic VSA applies **physics-inspired principles** to hyperdimensional computing:
| Physics | Computing (AVSA) | Clinical Medicine |
|---------|------------------|-------------------|
| Atom | 10,048-dim vector | Semantic concept |
| Proton (+) | Positive evidence | Finding FOR diagnosis |
| Electron (−) | Negative evidence | Finding AGAINST diagnosis |
| Molecule | BIND(a ⊗ b) | Clinical fact pair |
| Superposition | BUNDLE(⊕) | Patient record |
### Performance
| Metric | Result |
|--------|--------|
| F1 Score | 92.5% (25-category ICD-11) |
| Label Recall | 91.9% (comorbidity) |
| Latency | 11.97ms (p50) |
| Power | 15W (edge) |
### Why VSA?
- ✅ **Deterministic**: Same input → same output, always
- ✅ **Interpretable**: Algebraic operations are transparent
- ✅ **Efficient**: No training, no GPU required
- ✅ **Green AI**: 160× lower power than neural networks
### Links
- **Paper (DOI)**: [10.5281/zenodo.18650281](https://doi.org/10.5281/zenodo.18650281)
- **Code**: [GitHub](https://github.com/muhammadarshad/atomic-vsa-research)
- **Author**: Muhammad Arshad (marshad.dev@gmail.com)
""")
if __name__ == "__main__":
demo.launch()