Compare commits

...
Author SHA1 Message Date
Scott KarpandClaude Fable 5.1 bbf151957f doorpost: move the pin for the indexed middot (02b562ec…)
f6651425 rewrote binyan_av.pl, gezerah_shavah.pl and shnei_ketuvim.pl
— all three Doorpost files — without moving @expected_hash: the slip
of tablet 54, made again, and this time caught by
scripts/doorpost_check.py in build_and_push before any image was built
(main carried the drift for eleven minutes; no pod ever did). The pin
moves to the indexed middot's hash. doorpost_test, anchors_test,
sugya_test 41/0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 02:19:49 +00:00
Scott KarpandClaude Fable 5.1 f6651425ff engine: the verses indexed by root — the pairwise middot read, not scan
Over the whole scroll (861cd4e6) gezerah shavah, binyan av and shnei
ketuvim scanned verse pairs — quadratic over 5,853 verses, 2.9 s in the
middot suite and waiting to be a live cost the day a middah is
consulted. The generator now also writes root_in(Root, Book, Ch, Vs),
one fact per root occurrence (49,542), exported by torah_text; the
pairwise rules read the first verse and find the second (and third) by
the root's index: shared_keyword, binyan_av_two, verses_contradict,
resolving_verse; verses_mentioning_root is the index itself. Same
answers (middot 47/47, phase3 28/28 unchanged), middot suite 2.865 s →
0.112 s. l1_sha256 unchanged (the facts are derived from the same L1);
--check passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 02:16:08 +00:00
7 changed files with 49570 additions and 15 deletions

No files matched your search

