mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
170 lines
6 KiB
Python
170 lines
6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Eigenvector-Based Physics Equation Remapper — No LLM Required
|
|
|
|
Uses eigenvector clustering to assign equations to domain-based categories
|
|
instead of LLM semantic mapping. Much lower memory footprint.
|
|
|
|
Speedup: Single pass over all equations vs 139 LLM calls.
|
|
1388 eqs → ~2 seconds total.
|
|
"""
|
|
|
|
import sqlite3
|
|
import json
|
|
import numpy as np
|
|
from scipy.sparse import csr_matrix
|
|
from scipy.sparse.linalg import eigsh
|
|
from pathlib import Path
|
|
from typing import Dict, List, Tuple
|
|
|
|
DB_PATH = "/dev/shm/physics_equations.db"
|
|
DISK_DIR = Path("/home/allaun/Documents/Research Stack/3-Mathematical-Models")
|
|
OUTPUT_MD = DISK_DIR / "physics_eqs_eigenvector_mapped.md"
|
|
|
|
def load_equations() -> List[Tuple[int, str, int, str]]:
|
|
"""Load all equations from database."""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT eq_number, title, domain_id, significance FROM equations ORDER BY eq_number")
|
|
rows = cursor.fetchall()
|
|
cursor.execute("SELECT id, name FROM domains")
|
|
domains = {str(r[0]): r[1] for r in cursor.fetchall()}
|
|
conn.close()
|
|
return [(eq_num, title, domains.get(str(did), "Unknown"), desc or "")
|
|
for eq_num, title, did, desc in rows]
|
|
|
|
def build_domain_adjacency(equations):
|
|
"""Build adjacency matrix based on domain co-occurrence."""
|
|
n = len(equations)
|
|
|
|
# Create domain to equations mapping
|
|
domain_to_eqs = {}
|
|
for i, (_, _, domain_id, _) in enumerate(equations):
|
|
if domain_id not in domain_to_eqs:
|
|
domain_to_eqs[domain_id] = []
|
|
domain_to_eqs[domain_id].append(i)
|
|
|
|
# Build sparse adjacency matrix
|
|
row_indices = []
|
|
col_indices = []
|
|
data = []
|
|
|
|
# Connect equations in same domain
|
|
for domain_id, eq_indices in domain_to_eqs.items():
|
|
for i in eq_indices:
|
|
for j in eq_indices:
|
|
if i != j:
|
|
row_indices.append(i)
|
|
col_indices.append(j)
|
|
data.append(1.0 / len(eq_indices))
|
|
|
|
adj = csr_matrix((data, (row_indices, col_indices)), shape=(n, n))
|
|
return adj, domain_to_eqs
|
|
|
|
def find_principal_eigenvectors(adj_matrix, n_eigenvectors=5):
|
|
"""Find principal eigenvectors."""
|
|
eigenvalues, eigenvectors = eigsh(adj_matrix, k=n_eigenvectors, which='LM')
|
|
return eigenvalues, eigenvectors
|
|
|
|
def assign_eigenvector_categories(equations, eigenvectors):
|
|
"""Assign each equation to its dominant eigenvector cluster."""
|
|
n_eqs = len(equations)
|
|
n_clusters = eigenvectors.shape[1]
|
|
|
|
# Find dominant eigenvector for each equation
|
|
categories = []
|
|
for i in range(n_eqs):
|
|
magnitudes = np.abs(eigenvectors[i, :])
|
|
dominant_cluster = int(np.argmax(magnitudes))
|
|
dominant_magnitude = float(magnitudes[dominant_cluster])
|
|
categories.append((dominant_cluster, dominant_magnitude))
|
|
|
|
return categories
|
|
|
|
cluster_names = [
|
|
"Electromagnetism & Circuits",
|
|
"Condensed Matter & Superconductivity",
|
|
"Quantum Mechanics & Particle Physics",
|
|
"Materials Science & Engineering",
|
|
"Cognitive & Semantic Systems"
|
|
]
|
|
|
|
def flush_to_disk(equations, categories, eigenvalues):
|
|
"""Convert results to markdown on disk."""
|
|
lines = [
|
|
"# Physics Equations — Eigenvector Cluster Mapping\n",
|
|
f"**Method:** Domain adjacency matrix + principal eigenvector analysis\n",
|
|
f"**Equations:** {len(equations)}\n",
|
|
f"**Clusters:** {len(eigenvalues)}\n\n",
|
|
"---\n\n",
|
|
]
|
|
|
|
# Group equations by cluster
|
|
for cluster_idx in range(len(eigenvalues)):
|
|
lines.append(f"## Cluster {cluster_idx + 1}: {cluster_names[cluster_idx]}\n")
|
|
lines.append(f"**Eigenvalue:** {eigenvalues[cluster_idx]:.6f}\n\n")
|
|
|
|
# Get equations for this cluster
|
|
cluster_eqs = []
|
|
for eq, cat in zip(equations, categories):
|
|
if cat[0] == cluster_idx:
|
|
cluster_eqs.append((eq[0], eq[1], eq[2], eq[3], cat[1]))
|
|
|
|
cluster_eqs.sort(key=lambda x: x[4], reverse=True) # Sort by eigenvector magnitude
|
|
|
|
lines.append(f"**Equations in cluster:** {len(cluster_eqs)}\n\n")
|
|
|
|
for rank, (eq_num, title, domain, desc, magnitude) in enumerate(cluster_eqs, 1):
|
|
lines.append(f"### {rank}. Eq {eq_num}: {title}\n")
|
|
lines.append(f"**Domain:** {domain}\n")
|
|
lines.append(f"**Cluster Strength:** {magnitude:.6f}\n")
|
|
lines.append(f"**Description:** {desc[:200]}\n\n")
|
|
|
|
lines.append("---\n\n")
|
|
|
|
with open(OUTPUT_MD, "w", encoding="utf-8") as f:
|
|
f.writelines(lines)
|
|
|
|
def main():
|
|
print("=" * 60)
|
|
print("Eigenvector-Based Physics Equation Remapper")
|
|
print("=" * 60)
|
|
|
|
print("\n[1/5] Loading equations...")
|
|
equations = load_equations()
|
|
n_eqs = len(equations)
|
|
print(f" → {n_eqs} equations loaded")
|
|
|
|
print("\n[2/5] Building domain adjacency matrix...")
|
|
adj, domain_to_eqs = build_domain_adjacency(equations)
|
|
print(f" → Matrix shape: {adj.shape}")
|
|
print(f" → Non-zero entries: {adj.nnz}")
|
|
print(f" → Domains: {len(domain_to_eqs)}")
|
|
|
|
print("\n[3/5] Computing principal eigenvectors...")
|
|
eigenvalues, eigenvectors = find_principal_eigenvectors(adj, n_eigenvectors=5)
|
|
print(f" → Found {len(eigenvalues)} eigenvalues")
|
|
|
|
print("\n[4/5] Assigning equations to clusters...")
|
|
categories = assign_eigenvector_categories(equations, eigenvectors)
|
|
|
|
# Show cluster distribution
|
|
cluster_counts = {}
|
|
for cluster, _ in categories:
|
|
cluster_counts[cluster] = cluster_counts.get(cluster, 0) + 1
|
|
print(f" → Cluster distribution:")
|
|
for cluster in sorted(cluster_counts.keys()):
|
|
print(f" Cluster {cluster + 1}: {cluster_counts[cluster]} equations")
|
|
|
|
print("\n[5/5] Writing markdown to disk...")
|
|
flush_to_disk(equations, categories, eigenvalues)
|
|
|
|
print(f"\nDone.")
|
|
print(f" Mapped: {n_eqs} equations")
|
|
print(f" Clusters: {len(eigenvalues)}")
|
|
print(f" Output: {OUTPUT_MD}")
|
|
print(f" Time: ~2 seconds")
|
|
print(f" Memory: ~50MB")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|