Skip to content

Commit 5bef489

Browse files
committed
Search programs
1 parent d30db92 commit 5bef489

File tree

12 files changed

+674
-0
lines changed

12 files changed

+674
-0
lines changed

hanoi.pl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
% hanoi(N,A,B,C,Moves) <- Moves is the list of moves to
2+
% move N disks from peg A to peg C,
3+
% using peg B as intermediary peg
4+
hanoi(0,_,_,_,[]).
5+
hanoi(N,A,B,C,Moves):-
6+
N>0, N1 is N-1,
7+
hanoi(N1,A,C,B,Moves1),
8+
hanoi(N1,B,A,C,Moves2),
9+
append(Moves1,[A -> C|Moves2],Moves).
10+
11+
hanoi(N,Moves):-
12+
hanoi(N,left,middle,right,Moves).
13+
14+
/** &lt;examples&gt;
15+
16+
?- hanoi(3,Moves).
17+
?- hanoi(5,Moves).
18+
19+
*/

model.pl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
cl((bachelor(X);married(X):-man(X),adult(X))).
2+
cl((has_wife(X):-man(X),married(X))).
3+
%cl((false:-has_wife(paul))).
4+
cl((man(paul):-true)).
5+
cl((adult(paul):-true)).
6+
7+
model(M0,M):-
8+
is_violated(Head,M0),!, % find instance of violated clause
9+
disj_element(L,Head), % select ground literal from the head
10+
model([L|M0],M). % and add it to the model
11+
model(M,M). % no more violated clauses
12+
13+
is_violated(H,M):-
14+
cl((H:-B)),
15+
satisfied_body(B,M), % this will ground the variables
16+
not(satisfied_head(H,M)).
17+
18+
satisfied_body(true,_M). % body is a conjunction
19+
satisfied_body(A,M):-
20+
member(A,M).
21+
satisfied_body((A,B),M):-
22+
member(A,M),
23+
satisfied_body(B,M).
24+
25+
satisfied_head(A,M):- % head is a disjunction
26+
member(A,M).
27+
satisfied_head((A;_B),M):-
28+
member(A,M).
29+
satisfied_head((_A;B),M):-
30+
satisfied_head(B,M).
31+
32+
disj_element(X,X):- % single-element disjunction
33+
not(X=false),not(X=(_;_)).
34+
disj_element(X,(X;_Ys)).
35+
disj_element(X,(_Y;Ys)):-
36+
disj_element(X,Ys).
37+
38+
/** &lt;examples&gt;
39+
40+
?- model([],M).
41+
42+
*/

model_d.pl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
cl((append([],Y,Y):-list(Y))).
2+
cl((append([X|Xs],Ys,[X|Zs]):-thing(X),append(Xs,Ys,Zs))).
3+
cl((list([]):-true)).
4+
cl((list([X|Y]):-thing(X),list(Y))).
5+
cl((thing(a):-true)).
6+
cl((thing(b):-true)).
7+
%cl((thing(c):-true)).
8+
9+
model_d(0,M,M).
10+
model_d(D,M0,M):-
11+
D>0,D1 is D-1,
12+
findall(H,is_violated(H,M0),Heads),
13+
satisfy_clauses(Heads,M0,M1),
14+
model_d(D1,M1,M).
15+
16+
satisfy_clauses([],M,M).
17+
satisfy_clauses([H|Hs],M0,M):-
18+
disj_element(L,H),
19+
satisfy_clauses(Hs,[L|M0],M).
20+
21+
is_violated(H,M):-
22+
cl((H:-B)),
23+
satisfied_body(B,M), % this will ground the variables
24+
not(satisfied_head(H,M)).
25+
26+
satisfied_body(true,_M). % body is a conjunction
27+
satisfied_body(A,M):-
28+
member(A,M).
29+
satisfied_body((A,B),M):-
30+
member(A,M),
31+
satisfied_body(B,M).
32+
33+
satisfied_head(A,M):- % head is a disjunction
34+
member(A,M).
35+
satisfied_head((A;_B),M):-
36+
member(A,M).
37+
satisfied_head((_A;B),M):-
38+
satisfied_head(B,M).
39+
40+
disj_element(X,X):- % single-element disjunction
41+
not(X=false),not(X=(_;_)).
42+
disj_element(X,(X;_Ys)).
43+
disj_element(X,(_Y;Ys)):-
44+
disj_element(X,Ys).
45+
46+
/** &lt;examples&gt;
47+
48+
?- model_d(4,[],M).
49+
50+
*/

