3203. Introduction to Artificial Intelligence

Search and Reasoning


1. Search as inference control

When a problem-solving process is represented as state-space search, there are usually several ways to represent the states. One of them is to use predicate calculus, so that each state corresponds to a set of propositions.

Since applying an inference rule to a set of promises may produce new promises, a rule corresponds to a link from one state to another state (forward inference). Or, the promises may remain the same, but the desired conclusions change from state to state (backward inference), as displayed by a derivation tree. The two directions can be combined, as in refutation.

In this way, the inference process becomes a search process, with the logic responsible for the specifications of the states and valid state trnasitions, and search stragety for the selection of premises and rules in each step.


2. Logic and control in Prolog

A Prolog program can be seen as a simple inference system that uses given knowledge to answer questions (declaritive interpretation) and to achieve goals (procedural interpretation).

The logic part of Prolog is part of predicate calculus (resolution on Horn clauses) plus procedural interpretation of certain predicates. The control part of Prolog, roughly speaking, is a depth-first search algorithm.

As other depth-first search algorithms, Prolog uses backtracking to "undo" unsuccessful unifications. For example,

p(X) :- q(X), r(X).

?- trace, p(Y).
   Call: (7) p(_G2953) ? creep
   Call: (8) q(_G2953) ? creep
   Exit: (8) q(a) ? creep                /* try a/X first, works for q */
   Call: (8) r(a) ? creep
   Fail: (8) r(a) ? creep                /* but doesn't work for r */
   Redo: (8) q(_G2953) ? creep           /* backtracking */
   Exit: (8) q(b) ? creep                /* try b/X */
   Call: (8) r(b) ? creep
   Exit: (8) r(b) ? creep
   Exit: (7) p(b) ? creep
Y = b.

3. Prolog control predicates

In Prolog, there are ways to modify the default control mechanism (depth-first search).

The built-in predicate "cut" (exclamation point, !) always succeeds as a fact, but when there is a later attempt to backtrack, the goal will simply fail. The system won't even try other rules. For example,

p(X) :- q(X), !, r(X).
p(X) :- s(X).

?- trace, p(Y).
   Call: (7) p(_G2953) ? creep
   Call: (8) q(_G2953) ? creep
   Exit: (8) q(a) ? creep
   Call: (8) r(a) ? creep
   Fail: (8) r(a) ? creep
   Fail: (7) p(_G2953) ? creep

See tutorial for detailed explanation and example.

The built-in predicate repeat is defined using Prolog as

  repeat :- repeat.
Consequently, repeat will always succeed when called, as well as on backtracking. It is usually used the right-hand-side of a rule in the following structure:
  ..... :- repeat,
           (code to be repeated),
           (ending condition),
Example: writeNum(N) will write N, N-1, ..., 1, such as
?- writeNum(5).
A recursive solution is
writeNum(0) :- !.
writeNum(N) :- write(N), nl, M is N-1, writeNum(M).
To produce the same solution using repeat:
writeNum2(N) :- assert(n(N)), repeat, writeNum, retract(n(0)), !.
writeNum :- retract(n(M)), write(M), nl, M > 0, L is M-1, assert(n(L)).
Here are the example of file I/O in Prolog, which used the above repeat structure.