Why does my Prolog program repeat matches for the same thing when I press semicolon? - prolog

I'm trying to match things in compound terms.
This is my term:
program(
[
argument(int, source_account),
argument(int, destination_account),
argument(int, amount)
], [
change(source_account, amount),
change(destination_account, amount)
]).
I am trying to match the use of the arguments source_account and destination_account in the function term together into a list.
Currently interception_between(X, Y, Z) returns:
?- interception_between(X, Y, Z).
"Found fact no more body"
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [],
Z = [problem(change(_A))] ;
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B],
Z = [_B, problem(change(_A))] ;
But I think I should get:
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B],
Z = [problem(change(_B)), problem(change(_A))] ;
Due to the change(source_account, _) and change(destination_account)
Could you tell me What am I doing wrong?
When I press semicolon, I get this effect and I'm not sure why:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.4.2)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- interception_between(X, Y, Z).
"Found fact no more body"
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [],
Z = [problem(change(_A))] ;
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B],
Z = [_B, problem(change(_A))] ;
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B, _C],
Z = [_B, _C, problem(change(_A))] ;
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B, _C, _D],
Z = [_B, _C, _D, problem(change(_A))] ;
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B, _C, _D, _E],
Z = [_B, _C, _D, _E, problem(change(_A))] ;
X = program([argument(_, _A)|_], [change(_A, _)]),
Y = [_B, _C, _D, _E, _F],
Z = [_B, _C, _D, _E, _F, problem(change(_A))]
this is my code:
program(
[
argument(int, source_account),
argument(int, destination_account),
argument(int, amount)
], [
change(source_account, amount),
change(destination_account, amount)
]).
interception_between(
program(
[argument(_, ARGUMENT_VALUE)|_],
[change(ARGUMENT_VALUE, _)|[]]),
FACTS, NEW_FACTS1) :-
print("Found fact no more body"),
append(FACTS, [problem(change(ARGUMENT_VALUE))], NEW_FACTS1).
interception_between(
program([argument(_, ARGUMENT_VALUE)|ARGUMENT_LIST],
[change(ARGUMENT_VALUE, _)|BODY_LIST]
)
, FACTS, NEW_FACTS2) :-
print("Found fact, calling recursively"),
append(FACTS, [problem(change(ARGUMENT_VALUE))], NEW_FACTS1),
interception_between(
program(
ARGUMENT_LIST,
BODY_LIST
)
, NEW_FACTS1, NEW_FACTS2).
interception_between(
program( [], []), [], _).
interception_between(
program( _, []), [], _).

