Soundness and Completeness: Why the Rules Suffice
📍 Where we are: Part III · The EL Completion Algorithm — Chapter 10. Completion Rules handed us the six firing rules — CR1–CR4, the bottom rule CR⊥, and the role-chain rule CRχ — and watched them grow the two tables and to a fixpoint on the academic world. Now we ask the question that turns a clever loop into a reasoner: do those rules derive exactly the subsumptions that genuinely follow, no more and no fewer?
The completion algorithm is built, and it runs. But "it runs and the answers look right" is a hope, not a guarantee — a single passing example proves nothing about the next ontology. This chapter replaces the hope with a proof. We name the three properties a rule set must have before anyone may call it a decision procedure, argue that EL completion has all three, and then do the one thing a paper proof cannot do: run the from-scratch reasoner beside a production one and watch them agree, entry for entry.
Imagine hiring an inspector to certify a bridge before it opens. You need three separate promises before you trust the final stamp. First, the inspector never condemns a sound cable — no false alarms that shut a good bridge. Second, the inspector never walks past a frayed one — no misses. Third, the inspection actually finishes, by opening day, instead of pacing the deck forever. Only all three at once make the report worth acting on: an inspector who cries wolf, or overlooks a fault, or never comes back down is useless. A reasoner is that inspector, the class hierarchy is its report, and this chapter is the argument that our inspector has all three virtues — plus a second, independent inspector who checks the first.
What this chapter covers
- Three properties, one decision procedure — soundness (no false positives), completeness (no false negatives), and termination (always halts); only together do they license reading entailment off the table.
- Soundness, worked for CR4 — every rule preserves truth in every model, shown as a single display implication over the description-logic semantics.
- Completeness by canonical model — the saturated and are a model of the TBox that falsifies every subsumption the rules did not derive, so anything entailed must have been derived.
- Termination and the polynomial bound — and only grow, inside a ceiling fixed by the number of names and pairs, so the fixpoint arrives in polynomially many steps.
- The empirical cross-check —
reasoners.pypitsclassify()against HermiT and both land on 8 subsumptions and the same 2 unsatisfiable concepts. - Why an independent oracle matters — HermiT is a complete OWL 2 DL reasoner over a strict superset of EL, so its agreement is the strongest external check the from-scratch code can get.
Three properties, one decision procedure
Fix the vocabulary first. A TBox is the set of schema axioms (our academic world has 14 of them); a subsumption reads "every is a ." The question a classifier answers is entailment, written and read "the TBox entails ": it means the subsumption holds in every interpretation that obeys — there is no possible world consistent with the axioms in which some fails to be a . Completion answers this semantic question by a purely syntactic move: it fires rules until the table stops growing, then reports precisely when . That read-off is one line — return sup in S.get(sub, set()) (el_completion.py line 324).
For that syntactic test to mean the semantic entailment, three properties must line up. Naming them precisely is the whole discipline:
| Property | Plain meaning | What breaks without it | How EL completion secures it |
|---|---|---|---|
| Soundness | derives only entailed subsumptions — no false positives | the reasoner "proves" falsehoods; every answer is suspect | an invariant every rule preserves in every model [1] |
| Completeness | derives every entailed subsumption — no false negatives | the reasoner misses real consequences; silence stops meaning "does not follow" | a canonical model satisfying that falsifies every non-derived subsumption [2] |
| Termination | the saturation loop always halts | the answer can never be read off , because "done" never arrives | and grow monotonically inside a polynomial ceiling |
Only all three together earn the phrase decision procedure: an algorithm that, for every input, halts with the correct yes-or-no answer. Soundness and completeness are the correctness half, and they collapse into one clean biconditional,
whose left-to-right direction (, read "implies") is soundness and whose right-to-left direction () is completeness. One caveat keeps this honest: read the biconditional over the satisfiable names , those with . When is unsatisfiable (), the right side is vacuously true — holds for every by ex falso, since an empty concept is a subset of anything — yet the algorithm does not flood with every name; it reports apart as unsatisfiable, the separate job of the bottom rule. Termination is the third leg: it guarantees the left side is ever actually computed. The reasoner's own docstring states the target outright — "The algorithm is sound and complete for EL++ subsumption, and runs in time polynomial in the size of the TBox" (el_completion.py lines 38–39). Read that "EL++" against the constructors the academic world actually uses — conjunction, existentials, ⊥, and role chains, the tractable core that the six rules here decide; full EL++ additionally admits nominals and concrete domains, whose own completion rules this ontology never exercises. The rest of this chapter is why that sentence is true.
A decision procedure stands on three columns — soundness, completeness, termination — that together license the biconditional at its crown, while the cross-check against HermiT is the handshake beneath that corroborates the whole structure.
Original diagram by the authors, created with AI assistance.
Soundness: every rule preserves truth
Soundness says the rules never lie. The argument is one sturdy idea: keep an invariant that ties every syntactic entry to a semantic fact, and check that each rule preserves it.
First the semantics, decoded before any symbols. An interpretation is one possible world: it fixes a domain of individuals, reads each concept name as a set (its extension — the things that are 's in that world), and reads each role as a set of pairs . The constructors get their obvious meanings: conjunction is intersection, ("in both"), and the existential is ("the that are -related to some "). The world is a model of when it satisfies every axiom, each axiom meaning .
Now the invariant. Across the whole saturation, for every model of , we maintain:
In words: every subsumer the algorithm records is a real subsumption in every model, and every role edge it records is a real " has an -successor in " in every model. If this survives to the moment saturation stops, then forces in all models — which is exactly . So proving soundness is proving the invariant survives every rule firing.
It holds at the start: is seeded with just and (el_completion.py line 187, S = {a: {a, TOP} for a in names}), and together with are both trivially true. The inductive step checks each rule. Take CR4, the subtlest one — four lines of code plus its comment (el_completion.py lines 234–238):
# CR4: (A, B) ∈ R(r), B' ∈ S(B), ∃r.B' ⊑ C ⟹ C ∈ S(A)
for _, r, b_prime, c in nf4:
for (A, B) in list(R.get(r, ())):
if b_prime in S[B] and c not in S[A]:
S[A].add(c); changed = True
CR4 fires when three facts sit in the tables at once — , , and the axiom belongs to — and it concludes . Its soundness is the following implication, true in every model of , with each premise labelled by the table entry that guarantees it:
Read it pointwise, which is how you check it by hand. Take any individual . The first premise puts , so there is some with and . The second premise, , upgrades that witness to — so is -related to a , i.e. . The third premise, which is just the axiom holding in , then delivers . Since was arbitrary, — exactly the invariant for the newly written . The same one-model, pointwise check goes through for CR1, CR2, CR3, the bottom rule, and the role-chain rule; each simply chains the semantics of the constructor it touches. Because the invariant holds at the seed and is preserved by every firing, it holds at the fixpoint, and soundness follows [1].
Completeness: a model that falsifies everything else
Completeness is the mirror claim and the harder direction: if then the rules really did put into . By contraposition, whenever at the fixpoint, the subsumption genuinely does not follow — there must exist a model of in which some is not a . Completeness is proved by building that countermodel, once, out of the saturated tables themselves.
The construction is the canonical model , read directly off and [2]. Take one domain element for each satisfiable concept name (each with ), and define the extensions by the tables:
Two facts make this work, and both are consequences of saturation — the state in which no rule can fire any more. First, the tables are read off honestly: by construction iff . Second, is a genuine model of . This is where the completion rules earn their keep in reverse: each closure condition a model must satisfy corresponds to a rule that can no longer fire. Suppose violated an axiom — some with an -edge to a but . Unfolding the definitions, that says , , and all hold — so CR4's guard c not in S[A] would be true and the rule would still fire, contradicting that we stopped at a fixpoint. Saturation is exactly the statement that the canonical model has no such gaps; every axiom shape is guarded by the rule that would repair its violation.
The payoff is immediate, for any satisfiable name — one whose actually sits in . Since every is seeded with itself, always. So if , then yet : the canonical model is a witnessing world in which an is not a , hence . This is exactly why the domain excludes for unsatisfiable names: there holds vacuously for every (the ex-falso subsumptions again), so no countermodel exists or is wanted, and the bottom rule reports those names separately. Contrapositive: for every satisfiable , whatever is entailed was derived. One model, assembled from the saturated tables, simultaneously falsifies every non-derived subsumption between satisfiable names — that is the whole of completeness in a single object.
Termination and the polynomial bound
Correctness is worthless if the loop never stops, so termination is the third pillar — and for EL it arrives with a complexity bound as a bonus. The saturation loop is a plain while changed: that flips changed = False at the top of each pass and back to True only when a rule adds something new (el_completion.py lines 210–213):
rounds = [sizes()]
changed = True
while changed:
changed = False
Every rule adds to or and none ever removes — each is guarded by a not in test (c not in S[A], pair not in R[r]) that sets changed = True only on a genuine addition. So the tables grow monotonically, and they grow inside a fixed ceiling. Let be the set of concept names and the set of roles. Each is a subset of , and each a subset of , so the totals are capped:
A quantity that only increases and is bounded above must stabilize. Each productive pass adds at least one element to a total capped by those two ceilings, so after passes — polynomially many — nothing new appears, changed stays False, and the loop exits at the least fixpoint. Each pass itself does only polynomial work (scanning the axioms against the names), so the whole classification is polynomial in the size of the TBox — the PTIME result that lets OWL 2 EL reasoners scale to SNOMED CT and the Gene Ontology, ontologies with hundreds of thousands of concepts [1]. Our academic world reaches its fixpoint in just three rounds; the standalone run prints the climb, the sizes of and freezing the instant a pass changes nothing (python3 el_completion.py):
saturation reached a fixpoint in 3 rounds
round : |S| |R| (derived subsumers, derived role pairs)
0 : 23 0
1 : 34 7
2 : 39 7
3 : 39 7
The final row repeating the one above it — and , both unchanged — is termination made visible: round 3 fires every rule, produces nothing new, and the loop halts. That plateau is the executable form of : the moment the monotone operator maps the state to itself, the climb is over.
The empirical cross-check: from-scratch against HermiT
A proof is a meta-argument on paper; it says nothing about whether this Python faithfully implements it. A transcription slip, an off-by-one in a guard, a missing rule case — none of those show up in the mathematics. For that we need an independent witness. The companion reasoners.py rebuilds the identical academic-world ontology with owlready2, runs HermiT over it via sync_reasoner (reasoners.py line 99), calls the from-scratch classify() (line 136), and asserts that the two classifications match "entry for entry" (reasoners.py lines 139–152):
print("Reasoner (HermiT via owlready2) vs. from-scratch EL completion")
print(f" from-scratch subsumptions : {len(el_subs)}")
print(f" HermiT subsumptions : {len(r_subs)}")
print(f" from-scratch unsatisfiable: {sorted(el_unsat)}")
print(f" HermiT unsatisfiable : {sorted(r_unsat)}")
subs_agree = r_subs == el_subs
unsat_agree = r_unsat == el_unsat
...
assert subs_agree, ("subsumption mismatch", r_subs ^ el_subs)
assert unsat_agree, ("unsat mismatch", r_unsat ^ el_unsat)
print("\n AGREEMENT CONFIRMED — the from-scratch reasoner matches HermiT.")
The ^ in the assertion messages is set symmetric difference — the entries on which the two reasoners disagree — so a failure would print exactly what diverged. It never does. The committed output (python3 reasoners.py) is a clean agreement:
Reasoner (HermiT via owlready2) vs. from-scratch EL completion
from-scratch subsumptions : 8
HermiT subsumptions : 8
from-scratch unsatisfiable: ['TenuredStudent', 'TenuredStudentAdvisor']
HermiT unsatisfiable : ['TenuredStudent', 'TenuredStudentAdvisor']
subsumptions agree : True
unsatisfiable agree: True
AGREEMENT CONFIRMED — the from-scratch reasoner matches HermiT.
Both reasoners find the same 8 subsumptions — Dean ⊑ Person, Professor, Researcher; Professor ⊑ Person, Researcher; Researcher ⊑ Person; Student ⊑ Person, Researcher — and both flag the same 2 unsatisfiable concepts, TenuredStudent and TenuredStudentAdvisor, the deliberately over-constrained classes that make the bottom rule earn its keep. Two independent code paths — one written straight from the textbook completion rules, one a decade-hardened engine — arrive at an identical hierarchy.
Why an independent oracle is the strongest check
Agreement is only as convincing as the witness, and HermiT is the best available. It is a complete OWL 2 DL reasoner [3] — its decision procedure (a hypertableau calculus) is engineered for the full SROIQ description logic behind OWL 2 DL, which is a strict superset of the tiny EL fragment our completion algorithm handles. So HermiT is not a second copy of the same idea that might share the same blind spot; it decides subsumption by a completely different method over a far larger logic, and still lands on the same eight-and-two answer (reasoners.py docstring, lines 12–16: "a strict superset of EL, so agreement here is the strongest possible check"). The owlready2 distribution does not ship the EL-specialised ELK reasoner; driving the heavier, more general HermiT is deliberate, because a superset oracle agreeing is stronger evidence than a same-fragment tool agreeing — the same fragment could hide the same mistake. When a from-scratch implementation and an independent, more powerful reasoner concur on every entry, the residual chance that both are wrong in the same way is about as small as external validation gets. The proof tells us the rules are right; the oracle tells us the code is a faithful copy of the rules.
The unsolved part
Here is the honest boundary. The three-part correctness — soundness, completeness, termination — is a meta-theorem about the algorithm, not a fact the algorithm checks about itself. The reasoner classifies the ontology; it does not, and cannot from the inside, prove that its own rule set is complete for the EL fragment (with ⊥ and role chains) it implements. That proof lives in the mathematics and in our confidence in the code, and the HermiT cross-check corroborates the implementation, not the theorem: agreement on one ontology cannot certify agreement on all of them, and a bug that happens to be shared, or an ontology that quietly slips outside EL, could still fool both. The gap between "the rules are provably right" and "the machine has verified they are right on this input" is exactly the seam a proof-producing or certifying reasoner tries to close, by emitting a checkable justification alongside each answer.
And there is a broader story hiding in plain sight. Look back at how these rules work: our whole method was to derive consequences directly — start from the asserted axioms, fire truth-preserving rules, and saturate — rather than to assume the negation and hunt for a contradiction the way a tableau reasoner does. That forward, contradiction-free style has a name, consequence-based reasoning, and it is precisely what buys EL its polynomial-time guarantee. It is the last stop of this part.
Why it matters
Soundness and completeness are the entire reason the symbolic half of neuro-symbolic AI is worth its brittleness. A learned model answers every query but can be confidently wrong; a sound-and-complete reasoner answers a narrower question, but its "yes" is a guarantee and its "no" means "does not follow," full stop. That certainty is exactly what a neural approximation must be measured against: when a later differentiable or embedding-based reasoner ranks subsumptions by plausibility, the 8 exact subsumptions and 2 exact unsatisfiabilities certified here are the ground truth that says whether the soft model drifted — and the long-range unsatisfiability of TenuredStudentAdvisor, contradiction propagated backward through a role, is precisely the kind of inference soft models tend to miss. A decision procedure is the specification the learning half is trying to approximate, and you cannot tell an approximation is good without an exact answer to hold it to. Knowing the rules suffice, and knowing why, is what makes the completion algorithm usable as that yardstick rather than merely one more heuristic that happened to look right.
Key terms
- Decision procedure — an algorithm that halts on every input with the correct yes-or-no answer; for subsumption it demands soundness, completeness, and termination together.
- Soundness — derives only entailed subsumptions (); proved by an invariant every rule preserves in every model.
- Completeness — derives every entailed subsumption (, for satisfiable ); proved by a canonical model that falsifies every non-derived subsumption.
- Termination — the saturation loop always halts, because and grow monotonically inside a polynomial ceiling .
- Entailment — the subsumption holds in every model of the TBox; the semantic target the syntactic test must match.
- Canonical model — an interpretation built directly from the saturated and ; it satisfies yet witnesses the failure of everything the rules did not derive.
- Oracle (HermiT) — a complete OWL 2 DL reasoner over a strict superset of EL, used as an independent witness that the from-scratch classification is correct.
- Symmetric difference (the Python
^operator) — the set of entries on which two classifications disagree; empty here, which is why agreement is confirmed.
Where this leads
We have closed the loop on the completion algorithm: rules that are provably sound, complete, and terminating, corroborated by a production reasoner that matches them on every entry. But notice again how they work — they never guess, never assume a negation, never build a tableau and backtrack. They start from what is asserted and grind out consequences until nothing new appears, a monotone fixpoint climb. The next chapter, Consequence-Based Reasoning, gives that style its proper name and shows why deriving consequences directly, rather than searching for contradictions, is exactly what buys EL its polynomial-time classification — the same saturation trace we have been reading, seen now as one instance of a general and powerful reasoning paradigm.