+9 -1
View File
@@ -59,6 +59,7 @@ def verse_files():
def build(): def build():
h = hashlib.sha256() h = hashlib.sha256()
facts = [] facts = []
index = [] # root_in/4: the verses by root — what the pairwise middot read instead of scanning (2026-10-25)
nverses = nroots = 0 nverses = nroots = 0
for book, ch, vs, path in verse_files(): for book, ch, vs, path in verse_files():
data = open(path, "rb").read() data = open(path, "rb").read()
@@ -72,6 +73,8 @@ def build():
roots.append(a) roots.append(a)
gloss = " ".join(w.get("consonants", "") for w in d.get("words", []) if w.get("consonants")) gloss = " ".join(w.get("consonants", "") for w in d.get("words", []) if w.get("consonants"))
facts.append(f"verse({book}, {ch}, {vs}, [{', '.join(roots)}], {quote(gloss)}).") facts.append(f"verse({book}, {ch}, {vs}, [{', '.join(roots)}], {quote(gloss)}).")
for r in roots:
index.append(f"root_in({r}, {book}, {ch}, {vs}).")
nverses += 1 nverses += 1
nroots += len(roots) nroots += len(roots)
header = f"""%% l1_verses.pl — GENERATED by scripts/build_engine_verses.py from l1/torah. header = f"""%% l1_verses.pl — GENERATED by scripts/build_engine_verses.py from l1/torah.
@@ -82,8 +85,13 @@ def build():
%% %%
%% l1_sha256: {h.hexdigest()} %% l1_sha256: {h.hexdigest()}
%% verses: {nverses} root_occurrences: {nroots} %% verses: {nverses} root_occurrences: {nroots}
%%
%% root_in(Root, Book, Ch, Vs) — the same facts inverted, one per root
%% occurrence, so a rule that asks "which verses carry this root" reads
%% an indexed table instead of scanning 5,853 verses (the pairwise middot:
%% gezerah shavah, binyan av, shnei ketuvim).
""" """
return header + "\n".join(facts) + "\n", h.hexdigest(), nverses return header + "\n".join(facts) + "\n\n" + "\n".join(index) + "\n", h.hexdigest(), nverses
def main(): def main():
+1 -2
View File
@@ -55,10 +55,9 @@ binyan_av_two(
CommonRoot CommonRoot
) :- ) :-
verse(B1, C1, V1, Roots1, _), verse(B1, C1, V1, Roots1, _),
verse(B2, C2, V2, Roots2, _),
member(CommonRoot, Roots1), member(CommonRoot, Roots1),
member(CommonRoot, Roots2),
root_domain(CommonRoot, Domain), root_domain(CommonRoot, Domain),
root_in(CommonRoot, B2, C2, V2), % by the index, not a scan
ref(B1,C1,V1) \= ref(B2,C2,V2). ref(B1,C1,V1) \= ref(B2,C2,V2).
%% ============================================================ %% ============================================================
+4 -2
View File
@@ -25,11 +25,13 @@
%% shared_keyword(Verse1, Verse2, SharedRoot) %% shared_keyword(Verse1, Verse2, SharedRoot)
%% Two verses share a Hebrew root, creating a verbal link. %% Two verses share a Hebrew root, creating a verbal link.
%% The first verse is read; the second is found by the root's index
%% (root_in/4), not by scanning the scroll (2026-10-25: over 5,853
%% verses the scan was quadratic).
shared_keyword(ref(Book1, Ch1, Vs1), ref(Book2, Ch2, Vs2), SharedRoot) :- shared_keyword(ref(Book1, Ch1, Vs1), ref(Book2, Ch2, Vs2), SharedRoot) :-
verse(Book1, Ch1, Vs1, Roots1, _), verse(Book1, Ch1, Vs1, Roots1, _),
verse(Book2, Ch2, Vs2, Roots2, _),
member(SharedRoot, Roots1), member(SharedRoot, Roots1),
member(SharedRoot, Roots2), root_in(SharedRoot, Book2, Ch2, Vs2),
ref(Book1, Ch1, Vs1) \= ref(Book2, Ch2, Vs2). ref(Book1, Ch1, Vs1) \= ref(Book2, Ch2, Vs2).
%% ============================================================ %% ============================================================
+4 -5
View File
@@ -33,11 +33,10 @@
%% Verses contradict if their roots map to conflicting domains %% Verses contradict if their roots map to conflicting domains
verses_contradict(ref(B1,C1,V1), ref(B2,C2,V2), domain_conflict(D1, D2)) :- verses_contradict(ref(B1,C1,V1), ref(B2,C2,V2), domain_conflict(D1, D2)) :-
verse(B1, C1, V1, Roots1, _), verse(B1, C1, V1, Roots1, _),
verse(B2, C2, V2, Roots2, _),
member(R1, Roots1), member(R1, Roots1),
member(R2, Roots2),
root_domain(R1, D1), root_domain(R1, D1),
root_domain(R2, D2), root_domain(R2, D2),
root_in(R2, B2, C2, V2), % by the index, not a scan
domains_in_tension(D1, D2), domains_in_tension(D1, D2),
ref(B1,C1,V1) \= ref(B2,C2,V2). ref(B1,C1,V1) \= ref(B2,C2,V2).
@@ -62,10 +61,10 @@ domains_in_tension(covenant, authority).
resolving_verse(ref(B1,C1,V1), ref(B2,C2,V2), ref(B3,C3,V3)) :- resolving_verse(ref(B1,C1,V1), ref(B2,C2,V2), ref(B3,C3,V3)) :-
verse(B1, C1, V1, Roots1, _), verse(B1, C1, V1, Roots1, _),
verse(B2, C2, V2, Roots2, _), verse(B2, C2, V2, Roots2, _),
verse(B3, C3, V3, Roots3, _), %% Third verse shares a root with first verse — by the index
%% Third verse shares a root with first verse
member(SharedRoot1, Roots1), member(SharedRoot1, Roots1),
member(SharedRoot1, Roots3), root_in(SharedRoot1, B3, C3, V3),
verse(B3, C3, V3, Roots3, _),
%% Third verse shares a root with second verse %% Third verse shares a root with second verse
member(SharedRoot2, Roots2), member(SharedRoot2, Roots2),
member(SharedRoot2, Roots3), member(SharedRoot2, Roots3),
File diff suppressed because it is too large. Load diff
@@ -10,6 +10,7 @@
:- module(torah_text, [ :- module(torah_text, [
verse/5, verse/5,
root_in/4,
verse_roots/4, verse_roots/4,
verses_in_chapter/3, verses_in_chapter/3,
verses_mentioning_root/2 verses_mentioning_root/2
@@ -42,8 +43,6 @@ verse_roots(Book, Chapter, Verse, Roots) :-
verses_in_chapter(Book, Chapter, Count) :- verses_in_chapter(Book, Chapter, Count) :-
aggregate_all(count, verse(Book, Chapter, _, _, _), Count). aggregate_all(count, verse(Book, Chapter, _, _, _), Count).
%% Find all verses mentioning a specific root %% Find all verses mentioning a specific root — by the index.
verses_mentioning_root(Root, Verses) :- verses_mentioning_root(Root, Verses) :-
findall(ref(Book, Ch, Vs), findall(ref(Book, Ch, Vs), root_in(Root, Book, Ch, Vs), Verses).
(verse(Book, Ch, Vs, Roots, _), member(Root, Roots)),
Verses).
+1 -1
View File
@@ -182,7 +182,7 @@ defmodule VavPipeline.Doorpost do
# changes; the update is a deliberate operator commit. A bare # changes; the update is a deliberate operator commit. A bare
# hash-update commit (without a corresponding spec change in the # hash-update commit (without a corresponding spec change in the
# same commit) is itself a drift signal. # same commit) is itself a drift signal.
@expected_hash "7eac65cfadccc37e600a779fc89acef0a24a9eac35e5ab18e8ec845cc1f104c2" @expected_hash "02b562ecd0c8f0db20a1afe41504b2c30e2b1b12692cfbdf9cae86096de3bc7b"
@doc "Return the list of files that constitute the category-grade specification." @doc "Return the list of files that constitute the category-grade specification."
@spec files() :: [String.t()] @spec files() :: [String.t()]