A clue is in this behaviour in the output:
Y = [],
Y = [_B],
Y = [_B, _C],
Y = [_B, _C, _D],
Y = [_B, _C, _D, _E],
Y = [_B, _C, _D, _E, _F],
That pattern is the behaviour of backtracking over an unbounded list length:
?- length(Whatever, _).
Whatever = [] ;
Whatever = [_] ;
Whatever = [_, _] ;
Whatever = [_, _, _] ;
Whatever = [_, _, _, _] .
It's also a behaviour that can come out of append/3 when the first argument is not bounded length:
?- append(Y, [3], _Z). % only showing part of the output here:
Y = [],
Y = [_A],
Y = [_A, _B],
Y = [_A, _B, _C],
Y = [_A, _B, _C, _D],
Y = [_A, _B, _C, _D, _E],
Y = [_A, _B, _C, _D, _E, _F],
And it looks like your ?- interception_between(X, Y, Z). puts an unbound Y as FACTS and then append(FACTS, ... starts generating increasing lengths of that on backtracking.
I don't understand what the code is trying to achieve to suggest what to do about it.

Related

How to implement the factorial sequence in successor arithmetics for all argument modes?

The following Prolog program defines a predicate fact/2 for computing the factorial of an integer in successor arithmetics:
fact(0, s(0)).
fact(s(X), Y) :-
fact(X, Z),
prod(s(X), Z, Y).
prod(0, _, 0).
prod(s(U), V, W) :-
sum(V, X, W),
prod(V, U, X).
sum(0, Y, Y).
sum(s(X), Y, s(Z)) :-
sum(X, Y, Z).
It works with queries in this argument mode:
?- fact(s(0), s(0)).
true
; false.
It also works with queries in this argument mode:
?- fact(s(0), Y).
Y = s(0)
; false.
It also works with queries in this argument mode:
?- fact(X, Y).
X = 0, Y = s(0)
; X = Y, Y = s(0)
; X = Y, Y = s(s(0))
; X = s(s(s(0))), Y = s(s(s(s(s(s(0))))))
; …
But it exhausts resources with queries in this argument mode:
?- fact(X, s(0)).
X = 0
; X = s(0)
;
Stack limit (0.2Gb) exceeded
Stack sizes: local: 4Kb, global: 0.2Gb, trail: 0Kb
Stack depth: 2,503,730, last-call: 100%, Choice points: 13
In:
[2,503,730] sum('<garbage_collected>', _1328, _1330)
[38] prod('<garbage_collected>', <compound s/1>, '<garbage_collected>')
[33] fact('<garbage_collected>', <compound s/1>)
[32] fact('<garbage_collected>', <compound s/1>)
[31] swish_trace:swish_call('<garbage_collected>')
How to implement the factorial sequence in successor arithmetics for all argument modes?
The first question must be why? A failure-slice helps to understand the problem:
fact(0, s(0)) :- false.
fact(s(X), Y) :- fact(X, Z), false, prod(s(X), Z, Y).
This fragment alone terminates only if the first argument is given. If it is not, then there is no way to prevent non-termination, as Y is not restricted in any way in the visible part. So we have to change that part. A simple way is to observe that the second argument continually increases. In fact it grows quite fast, but for the sake of termination, one is enough:
fact2(N, F) :-
fact2(N, F, F).
fact2(0, s(0), _).
fact2(s(X), Y, s(B)) :- fact2(X, Z, B), prod(s(X), Z, Y).
And, should I add, this can be even proved.
fact2(A,B)terminates_if b(A);b(B).
% optimal. loops found: [fact2(s(_),s(_))]. NTI took 0ms,73i,73i
But, there is a caveat...
If only F is known, the program will now require temporally space proprotional to |F|! That is not an exclamation point but a factorial sign...
I think you can use cut to avoid backtracking when the second argument is a ground term.
fact(0, s(0)).
fact(s(X), Y) :-
fact(X, Z),
prod(s(X), Z, W),
(ground(Y) ->
!,
Y = W
; Y = W).
prod(0, _, 0).
prod(s(U), V, W) :- sum(V, X, W), prod(V, U, X).
sum(0, Y, Y).
sum(s(X), Y, s(Z)) :- sum(X, Y, Z).
Examples:
?- fact(N, 0).
false.
?- fact(N, s(s(s(0)))).
false.
?- fact(X, s(0)).
X = 0
; X = s(0)
; false.
?- fact(s(s(s(0))), s(s(s(s(s(s(0))))))).
true
; false.
?- fact(s(s(s(0))), s(s(s(s(s(0)))))).
; false.
?- fact(s(s(s(0))), Y).
Y = s(s(s(s(s(s(0))))))
; false.
?- fact(X, Y).
X = 0, Y = s(0)
; X = Y, Y = s(0)
; X = Y, Y = s(s(0))
; …
?- fact(s(s(X)), s(s(Y))).
X = Y, Y = 0
; X = s(0), Y = s(s(s(s(0))))
; …

All different Global Constraint in Prolog clpfd

I am trying to craete a custom clpfd global constraint, which is very similar to the all_diferent constraint.
The constraint should allow only lists with different non-zero items (so there can be multiple zeros).
Here is a working example in SICSTUS Prolog:
:- use_module(library(clpfd)).
mask([], [], []).
mask([H1|T1], [H2|T2], [P|R]) :-
P #= H1 * H2, mask(T1, T2, R).
diff(L) :-
diff_rec(L, L).
diff_rec([], _).
diff_rec([H|T], L) :-
fd_global(diff_zero(H, T, L), no_state, [val(H)]),
diff_rec(T, L).
:-multifile clpfd:dispatch_global/4.
clpfd:dispatch_global(diff_zero(X, Tail, List), S, S, Actions):-
(ground(X) ->
filter_diff(List, X, Tail, Actions)
;
Actions = []
).
filter_diff(_, 0, _, [exit]).
filter_diff([], _X, _Tail, [exit]).
filter_diff([Y|T], X, Tail, Actions):-
(T==Tail ->
Actions = RestActions
;
fd_set(Y, SetY),
fdset_del_element(SetY, X, NewSetY),
Actions = [Y in_set NewSetY | RestActions]
),!,
filter_diff(T, X, Tail, RestActions).
all_diff_zero(L, X) :-
length(L, N),
length(X, N),
domain(X, 0, 1),
mask(L, X, M),
diff(M),
!,
labeling([], X).
For a given list, all_diff_zero predicate should find a binary mask which together with the original list gives a list with all different non-zero items.
After commenting out the line with filter_diff(_, 0, _, [exit])., the diff works as a usual all different constraint (so for example all_diff_zero([ 3 , 1 , 1 ], X). gives me just X = [1,0,1]; X = [1,1,0]).
However, the all different or zero constraint with this line does not work at all:
?- all_diff_zero([ 3 , 1 , 1 ], X).
X = [0,0,0] ? ;
X = [0,0,1] ? ;
X = [0,1,0] ? ;
X = [0,0,0] ? ;
X = [0,0,1] ? ;
X = [0,1,0] ? ;
X = [0,1,0] ? ;
X = [1,0,0] ? ;
X = [1,0,0] ? ;
X = [1,0,1] ? ;
X = [1,0,0] ? ;
X = [1,0,0] ? ;
X = [1,0,1] ? ;
X = [1,0,0] ? ;
X = [1,0,0] ? ;
X = [1,0,1] ? ;
X = [1,0,1] ? ;
X = [1,0,1] ? ;
X = [1,1,0] ? ;
X = [1,1,0] ? ;
X = [1,1,1] ? ; % wrong
X = [1,1,0] ? ;
X = [1,1,1] ? ; % wrong
X = [1,1,0] ? ;
X = [1,1,1] ? ; % wrong
X = [1,1,0] ? ;
X = [1,1,1] ? ; % wrong
Note that the desired output is:
?- all_diff_zero([ 3 , 1 , 1 ], X).
X = [0,0,0] ? ;
X = [0,0,1] ? ;
X = [0,1,0] ? ;
X = [1,0,0] ? ;
X = [1,1,0] ? ;
X = [1,0,1] ? ;

What does the following Prolog program do?

What does this Prolog program do? I think it compares two variables? When I read this rule to me it says that m has a relationship to m2 if x is related to y
m(X, Y) :-
m2(X, Y, [ ] ).
m2([ ], X, X).
m2([X|Y], [X, X|Z], W) :-
m2(Y, Z, W).
let's try the most general query:
?- m(X,Y).
X = Y, Y = [] ;
X = [_G3566],
Y = [_G3566, _G3566] ;
X = [_G3566, _G3575],
Y = [_G3566, _G3566, _G3575, _G3575] ;
X = [_G3566, _G3575, _G3584],
Y = [_G3566, _G3566, _G3575, _G3575, _G3584, _G3584] ;
...
so, Ys seems to be simply the Xs sequence, with each element doubled...

Parent-query in prolog does not return ALL parentships

Given these facts:
male(jerry).
male(stuart).
male(warren).
male(peter).
female(kather).
female(maryalice).
female(ann).
brother(jerry,stuart).
brother(jerry,kather).
brother(peter, warren).
sister(ann, maryalice).
sister(kather,jerry).
parent_of(warren,jerry).
parent_of(maryalice,jerry).
As you can see warren and maryalice are parents of jerry, stuart and kather. What rules will I need to implement in order for the query parent_of(X,Y). to return
X=warren, Y=jerry
X=warren, Y=stuart
X=warren, Y=kather
X=maryalice, Y=jerry
X=maryalice, Y=stuart
X=maryalice, Y=kather
i.e all the parenthood relationships?
I have tried
parent_of(X,Y) :- parent_of(X,C), sibling(Y,C), X \= Y.
sibling(C,OC) :- brother(C,OC), C \= OC.
sibling(C,OC) :- sister(C,OC), C \= OC.
but querying parent_of(X,Y). returns this
X = warren,
Y = jerry ;
X = maryalice,
Y = jerry ;
X = warren,
Y = kather ;
X = maryalice,
Y = kather ;
X = warren,
Y = jerry ;
X = maryalice,
Y = jerry ;
X = warren,
Y = kather ;
X = maryalice,
Y = kather ;
X = warren,
Y = jerry ;
X = maryalice,
Y = jerry ;
X = warren,
Y = kather ;
X = maryalice,
Y = kather ;
X = warren,
Y = jerry ;
X = maryalice,
Y = jerry ;
X = warren,
Y = kather ;
........
Where the parenthood between warren and stuart and maryalice and stuart is missin (and it is also stuck in some kind of loop!).
Please help me out!
I would separate the fact parent_of from the predicate:
is_parent_of(X, Y) :- parent_of(X, Y).
is_parent_of(X, Y) :- parent_of(X, C), sibling(C, Y).
I don't think you need C \= Y here since your facts don't have anyone being their own sibling, so the check is superfluous. Likewise, it's superfluous to check to ensure we aren't capturing someone being their own parent.
With the above rules and your current database example, you get the results you want:
| ?- is_parent_of(X, Y).
X = warren
Y = jerry ? ;
X = maryalice
Y = jerry ? ;
X = warren
Y = stuart ? ;
X = warren
Y = kather ? ;
X = maryalice
Y = stuart ? ;
X = maryalice
Y = kather ? ;
(1 ms) no
| ?-

How to handle a path in Prolog graph traversal

I have written in Prolog:
edge(x, y).
edge(y, t).
edge(t, z).
edge(y, z).
edge(x, z).
edge(z, x).
path(Start, End, Path) :-
path3(Start, End, [Start], Path).
path3(End, End, RPath, Path) :-
reverse(RPath, Path).
path3(A,B,Path,[B|Path]) :-
edge(A,B),
!.
path3(A, B, Done, Path) :-
edge(A, Next),
\+ memberchk(Next, Done),
path3(Next, B, [Next|Done], Path).
Its taking care of cyclic graphs as well, I am getting an irregular output when I try to traverse same node from same node.
eg: path(x,x,P).
expected output should be:
P = [x, z, t, y, x]
P = [x, z, y, x]
P = [x, z, x]
However, I am getting output:
p = [x] ------------> wrong case
P = [x, z, t, y, x]
P = [x, z, y, x]
P = [x, z, x]
How can I get rid of this unwanted case.
Thanks
We use meta-predicate path/4 together with edge/2:
?- path(edge,Path,x,Last), edge(Last,x).
Last = z, Path = [x,y,t,z]
; Last = z, Path = [x,y,z]
; Last = z, Path = [x,z]
; false.
Alright! Above three answers are exactly what the OP wished for in the question.
Just for fun let's look at all possible paths based on edge/2!
?- path(edge,Path,From,To).
From = To , Path = [To]
; From = x, To = y, Path = [x,y]
; From = x, To = t, Path = [x,y,t]
; From = x, To = z, Path = [x,y,t,z]
; From = x, To = z, Path = [x,y,z]
; From = y, To = t, Path = [y,t]
; From = y, To = z, Path = [y,t,z]
; From = y, To = x, Path = [y,t,z,x]
; From = t, To = z, Path = [t,z]
; From = t, To = x, Path = [t,z,x]
; From = t, To = y, Path = [t,z,x,y]
; From = y, To = z, Path = [y,z]
; From = y, To = x, Path = [y,z,x]
; From = x, To = z, Path = [x,z]
; From = z, To = x, Path = [z,x]
; From = z, To = y, Path = [z,x,y]
; From = z, To = t, Path = [z,x,y,t]
; false.
path(Start, End, Path) :-
edge(Start,First),
path3(Start, End, [Start,First], Path).
should work

Resources