Liking cljdoc? Tell your friends :D

vaelii.impl.quality

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.

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.
raw docstring

censusclj

(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.
sourceraw docstring

default-limitclj

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.
sourceraw docstring

reportclj

(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.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close