setof creates many list instead of one list prolog - list

I have a function I created using prolog and for some reason it always creating multi list for each element instead of one list, can someone please help me with that?
here is what I wrote:(problem is the last functin creates many lists)
father(_father,_child) :- parent(_father,_child), gender(_father,male).
mother(_mother,_child) :- parent(_mother,_child), gender(_mother,female).
couple(_woman,_man):- gender(_woman,female),gender(_man,male),parent(_man,_child),parent(_woman,_child).
parents(_woman,_man,_child) :- father(_man,_child),mother(_woman,_child).
count([],0).
count([H|T],N) :- count(T,N1) , N is N1+1.
child_to_couple(_woman,_man,_num):- couple(_woman,_man),findall(_child,parents(_woman,_man,_child),_childs),count(_childs,_num).
num_of_childs(_list):- couple(_woman,_man),setof(childrens(_man,_woman,_num),child_to_couple(_woman,_man,_num),_list).
example of data:
gender(sagi,male).
gender(limor,female).
gender(yuval,male).
gender(gilad,male).
gender(shahaf,male).
gender(yaara,female).
parent(eyal,noam).
parent(shiri,yuval2).
parent(eyal,yuval2).
parent(shiri,yonatan).
parent(eyal,yonatan).
parent(shahaf,gan).
parent(yaara,gan).
but when I run
?- num_of_childs(_x).
I get:
_x = [childrens(mordechai, miriam, 1)] ;
_x = [childrens(salax, naima, 1)] ;
_x = [childrens(eli, bella, 2)] ;
_x = [childrens(eli, bella, 2)] ;
_x = [childrens(zvi, tova, 1)] ;
_x = [childrens(avram, yokeved, 1)] ;
_x = [childrens(haim, irit, 3)] ;
_x = [childrens(haim, irit, 3)] ;
_x = [childrens(haim, irit, 3)] ;
_x = [childrens(guy, pelit, 2)] ;
_x = [childrens(guy, pelit, 2)] ;
_x = [childrens(eyal, shiri, 3)] ;
_x = [childrens(eyal, shiri, 3)] ;
_x = [childrens(eyal, shiri, 3)] ;
_x = [childrens(sagi, limor, 2)] ;
_x = [childrens(sagi, limor, 2)] ;
_x = [childrens(shahaf, yaara, 1)] ;
instead of:
_x = [childrens(sagi, limor, 2),childrens(sagi, limor, 2),childrens(shahaf, yaara, 1),..........etc]

Your num_of_childs/1 calls couple/2 before the setof/3, so you get the number of results couple/2 returns. Since child_to_couple/3 also calls couple/2 you do not in fact need it here at all.
num_of_childs(L) :- findall(childrens(M,W,N),child_to_couple(W,M,N),L).
But the big problem is that couple/2, the way you have written it, always succeeds once per child. This propagates up so that child_to_couple/2 and num_of_childs/1 also succeed multiple times.
If you change to this
couple(W,M):-
gender(W,female), gender(M,male),
( parent(M,C), parent(W,C) -> true ; false ).
You get only one result per couple, regardless of the number of children. I have the feeling there may be an even simpler way to accomplish this, but I wasn't able to find it.
?- num_of_childs(L).
L = [childrens(eyal,shiri,2),childrens(shahaf,yaara,1)] ? ;
no
Addition: using a cut would be slightly simpler but also uglier.

Related

Splitting a list without creating an empty list in Prolog

split(L,X,Y):-append(X,Y,L).
creates 4 splits as follows:
X = [],
Y = [1, 2, 3] ;
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
X = [1, 2, 3],
Y = [] ;
I want to eliminate the empty list created during split and keep only combinations which do not have empty list that is
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
You can first specify the pattern for X and Y, by unifying these with a "cons":
split(L, X, Y) :-
X = [_|_],
Y = [_|_],
append(X, Y, L).
The advantage of using this approach, is that you will probably safe some cycles, since append/3 will not propose certain solutions that are empty lists, that then have to be filtered out.
In order to solve your problem, as said in the comments, you have to add a condition that checks if X or Y are empty, in this way:
split(L,X,Y):-
append(X,Y,L),
x\=[],
Y\=[].
Why the check is done after append/3? X = [] is true because X can be unified with [] when it is still uninstantiated. When you call split/3, initially X and Y are uninstantiated (if you use the tracer you can see something like _4604\=[]): X = [] succeds and so the negation fails and the program returns false if you put X\=[] and Y\=[] before append/3.
To better understand, i suggest you to read this article.