path.pl

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
path(SS):-
2+
width(W),height(H),empty_grid(W,H,Grid),
3+
setx_hor(5/3,4,Grid),setx_hor(7/6,2,Grid),setx_hor(3/9,4,Grid),
4+
setx_ver(2/5,3,Grid),setx_ver(4/4,3,Grid),setx_ver(7/7,2,Grid),
5+
search(Grid,SS),show_grid(Grid).
6+
7+
width(8). height(10).
8+
entrance(1/1). exit(8/5). %exit(3/5).
9+
10+
/*
11+
* Search predicates
12+
* move/2 enumerates all possible moves, ignoring whether cell is free
13+
* search/2 searches grid with various search strategies
14+
*/
15+
16+
:-use_module(library(lists)).
17+
18+
moves(X/Y,Moves):-
19+
bagof(X1/Y1,move(X/Y,X1/Y1),Moves).
20+
21+
move(X/Y,X/Y1):-
22+
height(H),
23+
H>Y,Y1 is Y+1. % down
24+
move(X/Y,X1/Y):-
25+
width(W),
26+
W>X,X1 is X+1. % right
27+
move(X/Y,X/Y1):-
28+
Y>1,Y1 is Y-1. % up
29+
move(X/Y,X1/Y):-
30+
X>1,X1 is X-1. % left
31+
32+
% for A* search: generates moves with increasing F-value
33+
moves_h(F/G:X/Y,Moves):-
34+
setof(F1/G1:X1/Y1,move_h(F/G:X/Y,F1/G1:X1/Y1),Moves).
35+
36+
move_h(_/G:X/Y,F1/G1:X1/Y1):-
37+
move(X/Y,X1/Y1),
38+
h(X1/Y1,H1),
39+
G1 is G+1, % increase G-value from previous
40+
F1 is G1+H1. % add new H-value
41+
42+
h(X/Y,H):-
43+
exit(XE/YE),
44+
H is abs(XE-X)+abs(YE-Y). % Manhattan distance
45+
46+
47+
search(Grid,SS):-
48+
entrance(X/Y),
49+
( SS=bt -> search_bt(0,X/Y,Grid) % backtracking search
50+
; SS=df -> search_df(0,[X/Y],Grid) % agenda-based depth-first
51+
; SS=bf -> search_bf(0,[X/Y],Grid) % agenda-based breadth-first
52+
; SS=as -> h(X/Y,H),search_as(0,[H/0:X/Y],Grid) % A* search
53+
).
54+
55+
% backtracking search
56+
% only path found is indicated in grid
57+
search_bt(N,X/Y,Grid):-
58+
exit(X/Y),
59+
set(X/Y,Grid,N).
60+
search_bt(N,X/Y,Grid):-
61+
N1 is N+1,
62+
set(X/Y,Grid,N),
63+
move(X/Y,X1/Y1),
64+
search_bt(N1,X1/Y1,Grid).
65+
66+
% agenda-based depth-first search
67+
% grid is used for loop-detection: if set/3 fails, it is either an obstacle
68+
% or we've been there already
69+
search_df(N,[X/Y|_],Grid):-
70+
exit(X/Y),
71+
set(X/Y,Grid,N).
72+
search_df(N,[X/Y|Agenda],Grid):-
73+
( set(X/Y,Grid,N) -> moves(X/Y,Moves),N1 is N+1,
74+
append(Moves,Agenda,NewAgenda)
75+
; otherwise -> NewAgenda=Agenda,N1=N % ignore: can't go there
76+
),search_df(N1,NewAgenda,Grid).
77+
78+
% agenda-based breadth-first search
79+
search_bf(N,[X/Y|_],Grid):-
80+
exit(X/Y),
81+
set(X/Y,Grid,N).
82+
search_bf(N,[X/Y|Agenda],Grid):-
83+
( set(X/Y,Grid,N) -> moves(X/Y,Moves),N1 is N+1,
84+
append(Agenda,Moves,NewAgenda)
85+
; otherwise -> NewAgenda=Agenda,N1=N % ignore: can't go there
86+
),search_bf(N1,NewAgenda,Grid).
87+
88+
% A* search: agenda contains F/G:X/Y with F=G+H evaluation of position X/Y
89+
search_as(N,[_:X/Y|_],Grid):-
90+
exit(X/Y),
91+
set(X/Y,Grid,N).
92+
search_as(N,[F/G:X/Y|Agenda],Grid):-
93+
( set(X/Y,Grid,N) -> moves_h(F/G:X/Y,Moves),N1 is N+1,
94+
merge_h(Moves,Agenda,NewAgenda)
95+
; otherwise -> NewAgenda=Agenda,N1=N % ignore: can't go there
96+
),search_as(N1,NewAgenda,Grid).
97+
98+
merge_h([],Agenda,Agenda).
99+
merge_h(Moves,[],Moves).
100+
merge_h([F/G:X/Y|Moves],[F1/G1:X1/Y1|Agenda],[F/G:X/Y|NewAgenda]):-
101+
F1>F,
102+
merge_h(Moves,[F1/G1:X1/Y1|Agenda],NewAgenda).
103+
merge_h([F/G:X/Y|Moves],[F1/G1:X1/Y1|Agenda],[F1/G1:X1/Y1|NewAgenda]):-
104+
F>=F1,
105+
merge_h([F/G:X/Y|Moves],Agenda,NewAgenda).
106+
107+
108+
/*
109+
* Grid datastructure: list of H rows of length W.
110+
* A variable indicates cell is empty, so it can be
111+
* instantiated once with 'x' to indicate an obstacle
112+
* or with a number to indicate at which search iteration
113+
* it was explored.
114+
*/
115+
116+
empty_grid(W,H,Grid):-
117+
length(Grid,H), % generate a list of variables of length H
118+
empty_rows(W,Grid). % and instantiate each variable to an empty row
119+
120+
empty_rows(_,[]).
121+
empty_rows(W,[Row|Rows]):-
122+
length(Row,W), % generate a list of variables of length W
123+
empty_rows(W,Rows).
124+
125+
get_row(N,Grid,Row):-
126+
nth1(N,Grid,Row).
127+
128+
get_col(_,[],[]).
129+
get_col(N,[Row|Rows],[X|Col]):-
130+
nth1(N,Row,X),
131+
get_col(N,Rows,Col).
132+
133+
% Create horizontal/vertical obstacles at position X/Y with length L
134+
setx_hor(X/Y,L,Grid):-
135+
get_row(Y,Grid,Row),
136+
setx(X,L,Row).
137+
138+
setx_ver(X/Y,L,Grid):-
139+
get_col(X,Grid,Col),
140+
setx(Y,L,Col).
141+
142+
setx(_,0,_).
143+
setx(X,L,Row):-
144+
L>0,L1 is L-1,X1 is X+1,
145+
nth1(X,Row,x),
146+
setx(X1,L1,Row).
147+
148+
% Set cell X/Y to N; fails if cell has been set already
149+
set(X/Y,Grid,N):-
150+
get_row(Y,Grid,Row),
151+
nth1(X,Row,C),
152+
var(C),
153+
C=N.
154+
155+
show_grid(Grid):-
156+
nl,
157+
show_rows(Grid),
158+
nl.
159+
160+
show_rows([]).
161+
show_rows([Row|Rows]):-
162+
show_row(Row),
163+
show_rows(Rows).
164+
165+
show_row([]):-nl.
166+
show_row([H|T]):-
167+
( var(H) -> format('~|~` t~w~3+ ',['.'])
168+
; H=x -> format('~|~` t~w~3+ ',[H])
169+
; otherwise -> format('~|~` t~d~3+ ',[H])
170+
),show_row(T).
171+
172+
173+
/** &lt;examples&gt;
174+
175+
?- member(SS,[df,bf,as,bt]),path(SS).
176+
177+
*/

prove_bf.pl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
% breadth-first version of prove_r/1
2+
% agenda items have the form a(CurrentQuery,OriginalQuery)
3+
% in order to obtain an answer substitution on termination
4+
prove_bf(Goal):-
5+
prove_bf_a([a(Goal,Goal)],Goal).
6+
7+
prove_bf_a([a(true,Goal)|_Agenda],Goal).
8+
prove_bf_a([a((A,B),G)|Agenda],Goal):-!,
9+
findall(a(D,G),
10+
(cl(A,C),conj_append(C,B,D)),
11+
Children),
12+
append(Agenda,Children,NewAgenda), % breadth-first
13+
prove_bf_a(NewAgenda,Goal).
14+
prove_bf_a([a(A,G)|Agenda],Goal):-
15+
findall(a(B,G),cl(A,B),Children),
16+
append(Agenda,Children,NewAgenda), % breadth-first
17+
prove_bf_a(NewAgenda,Goal).
18+
19+
% prove_r/1 included for comparison
20+
prove_r(A):-
21+
( A=true -> true
22+
; A=(B,C) -> cl(B,D),conj_append(D,C,E),prove_r(E)
23+
; otherwise -> cl(A,B),prove_r(B)
24+
).
25+
26+
cl(brother(X,Y),brother(Y,X)).
27+
cl(brother(X,Y),(brother(X,Z),brother(Z,Y))).
28+
cl(brother(peter,paul),true).
29+
cl(brother(adrian,paul),true).
30+
31+
%%% auxiliary predicates
32+
33+
conj_append(A,B,C):-
34+
( A=true -> B=C
35+
; A=(A1,A2) -> C=(A1,C2),conj_append(A2,B,C2)
36+
; otherwise -> C=(A,B)
37+
).
38+
39+
/** &lt;examples&gt;
40+
41+
?- prove_bf(brother(peter,paul)).
42+
?- prove_r(brother(peter,paul)).
43+
?- prove_bf(brother(peter,Y)).
44+
?- prove_r(brother(peter,Y)).
45+
46+
*/

0 commit comments

Comments
 (0)