Count the ups and downs - prolog

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.

Related

Multiple instances of Prolog clauses with identical ground head. Any uses besides for this besides (dubious) control of computation?

In SWI Prolog:
Exact clause duplicates are allowed:
a(1).
a(1).
?- a(X).
X = 1 ;
X = 1.
or even:
c :- format("Hello from first c!").
c :- format("Hello from second c!").
Hello from first c!
true ;
Hello from second c!
true.
More generally, so are clauses with identical fully ground heads but differing bodies:
b(1) :- format("Hello from first b!").
b(1) :- format("Hello from second b!").
?- b(1).
Hello from first b!
true ;
Hello from second b!
true.
Clauses with identical non-ground head feel somewhat more reasonable:
p(X) :- format("Yup, this is p(~w)",X).
p(X) :- format("Yup, this is also p(~w)",X).
p(X) :- format("You think you can get rid of good old p(~w) just like that?",X).
?- p('homer simpson').
Yup, this is p(homer simpson)
true ;
Yup, this is also p(homer simpson)
true ;
You think you can get rid of good old p(homer simpson) just like that?
true.
?- p(X).
Yup, this is p(_4782)
true ;
Yup, this is also p(_4782)
true ;
You think you can get rid of good old p(_4782) just like that?
true.
This covers the reasonable case of clauses with a guarded body:
p(X) :- X < 0, format("It's less than 0: ~w", X).
p(X) :- X =:= 0, format("It's exactly 0: ~w", X).
p(X) :- X > 0, format("It's larger than 0: ~w", X).
On second thoughts ... we already encounter the ultimate case in the built-in repeat:
?- repeat.
true ;
true ;
true ;
true ;
…
Or can construct an intermediate case easily:
h :- member(_,[1,2,3]).
?- h.
true ;
true ;
true.
Somehow textbooks gloss over the fact that predicates have additional semantics: they can not only be false or true for any given ground arguments, but they can actually be true(n) - "true n times, n ≥ 0" .
From a theory standpoint, this is dubious, at least for vanilla classical logic.
On the other hand, it is useful from a computational standpoint for:
Side-effects (rather for output than for input, and rather marginally).
Control of the computation (i.e. repeat).
Are there any other uses?
I really feel the compiler should flag variable-less cases like a/1, c/0, b/1 above as errors (easy to detect), and even repeat/0 should probably have a value: repeat(Count). Anything which redoes successfully should NOT redo successfully in the same context on exactly the same ground arguments. It has the same squishy feeling of irrelevancy as a(X) :- b(Y). b(Z). Brrr!.
Yes, for diagnostic purposes in pure programs. By duplicating a clause you can answer the question how often the clause contributes to solutions.
That is, you count the answers/solutions you get from a query and compare these to the same program plus the duplicated clause. If the number of (redundant) solutions now increases you know that this clause contributes. The ld factor tells you how often.
Note that a tracer cannot tell you this as easily.
Some observations in the particular case of duplicated clauses.
If the repeated clauses for predicate a/1 are found in a Logtalk object or in a Prolog module that can be compiled as an object, the Logtalk linter can warn you of duplicated clauses. For example, given the following module:
:- module(duplicates, []).
a(1).
a(1).
We get:
?- set_logtalk_flag(duplicated_clauses, warning).
true.
?- {duplicates}.
* Duplicated clause: a(1)
* first found at or above line 3
* while compiling object duplicates
* in file /Users/pmoura/duplicates.lgt at or above line 4
*
% [ /Users/pmoura/duplicates.lgt loaded ]
% 1 compilation warning
true.
This particular lint warning is usually turned off by default due to its computational cost. If you load the tutor tool prior to the compilation of the module, you will get instead:
?- {tutor(loader)}.
...
% (0 warnings)
true.
?- set_logtalk_flag(duplicated_clauses, warning).
true.
?- {duplicates}.
* Duplicated clause: a(1)
* first found at or above line 3
* while compiling object duplicates
* in file /Users/pmoura/Desktop/duplicates.lgt at or above line 4
* Duplicated clauses are usually a source code editing error and can
* result in spurious choice-points, degrading performance. Delete or
* correct the duplicated clause to fix this warning.
*
% [ /Users/pmoura/Desktop/duplicates.lgt loaded ]
% 1 compilation warning
true.
The warning is useful and proved itself worth in non-trivial codebases.
#false mentions in his answer using duplicated clauses to "answer the question how often the clause contributes to solutions." He also mentions "that a tracer cannot tell you this as easily".
A better solution to this use case is to use a ports profiler tool as found in e.g. ECLiPSe and Logtalk. No need to duplicate clauses to gather that information.
As an example, consider the following pure program, saved in a pure.pl file:
a :- b, c.
b.
b :- d.
c.
d.
Let's include this code in an object. We can define it in a source file:
:- object(pure).
:- set_logtalk_flag(debug, on).
:- public(a/0).
:- include('pure.pl').
:- end_object.
Alternatively, we can create pure as a dynamic object:
?- create_object(pure, [], [set_logtalk_flag(debug,on), public(a/0), include('pure.pl')], []).
true.
Either way, after loading or creating the pure object and loading the ports_profiler tool, we can e.g. query all solutions for the a/0 predicate and then print the profiling data:
?- {ports_profiler(loader)}.
...
% (0 warnings)
true.
?- pure::a.
true ;
true.
?- ports_profiler::data.
-------------------------------------------------------------------
Entity Predicate Fact Rule Call Exit *Exit Fail Redo Error
-------------------------------------------------------------------
pure a/0 0 1 1 1 1 0 1 0
pure b/0 1 1 1 1 1 0 1 0
pure c/0 2 0 2 2 0 0 0 0
pure d/0 1 0 1 1 0 0 0 0
-------------------------------------------------------------------
true.
The table displays port crossing information for all predicates used in the query to the a/0 predicate. For example, that the predicate c/0 as called twice (for the two solutions to a/0) and exited deterministically. On the other hand, the predicate b/0 was called once by succeeded twice (on of them non-deterministically) due to backtracking.
For details on the portable port_profiler tool and a discussion on the insights that it can provide, see:
https://logtalk.org/manuals/devtools/ports_profiler.html

