Related
Using Prolog, I first created two facts called grade and food: The first fact is grade(X,Y) where X is the student (rob or matt) and Y is the grade level (freshman or sophomore). The second fact is food(X,Y) where X is the student (rob or matt) and Y is the food (pizza, burger, pasta, wrap).
I created a rule called preference(X,Y), where X is the student (rob or matt) and Y is the students' preference.
I want to enter preference(rob,X). in the GNU Prolog and have it return:
sophomore, pizza, burger.
However, it keeps returning: sophomore, pizza, pizza.
How do I fix this problem? I've spent hours looking into this. Thanks
This is the code I have:
grade(rob, sophomore).
grade(matt, freshman).
food(rob, pizza).
food(rob, burger).
food(matt, pasta).
food(matt, wrap).
preference(X,Y):-
grade(X,A),
food(X,B),
food(X,C),
Y = (A, B, C).
The way you have defined your facts is nice. The way you query it is not conventional. Here is how I would do it. The "preference" rule is simpler:
grade(rob, sophomore).
grade(matt, freshman).
food(rob, pizza).
food(rob, burger).
food(matt, pasta).
food(matt, wrap).
preference(X, A, Y):-
grade(X, A),
food(X, Y).
You conventionally query the database and get all solutions with backtracking:
?- preference(rob, Grade, Food).
Grade = sophomore,
Food = pizza ;
Grade = sophomore,
Food = burger.
If you want to collect the foods, you can use bagof/setof, like this:
?- bagof(Food, preference(rob, Grade, Food), Foods).
Grade = sophomore,
Foods = [pizza, burger].
What if you want to query all freshmen?
?- bagof(Food, preference(Person, freshman, Food), Foods).
Person = matt,
Foods = [pasta, wrap].
You need to state that the value of B and C are different; there are multiple ways to do that, for the simplicity I go with \==/2 (documentation):
preference(X,Y):-
grade(X,A),
food(X,B),
food(X,C),
B\==C,
Y = (A, B, C).
Gives the output
| ?- preference(X,Y).
X = rob
Y = (sophomore,pizza,burger) ? ;
X = rob
Y = (sophomore,burger,pizza) ? ;
X = matt
Y = (freshman,pasta,wrap) ? ;
X = matt
Y = (freshman,wrap,pasta) ? ;
no
If you don't want to have the basically doubled entries you can go with the (in this case lexical) "less than" #</2:
preference(X,Y):-
grade(X,A),
food(X,B),
food(X,C),
B #< C,
Y = (A, B, C).
| ?- preference(X,Y).
X = rob
Y = (sophomore,burger,pizza) ? ;
X = matt
Y = (freshman,pasta,wrap) ? ;
no
I may be wrong, but I suspect this may be a misunderstanding of prolog in general in addition to a non-intuitive REPL. Prolog doesn't really "return" a value, it just tries to match the variables to values that make your predicates true, and I would be willing to bet you're hitting enter after you see the first result.
The way preference is currently written B and C will match any two foods that rob is associated with. This could be pizza, pizza or pizza, burger or burger, pizza, or so on. It does not check whether B and C are equal. When I run preference(rob,X). prolog does not only give me the first result UNLESS I hit enter.
| ?- preference(rob,X).
X = (sophomore,pizza,pizza) ? ?
Action (; for next solution, a for all solutions, RET to stop) ?
If you hit a (or spam ; a few times) prolog will give you the rest of the results.
| ?- preference(rob,X).
X = (sophomore,pizza,pizza) ? a
X = (sophomore,pizza,burger)
X = (sophomore,burger,pizza)
X = (sophomore,burger,burger)
yes
| ?-
I think that all you really need to get all of a person's preferences is just food unless you specifically need them in a tuple or list which will take some slightly more complicated logic (let me know in a comment if that's what you're looking for)
| ?- food(rob, X).
X = pizza ? a
X = burger
yes
| ?-
I have an exam coming up and I'm going through past papers to help my understanding.
I came across the following past paper question:
Consider the following queries and answers. Some answers coincide with
what SWI-Prolog would infer whereas others are erroneous. Indicate which
answers are genuine and which ones are fake (no explanation of your answer
is required).
(i) |?- [A, B, C] ins 0 .. 2, A #= B + C.
A = 0..2 B = 0..2 C = 0..2
(ii) |?- A in 0 .. 3, A * A #= A.
A = 0..2
(iii) |?- [A, B] ins -1 .. 1, A #= B.
A = 1 B = 1
(iv) |?- [A, B] ins 0 .. 3, A #= B + 1.
A = 1..3 B = 1..2
I'm struggling to see how each one is either true or false. Would someone be able to explain to me how to figure these out please.
Thank you, really appreciate the help.
The key principle for deciding which answers are admissible and which are not is to look whether the residual program is declaratively equivalent to the original query. If the residual constraints admit any solution that the original query does not, or the other way around, then the answer is fake (or you have found a mistake in the CLP(FD) solver). If the shown answer is not even syntactically valid, then the answer is definitely fake.
Let's do it:
(i) |?- [A, B, C] ins 0 .. 2, A #= B + C.
suggested answer: A = 0..2 B = 0..2 C = 0..2
WRONG! The original query constrains the variables to integers, but this answer is not even a syntactically valid Prolog program.
(ii) |?- A in 0 .. 3, A * A #= A.
suggested answer: A = 0..2
WRONG! The original query constrains A to integers, but according to this residual program, A = 0..2 is a valid solution. The term ..(0, 2) is not an integer.
(iii) |?- [A, B] ins -1 .. 1, A #= B.
suggested answer: A = 1 B = 1
WRONG! Not syntactically valid.
(iv) |?- [A, B] ins 0 .. 3, A #= B + 1.
suggested answer: A = 1..3 B = 1..2
WRONG! Not syntactically valid.
Note that even if all shown answers were syntactically valid and =/2 were replaced by in/2 in the residual goals of (i), (ii) and (iv), these answer would still be all wrong, because you can in each case find solutions that either are not admissible by the original query or the residual goals, but not both. I leave solving these cases as an exercise for you, for example, suppose the respective answers are:
A in 0..2, B in 0..2, C in 0..2.
A in 0..2.
A = 1, B = 1.
A in 1..3, B in 1..2.
and find a witness for each case to show that the residual goals are semantically different from the respective original query.
For example, in case (1), A = B = C = 2 would be a valid solution according to the residual constraints, but obviously the original constraints exclude this solution, because 2 #= 2 + 2 does not hold!
A variable is always restricted to get a value contained in its domain, and arithmetic constrains only reduce the domain of involved variables.
So, try to 'label' all variables - that is, assign values from answers reported domains. Of course, if the arithmetic relation is not satisfied, you can say the answer is faked. Take ii). Does it hold for A=0 ? What about A=2 ?
This 'test' of course doesn't suffice to answer all questions. Some reported domains are narrower. For instance, take iii). Can you see any reason that excludes -1, or 0. If you cannot, you should mark the answer as faked.
I'd like to assert facts about all members of a List in prolog, and have any resulting unification retained. As an example, I'd like to assert that each list member is equal to five, but none of the below constructs does this:
?- L=[X,Y,Z], forall(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
?- L=[X,Y,Z], foreach(member(E,L), E=5).
L = [_h27057686,_h27057704,_h27057722]
X = _h27057686
Y = _h27057704
Z = _h27057722
yes
I would like a way to pose the query such that X=5,Y=5, and Z=5.
There is a lot of terminology that you might be getting wrong, or I am misunderstanding you.
"Equal to" is not the same as "could unify", or "unify", but it depends how you mean it.
With SWI-Prolog, from the top level:
?- X == 5.
false. % the free variable X is not the integer 5
?- unifiable(X, 5, U).
U = [X=5]. % you could unify X with 5, then X will be 5
?- X = 5.
X = 5. % X unifies with 5 (and is now bound to the integer 5)
The comment by CapelliC already has the answer that you are most likely after: given a list of variables (either free or not), make so that each variable in the list is bound to the integer 5. This is best done by unification (the third query above). The maplist simply applies the unification to each element of the list.
PS. In case you are wondering how to read the maplist(=(5), L):
These three are equivalent:
maplist(=(5), [X,Y,Z])
maplist(=, [5,5,5], [X,Y,Z])
X=5, Y=5, Z=5
And of course X=5 is the same as =(X,5).
so I just got started with Prolog this semester, and got the homework to implement a pretty basic d(function, variable, derivative) which I did like this:
d(X,X,1) :- !.
d(C,X,0) :- atomic(C). %, (C \= X).
d(X**E,X,E*X**(E-1)).
d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).
d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).
d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
I know this is not complete, but it covers all the tasks required in the exercise.
However,
?- d((x*x+2*x+3)/(3*x),x,R).
leads to
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)).
which doesn't look pretty at all. is/2 unfortunately doesn't like my x as it is not a number...
Is there a simple solution to achieve a cleaner result?
I would rather see this as two separate problems:
First, get derivation right (you're probably getting close, depending on your concrete requirements).
Then, work on simplifying expressions on an algebraic level. Exploit algebraic identities, see if applying the laws of commutativity / associativity / distributivity on some subexpressions enable their rewriting into something equivalent (but simpler / more compact).
As a starting point, you may want to look at the somewhat related question "Replacing parts of expression in prolog".
Here's a simplistic sketch how you could do the simplification—using iwhen/2 to safeguard against insufficient instantiation:
expr_simplified(A, B) :-
iwhen(ground(A), xpr_simplr(A,B)).
xpr_simplr(A, B) :-
( atomic(A)
-> A = B
; ( A = X+0 ; A = 0+X ; A = 1*X ; A = X*1 )
-> xpr_simplr(X, B)
; ( A = 0*_ ; A = _*0 )
-> B = 0
; A = X+X
-> B = X*2
; A = X*X
-> B = X**2
; A = X**1
-> B = X
; A =.. [F|Xs0], % defaulty catch-all
maplist(xpr_simplr, Xs0, Xs),
B =.. [F|Xs]
).
Let's see what it does with the expression you gave. We apply expr_simplified/2 until we reach a fixed point:
?- A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
expr_simplified(A,B),
expr_simplified(B,C),
expr_simplified(C,D).
A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
B = ((x+x+(0+2))*(3*x)-(x**2+2*x+3)*(0+3))/(3*x)**2,
C = ((x*2+2)*(3*x)-(x**2+2*x+3)*3)/(3*x)**2,
D = C. % fixed point reached
As imperfect as the simplifier is, the expression got a lot more readable.
a possibility to get a number is to replace each instance of variable x with a value, visiting the derived tree. You should do writing a clause to match each binary operator, or use a generic visit, like
set_vars(E, Vs, Ev) :-
E =.. [F,L,R],
set_vars(L, Vs, Lv),
set_vars(R, Vs, Rv),
Ev =.. [F,Lv,Rv].
set_vars(V, Vs, N) :- memberchk(V=N, Vs).
set_vars(V, _, V).
that yields
?- d((x*x+2*x+3)/(3*x),x,R), set_vars(R,[x=5],E), T is E.
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)),
E = ((1*5+5*1+ (0*5+2*1)+0)* (3*5)- (5*5+2*5+3)* (0*5+3*1))/ (3*5* (3*5)),
T = 0.29333333333333333
but, there is a bug in your first clause, that once corrected, will allow to evaluate directly the derived expression:
d(X,V,1) :- X == V, !.
...
now, we can throw away the utility set_vars/3, so
?- d((T*T+2*T+3)/(3*T),T,R), T=8, V is R.
T = 8,
R = ((1*8+8*1+ (0*8+2*1)+0)* (3*8)- (8*8+2*8+3)* (0*8+3*1))/ (3*8* (3*8)),
V = 0.3177083333333333.
I'm new to Prolog as I'm just starting to learn and write up my own small set of database rules. Using my own .pl file of database rules, I'm having a small problem with a query that I enter in Prolog, using these rules. Below shows my small database of rules:
staff(andy,18235,3).
staff(beth,19874,4).
staff(andy,18235,5).
staff(carl,16789,2).
staff(earl,34567,9).
sum([], 0).
sum([H|T], X) :-
sum(T, X1),
X is X1 + H.
getincome(Name, Income) :-
findall(Income,staff(Name,_,Income),Member),
sum(Member, Income).
As you can see, I have written a rule that finds the total income for a particular member of staff. This works very fine, as when I input:
?- getincome(andy, X).
The program always returns:
X = 8
As it should do, however whenever I instead input:
?- getincome(andy, 8).
This always returns false, when it should be true.
However when I also input:
?- getincome(andy, 3).
This returns true, due to already being in the database.
I'm just wondering, how could I modify this rule so that this could output true for the correct summation value, entered for any given staff (most particularly Andy), as opposed to the value already in the given database?
Ignore my question above!
Thanks for the help 'false'. I'm also having another issue, this time to do with working out and displaying the sum of the income for each member. I have modified my rules, in order to display this, as follows:
getincome(Name, I) :- staff(Name, _, _ ), findall(Income,staff(Name,_,Income),Member), sum(Member, I).
Whenever I enter the query:
?- getincome(X, Y).
I keep getting duplicate results of staff (most notably Andy, of course), as show below:
X = andy,
Y = 8 ;
X = beth,
Y = 4 ;
X = andy,
Y = 8 ;
X = carl,
Y = 2 ;
X = earl,
Y = 9.
What changes can I make to avoid these duplicates?
library(aggregate) offers a clean interface to solve such kind of problems:
?- aggregate(sum(S), K^staff(E,K,S), I).
E = andy,
I = 8 ;
E = beth,
I = 4 ;
E = carl,
I = 2 ;
E = earl,
I = 9.
One way to do this is to use bagof to collect each set of incomes:
person_income(Name, Income) :-
bagof(I, X^staff(Name,X,I), Incomes), % Incomes for a given name
sumlist(Incomes, Income). % Sum the incomes
With results:
| ?- person_income(Name, Income).
Income = 8
Name = andy ? a
Income = 4
Name = beth
Income = 2
Name = carl
Income = 9
Name = earl
yes
| ?- person_income(andy, Income).
Income = 8
yes
| ?- person_income(Name, 8).
Name = andy ? a
no
| ?-
I named this person_income to emphasize that it's a relation between a person and their income, rather than getincome which is more of an imperative notion, and doesn't really reflect that you can do more with the relation than just "get the income". Also, I'm using SWI Prolog's sumlist/2 here. GNU Prolog has sum_list/2. And as #CappeliC indicates in his answer, SWI Prolog has a handy aggregate predicate for operations like this.