Prolog returning false for summation query - prolog

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.

Related

How to make a rule return all details of a fact using Prolog

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
| ?-

How not to show if there is same result occurs more than once- Prolog

Scenario
I have the code as below. My question is how to don't show appearing same result more than once.
male(charles).
male(andrew).
male(edward).
female(ann).
age(charles, 70).
age(ann, 65).
age(andrew, 60).
age(edward, 55).
nextking(X) :- age(X,P), age(Y,Q),
P>=Q, X\==Y; age(X,55).
Current Output
What I need
I need the output to be charles, ann, andrew, edward. No repetition of names.
With a fairly recent version, you can use library(solution_sequences):
?- distinct(nextking(X)).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
or use the classic 'all solutions' builtin:
?- setof(K,K^nextking(K),Ks),member(X,Ks).
Ks = [andrew, ann, charles, edward],
X = andrew ;
Ks = [andrew, ann, charles, edward],
X = ann ;
...
but in this case, we loose the answer order defined by the KB.
Your nextking/1 predicate is rather inefficient, and furthermore does not guarantee the persons to be sorted by age.
If we would for example put charles last in the list of facts, we get:
?- nextking(X).
X = ann ;
X = ann ;
X = andrew ;
X = charles ;
X = charles ;
X = charles ;
X = edward.
basically te predicate you wrote has two clauses:
nextking(X) :-
age(X,P),
age(Y,Q),
P >= Q,
X\==Y.
nextking(X) :-
age(X, 55).
The first simply will yield any X for which there exists a person Y that is younger. But that thus gives no guarantees that these elements are sorted. Finally the last predicate will unify with all persons X that are 55 years old. For this specific case this works, but it would mean if we state another fact age(louise, 14), then this will fail. Not only is the approach incorrect, but even if it was correct it will be very "unstable".
We can make use of the setof/3 [swi-doc] predicate that does not only perform a uniqness filter, but also sorts the elements.
Since we want to sort the members of the royal family by descending age, we thus should construct 2-tuples (or an other structure that encapsulates the two parameters) where the first parameter contains the negative age, and the second parameter the corresponding person.
We can then use member/2 [swi-doc] to "unwind" the list in individual unifications:
nextking(X) :-
setof((NA, X), A^(age(X, A), NA is -A), Royals),
member((_, X), Royals).
This will produce the list of elements like:
?- nextking(X).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
regardless how the facts are ordered in the source file.

Prolog internal variable names

I have a large numbers of facts that are already in my file (position(M,P)), M is the name and P is the position of the player , I am asked to do a player_list(L,N), L is the list of players and N is the size of this list. I did it and it works the problem is that it gives the list without the names it gives me numbers and not names
player_list([H|T],N):- L = [H|T],
position(H,P),
\+ member(H,L),
append(L,H),
player_list(T,N).
what I get is:
?- player_list(X,4).
X = [_9176, _9182, _9188, _9194] .
so what should I do ?
You could use an additional list as an argument to keep track of the players you already have. This list is empty at the beginning, so the calling predicate calls the predicate describing the actual relation with [] as an additional argument:
player_list(PLs,L) :-
pl_l_(PLs,L,[]). % <- actual relation
The definition you posted is missing a base case, that is, if you already have the desired amount of players, you can stop adding others. In this case the number of players to add is zero otherwise it is greater than zero. You also have to describe that the head of the list (PL) is a player (whose position you don't care about, so the variable is preceded by an underscore (_P), otherwise the goal is just like in your code) and is not in the accumulator yet (as opposed to your code, where you check if PL is not in L) but in the recursive call it is in the accumulator. You can achieve the latter by having [PL|Acc0] in the recursive goal, so you don't need append/2. Putting all this together, your code might look something like this:
pl_l_([],0,_). % base case
pl_l_([PL|PLs],L1,Acc0) :-
L1 > 0, % number of players yet to add
L0 is L1-1, % new number of players to add
position(PL,_P), % PL is a player and
\+ member(PL,Acc0), % not in the accumulator yet
pl_l_(PLs,L0,[PL|Acc0]). % the relation holds for PLs, L0 and [PL|Acc0] as well
With respect to your comment, I assume that your code contains the following four facts:
position(zlatan,center).
position(rooney,forward).
position(ronaldo,forward).
position(messi,forward).
Then your example query yields the desired results:
?- player_list(X,4).
X = [zlatan,rooney,ronaldo,messi] ? ;
X = [zlatan,rooney,messi,ronaldo] ? ;
...
If you intend to use the predicate the other way around as well, I suggest the use of CLP(FD). To see why, consider the most general query:
?- player_list(X,Y).
X = [],
Y = 0 ? ;
ERROR at clause 2 of user:pl_l_/3 !!
INSTANTIATION ERROR- =:=/2: expected bound value
You get this error because >/2 expects both arguments to be ground. You can modify the predicate pl_l_/3 to use CLP(FD) like so:
:- use_module(library(clpfd)).
pl_l_([],0,_).
pl_l_([PL|PLs],L1,Acc0) :-
L1 #> 0, % <- new
L0 #= L1-1, % <- new
position(PL,_P),
\+ member(PL,Acc0),
pl_l_(PLs,L0,[PL|Acc0]).
With these modifications the predicate is more versatile:
?- player_list([zlatan,messi,ronaldo],Y).
Y = 3
?- player_list(X,Y).
X = [],
Y = 0 ? ;
X = [zlatan],
Y = 1 ? ;
X = [zlatan,rooney],
Y = 2 ?
...

How can I assert facts about all List members in Prolog?

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).

