What is the meaning of "^" in prolog? [duplicate] - prolog

I had a quick question re. existential qualifier using setof in prolog (i.e. ^).
using SICStus it seems that (despite what a number of websites claim), S does indeed appear to be quantified in the code below (using the bog standard, mother of / child of facts, which i havent included here):
child(M,F,C) :- setof(X,(mother(S,X)),C).
i check the unification using:
child(M,F,C) :- setof(X-S,(mother(S,X)),C).
so the following code, with the existential operator seem to make no difference:
child(M,F,C) :- setof(X,S^(mother(S,X)),C).
Any ideas why this is? What would be a situation where you would need the unifier then?
thanks!

Ok, I'm not sure I can explain it perfectly, but let me try.
It has to do with the fact that you are querying over a 2-ary relation, mother/2. In that case using X-S as the template has a similar effect on the result set C as using S^ in front of the goal. In X-S you are using both variables in the template, and therefore each possible binding of X and S is included in C. You get the same effect using S^ in front of the goal, as this is saying "ignore bindings of S when constructing the result".
But the difference between the two becomes clearer when you query over a 3-ary relation. The SWI manual has this example:
foo(a, b, c).
foo(a, b, d).
foo(b, c, e).
foo(b, c, f).
foo(c, c, g).
Now do similar queries as in your example
setof(X-Z, foo(X,Y,Z), C).
and
setof(Z, X^foo(X,Y,Z), C).
and you get different results.
It's not just checking unification, X-Z effectively changes your result set.
Hope that helps.
Edit: Maybe it clarifies things when I include the results of the two queries above. The first one goes like this:
?- setof(X-Z, foo(X,Y,Z), C).
Y = b
C = [a-c, a-d] ;
Y = c
C = [b-e, b-f, c-g] ;
No
The second one yields:
?- setof(Z, X^foo(X,Y,Z), C).
Y = b
C = [c, d] ;
Y = c
C = [e, f, g] ;
No

Related

Prolog - Constraint Library - Variable Scope

I'm working on trying to solve an LSAT logic problem with Prolog. I'm trying to get Prolog to tell me whether possible values for actors in a line are valid.
I wrote the following:
:- use_module(library(clpfd)).
actor("Jeff",A) :-
A #>= 0,
A #<5.
actor("Rich",C) :-
C #>= 0,
C #<5,
actor("Jeff",A),
A #< C.
When I query:
?- actor("Rich",0).
false.
Which is right since Jeff is < than Rich and Jeff is => 0 so Rich cannot be 0.
But, when I query:
?- actor("Jeff",1), actor("Rich",1).
true
I also get true, which is impossible because Rich > Jeff.
I feel the problem is because of something going on with my variable. I don't understand how
actor("Jeff",A),
A #< C.
is evaluating. It seems to me that actor("Jeff",A) should be set to actor("Jeff",1) and then 1 #< 1 should fail.
Variables within a clause or local to that clause.
In your case, to understand the issue, consider first the following query:
?- actor("Rich", C),
C = 1.
C = 1.
This does not tell us a lot, so we apply the following purely algebraic reasoning: For the goal actor("Rich", C), we substitute the body of the single matching clause:
?- C #>= 0,
C #< 5,
actor("Jeff",A),
A #< C,
C = 1.
The answer is:
C = 1,
A = 0.
This shows that when C is 1, then A is 0. However, on the toplevel, you did not see this because this variable only occurs within the clause for "Rich". Making this explicit shows that there is a solution that satisfies the constraint within that clause, but it is not linked to the variable we want.
There are several ways out. One of them is to make A available as an argument so that you can explicitly refer to it from the toplevel. In general, to link the relevant entities together, you will have to introduce arguments for each of your clauses, so that you can refer to the variables you need to reason about, instead of introducing new ones within each clause.
For example, in your case, this could look as follows:
actor("Jeff", A, _) :-
A #>= 0,
A #< 5.
actor("Rich", A, C) :-
C #>= 0,
C #< 5,
actor("Jeff", A, C),
A #< C.
I have used A to refer to Jeff, and C to refer to Rich.
While we are at at, let us tidy up the code, and use the following essentially equivalent version:
actor(jeff, A, _) :- A in 0..4.
actor(rich, A, C) :- C in 0..4, actor(jeff, A, C), A #< C.
Make sure you understand the following answer:
?- actor(jeff, 1, C), actor(rich, C, 1).
C = 0.
Your original example now yields false, exactly as expected:
?- actor(rich, 1, 1).
false.
Thus, you should be able to solve your task in principle.
However, there is a much simpler way to solve all this, which avoids the reification overload.
Instead of painstakingly keeping track of connections between names and corresponding variables, let us use the variables directly with the intended names. For example, what do you say about this:
?- Jeff in 0..4,
Rich in 0..4,
Jeff #< Rich.
This uses Prolog variables to denote the people, and makes the work a lot simpler. In this representation, your query becomes:
?- Jeff in 0..4,
Rich in 0..4,
Jeff #< Rich,
Jeff = 1,
Rich = 1.
And this obviously results in false.

Prolog unification process (concat)

The following code works, but I have certain doubts as to how it does things under the hood. For example, on the first call to Exit(9) I don't understand how c is moved to the variable O. Is this part of the unification process or something else entirely? Care anyone to explain?
concat([], List, List).
concat([Head|[]], List, [Head|List]).
concat([Head|Tail], List, Concat) :- concat(Tail, List, C), concat([Head], C, Concat).
You can do 'by hand' the unification process, to verify that the trace line labelled Exit:(9) actually 'cons-ed' [c] to [x,y,z]:
?- [Head|[]]=[c],List=[x,y,z],[Head|List]=O.
Head = c,
List = [x, y, z],
O = [c, x, y, z].
but, you cannot claim it works:
?- concat([a,b,c],[x,y,z],L).
L = [a, b, c, x, y, z] ;
L = [a, b, c, x, y, z] ;
...
it doesn't terminate, and this clearly indicate some problem. The second clause is redundant - both in behaviour and syntax. It would be usually written like
concat([Head], List, [Head|List]).
since the empty tail list it's implicitly present in every list - except where a tail is explicitly indicated:
?- [Head|[]]=[X].
Head = X.
About the behaviour, you can see from your trace that it's the first clause that is never used. So, you can think it's the first that is redundant - maybe you added the second because of the last call of the third clause, where a 'singleton' list is required (I mean ...,concat([Head], C, Concat).). But such call it's causing the non termination issue. Better to simplify the whole program, removing the second clause and simplifying the third....

Prolog: lexicographic comparison and split a list

Given atom x, I am trying to split a list into one with atoms smaller than x and one with atoms equal to or greater than x.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]
Below is what I've tried so far. I get the concept.However my code includes the atom that is equivalent to x in AtomSmall list, not AtomBig, although I check the case with before predicate.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]
before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).
split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).
Please help!
In SWI-Prolog, you can use partition/4 from library(lists) and the standard order comparison (#>)/2:
?- lists:partition(#>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Since the order of arguments in comparison is fixed passing the pivot in as first argument, a lambda expression (using library(yall), needs a recent version) can help to give a more intuitive reading:
?- partition([E]>>(E#<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Anyway, your code could be patched like this:
split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1#<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1#<X,split(X,T1,Small,Big).
?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.
Your before/2 predicate succeeds if the arguments are lexicographically equivalent. For example, before(a, a) is true. That's because your 3rd clause allows equal values throughout the list until the base case finally succeeds with two empty lists.
In addition, something you haven't encountered yet evidently, is that before(X, Y) will fail if X and Y are different length atoms. For example, before(ab, abc) will fail. So your small/2 needs to take care of that case as well.
A refactoring of small/2 will fix that:
% 1st clause is fixed so unequal length atoms are handled properly
small([], _).
small([H1|_], [H2|_]) :- H1 < H2.
% 3rd clause is fixed so that equal atoms won't succeed here
small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]).
But... you don't need to go through all that with before/2. Prolog knows how to compare, in a sensible way, atoms (and general Prolog terms) using the #< and #> operators, as #CapelliC indicated in his answer. So your before/2 just becomes:
before(X, Y) :- X #< Y.
And you don't need small/2 at all. That's basically the second solution that #CapelliC showed in his answer.

PROLOG how to "connect" similar objects

Hey im new to prolog and was wondering:
Let's say i have this code:
component(a,b).
component(a,c).
component(a,d).
component(b,e).
component(b,f).
and i want to create an argument
consistsof(X,Y):- component(X,Y); component(Y,Z).
that gives me:
Y= b,c,d,e,f
so i want to get the result of "a" plus the result of the ones "a" is connected with (b,e) and (b,f). Im sorry if im not very specific.
I would use a transitive closure
part_of(Object, Part) :-
component(Object, C), (Part = C ; part_of(C, Part)).
and setof/3
?- setof(C, part_of(a,C), L).
L = [b, c, d, e, f].
note this requires an acyclic graph, or will loop forever

existential qualifier in prolog, using setof / bagof

I had a quick question re. existential qualifier using setof in prolog (i.e. ^).
using SICStus it seems that (despite what a number of websites claim), S does indeed appear to be quantified in the code below (using the bog standard, mother of / child of facts, which i havent included here):
child(M,F,C) :- setof(X,(mother(S,X)),C).
i check the unification using:
child(M,F,C) :- setof(X-S,(mother(S,X)),C).
so the following code, with the existential operator seem to make no difference:
child(M,F,C) :- setof(X,S^(mother(S,X)),C).
Any ideas why this is? What would be a situation where you would need the unifier then?
thanks!
Ok, I'm not sure I can explain it perfectly, but let me try.
It has to do with the fact that you are querying over a 2-ary relation, mother/2. In that case using X-S as the template has a similar effect on the result set C as using S^ in front of the goal. In X-S you are using both variables in the template, and therefore each possible binding of X and S is included in C. You get the same effect using S^ in front of the goal, as this is saying "ignore bindings of S when constructing the result".
But the difference between the two becomes clearer when you query over a 3-ary relation. The SWI manual has this example:
foo(a, b, c).
foo(a, b, d).
foo(b, c, e).
foo(b, c, f).
foo(c, c, g).
Now do similar queries as in your example
setof(X-Z, foo(X,Y,Z), C).
and
setof(Z, X^foo(X,Y,Z), C).
and you get different results.
It's not just checking unification, X-Z effectively changes your result set.
Hope that helps.
Edit: Maybe it clarifies things when I include the results of the two queries above. The first one goes like this:
?- setof(X-Z, foo(X,Y,Z), C).
Y = b
C = [a-c, a-d] ;
Y = c
C = [b-e, b-f, c-g] ;
No
The second one yields:
?- setof(Z, X^foo(X,Y,Z), C).
Y = b
C = [c, d] ;
Y = c
C = [e, f, g] ;
No

Resources