Skip to content

Joins: find exclusions through shared keys, not every pair - #189

Merged
deanberris merged 3 commits into
mainfrom
claude/profile-solafide
Nov 2, 2026
Merged

deanberris merged 3 commits into
mainfrom
claude/profile-solafide

Conversation

@deanberris

@deanberris deanberris commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #176. The first of three changes from profiling Meanings.SolaFide and SolaFide.Dispute.

Why

Meanings.SolaFide took 64 s, and 51 s of it was one proof: that the pinned exclusions are exactly what the meanings contain. The kernel checked it by testing all 6,105 pairs of the argument's 111 claims for a clash.

Two first guesses were wrong; both are recorded in the ledger so nobody tries them again:

  • That the kernel re-closed each meaning for every pair. A literal table of closed meanings, and one of their coherence, each checked once, changed nothing: 44 s.
  • That closing the meanings was the cost. It takes 0.4 s for all 111 claims.

The cost was the clash check itself. It compares whole facts and terms a field at a time, about 100 µs a comparison, some 400,000 comparisons in all.

What this does

Two coherent meanings can clash only where they touch. Seen as a graph, claims meet through their keys:

  • a literal meets its negation in one fact;
  • a definition's rule (only, functional) relates two facts about one thing;
  • a nogood is completed by the other meaning's literal.

The changes:

  • Ontology.Key, keysOf, shares_of_clash: a meaning's keys, and the proof that two coherent meanings that clash share one.
  • HasMeanings.exclusionsUnder: each meaning is closed once (shapedUnder), then the claims are taken from the last to the first, against an index from keys to the later claims holding them. Each claim is checked only against the claims it shares a key with.
  • The definition is kept as exclusionsByPairs. exclusionsUnder_eq proves the two are the same list, pair for pair and in order. So every pin stands unchanged, and no argument, statement or generated file changes.

The entailments were tried the same way, indexed by each claim's first literal. They gained only 9.7 s → 8.3 s, because their check already stops at the first literal missing. The loop over pairs is their cost, and the index doesn't remove it, so they're left as they are and recorded in the ledger.

A regression CI caught, fixed

The first push closed each later claim's meaning again for every claim before it, inside the walk. The kernel shares those repeated terms, so the proof was not slowed. But #check_ontology runs the same function compiled, once per definition, and paid for every closing. CI's benchmark gate found it 5.1% slower than main (p = 0.008). The second push closes each meaning once, before the walk, and the proof of equality carries over.

Measured

scripts/bench-ab.sh origin/main, five interleaved rounds, on the current head. Result: IMPROVED, nothing worse.

Benchmark main This PR Change p Peak memory
Sola fide exclusions, 111 claims (new) 45.4 s 10.6 s −77% 0.008 3.43 → 1.06 GiB
Checks: ontology 3.16 s 1.69 s −47% 0.008 24 → 24 MiB
The other three checks — — within noise ≥ 0.22 unchanged

Measured by hand on the first push, clean, on the same machine:

Before This PR
Meanings.SolaFide 64 s 24 s (31 s in the parallel build)
Arguments, lake build 225 s, 13.8 GiB peak 204 s, 10.9 GiB peak
Arguments, kernel replay 9.3 GiB peak 6.9 GiB peak, 226 s

The exclusions proof was the largest single holder of memory in both the build and the replay.

The round is recorded as round 7 in docs/src/performance.md. The semantics chapter says how the exclusions are found.

Also

A pin: #check_citations in the arguments now scans 2,319 definitions.

Checks

All pass on the current head:

  • lake build, including TestimonyTools, the arguments and the examples
  • lake lint and lake exe axiom-audit, in all three packages
  • scripts/kernel-replay.sh, in all three packages
  • scripts/testimony_lint.py
  • bibgen, argtex, statusgen and argdoc with --check, and exampletex --check
  • mdbook build docs

Generated by Claude Code

The sola fide joins took the kernel 51 seconds: every one of 6105 pairs of
claims was checked for a clash, each check a comparison of whole facts.

- Ontology: a meaning's keys are the facts it affirms, denies or holds in a
  nogood, and the things its relations are about. shares_of_clash: two
  coherent meanings that clash share a key, since a literal meets its negation
  in one fact, a rule relates facts about one thing, and a nogood is completed
  by the other meaning's literal.
- Meaning: the definition stays, as exclusionsByPairs. exclusionsUnder now
  takes the claims from the last to the first, each against an index of the
  keys of the claims after it, and checks only those it shares a key with.
  exclusionsUnder_eq: the two are the same list, pair for pair and in order.
- Docs: the semantics chapter says how the exclusions are found.
- bench: the sola fide exclusions. Pinned: 2318 library definitions for
  #check_citations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BC49XsbtehCbmJMavF1K5Q
The sola fide exclusions 45.0 s to 13.0 s and 3.43 to 1.03 GiB (p = 0.008); the
arguments' clean build 204 s at a 10.9 GiB peak, the kernel replay's peak 6.9
GiB. Two wrong first guesses recorded, and the entailments left as they are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BC49XsbtehCbmJMavF1K5Q
The key-index walk closed each later claim's meaning again for every claim
before it. The kernel shares those repeated terms, so the proof was not slowed,
but the ontology check runs the same function compiled, once for every
definition, and paid for each closing: CI's benchmark gate found it 5% slower
than main (p = 0.008). `exclusionsGo` now walks the claims already paired with
their closed meanings (`HasMeanings.shapedUnder`), and `exclusionsUnder_eq`
still proves the list the pairwise definition's.

Against main, five interleaved rounds: the ontology check 3.16 s to 1.69 s
(-47%, p = 0.008); the sola fide exclusions 45.4 s to 10.6 s (-77%,
p = 0.008), 3.43 to 1.06 GiB. Ledger round 7 updated; the citation check's
pin moves to 2319 definitions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BC49XsbtehCbmJMavF1K5Q
@deanberris
deanberris marked this pull request as ready for review November 2, 2026 06:47
@deanberris
deanberris merged commit 2e3e72e into main Nov 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants