- 60 Views
- Uploaded on
- Presentation posted in: General

Logic Programming – Part 2

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Logic Programming – Part 2

Lists

Backtracking Optimization (via the cut operator)

Meta-Circular Interpreters

- [] – The empty list
- [X,2,f(Y)] – A 3 element list
- [X|Xs] – A list starting with X. Xs is a list as well.
- Example - [3,5] may be written as [3|5|[]]

Question: Which sentences can be constructed using this grammar?

s -> npvp

np -> det n

vp -> v np| v

det -> a | the

n -> woman | man

v -> shoots

Lets make relations out of it:

s(Z) :- np(X), vp(Y), append(X,Y,Z).np(Z) :- det(X), n(Y), append(X,Y,Z).vp(Z) :- v(X), np(Y), append(X,Y,Z).vp(Z) :- v(Z).det([the]).det([a]).n([woman]).n([man]).v([shoots]).

s -> np vp

np -> det n

vp -> v np| v

det -> a | the

n -> woman | man

v -> shoots

- We can ask simple queries like:
- Prolog generates entire sentences!

s([a,woman,shoots,a,man]).true

?-s(X).X = [a,woman,shoots,a,woman] ;

X = [a,woman,shoots,a,man] ;X = [a,woman,shoots,the,woman] ;X = [a,woman,shoots,the,man] ;X = [a,woman,shoots]

…

?-s([the,man|X]).

X = [shoots,a,woman] ;X = [shoots,a,man] ;X = [shoots,the,woman]

…

- Question: Add a few rules to the grammar
What should we change in the code?

- Answer: we add the following code

s -> npvp

np -> det n | detadj n

vp -> v np| v

det -> a | the

n -> woman | man

v -> shoots

adj -> vicious | marvelous

np(Z) :- det(X), adj(W), n(Y), append([X,W,Y],Z).

adj([vicious]).

adj([marvelous]).

Lists – The date Relation

- In this example we’ll work with dates
- We assume, for simplicity that a date comprises of a week day and an hour
- We define the possible week days and hours with lists:

week_day(['Sun', 'Mon', 'Tue','Wed','Thu','Fri','Sat']).

hour([0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]).

Lists – The date Relation

- Q: How can we tell if hour 2 is before 9?
- A:
- A < relation isn’t really possible to implement.(More details in the PS document)
- We can only do so by checking precedence in the lists above.

week_day(['Sun', 'Mon', 'Tue','Wed','Thu','Fri','Sat']).

hour([0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]).

date([H,W]) :- hour(Hour_list), member(H, Hour_list),

week_day(Weekday_list), member(W, Weekday_list).

dateLT( date([_,W1]), date([_,W2]) ) :- week_day(Weekday_list), precedes(W1,W2,Weekday_list).

dateLT( date([H1,W]), date([H2,W]) ) :-

hour(Hour_list),

precedes(H1,H2,Hour_list).

Example queries:

?- date([1,'Sun']).

true

dateLT(date([5,'Mon']), date([1,'Tue'])).

true

Lists – The date Relation

- precedes is defined using append /2

precedes(X,Y,Z) :- append( [_,[X],_,[Y],_] , Z ).

- Notice that the first argument is a list of lists
- This version of append is a strong pattern matcher

- Merge 2 ordered date-lists

% Signature: merge(Xs, Ys, Zs)/3

% purpose: Zs is an ordered list of dates obtained

% by merging the ordered lists of dates Xs and Ys.

merge([X|Xs] , [Y|Ys] , [X|Zs]) :- dateLT(X,Y), merge(Xs, [Y|Ys] ,Zs).

merge([X|Xs] , [X|Ys] , [X,X|Zs]) :- merge(Xs, Ys, Zs).

merge([X|Xs],[Y|Ys],[Y|Zs]) :- dateLT(Y,X), merge( [X|Xs] ,Ys, Zs).

merge(Xs,[ ], Xs).

merge([ ],Ys, Ys).

?- merge( [date([5,'Sun']), date([5,'Mon'])], X,

[date([2, 'Sun']), date([5,'Sun']), date([5, 'Mon'])]).

X = [date([2, 'Sun'])]

merge([d1,d3,d5],[d2,d3],Xs)

{X_1=d1,Xs_1=[d3,d5],

Y_1=d2,Ys_1=[d3],Xs=[d1|Zs_1] } Rule 1

dateLT(d1,d2),

merge([d3,d5], [d2,d3] ,Zs_1)

merge([d3,d5], [d2,d3] ,Zs_1)

Rule 1 – failure branch…

Rule 2 – failure branch…

dateLT(d2,d3),

merge([d3,d5], [d3] ,Zs_2)

merge([d3,d5], [d3] ,Zs_2)

Rule 1 – failure branch…

{ X_3=d3,Xs_3=[d5],Ys_3=[],

Zs_2=[d3,d3|Zs_3] } Rule 2

merge([d5], [] ,Zs_3)

true

{ Xs_4=[d5], Zs_3=[d5] } Fact 4

Rule 3 – failure branch…

Rule 2 – failure branch…

{ X_2=d3,Xs_2=[d5],

Y_2=d2,Ys_2=[d3],

Zs_1=[d2|Zs_2]} Rule 3

Rule 3 – failure branch…

The cut operator (denoted ‘!’) allows to prune trees from unwanted branches.

- A cut prunes all the goals below it
- A cut prunes all alternative solutions of goals to the left of it
- A cut does not affect the goals to it’s right
- The cut operator is a goal that always succeeds

merge([d1,d3,d5],[d2,d3],Xs)

Rule 3 – failure branch…

dateLT(d1,d2),

!,

merge([d3,d5], [d2,d3] ,Zs_1)

Rule 2 – failure branch…

!,

merge([d3,d5], [d2,d3] ,Zs_1)

merge([d3,d5], [d2,d3] ,Zs_1)

- In the merge example, only 1 of the 3 first rules can be true. There is no reason to try the others.
- Modify rule 1:

merge([X|Xs] ,[Y|Ys], [X|Zs]) :- dateLT(X,Y), !, merge (Xs, [Y |Ys],Zs).

- How many results does this query return?
- Why does this happen?
The query fits both rules 4 and 5

- How can we avoid this?
Add cut to rule 4

?- merge([],[],X) .

X = [];

X = [];

No

merge(Xs, [ ],Xs) :- !.

% Signature: solve(Goal)/1

% Purpose: Goal is true if it is true when posed to the original program P.

solve(true) :- !.

solve( (A, B) ) :- solve(A), solve(B).

solve(A) :- clause(A, B), solve(B).

clause finds the first rule unifying with A with body B

?- clause( parent(X,isaac),Body).

X = abrahamBody = true

?- clause(ancestor(abraham, P),Body).

P = Y, Body = parent(abraham, Y) ;

P = Z, Body = parent(abraham, Y), ancestor(Y, Z)

solve(ancestor(abraham, P))

{A_1 = ancestor(abraham, P)}

Rule 3 solve

clause(ancestor(abraham, P), B_1), solve(B_1)

{ B_1 = parent(abraham, P), X_2 = abraham, Y_2 = P }

Rule 1 ancestor

{ B_1 = parent(abraham,Y_2),

ancestor(Y_2, P) }Rule 2 ancestor

solve(parent(abraham, P))

solve(parent(abraham,Y_2), ancestor(Y_2, P))

{A_3 = parent(abraham,Y_2)

B_3 = ancestor(Y_2, P}

Rule 2 solve

{A_3 = parent(abraham, P)}

Rule 3 solve

solve( parent(abraham,Y_2)),

solve(ancestor(Y_2, P))

clause(parent(abraham, P), B_3),

solve(B_3).

{P = issac, B_3 =true}

Fact 1 parent

{A_4 = parent(abraham,Y_2)}

Rule 3 solve

solve(true)

clause(parent(abraham, Y_2), B_4),

solve(B_4)

solve(ancestor(Y_2, P))

Fact 1 solve

!

{Y_2 = issac, B_4 =true}

Fact 1 parent

solve(true) ,

solve(ancestor(issac, P))

{P = issac}

true

- In this version we control the goal selection order by using a stack of goals
- Preprocessing – The given program is converted into a program with a single predicate rule containing only facts
- Queries are checked against the new program

% Signature: solve(Goal)/1% Purpose: Goal is true if it is true when posed to the original program P.1. solve(Goal) :- solve(Goal, []).

% Signature: solve(Goal, Rest_of_goals)/21.solve([],[]).2.solve([],[G | Goals]):- solve(G, Goals).3.solve([A|B],Goals):- append(B, Goals, Goals1), solve(A, Goals1).4.solve( A, Goals) :- rule(A, B), solve(B, Goals).

Sample converted program:

%rule (Head, BodyList)/21. rule( member(X, [X|_] ), [] ).2. rule( member(X, [_|Ys] ), [member(X, Ys)] ).

solve(member(X, [a, b, c]))

{Goal_1 = member(X, [a, b, c])}

Rule 1 solve

solve(member(X, [a, b, c]), [])

{ A_2 = member(X, [a, b, c],Goals_1 = [] }

Rule 4 solve

rule(member(X, [a, b, c], B_2), solve(B_2, [])

{ X_3=X,Ys_3=[b, c],B_2 = [member(X, [b,c])]}Rule 2 rule

{ X=a,X_3 = a, Xs_3=[b, c],B_2 = [] }

Rule 1 rule

solve([],[])

solve([member(X, [b,c])], [])

Rule 1 solve

{ A_4= member(X, [b,c]),

B_4=[], Goals_4=[] } Rule 3 rule

true

append([], [], Goals1_4),

solve(member(X, [b,c]), Goals1_4).

{X=a}

{ Goals1_4=[]}

Rule of append

solve(member(X, [b,c]), []).

{ A_5=member(X,[b,c]), Goals_5=[]}

Rule 4 solve

rule(member(X,[b,c]), B_5),

solve(B_5, [])

{ X=b,X_6 = b,B_5 = [] } Rule 1 rule

solve([],[])

Rule 1 solve

true

{X=b}