=== BIP_v10_structure_analysis.ipynb ===

# ---
#@title 1. Setup & Load Trained Model { display-mode: "form" }
#@markdown **Two options:**
#@markdown 1. **Google Drive**: If you ran v9 with Drive mounted
#@markdown 2. **Upload**: If you downloaded the zip from v9

#@markdown ---
USE_GOOGLE_DRIVE = False  #@param {type:"boolean"}
#@markdown Set to True if you have results in Google Drive, False to upload zip file.

import os, subprocess, sys
for dep in ["transformers", "torch", "sentence-transformers", "scikit-learn", "umap-learn", "networkx",

# ---
#@title 3. Extract z_bond Embeddings from All Data { display-mode: "form" }
#@markdown Extracts the learned moral embeddings for analysis.

from torch.utils.data import Dataset, DataLoader

# Load model
model = BIPModel().to(device)

# Try to load best model
# Try multiple locations (Drive, uploaded, local)
model_paths = [
    # Uploaded/extracted location
    "models/best_hebrew_to_others.pt",
    "models/best_mixed_baseline.pt",
    "models/best_semitic_to_non_semitic.pt",
    "models/best_anc

# ---
#@title 4. Analyze Dimensionality: How Many Dimensions Does Ethics Need? { display-mode: "form" }
#@markdown Uses PCA to find the intrinsic dimensionality of moral space.

print("="*60)
print("DIMENSIONALITY ANALYSIS")
print("="*60)
print()
print("Question: How many dimensions does moral cognition really need?")
print()

# PCA analysis
pca_full = PCA()
pca_full.fit(Z)

# Variance explained
var_explained = pca_full.explained_variance_ratio_
cum_var = np.cumsum(var_explained)

print("Variance expl

# ---
#@title 5. Visualize Moral Space (2D Projections) { display-mode: "form" }
#@markdown Projects the 64D space to 2D for visualization.

print("="*60)
print("VISUALIZING MORAL SPACE")
print("="*60)

# Reduce to 2D using different methods
pca_2d = PCA(n_components=2)
Z_pca = pca_2d.fit_transform(Z)

print("Running t-SNE (this takes a minute)...")
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
Z_tsne = tsne.fit_transform(Z[:10000])  # Subsample for speed

if HAS_UMAP:
    print("Running

# ---
#@title 6. Cluster Analysis: Are There Natural Moral Categories? { display-mode: "form" }
#@markdown Tests if the embedding space has natural clusters.

print("="*60)
print("CLUSTER ANALYSIS")
print("="*60)
print()
print("Question: Does moral space have discrete categories or continuous gradients?")
print()

# Try different numbers of clusters
silhouette_scores = []
k_range = range(2, 15)

print("Testing K-Means with different K...")
for k in tqdm(k_range):
    kmeans = KMeans(n_clusters=k, rand

# ---
#@title 7. Compute Bond Centroids: The "Platonic" Moral Concepts { display-mode: "form" }
#@markdown Finds the center of each bond type - the "ideal" moral concept.

print("="*60)
print("BOND CENTROIDS: Platonic Ideals of Moral Concepts")
print("="*60)
print()
print("Each centroid represents the 'pure' form of a moral concept.")
print()

# Compute centroids for each bond type
bond_centroids = {}
bond_stds = {}

for bond in set(all_bonds):
    mask = [b == bond for b in all_bonds]
    Z_bond = Z[

# ---
#@title 8. Test for Algebraic Structure: Moral Arithmetic { display-mode: "form" }
#@markdown Tests if moral concepts have algebraic relationships.
#@markdown e.g., Does OBLIGATION - AUTHORITY + FAMILY = FILIAL_PIETY?

print("="*60)
print("ALGEBRAIC STRUCTURE: Moral Arithmetic")
print("="*60)
print()
print("Testing if moral concepts have vector arithmetic like word2vec.")
print("(king - man + woman = queen)")
print()

def find_nearest_bond(vec, exclude=None):
    """Find the bond whose centroid 

# ---
#@title 9. Build Moral Graph: Network Structure { display-mode: "form" }
#@markdown Builds a graph where edges connect similar moral concepts.

print("="*60)
print("MORAL GRAPH: Network Structure of Ethics")
print("="*60)
print()

# Build graph from bond centroids
G = nx.Graph()

# Add nodes
for bond in bonds:
    G.add_node(bond)

# Add edges based on distance (threshold)
threshold = np.percentile(dist_matrix[dist_matrix > 0], 30)  # Connect closest 30%

for i, b1 in enumerate(bonds):
    for j

# ---
#@title 10. Test Lattice Structure (Hohfeld's Framework) { display-mode: "form" }
#@markdown Tests if the embedding space respects Hohfeld's deontic square.

print("="*60)
print("TESTING HOHFELD'S LATTICE STRUCTURE")
print("="*60)
print()
print("Hohfeld's framework says:")
print("  RIGHT ←correlative→ DUTY")
print("  RIGHT ←opposite→ NO_RIGHT")
print("  This forms a 'square of opposition'")
print()

# Compute Hohfeld centroids
hohfeld_centroids = {}
for h in ['OBLIGATION', 'RIGHT', 'LIBERTY', No

# ---
#@title 11. Extract Simplified Model: The Essence of Moral Structure { display-mode: "form" }
#@markdown Distills the learned structure into interpretable form.

print("="*60)
print("EXTRACTING THE ESSENCE: Simplified Moral Structure")
print("="*60)
print()

# 1. Key dimensions from PCA
print("1. PRINCIPAL MORAL DIMENSIONS")
print("-" * 40)

pca_full = PCA(n_components=10)
Z_reduced = pca_full.fit_transform(Z)

print("Top dimensions and what they capture:")
for i in range(min(5, len(pca_full.com

# ---
#@title 12. Generate LaTeX for Paper { display-mode: "form" }
#@markdown Generates LaTeX tables and figures for publication.

print("="*60)
print("GENERATING LATEX FOR PUBLICATION")
print("="*60)

# Table 1: Bond centroids distances
print("\n% Table: Distance matrix between moral concepts")
print("\\begin{table}[h]")
print("\\centering")
print("\\caption{Euclidean distances between bond type centroids}")
print("\\begin{tabular}{l" + "c"*min(6, len(bonds)) + "}")
print("\\toprule")
print(" & " + 