How to implement a not_all_equal/1 predicate

How would one implement a not_all_equal/1 predicate, which succeeds if the given list contains at least 2 different elements and fails otherwise?
Here is my attempt (a not very pure one):
not_all_equal(L) :-
( member(H1, L), member(H2, L), H1 \= H2 -> true
; list_to_set(L, S),
not_all_equal_(S)
).
not_all_equal_([H|T]) :-
( member(H1, T), dif(H, H1)
; not_all_equal_(T)
).
This however does not always have the best behaviour:
?- not_all_equal([A,B,C]), A = a, B = b.
A = a,
B = b ;
A = a,
B = b,
dif(a, C) ;
A = a,
B = b,
dif(b, C) ;
false.
In this example, only the first answer should come out, the two other ones are superfluous.
Here is a partial implementation using library(reif) for SICStus|SWI. It's certainly correct, as it produces an error when it is unable to proceed. But it lacks the generality we'd like to have.
not_all_equalp([A,B]) :-
dif(A,B).
not_all_equalp([A,B,C]) :-
if_(( dif(A,B) ; dif(A,C) ; dif(B,C) ), true, false ).
not_all_equalp([A,B,C,D]) :-
if_(( dif(A,B) ; dif(A,C) ; dif(A,D) ; dif(B,C) ; dif(B,D) ), true, false ).
not_all_equalp([_,_,_,_,_|_]) :-
throw(error(representation_error(reified_disjunction),'C\'est trop !')).
?- not_all_equalp(L).
L = [_A,_B], dif(_A,_B)
; L = [_A,_A,_B], dif(_A,_B)
; L = [_A,_B,_C], dif(_A,_B)
; L = [_A,_A,_A,_B], dif(_A,_B)
; L = [_A,_A,_B,_C], dif(_A,_B)
; L = [_A,_B,_C,_D], dif(_A,_B)
; error(representation_error(reified_disjunction),'C\'est trop !').
?- not_all_equalp([A,B,C]), A = a, B = b.
A = a, B = b
; false.
Edit: Now I realize that I do not need to add that many dif/2 goals at all! It suffices that one variable is different to the first one! No need for mutual exclusivity! I still feel a bit insecure to remove the dif(B,C) goals ...
not_all_equalp([A,B]) :-
dif(A,B).
not_all_equalp([A,B,C]) :-
if_(( dif(A,B) ; dif(A,C) ), true, false ).
not_all_equalp([A,B,C,D]) :-
if_(( dif(A,B) ; dif(A,C) ; dif(A,D) ), true, false ).
not_all_equalp([_,_,_,_,_|_]) :-
throw(error(representation_error(reified_disjunction),'C\'est trop !')).
The answers are exactly the same... what is happening here, me thinks. Is this version weaker, that is less consistent?
Here's a straightforward way you can do it and preserve logical-purity!
not_all_equal([E|Es]) :-
some_dif(Es, E).
some_dif([X|Xs], E) :-
( dif(X, E)
; X = E, some_dif(Xs, E)
).
Here are some sample queries using SWI-Prolog 7.7.2.
First, the most general query:
?- not_all_equal(Es).
dif(_A,_B), Es = [_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_A,_A,_B|_C]
...
Next, the query the OP gave in the question:
?- not_all_equal([A,B,C]), A=a, B=b.
A = a, B = b
; false. % <- the toplevel hints at non-determinism
Last, let's put the subgoal A=a, B=b upfront:
?- A=a, B=b, not_all_equal([A,B,C]).
A = a, B = b
; false. % <- (non-deterministic, like above)
Good, but ideally the last query should have succeeded deterministically!
Enter library(reif)
First argument indexing
takes the principal functor of the first predicate argument (plus a few simple built-in tests) into account to improve the determinism of sufficiently instantiated goals.
This, by itself, does not cover dif/2 satisfactorily.
What can we do? Work with
reified term equality/inequality—effectively indexing dif/2!
some_dif([X|Xs], E) :- % some_dif([X|Xs], E) :-
if_(dif(X,E), true, % ( dif(X,E), true
(X = E, some_dif(Xs,E)) % ; X = E, some_dif(Xs,E)
). % ).
Notice the similarities of the new and the old implementation!
Above, the goal X = E is redundant on the left-hand side. Let's remove it!
some_dif([X|Xs], E) :-
if_(dif(X,E), true, some_dif(Xs,E)).
Sweet! But, alas, we're not quite done (yet)!
?- not_all_equal(Xs).
DOES NOT TERMINATE
What's going on?
It turns out that the implementation of dif/3 prevents us from getting a nice answer sequence for the most general query. To do so—without using additional goals forcing fair enumeration—we need a tweaked implementation of dif/3, which I call diffirst/3:
diffirst(X, Y, T) :-
( X == Y -> T = false
; X \= Y -> T = true
; T = true, dif(X, Y)
; T = false, X = Y
).
Let's use diffirst/3 instead of dif/3 in the definition of predicate some_dif/2:
some_dif([X|Xs], E) :-
if_(diffirst(X,E), true, some_dif(Xs,E)).
So, at long last, here are above queries with the new some_dif/2:
?- not_all_equal(Es). % query #1
dif(_A,_B), Es = [_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_B|_C]
; dif(_A,_B), Es = [_A,_A,_A,_B|_C]
...
?- not_all_equal([A,B,C]), A=a, B=b. % query #2
A = a, B = b
; false.
?- A=a, B=b, not_all_equal([A,B,C]). % query #3
A = a, B = b.
Query #1 does not terminate, but has the same nice compact answer sequence. Good!
Query #2 is still non-determinstic. Okay. To me this is as good as it gets.
Query #3 has become deterministic: Better now!
The bottom line:
Use library(reif) to tame excess non-determinism while preserving logical purity!
diffirst/3 should find its way into library(reif) :)
EDIT: more general using a meta-predicate (suggested by a comment; thx!)
Let's generalize some_dif/2 like so:
:- meta_predicate some(2,?).
some(P_2, [X|Xs]) :-
if_(call(P_2,X), true, some(P_2,Xs)).
some/2 can be used with reified predicates other than diffirst/3.
Here an update to not_all_equal/1 which now uses some/2 instead of some_dif/2:
not_all_equal([X|Xs]) :-
some(diffirst(X), Xs).
Above sample queries still give the same answers, so I won't show these here.

