Five readings about the knowledge, where the rest of the instrumentation reads the engine: which rules never fire, how skewed the predicate extents are, how deep the rule graph's chains reach, how much of the taxonomy is connected to anything, and which argument declarations name a position their predicate does not have.
settle-stats and chain-stats answer how the engine ran. These answer whether the
knowledge is any good, which is the question the author of a large KB has and the one
nothing else here asks. None of it is a gate: a threshold on somebody's ontology is not
a build failure, and lein perf gates the engine while this reports on the content.
Every reading comes off state that already exists, and nothing new is indexed. A
rule -> firings index would be a second copy of the JTMS adjacency to keep in step,
which is the failure class the taxonomy's single :support map exists to avoid. So the
cost is
O(terms + rules + firings + ancestor pairs + declarations × super-predicates) and never
O(sentexes) — the vocabulary, which on a KB of a million facts about a hundred
individuals is a hundred-odd names. Ancestor pairs and not edges, which is the term
worth spelling out: taxonomy-coverage reads each type's whole genl up-closure to find
the root, so a chain of V types costs Θ(V²) where it has V−1 edges. Vocabulary-sized on
any ontology anybody writes, which is the claim that matters, and not an edge count:
:consequences adjacency, the candidate
set jtms/restrength-informant* uses, and never scans the justification map. At
11.5M justifications that difference is the report existing or not.(genl ?a ?b) & (genl ?b ?c) => (genl ?a ?c) alone
makes it so — so memoizing a path re-explores the reachable subgraph along every one
of them. Memoize the component.× super-predicates above and the
one term of the formula that is not flat. It is also the second reader of the record
store, for the declarations themselves — vocabulary, and therefore few.Every count is of what is stored. A believed extent is O(n) per predicate
(vaelii.core/count-with-functor says why), which would turn an O(predicates) report
into an O(sentexes) one — and stored-vs-believed is exactly the distinction an author
wants to see rather than have chosen for them. Two readings consult belief anyway: the
firing census, because "fired and every conclusion defeated" is a category and not a
rounding error, and the declaration census, because a disbelieved declaration constrains
nothing for a reason that has nothing to do with the position it names.
Five readings about the **knowledge**, where the rest of the instrumentation reads the engine: which rules never fire, how skewed the predicate extents are, how deep the rule graph's chains reach, how much of the taxonomy is connected to anything, and which argument declarations name a position their predicate does not have. `settle-stats` and `chain-stats` answer *how the engine ran*. These answer *whether the knowledge is any good*, which is the question the author of a large KB has and the one nothing else here asks. None of it is a gate: a threshold on somebody's ontology is not a build failure, and `lein perf` gates the engine while this reports on the content. **Every reading comes off state that already exists, and nothing new is indexed.** A `rule -> firings` index would be a second copy of the JTMS adjacency to keep in step, which is the failure class the taxonomy's single `:support` map exists to avoid. So the cost is `O(terms + rules + firings + ancestor pairs + declarations × super-predicates)` and never `O(sentexes)` — the **vocabulary**, which on a KB of a million facts about a hundred individuals is a hundred-odd names. **Ancestor pairs and not edges**, which is the term worth spelling out: `taxonomy-coverage` reads each type's whole `genl` up-closure to find the root, so a chain of V types costs Θ(V²) where it has V−1 edges. Vocabulary-sized on any ontology anybody writes, which is the claim that matters, and not an edge count: - **One walk over the term roster**, and one is the number: the functor names come off it by filter, and the type-shaped names come off *those* rather than off the roster a second time. Measured at 8x the terms for 8x the cost, so the walk is the term the formula above leads with. - **Three O(1) index reads per functor name** — the stored extent off the count-aware trie, and the rule postings *both* ways. That is everything the extent and chain readings need, and it is where the rule handles come from, so nothing on this pass reaches the record store beyond the handful of rules the report actually lists. - **The firing census reads each rule's own `:consequences` adjacency**, the candidate set `jtms/restrength-informant*` uses, and never scans the justification map. At 11.5M justifications that difference is the report existing or not. - **The chain depth condenses strongly-connected components first.** A KB's rule graph is cyclic in the ordinary case — `(genl ?a ?b) & (genl ?b ?c) => (genl ?a ?c)` alone makes it so — so memoizing a *path* re-explores the reachable subgraph along every one of them. Memoize the component. - **The declaration census enumerates the declarations** and asks each what binds its own predicate's length, rather than asking every predicate what declares it. That is a map read where the predicate carries a length of its own and one arity read per super-predicate where it inherits one, which is the `× super-predicates` above and the one term of the formula that is not flat. It is also the second reader of the record store, for the declarations themselves — vocabulary, and therefore few. Every count is of what is **stored**. A believed extent is O(n) per predicate (`vaelii.core/count-with-functor` says why), which would turn an O(predicates) report into an O(sentexes) one — and stored-vs-believed is exactly the distinction an author wants to see rather than have chosen for them. Two readings consult belief anyway: the firing census, because "fired and every conclusion defeated" is a category and not a rounding error, and the declaration census, because a disbelieved declaration constrains nothing for a reason that has nothing to do with the position it names.
(census kb {:keys [limit on-progress]})The five readings as one map — {:rules … :extents … :chains … :taxonomy … :declarations …}. vaelii.core/kb-quality is the door and documents the options.
The five readings as one map — `{:rules … :extents … :chains … :taxonomy …
:declarations …}`. `vaelii.core/kb-quality` is the door and documents the options.How many rules and how many heavy predicates the report lists before it says it
truncated. A cap rather than the whole set because the counts are the headline and a
30,000-entry list is not one; :limit raises it.
How many rules and how many heavy predicates the report lists before it says it truncated. A cap rather than the whole set because the *counts* are the headline and a 30,000-entry list is not one; `:limit` raises it.
(report {:keys [rules extents chains taxonomy declarations] :as quality})The census map as Markdown — the five readings in the order an author reads them,
the counts first and the lists after. A map that is not a census answer is refused
(:not-a-report) rather than rendered as a page of zeros, which is what a caller passing
the wrong map would otherwise be handed and believe.
:declarations is not in the shape test, and that is deliberate: a census answer
from before this reading existed is still a census answer, and refusing to render one
would turn a stored report into an unreadable one. The section is written when the key
is there and omitted when it is not, and a listed entry's reason line is the :message
the census carries rather than a second derivation of it — which would be the same
sentence written twice, free to drift on either side.
The `census` map as Markdown — the five readings in the order an author reads them, the counts first and the lists after. A map that is not a `census` answer is refused (`:not-a-report`) rather than rendered as a page of zeros, which is what a caller passing the wrong map would otherwise be handed and believe. `:declarations` is **not** in the shape test, and that is deliberate: a census answer from before this reading existed is still a census answer, and refusing to render one would turn a stored report into an unreadable one. The section is written when the key is there and omitted when it is not, and a listed entry's reason line is the `:message` the census carries rather than a second derivation of it — which would be the same sentence written twice, free to drift on either side.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |