Research-Stack/5-Applications/scripts/compute_distance_matrix.py

111 lines
3.1 KiB
Python

#!/usr/bin/env python3
import json
import numpy as np
import pandas as pd
from pathlib import Path
from scipy.spatial.distance import cosine
# Paths
BASE_PATH = Path('/home/allaun/Documents/Research Stack')
EQUATION_FOREST_PATH = BASE_PATH / 'shared-data/data/equations_forest.jsonl'
DISTANCE_MATRIX_PATH = BASE_PATH / 'shared-data/data/equation_distance_matrix.csv'
# Weights
WEIGHTS = {
'kernel': 0.35,
'street': 0.20,
'bridge': 0.20,
'typing': 0.10,
'failure': 0.10,
'numeric': 0.05
}
def compute_distance(node1, node2):
"""Compute the weighted distance between two nodes."""
# 1. Kernel Distance (Cosine)
v1 = np.array(node1['foundation_vector'])
v2 = np.array(node2['foundation_vector'])
if np.all(v1 == 0) and np.all(v2 == 0):
d_kernel = 0.0
elif np.all(v1 == 0) or np.all(v2 == 0):
d_kernel = 1.0
else:
# Cosine distance returns 1 - cosine_similarity
try:
d_kernel = cosine(v1, v2)
if np.isnan(d_kernel): d_kernel = 1.0
except:
d_kernel = 1.0
# 2. Street Distance (Layer)
d_street = 0.0 if node1['layer'] == node2['layer'] else 1.0
# 3. Bridge/Shape Distance
if node1['shape_uuid'] == node2['shape_uuid']:
d_bridge = 0.0
elif node1['bind_class'] == node2['bind_class'] and node1['bind_class']:
d_bridge = 0.5
else:
d_bridge = 1.0
# 4. Typing Distance
d_typing = 0.0 if node1['typed_status'] == node2['typed_status'] else 1.0
# 5. Failure Distance (Stubbed to 0 for now as data is sparse)
d_failure = 0.0
# 6. Numeric Distance (Genome18 Address)
addr1 = node1.get('genome18_address', 0)
addr2 = node2.get('genome18_address', 0)
# Normalized by max 18-bit address space
d_numeric = abs(addr1 - addr2) / 262144.0
# Weighted Sum
total_dist = (
WEIGHTS['kernel'] * d_kernel +
WEIGHTS['street'] * d_street +
WEIGHTS['bridge'] * d_bridge +
WEIGHTS['typing'] * d_typing +
WEIGHTS['failure'] * d_failure +
WEIGHTS['numeric'] * d_numeric
)
return total_dist
def main():
if not EQUATION_FOREST_PATH.exists():
print(f"Error: {EQUATION_FOREST_PATH} not found.")
return
nodes = []
with open(EQUATION_FOREST_PATH, 'r') as f:
for line in f:
if line.strip():
nodes.append(json.loads(line))
n = len(nodes)
print(f"Computing distance matrix for {n} nodes...")
# Initialize matrix
matrix = np.zeros((n, n))
# Compute pairwise distances (optimized for symmetry)
for i in range(n):
if i % 100 == 0:
print(f"Progress: {i}/{n} nodes...")
for j in range(i + 1, n):
dist = compute_distance(nodes[i], nodes[j])
matrix[i, j] = dist
matrix[j, i] = dist
# Create DataFrame for CSV export
names = [node['model_name'] for node in nodes]
df = pd.DataFrame(matrix, index=names, columns=names)
# Save to CSV
df.to_csv(DISTANCE_MATRIX_PATH)
print(f"Successfully saved distance matrix to {DISTANCE_MATRIX_PATH}")
if __name__ == '__main__':
main()