Prolog subtract value not working

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 .

How Prolog's logical update view works for assert and retract?

Can someone please explain the Prolog logical view about assert and retract in details?
For example in code below, in the first run Prolog returns true and in subsequent runs returns false. I don't know why because of Prolog logical view when asserta(nextBound(100)) satisfies, nice(X) is still frozen with values when it started so this change should be ignore and nextbound(100) must be false.
nextBound(10000).
nice(X) :-
asserta(nextBound(100)),
retract(nextBound(10000)),
nextBound(100).
You can do a trace to determine what happens:
| ?- nice(_).
1 1 Call: nice(_17) ?
2 2 Call: asserta(nextBound(100)) ?
2 2 Exit: asserta(nextBound(100)) ? <-- 1st assert of netBound(100) succeeds
3 2 Call: retract(nextBound(10000)) ?
3 2 Exit: retract(nextBound(10000)) ? <-- retract nextBound(10000) succeeds
4 2 Call: nextBound(100) ?
4 2 Exit: nextBound(100) ? <-- Succeeds because netBound(100) now a fact
1 1 Exit: nice(_17) ?
(1 ms) yes
{trace}
| ?- nice(_).
1 1 Call: nice(_17) ?
2 2 Call: asserta(nextBound(100)) ?
2 2 Exit: asserta(nextBound(100)) ? <-- 2nd assert of netBound(100) succeeds
3 2 Call: retract(nextBound(10000)) ?
3 2 Fail: retract(nextBound(10000)) ? <-- retract nextBound(10000) fails
1 1 Fail: nice(_17) ?
(3 ms) no
{trace}
| ?-
You can see that, in the first case, first the nextBound(100) fact is successfully asserted (for the 1st time). Then, the retract(nextBound(10000)) succeeds because nextBound(10000). is a fact which exists in the data. Following that, the query nextBound(100) succeeds because two steps before this fact was asserted into the data.
On the second execution of nice(_), nextBound(10000) doesn't exist because it was retracted in the first execution, and the code doesn't re-assert it. So, in the second execution of nice(_), retract(nextBound(10000)) fails because the fact nextBound(10000) doesn't exist and the entire second execution of nice(_) fails at that point since backtracking over asserta and retract do not re-execute and produce additional results.
A listing shows that now there are two nextBound(100) facts, since we've asserted one in each of the two runs of nice(_), and no nextBound(10000) since it was retracted in the first run of nice(_):
| ?- listing.
% file: user
nice(_) :-
asserta(nextBound(100)),
retract(nextBound(10000)),
nextBound(100).
% file: user_input
nextBound(100).
nextBound(100).
(1 ms) yes
| ?-
The logical update view, as stated in the SWI documentation, says, Starting with SWI-Prolog 3.3.0 we adhere to the logical update view, where backtrackable predicates that enter the definition of a predicate will not see any changes (either caused by assert/1 or retract/1) to the predicate.
In other words, the logical update view prevents the predicate from dynamically changing itself while it's executing. That's not the scenario here.
In fact, it's critical in Prolog that, during the execution of a predicate, if you assert a fact at one point in the predicate, that result must be visible in it immediately, or the predicate may not be able to function properly. There are many many common library predicates that rely on this behavior.
To start from a historical view, the logical update view has been first implemented in Quintus 2.0 (whose current successor is SICStus) and described in the literature in 1987. It has been adopted in ISO Prolog ISO/IEC 13211-1:1995. The principal idea is that any goal of a dynamic predicate will take exactly those clauses into account that are present at the point in time when the goal is executed. Any further changes — be they additions or deletions — are not taken into account for the execution of that very goal.
Prior to the logical update view, there have been various more or less consistent implementations, most were incompatible with various optimizations for Prolog systems. Note that the difference only shows if you have goals that may have more than one answer. Either as a simple goal, or when using retract and you are using retract/1 or assertz/1. The difference does not show when using asserta/1 only. So your example cannot clarify the differences.
Consider a dynamic predicate p/1. Since the following interaction is using the toplevel only, I will make p/1 known to the system by asserting a fact and immediately retracting all facts of p/1. Also, I will remove all facts with retractall(p(_)) before starting the next query.
?- asserta(p(1)).
true. % now p/1 is known to the system.
?- retractall(p(_)), assertz(p(1)), p(X), assertz(p(2)).
X = 1. % only one answer!
?- retractall(p(_)), assertz(p(1)), p(X), assertz(p(2)), p(Y).
X = 1, Y = X
; X = 1, Y = 2.
So the first goal p(X) sees only p(1), whereas the second goal p(Y) sees both. This applies for any active goal:
?- retractall(p(_)), assertz(p(1)), assertz(p(2)), p(X), assertz(p(3)), p(Y).
X = 1, Y = X
; X = 1, Y = 2
; X = 1, Y = 3
; X = 2, Y = 1
; X = 2, Y = X
; X = 2, Y = 3
; X = 2, Y = 3
; false.
Again, note that X is only 1 or 2 but not 3.
Alternatively, you can imagine that each goal p(X) is replaced by:
... findall(Xi, p(Xi), Xis), member(X, Xis) ...
This shows you a bit the idea behind: Conceptually, all answers are stored temporally, and only then each answer is shown.
Er, above is not quite true, for only the clauses of p/1 are handled this way. That is, as long as you are storing only facts, above explanation is perfect, but should you also store rules, you would need a more complex explanation, roughly:
... findall(Xi-Bi, clause(p(Xi),Bi), XiBis), member(X-B,XiBis), B ...
And, again, this is not the plain truth, for some more exotic issues like cuts might intervene. I will leave it that way for the moment1.
Similarly, retract/1 will also see and delete the clauses it sees at the point in time of executing it. For most situations this is quite intuitive and agrees with our expectations. Nevertheless, there are quite absurd situations as the following:
?- retractall(p(_)),
assertz(p(1)), assertz(p(2)),
retract(p(X)), ( X = 1, retract(p(Y)) ; X = 2, Y = none ).
X = 1, Y = 2
; X = 2, Y = none.
Here, the fact p(2) was deleted twice, although the data base contained only a single fact p(2).
Footnotes
1 Actually, replace
... p(X) ...
by
... findall(Xi-Bi, clause(p(Xi),Bi), XiBis), answs_goal_x(XiBis,X, G), G ...
with
answs_goal_x([], _, true).
answs_goal_x([Xi-Bi|XiBis], X, ( X = Xi, Bi ; G) ) :-
answs_goal_x(XiBis, X, G).

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.

Generating integers < limit

I am trying to generate all integers (natural numbers) smaller than a limit, let's say 10.
I have a predicate nat(X) which produces all numbers from 0 to infinity.
Now my problem is, if I do:
nat10(X) :- nat(X), X =< 10.
This will never terminate, as it tries to find other solutions with nat(X) until infinity.
I need a construct that let's me fail the whole predicate if one subgoal fails. How would I go about doing that?
Depending upon the problem being solved, you might want to consider constraint logic programming over finite domains (CLPFD).
But in this context, you need just prevent Prolog from backtracking if X > 10. The current predicate nat10/1 has no such constraint, so we'll add it:
nat10(X) :- nat(X), ( X > 10 -> !, fail ; true ).
So if X > 10, we do a cut (!) to prevent backtracking to nat(X) (thus avoiding generating natural numbers above 10 infinitely) and then simply fail. Otherwise, we succeed (true).
| ?- nat10(X).
X = 1 ? ;
X = 2 ? ;
...
X = 9 ? ;
X = 10 ? ;
(3 ms) no
| ?-
If you can use clpfd, then this answer is for you!
:- use_module(library(clpfd)).
Simply try:
nat10(X) :-
X in 0..10,
indomain(X).

Resources