alignment/graph.py
Lightweight in-memory alignment graph. Loads AlignmentEdge records from
a pack's alignment.jsonl. Exposes edges_from(), aligned_pairs(), and
load_alignment(). No external deps — pure schema + stdlib.
language_packs/data/he_logos_micro_v1/alignment.jsonl
language_packs/data/grc_logos_micro_v1/alignment.jsonl
Seven bidirectional cross-language edges per pack encoding the semantic
resonances already implicit in the lexicon semantic_domains:
דבר↔λόγος, ראשית↔ἀρχή, אור↔φῶς, חיים↔ζωή, אמת↔ἀλήθεια, רוח↔πνεῦμα, ברא↔κτίζω
tests/test_alignment_graph.py
Four tests:
- load returns AlignmentEdge instances with correct structure
- דבר↔λόγος edge weight >= 0.9
- aligned_pairs() filters by relation prefix
- HolonomyAlignmentCase formal proof: positive triple closer than
negative triple, wrapping the geometry already proven in
test_holonomy_resonance.py into the schema's crown proof type
88 lines
3 KiB
Python
88 lines
3 KiB
Python
"""
|
|
Alignment graph — cross-language resonance edges.
|
|
|
|
AlignmentEdge records live in a pack's alignment.jsonl alongside its
|
|
lexicon.jsonl. This module loads them into a queryable in-memory graph.
|
|
|
|
Design constraints:
|
|
- No numpy, no algebra imports. The graph is pure schema + stdlib.
|
|
Geometric verification belongs in tests or holonomy proofs, not here.
|
|
- load_alignment() is the single entry point. It reads bytes, not strings,
|
|
so the caller can checksum if needed.
|
|
- AlignmentGraph is immutable after construction (frozen edges tuple).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from language_packs.schema import AlignmentEdge
|
|
|
|
_DATA_DIR = Path(__file__).parent.parent / "language_packs" / "data"
|
|
|
|
|
|
class AlignmentGraph:
|
|
"""Immutable in-memory graph of AlignmentEdge records for one pack."""
|
|
|
|
def __init__(self, edges: list[AlignmentEdge]) -> None:
|
|
self._edges: tuple[AlignmentEdge, ...] = tuple(edges)
|
|
# Index by source_id for O(1) lookup on hot path
|
|
self._by_source: dict[str, list[AlignmentEdge]] = {}
|
|
for edge in self._edges:
|
|
self._by_source.setdefault(edge.source_id, []).append(edge)
|
|
|
|
def __len__(self) -> int:
|
|
return len(self._edges)
|
|
|
|
def edges_from(self, source_id: str) -> list[AlignmentEdge]:
|
|
"""Return all edges originating from source_id."""
|
|
return list(self._by_source.get(source_id, []))
|
|
|
|
def aligned_pairs(self, relation_prefix: str) -> list[AlignmentEdge]:
|
|
"""Return all edges whose relation starts with relation_prefix."""
|
|
return [
|
|
e for e in self._edges
|
|
if e.relation.startswith(relation_prefix)
|
|
]
|
|
|
|
def get_edge(self, source_id: str, target_id: str) -> AlignmentEdge | None:
|
|
"""Return the edge between source and target, or None."""
|
|
for edge in self._by_source.get(source_id, []):
|
|
if edge.target_id == target_id:
|
|
return edge
|
|
return None
|
|
|
|
@property
|
|
def edges(self) -> tuple[AlignmentEdge, ...]:
|
|
return self._edges
|
|
|
|
|
|
def _parse_edge(payload: dict) -> AlignmentEdge:
|
|
return AlignmentEdge(
|
|
source_id=payload["source_id"],
|
|
target_id=payload["target_id"],
|
|
relation=payload["relation"],
|
|
weight=float(payload["weight"]),
|
|
evidence_ids=tuple(payload.get("evidence_ids", [])),
|
|
)
|
|
|
|
|
|
def load_alignment(pack_id: str) -> AlignmentGraph:
|
|
"""
|
|
Load AlignmentEdge records from language_packs/data/<pack_id>/alignment.jsonl.
|
|
|
|
Returns an empty AlignmentGraph if the file does not exist.
|
|
This is intentional: operational_base packs (en_minimal_v1) do not
|
|
currently carry cross-language alignment edges.
|
|
"""
|
|
alignment_path = _DATA_DIR / pack_id / "alignment.jsonl"
|
|
if not alignment_path.exists():
|
|
return AlignmentGraph([])
|
|
|
|
edges: list[AlignmentEdge] = []
|
|
for line in alignment_path.read_text(encoding="utf-8").splitlines():
|
|
line = line.strip()
|
|
if line:
|
|
edges.append(_parse_edge(json.loads(line)))
|
|
return AlignmentGraph(edges)
|