Inference in First-Order Logic
Propositional inference lifts to first-order logic once we can make terms match. Unification is that machinery: the algorithm that finds the substitution making two expressions identical, and the basis of generalized modus ponens.
╌╌╌╌
First-order logic
gave us a language with variables, quantifiers, functions, and relations — enough
to say all greedy kings are evil
in one sentence instead of one per king. The
question this lesson answers is procedural: given a knowledge base written in
that language and a query, how does a machine decide whether the query follows?
The propositional machinery of the previous module already gives sound and
complete inference for the quantifier-free case.1 The whole task is to
lift it to sentences that quantify over objects — and the single piece of new
machinery that makes the lift work is unification, the algorithm that makes
two terms match.
Lifting propositional inference
Start with the standard folkloric axiom, that greedy kings are evil,
together with the facts and . A human sees at once that follows. To make a machine see it, the first idea is to strip the quantifier by substituting ground terms for the variable.
Substituting turns the axiom into the propositional implication , and now propositional modus ponens finishes the job. Existentials are handled by a dual rule, but with a twist: the object the existential asserts must be given a fresh name.
From we may infer as long as is new. Giving the object the name of an existing constant — say , when we only know some number just above exists — would assert a falsehood.2 Universal instantiation can be applied repeatedly and the original kept; existential instantiation is applied once and the existential discarded. The result is not logically equivalent to the original, but it is inferentially equivalent: satisfiable exactly when the original is.
Applying universal instantiation to every ground term reduces first-order inference to propositional inference — a technique called propositionalization. Replace each universally quantified sentence by the set of all its ground instances, view each ground atom like as a propositional symbol, and run any complete propositional algorithm.3 It works, and by a theorem of Herbrand (1930) any entailed sentence has a proof using only a finite subset of the instantiations, so we can enumerate ground terms by increasing nesting depth until the proof appears. But there is a catch.
The moment the knowledge base mentions a function symbol like , the set of ground terms is infinite, and the propositional knowledge base never finishes generating. Worse, if the query is not entailed, the procedure can run forever without ever knowing whether it is stuck or one step from a proof. This is a fundamental limit: entailment in first-order logic is semidecidable.4 There is an algorithm that says yes to every entailed sentence, but none that also says no to every non-entailed one — the first-order analogue of the halting problem, proved independently by Turing and Church in 1936.
Unification
Propositionalization is also wasteful. To prove from the axiom and the two facts about John, it generates and every other irrelevant instance. A human never does this. A human matches the pattern against the known facts, reads off that must be , and infers only . Unification is that matching step made precise.
The substitution unifies with . A substitution binds variables to terms; applying it replaces each variable by its bound term throughout the expression. Some queries have richer answers. To answer — whom does John know? — we unify it against every fact in the base:5
The last one fails, and the reason is instructive: is asked to be (to
match the first argument) and (to match the second) at once. Yet
means everyone knows Elizabeth,
so John surely knows her —
the failure is an accident of the two sentences reusing the variable name . The
fix is standardizing apart: rename one sentence's variables before unifying,
turning the second into , after which
succeeds.6
The most general unifier
When a pair unifies at all, it usually unifies in many ways. admits , which leaves the result as , and also , which pins everything to . The first is more general: it constrains the variables less, and every other unifier is an instance of it. For any unifiable pair there is a single most general unifier (MGU), unique up to renaming, and it is what returns.
The algorithm walks the two expressions in step, side by side.
Constants must
match; a variable matched against a term binds to it (consulting so
earlier bindings stay consistent); two compound expressions recurse on their
function symbol and argument lists.7 One step has its own name. When
binding a variable to a compound term, we must check that the variable does not
occur inside that term: cannot unify with , because no finite
substitution makes equal to . This is the occur check, and it is what
makes unification's cost quadratic rather than linear in the size of the terms.
Most Prolog systems omit it for speed, at the price of occasionally unsound
inferences.
- 1input: , , expressions (variable, constant, list, or compound)
- 2input: , the substitution built so far (defaults to empty)
- 3if then return failure
- 4else if then return
- 5else if is a variable then return
- 6else if is a variable then return
- 7else if and are compound then
- 8return
- 9else if and are lists then
- 10return
- 11else return failure
- 12
- 13function
- 14if then return
- 15else if then return
- 16else if then return failure
- 17else return with added
To see the recursion concretely, trace from the empty substitution. The two expressions are compound, so the top call recurses on operator and arguments. The operator unifies with itself, leaving empty; then the argument lists are unified element by element, threading through each step.
- First arguments. . Here is a variable and is not, so runs; is unbound, is not a variable, the occur check on a constant is vacuous, and the binding is added. Now .
- Second arguments. . Now is a variable, so runs. is unbound and is not in the domain of . The occur check asks whether appears inside ; it does not, so the binding is added.
The returned substitution is , matching the third line of the table above. Applying it to either expression yields .
Now trace the occur check on a failing pair. Unifying with — a variable against a term that contains it — reaches ; is unbound and is not in , but walks into the argument of , finds , and returns true, so the whole call returns failure. No finite term equals , and the check is what prevents the algorithm from binding to an infinite structure.
Storing and retrieving clauses
Every inference step above ends by asking the knowledge base a question: which stored facts unify with this pattern? Done naively, answering it means attempting against every sentence in the base, and for a large base that scan dominates the running time. The fix is to index the clauses so that only plausible matches are ever tested.8
The coarsest useful scheme is predicate indexing: keep a separate bucket per predicate symbol, so a query on never touches the facts. When a single predicate holds most of the base — for every employee in a company, queried both by employer and by employee — a finer index on argument positions helps, at the cost of maintaining more index keys. The tradeoff is the standard database one: more keys make retrieval faster and updates slower.
The general structure behind such schemes is the subsumption lattice. A literal subsumes when some substitution turns into , so is the more general pattern. The queries that could match a stored fact are exactly its subsumers, and they form a lattice ordered by generality: the fact itself at the bottom, the all-variables pattern at the top, and partially-instantiated patterns in between. To answer a query, walk down from the query pattern collecting the facts filed beneath it.
The lattice grows quickly: a fact with arguments has subsumers, so indexing every fact under all of them is only worthwhile when is small, which for most predicates it is.
Generalized modus ponens
Unification lets us state a single inference rule that does all the work of matching and firing an implication in one lifted step. Suppose the axiom is and we know and — being more ambitious — , that everyone is greedy. We want . The substitution makes the premises and identical to the known and at once, so we may assert the conclusion under .
This is a lifted rule — it raises ordinary modus ponens from ground propositional logic to first-order logic. Its soundness is quick: for any sentence with universally quantified variables, by universal instantiation, so the lifted step is just a ground modus ponens hiding behind the substitution. What it gains over propositionalization is that it makes only the substitutions the proof needs, never the irrelevant ones.
Forward chaining
Generalized modus ponens is the atom of inference; the two chaining algorithms are strategies for applying it. Forward chaining is data-driven: start from the known facts, fire every rule whose premises are satisfied, add the conclusions, and repeat until the query appears or nothing new can be derived.9 It works on definite clauses — disjunctions of literals with exactly one positive, written as an implication whose premise is a conjunction of positive literals and whose conclusion is a single positive literal. When the clauses also contain no function symbols, the language is called Datalog, and inference is not merely semidecidable but decidable, because the set of ground facts is finite.
The crime example
The canonical worked problem: prove that Colonel West is a criminal.10
The law says it is a crime for an American to sell weapons to hostile nations. The country Nono, an enemy of America, has some missiles, and all of its missiles were sold to it by Colonel West, who is American.
Rendered as definite clauses (universal quantifiers on variables left implicit):
The existential in Nono has some missiles
is skolemized into two ground facts by
existential instantiation, introducing a new constant : and
. The rest are already ground: and . Forward chaining now sweeps the rules. On the first iteration
fires with to add ; adds ;
adds . On the second iteration rule finally fires,
with , concluding . A third pass adds
nothing — the knowledge base has reached a fixed point.
FOL-FC-ASK is easy to characterize. It is sound, being nothing but repeated generalized modus ponens, and it is complete for definite-clause knowledge bases: it derives every fact those clauses entail. For Datalog it terminates in polynomial time. A new fact is not counted as new if it is merely a renaming of an existing one — and say the same thing. With function symbols the fixed point can be infinite (the Peano axioms generate forever), so completeness again bumps into semidecidability.
- 1input: , a set of first-order definite clauses; , the atomic query
- 2: , the sentences inferred on each iteration
- 3repeat
- 4
- 5for each rule in do
- 6standardize the variables of the rule apart
- 7for each with do
- 8for some already in
- 9
- 10if does not unify with any sentence in or then
- 11add to
- 12
- 13if then return
- 14add to
- 15until is empty
- 16return false
The inner loop's cost is the matching of a rule's premise against the facts, called pattern matching, and it is where forward chaining spends its time. Ordering the conjuncts to test the most constrained one first — the conjunct ordering problem, solved heuristically much as the minimum-remaining-values rule solves constraint satisfaction — and incremental schemes like the rete network, which retains partial matches across iterations instead of recomputing them, are what make production systems run large rule sets in real time. Because forward chaining draws every entailed conclusion, including ones irrelevant to the query, it suits systems that react to newly arrived data — but wastes effort when the goal is specific.
Backward chaining
Backward chaining inverts the direction. It is goal-driven: to prove the query, find rules whose conclusion unifies with it, and recursively prove their premises.11 The search has the shape of an AND–OR tree. The OR branching is over rules: a goal can be established by any clause whose head unifies with it. The AND branching is within a rule: all of the conjuncts in its premise must be proved. On the crime knowledge base, proving unifies with the head of and spawns four subgoals — , , , — each pursued in turn, the substitution from each success carried into the next.
Because a query can succeed in several ways — might hold with and with — backward chaining is implemented as a generator that yields substitutions one at a time. FOL-BC-OR fetches each candidate rule, stands its variables apart, unifies its head with the goal, and proves the premise conjuncts through FOL-BC-AND, which threads the accumulated substitution from one conjunct to the next.
- 1input: , definite clauses; , the atomic goal
- 2return
- 3
- 4functionyields substitutions
- 5for each rule in do
- 6standardize apart
- 7for each in do
- 8yield
- 9
- 10functionyields substitutions
- 11if then return
- 12else if is empty then yield
- 13else
- 14
- 15for each in do
- 16for each in do
- 17yield
Backward chaining is a depth-first search, so its space cost is linear in the proof size, but — unlike forward chaining — it can loop on repeated subgoals and is incomplete when a branch recurses without end. Its advantage is directedness: it touches only rules relevant to the goal.
Logic programming
Backward chaining is the execution model of logic programming, and Prolog is its most widely used language. Kowalski's slogan captures the idea: a program is knowledge plus a control strategy for running inference over it,
A Prolog clause is written head-first with the implication reversed and conjuncts
comma-separated, uppercase for variables and lowercase for constants — the crime
rule reads criminal(X) :- american(X), weapon(Y), sells(X,Y,Z), hostile(Z). The
appeal is that a single relational definition runs in every direction. Given
append([], Y, Y).
append([A|X], Y, [A|Z]) :- append(X, Y, Z).
the query append(X, Y, [1,2]) asks not what is the result of appending
but
"which two lists append to give [1,2]," and yields all three splits. Prolog
departs from pure logic in ways that buy speed: it uses depth-first search with no
loop check (fast when the axioms are ordered well, incomplete otherwise), omits the
occur check (occasionally unsound), and treats negation as failure to prove. These
are the compromises between declarativeness and efficiency that make it a practical
language rather than a theorem prover.
Where this continues
Forward and backward chaining are complete only for definite clauses — Horn knowledge bases, where every rule has a single positive conclusion. Real first-order knowledge has disjunctions and negations that Horn form cannot express, and for those we need one more inference rule: a single sound and complete procedure for all of first-order logic.
This continues in First-Order Resolution, which converts arbitrary sentences to CNF by skolemizing away the existentials, lifts the resolution rule with unification, and refutes the negated goal — the proof system Gödel showed is complete for first-order entailment.
Footnotes
- Russell & Norvig, AIMA, Ch. 9 — introduction: Chapter 7 established sound and complete propositional inference; Chapter 9 extends it to first-order logic via inference rules for quantifiers, unification, and the forward-chaining, backward-chaining, and resolution families. ↩
- Russell & Norvig, AIMA, §9.1.1 — Inference rules for quantifiers: universal instantiation over ground terms, existential instantiation with a fresh Skolem constant, and inferential (not logical) equivalence of the resulting knowledge base. ↩
- Russell & Norvig, AIMA, §9.1.2 — Reduction to propositional inference: replacing a universally quantified sentence by all its ground instances, propositionalization, and Herbrand's theorem guaranteeing a finite sufficient subset. ↩
- Russell & Norvig, AIMA, §9.1.2 — the semidecidability of first-order entailment: algorithms say yes to every entailed sentence but none says no to every non-entailed one, the analogue of Turing's and Church's 1936 undecidability results. ↩
- Russell & Norvig, AIMA, §9.2.2 — Unification: returning a substitution with , the four examples, and the occur check making the algorithm quadratic. ↩
- Russell & Norvig, AIMA, §9.2.2 — standardizing apart to avoid variable-name clashes, and the most general unifier being unique up to renaming for every unifiable pair. ↩
- Russell & Norvig, AIMA, §9.2.2, Figure 9.1 — the recursive / algorithm comparing structures element by element, consulting for consistency, with the occur check on variable-to-compound bindings. ↩
- Russell & Norvig, AIMA, §9.2.3 — Storage and retrieval: predicate and argument indexing over /, the tradeoff between index keys and update cost, and the subsumption lattice with its subsumers for an -argument literal. ↩
- Russell & Norvig, AIMA, §9.3 — Forward Chaining: first-order definite clauses, Datalog and its decidability, FOL-FC-ASK (Figure 9.3), soundness and completeness, the fixed point, renaming, pattern matching, conjunct ordering, and rete/production systems. ↩
- Russell & Norvig, AIMA, §9.3.1–9.3.2 — the crime/Colonel West example: the definite-clause encoding (9.3)–(9.10), skolemizing
Nono has missiles
into , the two forward-chaining iterations, and the proof tree of Figure 9.4. ↩ - Russell & Norvig, AIMA, §9.4.1 — Backward Chaining: the AND–OR search, FOL-BC-ASK as a generator (Figure 9.6), threading substitutions through conjuncts, the goal tree of Figure 9.7, and depth-first incompleteness on repeated subgoals. ↩
╌╌ END ╌╌