0203. 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 propositions may produce new propositions, a rule corresponds to a link from one state to another state (forward inference). Or, the propositions may remain the same, but the goals change from state to state (backward inference), as displayed by a derivation tree.

In this way, the inference process becomes a search process, starting from an initial state that corresponds to the given premises, and ending at a final state where a desired conclusion is obtained, or the other way around.

 

2. Logic and control in Prolog

A Prolog program can be seen as a simple inference system that uses given knowledge to answer questions (though it often generates side effects, as the result of procedural interpretation).

The logic part of Prolog is part of predicate calculus 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).
q(a).
q(b).
r(b).

?- trace, p(Y).
   Call: (7) p(_G157) ? creep
   Call: (8) q(_G157) ? 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(_G157) ? 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, and it stops backtracking by making the goal to fail. See tutorial for detailed explanation and example.

The built-in predicate repeat is defined using Prolog as

  repeat.
  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).
5
4
3
2
1

Yes
A recursive solution is
writeNum(0).
writeNum(N) :- write(N), nl, M is N-1, writeNum(M).
A solution using repeat is
writeNum2(N) :- assert(n(N)), repeat, writeNum, retract(n(0)).
writeNum :- retract(n(M)), write(M), nl, L is M-1, assert(n(L)).
Here is an example of file I/O in Prolog, which used the above repeat structure.