Prolog subtract value not working - prolog

I got this knowledge base:
bottle(b1).
bottle(b2).
bottle(b3).
bottle(b4).
full(bottle(b1),100).
full(bottle(b2),150).
full(bottle(b3),300).
full(bottle(b4),400).
consume(bottle(X),Milliliter) :-
full(bottle(X),Y),
Milliliter=<Y,
Y-10.
So I want to use the consume predicate, and I want to reduce the value assigned to full as much as the value which is getting consumed. Is it allowed to subtract from static values and how could I work around this problem to achieve only the value true if there hasn't been consumed the bottle yet.

If you want to "update" the KB when you call "consume", you will have to retract and assert the fact, for example...
% Use this to add the initial facts (if you don;t have a clause to do this, prolog complains about modifying static clauses...)
addfacts :-
asserta(full(bottle(b1),100)),
asserta(full(bottle(b2),150)),
asserta(full(bottle(b3),300)),
asserta(full(bottle(b4),400)).
consume(bottle(X), Millis) :-
% Retract the current state of the bottle
retract(full(bottle(X), V)),
% Calculate the new Millis after consumption
Y is V - Millis,
% Check it was possible (there should be 0 or more millis left after)
Y >= 0,
% Add the new fact
asserta(full(bottle(X), Y)).
Now in prolog, you can do...
1 ?- addfacts.
true.
2 ?- full(bottle(b1), X).
X = 100.
3 ?- consume(bottle(b1), 10).
true.
4 ?- full(bottle(b1), X).
X = 90 .

Related

Recursion confuses me

I have understood the theory part of Recursion. I have seen exercises but I get confused. I've tried to solve some, some I understand and some I don't. This exercise is confusing me. I can't understand why, so I use comments to show you my weak points. I should have power (X,N,P) so P=X^N.
Some examples:
?- power(3,5,X).
X = 243
?- power(4,3,X).
X = 64
?- power(2,4,X).
X = 16
The solution of this exercise is: (See comments too)
power(X,0,1). % I know how works recursion,but those numbers 0 or 1 why?
power(X,1,X). % X,1,X i can't get it.
power(X,N,P) :- % X,N,P if only
N1 is N-1, % N1=N-1 ..ok i understand
power(X,N1,P1), % P1 is used to reach the the P
P is P1*X. % P = P1*X
What I know recursion, I use a different my example
related(X, Y) :-
parent(X, Z),
related(Z, Y).
Compare my example with the exercise. I could say that my first line, what I think. Please help me out with it is a lot of confusing.
related(X, Y) :- is similar to power(X,N,P) :- . Second sentence of my example parent(X, Z), is similar to N1 is N-1, and the third sentence is related(Z, Y). similar to power(X,N1,P1), and P is P1*X..
Let's go over the definition of the predicate step by step. First you have the fact...
power(X,0,1).
... that states: The 0th power of any X is 1. Then there is the fact...
power(X,1,X).
... that states: The 1st power of any X is X itself. Finally, you have a recursive rule that reads:
power(X,N,P) :- % P is the Nth power of X if
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Possibly your confusion is due to the two base cases that are expressed by the two facts (one of those is actually superfluous). Let's consider the following queries:
?- power(5,0,X).
X = 1 ;
ERROR: Out of local stack
The answer 1 is certainly what we expect, but then the predicate loops until it runs out of stack. That's certainly not desirable. And this query...
?- power(5,1,X).
X = 5 ;
X = 5 ;
ERROR: Out of local stack
... yields the correct answer twice before running out of stack. The reason for the redundant answer is that the recursive rule can reduce any given N to zero and to one thus yielding the same answer twice. If you look at the structure of your recursive rule, it is obvious that the first base case is sufficient, so let's remove the second. The reason for looping out of stack is that, after N becomes zero, the recursive rule will search for other solutions (for N=-1, N=-2, N=-3,...) that do not exist. To avoid that, you can add a goal that prevents the recursive rule from further search, if N is equal to or smaller than zero. That leaves you with following definition:
power(X,0,1). % the 0th power of any X is 1
power(X,N,P) :- % P is the Nth power of X if
N > 0, % N > 0 and
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Now the predicate works as expected:
?- power(5,0,X).
X = 1 ;
false.
?- power(5,1,X).
X = 5 ;
false.
?- power(5,3,X).
X = 125 ;
false.
I hope this alleviates some of your confusions.

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

Prolog Use of Cuts