map two lists together in prolog

I have two facts which are x(a, b, c) and g(x, y, z).
I want to create a rule to print all possible answers such that if I pick one member from the first fact and match it with a member from the second fact then I can't match another member from the first fact to the same member in the second fact that was matched before, for ex. [a,x], [b, x] are not acceptable.
... X = [[a,x],[b,y],[c,z]]
... X = [[a,y],[b,z],[c,x]]
... X = [[a,z],[b,x],[c,y]]
.
.
.
you get the point I hope, there should be 9 I think.
Why do you think that there should be 9 in your sample? There should be exactly 6:
:- use_module(library(lambda)).
?- maplist(\K^V^KV^(KV = K-V), [a,b,c], Rs, LRs), permutation([x,y,z], Rs).
Rs = [x,y,z], LRs = [a-x,b-y,c-z]
; Rs = [x,z,y], LRs = [a-x,b-z,c-y]
; Rs = [y,x,z], LRs = [a-y,b-x,c-z]
; Rs = [y,z,x], LRs = [a-y,b-z,c-x]
; Rs = [z,x,y], LRs = [a-z,b-x,c-y]
; Rs = [z,y,x], LRs = [a-z,b-y,c-x]
; false.

Confusing SML statement

I have this statement:
let val x =
let val x = 5
in(fn y =>(y,x+y))
end
in
let val y=3 and z=10
in x z
end
end;
The output is :
(10,15)
I've been trying to track how this answer was produced but am getting confused. Is there a better way to write this that would help me understand what variables are being used where? Thank you!
First, some alpha-conversion:
let val fnPairOfInputAndInputPlus5 =
let val five = 5
in ( fn input => ( input, five + input ) )
end
in let val ignored = 3 and input = 10
in fnPairOfInputAndInputPlus5 input
end
end;
This code is demonstrating that when you declare a function value, unbound values in the declaring scope, such as the value five, are "enclosed" by the declaration (hence the term "closures"). Thus the function always returns a pair consisting of its input and its input plus five.
You could simplify it to
let fun f y = (y,5+y)
val y=3 and z=10
in
f z
end;
Note that the two instances of y are independent. The inner occurrence of x (which I've eliminated) is independent of the outer one (now renamed f).
Can be understood using manual evaluation with detailed explanations.
Starting with your initial expression:
let val x =
let val x = 5
in (fn y => (y,x + y))
end
in
let val y = 3 and z = 10
in x z
end
end;
Line 2,3,4 is an expression whose type is a function, as you see in the in part. It does not depends on any outer context, so it may be simplified as just fn y => (y, 5 + y), substituting x to 5, according to the binding given in let.
So you now have this:
let val x = fn y => (y, 5 + y)
in
let val y = 3 and z = 10
in x z
end
end;
After substitution of x (and removal of the let which in then now not necessary any more):
let val y = 3 and z = 10
in (fn y => (y, 5 + y)) z
end;
Note the y appearing in (y, 5 + y) are bound to the function's argument, and not to 3. There is no reference to this outer y, so its biding may be removed.
Now you have:
let z = 10
in (fn y => (y, 5 + y)) z
end;
Substituting z to 10 and removing the let which is not necessary any more, you get:
(fn y => (y, 5 + y)) 10;
This is a function application. You may evaluate it, to get:
(10, 5 + 10);
Which gives the final and constant result you noticed:
(10, 15);

Prolog Creating A List

I try to create a list from the facts:
mother(jane,jerry).
mother(susan,riche).
mother(helen,kuyt).
I want to convert mothers' names to a list that has a number of elements in it like:
momlist([jane,susan],2).
momlist([jane,susan,helen],3).
momlist([jane],1).
I tried to create this with:
momlist(X,Number):- mom(X,_),
NewNum is Number-1,
NewNum > 0,
write(x),
momlist(X,NewNum).
It just write number times mom's names..
How can I produce a list with these fact?
Best regards and thanks a lot.
Here it is
mother(jane,jerry).
mother(susan,riche).
mother(helen,kuyt).
mother(govno,mocha).
mother(ponos,albinos).
momlist( X, L ) :-
length( X, L ),
gen_mum( X ),
is_set( X ).
gen_mum( [] ).
gen_mum( [X|Xs] ) :-
mother( X, _ ),
gen_mum( Xs ).
So
?- momlist(X, 3).
X = [jane, susan, helen] ;
X = [jane, susan, govno] ;
X = [jane, susan, ponos] ;
X = [jane, helen, susan] ;
X = [jane, helen, govno] ;
X = [jane, helen, ponos] ;
X = [jane, govno, susan] ;
And
?- momlist(X, 2).
X = [jane, susan] ;
X = [jane, helen] ;
X = [jane, govno] ;
X = [jane, ponos] ;
X = [susan, jane] ;
X = [susan, helen] ;
X = [susan, govno] ;
X = [susan, ponos] ;
X = [helen, jane] ;
Is that what you want?
A couple of minor problems with the accepted answer:
Adding a second child for a mother (e.g. mother(helen,todd).), will give duplicate results.
gen_mum produces a lot of results that are rejected because they are not a set (e.g. X = [jane, jane,jane]; X=[jane,jane,helen]].
Another possible solution would be:
momlist(X,L):-
setof(M, C^mother(M,C), AllMoms),
perm(L, AllMoms, X).
perm(0, _, []):- !.
perm(N, From, [H|T]):-
select(H, From, NewFrom),
NewN is N-1,
perm(NewN, NewFrom, T).
Also if you don't want [jane,helen] aswell as [helen,jane] etc. then you can use subset instead of perm:
subset(0,_,[]):- !.
subset(N, [M|TM], [M|T]):-
NewN is N-1,
subset(NewN, TM, T).
subset(N, [_|TM], L):-
subset(N, TM, L).