This page provides sample programs for selected examples described in Wolfgang Ertel’s Introduction to Artificial Intelligence. The programs are intended only for running and comparing their output with the corresponding descriptions in the book.
The required programs are already installed in the development environment of the public repository VNU-HUS-IntroAI-Exercises.
The file chapter3.zip contains the following files:
| File | Description |
|---|---|
halbgr1.lop |
Solving the mathematical example in Section 3.7 by the E theorem prover |
halbgr2.lop |
Improving halbgr1.lop by using the power of the built-in “equality” in E instead of the predicate eq |
proof.sh |
All *.lop files are for the E theorem prover and can be run with the command bash proof.sh <filename>. |
Create a directory for the sample code, change to that directory, and download the ZIP file for Chapter 3 from this course website:
mkdir -p ~/MAT3508/samplecode
cd ~/MAT3508/samplecode
wget -nc https://hoanganhduc.github.io/teaching/VNU-HUS/2026/winter/MAT3508/samplecode/chapter3.zip
Extract the ZIP file:
unzip -o chapter3.zip
The ZIP file can also be downloaded directly: chapter3.zip.
Change to the directory containing the Chapter 3 files before running them:
cd ~/MAT3508/samplecode/chapter3
The script proof.sh is a wrapper for eprover. When it receives the name of a .lop file, it runs:
eprover --proof-object <filename> | epclextract
The option --proof-object asks E to include a proof object in its output. The pipe sends that output to epclextract, which extracts the generated proof. Therefore, proof.sh does not implement a separate prover; it provides a shorter way to run the same eprover and epclextract pipeline.
proof.shbash proof.sh halbgr1.lop
bash proof.sh halbgr2.lop
eprover directlyeprover --proof-object halbgr1.lop | epclextract
eprover --proof-object halbgr2.lop | epclextract
The first file represents equality by the predicate eq; the second uses the built-in equality of E. Compare the generated proofs with the discussion in Section 3.7 of the book. The command described as eproof in the book is no longer available.
The file chapter5.zip contains the following files:
| Files | Description |
|---|---|
rel.pl, rel01.pl, rel02.pl |
Different versions of a PROLOG program to solve the family relationships example (Section 5.2). The first version is rel.pl. Line 8 of this version, child(X,Z,Y) :- child(X,Y,Z)., is a recursive definition which may cause the program to run forever. In rel01.pl, this issue is resolved, but the new issue is that the symmetry of child as described in line 8 before is no longer given. The final version rel02.pl resolves both issues. |
max.pl, maxwCut.pl |
Illustrating the cut operation in PROLOG (Section 5.3) |
append.pl |
A PROLOG implementation of the predicate append(X, Y, Z) that appends the list Y to the list X and saves the result to the list Z (Section 5.4) |
nrev.pl, accrev.pl |
Two PROLOG implementations for the task of reversing a list. nrev.pl is an implementation of the naive reverse algorithm—which is very inefficient due to calling append. accrev.pl is a more efficient implementation using a temporary store, known as the accumulator (Section 5.4) |
dynamic_rel.pl |
A dynamic version of the PROLOG program used in the family relationships example. This is an example illustrating the use of the built-in asserta PROLOG predicate to insert the derived facts to the beginning of the knowledge base to avoid a repeated derivation |
plan.pl, plan1.pl |
Fig. 5.4, the first version of a PROLOG program to solve the famous farmer-wolf-goat-cabbage problem. plan1.pl is the same as plan.pl but having extra comments to explain the code in details |
raumplan.pl |
Fig. 5.5, A GNU-PROLOG program for solving the room scheduling problem in Example 5.2. This is also an example illustrating the use of Constraint Logic Programming (CLP) |
Create a directory for the sample code, change to that directory, and download the ZIP file for Chapter 5 from this course website:
mkdir -p ~/MAT3508/samplecode
cd ~/MAT3508/samplecode
wget -nc https://hoanganhduc.github.io/teaching/VNU-HUS/2026/winter/MAT3508/samplecode/chapter5.zip
Extract the ZIP file:
unzip -o chapter5.zip
The ZIP file can also be downloaded directly: chapter5.zip.
Change to the directory containing the Chapter 5 files before starting PROLOG:
cd ~/MAT3508/samplecode/chapter5
Enter halt. at a PROLOG prompt to exit the current session before loading a different version of a program.
Each SWI-Prolog example below shows two ways to load the program:
[filename]. at the PROLOG prompt.In the second method, ?- is the SWI-Prolog prompt and should not be typed as part of the query.
swipl -q -s rel.pl
?- child(oscar, X, Y).
swipl
?- [rel].
?- child(oscar, X, Y).
Enter ; to request further answers. Enter halt. and start a new session with rel01.pl, then with rel02.pl, using either of the two methods above. For example, the step-by-step method for rel01.pl is:
?- [rel01].
?- child(oscar, X, Y).
Compare the behavior of the three versions. In rel.pl, the recursive definition of child/3 may continue indefinitely. rel01.pl avoids that recursion but does not retain the symmetry of child/3; rel02.pl uses child_fact/3 to retain the symmetry without the same recursive definition.
swipl -q -s max.pl
?- max(3, 2, M).
swipl
?- [max].
?- max(3, 2, M).
Enter halt. and repeat with maxwCut.pl, using either swipl -q -s maxwCut.pl or [maxwCut].. Compare the definitions with the discussion of the cut operation in Section 5.3.
The predicates in nrev.pl call append/3, so load append.pl, nrev.pl, and accrev.pl in the same session.
swipl -q -g "['append.pl', 'nrev.pl', 'accrev.pl']"
?- append([a, b], [c, d], L).
?- nrev([a, b, c], R).
?- accrev([a, b, c], [], R).
swipl
?- [append, nrev, accrev].
?- append([a, b], [c, d], L).
?- nrev([a, b, c], R).
?- accrev([a, b, c], [], R).
Compare the two implementations of list reversal described in Section 5.4.
swipl -q -s dynamic_rel.pl
?- descendant(eve, karen).
?- listing(descendant/2).
swipl
?- [dynamic_rel].
?- descendant(eve, karen).
?- listing(descendant/2).
The second query displays the descendant/2 facts inserted by asserta/1 during the first query.
The predicate plan/4 in plan.pl can be called directly after loading the file.
swipl -q -s plan.pl
?- plan(state(left,left,left,left), state(right,right,right,right), [state(left,left,left,left)], Path).
swipl
?- [plan].
?- plan(state(left,left,left,left), state(right,right,right,right), [state(left,left,left,left)], Path).
The predicate start/0 currently calls write_path/1, which is not defined in plan.pl. To display a generated path with start., replace write_path(Path). by:
write(Path).
Run start. and observe the first path. Then try the following version and run start. again:
write(Path), fail.
The second version forces backtracking and displays all generated paths. The file plan1.pl already uses write(Path), fail.. It can be loaded directly from the command line:
swipl -q -s plan1.pl
?- start.
Alternatively, load it step by step from inside SWI-Prolog:
swipl
?- [plan1].
?- start.
raumplan.pl must be run with GNU Prolog.
gprolog --consult-file raumplan.pl
| ?- start.
gprolog
| ?- [raumplan].
| ?- start.
Compare the result with the room scheduling problem in Example 5.2 and Figure 5.5 of the book.