How do I work with equations that are passed on in the goal/query of prolog?

I have this scenario wherein I get a linear equation in the Prolog query like below:
?- myquery( 3X + 5Y = 10, Result).
So my query has an equation 3X + 5Y = 10, which in general assumes the form AX + BY = C, where A=3, B=5 and C=10.
Now, in my prolog program, I am trying to define a predicate that can take in the expression mentioned in the query above. That is, I somehow want to get A, B and C values and also the operator involved (in the above case the plus operator) stored and then used on the logic that I define withing the program. I am wondering how this can be done.
To be more generic, the question is how do I identify the constants and the operator involved in an equation that is passed on through the goal/query?
SWI-Prolog has a constraint library clp(Q,R) that solve at symbolic level these equations:
[debug] ?- [library(clpq)].
% library(clpq) compiled into clpq 0,27 sec, 992 clauses
true.
?- {3 * X + 5 * Y = 10}.
{Y=2-3 rdiv 5*X}.
Eclipse will surely have something more advanced. These libraries aren't simple, tough...
Of interest to you, the Prolog syntax is used, as a host language, so the usual builtins could be applied for identify vars, constants, and the like.
The following transcript may prove illuminating:
32 ?- Term = (3*_X + 5*_Y = 10), functor(Term,F,A).
Term = 3*_G527+5*_G530=10
F = =
A = 2
33 ?- Term = (3*_X + 5*_Y = 10), arg(Arg,Term,Val).
Term = 3*_G459+5*_G462=10
Arg = 1
Val = 3*_G459+5*_G462 ; % user pressed ';' interactively
Term = 3*_G459+5*_G462=10
Arg = 2
Val = 10 ; % user pressed ';' interactively
No
35 ?- Term = (3*_X + 5*_Y = 10), arg(1,Term,Val1), functor(Val1,F1,A1),
arg(2,Val1,Val12).
Term = 3*_G693+5*_G696=10
Val1 = 3*_G693+5*_G696
F1 = +
A1 = 2
Val12 = 5*_G696
The last query reads: for Term as given, 1st arg of Term is Val1, the functor of Val1 is F1 with arity A1 (meaning, it has A1 args - subparts - itself), and 2nd arg of the term in Val1 is stored under Val12 name. To clarify, any symbolic data in Prolog is in the form of fff(aa,bb,cc,...) where fff is some name, called functor, and the "arguments" in that expression can be accessed through the arg call.
That means that the original expression (3*_X + 5*_Y = 10) is actually stored in Prolog as '='( '+'( '*'(3,_X), '*'(5,_Y)), 10). When you get to the atomic parts (functors with arity 0), you can check them further:
47 ?- arg(1,(3*X),V), functor(V,F,A), number(V).
X = _G441
V = 3
F = 3
A = 0
Yes
EDIT: to answer your other question (from the comments):
1 ?- (3*_X + 5*_Y = 10) = (A*X + B*Y = C).
A = 3
X = _G412
B = 5
Y = _G415
C = 10
Yes
If you insist on not writing out the multiplication sign * explicitly, you will have to represent your terms as strings, and to analyze that string. That would be a much more involved task.
EDIT: another thing to try is =.. predicate, called "Univ":
4 ?- (3*_X + 5*_Y = 10) =.. X.
X = [=, 3*_G454+5*_G457, 10]
Yes
5 ?- (3*_X + 5*_Y = 10) =.. X, X=[X1,X2,X3], X2 =.. Y.
X = [=, 3*_G545+5*_G548, 10]
X1 = =
X2 = 3*_G545+5*_G548
X3 = 10
Y = [+, 3*_G545, 5*_G548]
Yes
You can for example use term inspection predicates: arg/3, functor/3, var/1, (=..)/2 etc.
You might want to take a look at examples of symbolic differentiation implemented using term rewrite rules; they handle such expressions.
Here's a chapter (minus 1 page) from the book Clause and Effect that you might find useful:
Clause and Effect - Chapter Six: Term Rewriting
Another from The art of Prolog: advanced programming techniques
23 An equation solver
Programming in Prolog also has a section (7.11) on symbolic differentiation.

Resources