I am re-writing the following function in Prolog:
V1:
f(X,Y):- X < 2, Y is X+1.
f(X,3):- 2 =< X, X < 5.
f(X,Y):- 5 =< X, Y is 8-X.
As V2:
f(X,Y) :-
X < 2,
Y is X + 1.
f(X,Y) :-
X >= 2,
X < 5,
Y is 3.
f(X,Y) :-
X >= 5,
Y is 8-X.
I then wanted to experiment with cuts. For green cuts (V3):
f(X,Y) :-
X < 2, !,
Y is X + 1.
f(X,Y) :-
X >= 2,
X < 5, !,
Y is 3.
f(X,Y) :-
X >= 5,
Y is 8-X.
For red cuts (V4):
f(X,Y) :-
X < 2, !,
Y is X + 1.
f(X,Y) :-
X < 5, !,
Y is 3.
f(X,Y) :-
Y is 8-X.
However, I don't understand their advantage, as deleting the cuts would allow the same behaviour of the code... Any help?
All your versions V1..V4 are observationally equivalent, so you got some reasoning right. Still, there are differences.
Avoiding superfluous choice points
In many implementations, V1 and V2 might be particularly less efficient, for, internally, they "leave open a choice point". This is so because such Prologs do not look any further to the other rules. So each goal f(1,X) consumes a bit of memory that can be freed only on backtracking (or using !). Here is a simple way to try this out yourself:
loop(Goal) :-
Goal,
loop(Goal).
Here is what I get in SWI:
?- time(loop(f1(1,2))).
% 5,991,554 inferences, 81.282 CPU in 81.443 seconds (100% CPU, 73713 Lips)
ERROR: Out of local stack
?- time(loop(f2(1,2))).
% 5,991,553 inferences, 85.032 CPU in 85.212 seconds (100% CPU, 70462 Lips)
ERROR: Out of local stack
Whereas V3 and V4 seem to run indefinitely - at least much longer than 85s. Experiments such as this one are funny for very tiny programs but are not very practical for bigger ones. Fortunately, there is a simple way to tell in many Prologs whether or not a query is executed determinately. To see if your system does this, enter:
?- X = 1.
X = 1.
For your variations:
?- f1(1,2).
true
; % <== Prolog asked for another answer
false. % <== only to conclude that there is none.
?- f2(1,2).
true
; false. % same again
?- f3(1,2).
true. % <== Prolog knows there will be no further answer
?- f4(1,2).
true.
Avoiding recalculations - making cuts red
While V3 avoids superfluous choice points, V4 now even avoids superfluous calculations. So it should be the most efficient. But it comes at the price of fixing the order of the clauses.
However, V3 was only possible, because two necessary conditions for green cuts coincided:
Non-overlapping conditions. That should be obvious to you.
Safe testing of instantiations. This is far from obvious. Please note that the goal X < 2 has an implicit test for a correct instantiation attached! It produces an instantiation error should X be an uninstantiated variable. It is because of this very test that the cut in V3 happens to be a green cut. Without that testing, it would be a red cut.
Note also that V1 and V2 would not be equivalent, if the second rule would be alone! For the goal f(X,5). would fail in V1 but it would produce an error in V2.
As you noted the first version shows green cuts and the second red cuts.
It is not necessary that you will feel the difference between these two versions.
a) one reason can be efficiency, but for toy codes with fast machines you hardly notice it.
b) shuffling the rules should not change code's behavior in case of green cuts, and that's true for the first code. But in the second code, if you put the second clause before the first one than the behavior changes: f(0,3) is true, but initially it was false. Therefore you would feel difference if you shuffle the rules.
Advantage of shuffling is that you don't care about order but content - that's one of the points declarative programing.

Count the ups and downs

In SWI-Prolog, I want to count how many times the user types up and down. Every time he types up, the up counter (xu) will be increased and the down counter (xd) will be decreased. The same will happen when the user types down.This what I have:
:- dynamic xd/1, xu/1.
xd(0).
xu(0).
up :-
retract(xu(Xu)),
succ(Xu, Xu1),
asserta(xu(Xu1)),
retract(xd(Xd)),
succ(Xd1,Xd),
asserta(xd(Xd1)).
down :-
retract(xd(Xd)),
succ(Xd, Xd1),
asserta(xd(Xd1)),
retract(xu(Xu)),
succ(Xu1,Xu),
asserta(xu(Xu1)).
But I have 2 problems:
Whenever the user types up. or down., he gets false. but the xu or xd (respectively) is being increased. For instance
1 ?- down.
false.
2 ?- down.
false.
3 ?- xd(X).
X = 2.
The second problem I have is that if the user starts typing up. a couple of times, and then down., the xd counter won't increase. For instance:
1 ?- down.
false.
2 ?- down.
false.
3 ?- xd(X).
X = 2.
4 ?- up.
false.
5 ?- xu(X).
false.
What am I doing wrong?
The problem is with succ/2. It only works on positive numbers.
From the documentation
succ(X, 0) fails silently
Assertions and retractions, however, are not backtrackable. So the increased counter gets asserted, while the decreased value only gets retracted, but never asserted. That's why you're seeing
5 ?- xu(X).
false.
instead of
5 ?- xu(X).
X = 0.
I recommend you use X1 is X + 1 and X1 is X - 1 instead.

deduction from two goals

Suppose I have such goals:
times(0,_,0). % zero times X is zero
times(X,Y,Z) :- times(Y,X,Z) ,!. % X * Y = Y * X
When I try to ask:
?- times(0,1,X).
I get the double answer :
X = 0 ;
X = 0.
Possibly because first answer is deduced from the fact and second - from the rule.
Question - how to make prolog to give only one answer instead of two ?
add a cut to 'confirm' the first choice:
times(0,_,0) :- !.
or ban the 0 from the second:
times(X,Y,Z) :- X \= 0, times(Y,X,Z).
I've deleted the cut, but leave it if there are more rules.
But I think the 'reflexivity' rule will put you in trouble, with undue recursion.

Resources