Logic and Planning/Inference in First-Order Logic

Lesson 3.53,062 words

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.

Propositionalization instantiates a quantified axiom at every ground term. With a function symbol the set of ground terms is infinite — , , , ... — so the propositional KB never finishes generating.

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 most general unifier of and is , sitting above every other unifier — each of which (like the fully-ground ) is obtained from it by a further substitution.

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.

Algorithm:Unify(x,y,θ)\textsc{Unify}(x, y, \theta)return an MGU of xx and yy, or failure
  1. 1
    input: xx, yy, expressions (variable, constant, list, or compound)
  2. 2
    input: θ\theta, the substitution built so far (defaults to empty)
  3. 3
    if θ=failure\theta = failure then return failure
  4. 4
    else if x=yx = y then return θ\theta
  5. 5
    else if xx is a variable then return Unify-Var(x,y,θ)\textsc{Unify-Var}(x, y, \theta)
  6. 6
    else if yy is a variable then return Unify-Var(y,x,θ)\textsc{Unify-Var}(y, x, \theta)
  7. 7
    else if xx and yy are compound then
  8. 8
    return Unify(Args(x),Args(y),Unify(Op(x),Op(y),θ))\textsc{Unify}(\text{Args}(x), \text{Args}(y), \textsc{Unify}(\text{Op}(x), \text{Op}(y), \theta))
  9. 9
    else if xx and yy are lists then
  10. 10
    return Unify(Rest(x),Rest(y),Unify(First(x),First(y),θ))\textsc{Unify}(\text{Rest}(x), \text{Rest}(y), \textsc{Unify}(\text{First}(x), \text{First}(y), \theta))
  11. 11
    else return failure
  12. 12
  13. 13
    function Unify-Var(var,x,θ)\textsc{Unify-Var}(var, x, \theta)
  14. 14
    if {var/val}θ\{var/val\} \in \theta then return Unify(val,x,θ)\textsc{Unify}(val, x, \theta)
  15. 15
    else if {x/val}θ\{x/val\} \in \theta then return Unify(var,val,θ)\textsc{Unify}(var, val, \theta)
  16. 16
    else if Occur-Check(var,x)\textsc{Occur-Check}(var, x) then return failure
  17. 17
    else return θ\theta with {var/x}\{var/x\} 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.

  1. 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 .
  2. 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.

The recursion of . The top call splits into operator and two argument unifications; grows left to right, established at the first argument feeding into the second, where binds to . The inset shows the occur check rejecting against .

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 subsumption lattice for . The most general pattern sits at the top; each downward edge instantiates one argument, until the fully ground fact sits at the bottom. A query is one node of this lattice, and its matches are the facts filed at or below 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.

The proof tree forward chaining builds for the crime example. Initial facts sit at the bottom; facts inferred on the first iteration in the middle; , inferred on the second, at the top. Each node is joined to the premises that produced it.

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.

Algorithm:FOL-FC-Ask(KB,α)\textsc{FOL-FC-Ask}(KB, \alpha) — data-driven forward chaining
  1. 1
    input: KBKB, a set of first-order definite clauses; α\alpha, the atomic query
  2. 2
    locallocal: newnew, the sentences inferred on each iteration
  3. 3
    repeat
  4. 4
    new{}new \gets \{\,\}
  5. 5
    for each rule (p1pn    q)(p_1 \land \cdots \land p_n \implies q) in KBKB do
  6. 6
    standardize the variables of the rule apart
  7. 7
    for each θ\theta with Subst(θ,p1pn)=Subst(θ,p1pn)\textsc{Subst}(\theta, p_1 \land \cdots \land p_n) = \textsc{Subst}(\theta, p_1' \land \cdots \land p_n') do
  8. 8
    for some p1,,pnp_1', \ldots, p_n' already in KBKB
  9. 9
    qSubst(θ,q)q' \gets \textsc{Subst}(\theta, q)
  10. 10
    if qq' does not unify with any sentence in KBKB or newnew then
  11. 11
    add qq' to newnew
  12. 12
    ϕUnify(q,α)\phi \gets \textsc{Unify}(q', \alpha)
  13. 13
    if ϕfailure\phi \ne failure then return ϕ\phi
  14. 14
    add newnew to KBKB
  15. 15
    until newnew is empty
  16. 16
    return 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.

The goal tree backward chaining builds to prove , read depth-first, left to right. Each conjunct of rule is a subgoal; the binding found for one is threaded into the next, so by the time is reached, is already bound to . Braces show the substitution returned.

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.

Algorithm:FOL-BC-Ask(KB,query)\textsc{FOL-BC-Ask}(KB, query) — goal-driven backward chaining
  1. 1
    input: KBKB, definite clauses; queryquery, the atomic goal
  2. 2
    return FOL-BC-Or(KB,query,{})\textsc{FOL-BC-Or}(KB, query, \{\,\})
  3. 3
  4. 4
    function FOL-BC-Or(KB,goal,θ)\textsc{FOL-BC-Or}(KB, goal, \theta)
    yields substitutions
  5. 5
    for each rule (lhs    rhs)(lhs \implies rhs) in Fetch-Rules(KB,goal)\textsc{Fetch-Rules}(KB, goal) do
  6. 6
    standardize (lhs,rhs)(lhs, rhs) apart
  7. 7
    for each θ\theta' in FOL-BC-And(KB,lhs,Unify(rhs,goal,θ))\textsc{FOL-BC-And}(KB, lhs, \textsc{Unify}(rhs, goal, \theta)) do
  8. 8
    yield θ\theta'
  9. 9
  10. 10
    function FOL-BC-And(KB,goals,θ)\textsc{FOL-BC-And}(KB, goals, \theta)
    yields substitutions
  11. 11
    if θ=failure\theta = failure then return
  12. 12
    else if goalsgoals is empty then yield θ\theta
  13. 13
    else
  14. 14
    first,restFirst(goals),Rest(goals)first, rest \gets \textsc{First}(goals), \textsc{Rest}(goals)
  15. 15
    for each θ\theta' in FOL-BC-Or(KB,Subst(θ,first),θ)\textsc{FOL-BC-Or}(KB, \textsc{Subst}(\theta, first), \theta) do
  16. 16
    for each θ\theta'' in FOL-BC-And(KB,rest,θ)\textsc{FOL-BC-And}(KB, rest, \theta') do
  17. 17
    yield θ\theta''

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

prolog
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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. Russell & Norvig, AIMA, §9.2.2 — Unification: returning a substitution with , the four examples, and the occur check making the algorithm quadratic.
  6. 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.
  7. 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.
  8. 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.
  9. 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.
  10. 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.
  11. 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 ╌╌