This is a cube, the edges of which are directional; It can only go left to right, back to front and top to bottom.
edge(a,b).
edge(a,c).
edge(a,e).
edge(b,d).
edge(b,f).
edge(c,d).
edge(c,g).
edge(d,h).
edge(e,f).
edge(e,g).
edge(f,h).
edge(g,h).
With the method below we can check if we can go from A-H for example: cango(A,H).
move(X,Y):- edge(X,Y).
move(X,Y):- edge(X,Z), move(Z,Y).
With move2, I'm trying to impalement counting of steps required.
move2(X,Y,N):- N is N+1, edge(X,Y).
move2(X,Y,N):- N is N+1, edge(X,Z), move2(Z,Y,N).
How would I implement this?
arithmetic evaluation is carried out as usual in Prolog, but assignment doesn't work as usual. Then you need to introduce a new variable to increment value:
move2(X,Y,N,T):- T is N+1, edge(X,Y).
move2(X,Y,N,T):- M is N+1, edge(X,Z), move2(Z,Y,M,T).
and initialize N to 0 at first call. Such added variables (T in our case) are often called accumulators.
move2(X,Y,1):- edge(X,Y), ! .
move2(X,Y,NN):- edge(X,Z), move2(Z,Y,N), NN is N+1 .
(is)/2 is very sensitive to instantiations in its second argument. That means that you cannot use it in an entirely relational manner. You can ask X is 1+1., you can even ask 2 is 1+1. but you cannot ask: 2 is X+1.
So when you are programming with predicates like (is)/2, you have to imagine what modes a predicate will be used with. Such considerations easily lead to errors, in particular, if you just started. But don't worry, also more proficient programmers still fall prey to such problems.
There is a clean alternative in several Prolog systems: In SICStus, YAP, SWI there is a library(clpfd) which permits you to express relations between integers. Usually this library is used for constraint programming, but you can also use it as a safe and clean replacement for (is)/2 on the integers. Even more so, this library is often very efficiently compiled such that the resulting code is comparable in speed to (is)/2.
?- use_module(library(clpfd)).
true.
?- X #= 1+1.
X = 2.
?- 2 #= 1+1.
true.
?- 2 #= X+1.
X = 1.
So now back to your program, you can simply write:
move2(X,Y,1):- edge(X,Y).
move2(X,Y,N0):- N0 #>= 1, N0 #= N1+1, edge(X,Z), move2(Z,Y,N1).
You get now all distances as required.
But there is more to it ...
To make sure that move2/3 actually terminates, try:
?- move2(A, B, N), false.
false.
Now we can be sure that move2/3 always terminates. Always?
Assume you have added a further edge:
edge(f, f).
Now above query loops. But still you can use your program to your advantage!
Determine the number of nodes:
?- setof(C,A^B^(edge(A,B),member(C,[A,B])),Cs), length(Cs, N).
Cs = [a, b, c, d, e, f, g, h], N = 8.
So the longest path will take just 7 steps!
Now you can ask the query again, but now by constraining N to a value less than or equal to7:
?- 7 #>= N, move2(A,B, N), false.
false.
With this additional constraint, you have again a terminating definition! No more loops.
Related
So, my goal is to make a map colourer in Prolog. Here's the map I'm using:
And this are my colouring constraints:
colouring([A,B,C,D,E,F]) :-
maplist( #\=(A), [B,C,D,E] ),
maplist( #\=(B), [C,D,F]),
C #\= D,
maplist( #\=(D), [E,F]),
E #\= F.
Where [A,B,C,D,E,F] is a list of numbers(colors) from 1 to n.
So I want my solver to, given a List of 6 colors and a natural number N, determine the colors and N constraints both ways, in a way that even the most general query could yield results:
regions_ncolors(L,N) :- colouring(L), L ins 1..N, label(L).
Where the most general query is regions_ncolors(L,N).
However, the operator ins doesn't seem to accept a variable N, it instead yields an argument not sufficiently instantiated error. I've tried using this solution instead:
int_cset_(N,Acc,Acc) :- N #= 0.
int_cset_(N,Acc,Cs) :- N_1 #= N-1, int_cset_(N_1,[N|Acc],Cs).
int_cset(N,Cs) :- int_cset_(N,[],Cs).
% most general solver
regions_ncolors(L,N) :- colouring(L), int_cset(N,Cs), subset(L,Cs), label(L).
Where the arguments in int_cset(N,Cs) is a natural number(N) and the counting set Sn = {1,2,...,N}
But this solution is buggy as regions_ncolors(L,N). only returns the same(one) solution for all N, and when I try to add a constraint to N, it goes in an infinite loop.
So what can I do to make the most general query work both ways(for not-instantiated variables)?
Thanks in advance!
Btw, I added a swi-prolog tag in my last post although it was removed by moderation. I don't know if this question is specific to swi-prolog which is why I'm keeping the tag, just in case :)
Your colouring is too specific, you encode the topology of your map into it. Not a problem as is, but it defeats of the purpose of then having a "most general query" solution for just any list.
If you want to avoid the problem of having a free variable instead of a list, you could first instantiate the list with length/2. Compare:
?- L ins 1..3.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [16] throw(error(instantiation_error,_86828))
ERROR: [10] clpfd:(_86858 ins 1..3) ...
Is that the same problem as you see?
If you first make a list and a corresponding set:
?- length(L, N), L ins 1..N.
L = [],
N = 0 ;
L = [1],
N = 1 ;
L = [_A, _B],
N = 2,
_A in 1..2,
_B in 1..2 ;
L = [_A, _B, _C],
N = 3,
_A in 1..3,
_B in 1..3,
_C in 1..3 .
If you use length/2 like this you will enumerate the possible lists and integer sets completely outside of the CLP(FD) labeling. You can then add more constraints on the variables on the list and if necessary, use labeling.
Does that help you get any further with your problem? I am not sure how it helps for the colouring problem. You would need a different representation of the map topology so that you don't have to manually define it within a predicate like your colouring/1 you have in your question.
There are several issues in your program.
subset/2 is impure
SWI's (by default) built-in predicate subset/2 is not the pure relation you are hoping for. Instead, it expects that both arguments are already sufficiently instantiated. And if not, it takes a guess and sticks to it:
?- colouring(L), subset(L,[1,2,3,4,5]).
L = [1,2,3,4,2,1].
?- colouring(L), subset(L,[1,2,3,4,5]), L = [2|_].
false.
?- L = [2|_], colouring(L), subset(L,[1,2,3,4,5]), L = [2|_].
L = [2,1,3,4,1,2].
With a pure definition it is impossible that adding a further goal as L = [2|_] in the third query makes a failing query succeed.
In general it is a good idea to not interfere with labeling/2 except for the order of variables and the options argument. The internal implementation is often much faster than manual instantiations.
Also, your map is far too simple to expose subset/2s weakness. Not sure what the minimal failing graph is, but here is one such example from
R. Janczewski et al. The smallest hard-to-color graph for algorithm DSATUR, Discrete Mathematics 236 (2001) p.164.
colouring_m13([K1,K2,K3,K6,K5,K7,K4]):-
maplist(#\=(K1), [K2,K3,K4,K7]),
maplist(#\=(K2), [K3,K5,K6]),
maplist(#\=(K3), [K4,K5]),
maplist(#\=(K4), [K5,K7]),
maplist(#\=(K5), [K6,K7]),
maplist(#\=(K6), [K7]).
?- colouring_m13(L), subset(L,[1,2,3,4]).
false. % incomplete
?- L = [3|_], colouring_m13(L), subset(L,[1,2,3,4]).
L = [3,1,2,2,3,1,4].
int_cset/2 never terminates
... (except for some error cases like int_cset(non_integer, _).). As an example consider:
?- int_cset(1,Cs).
Cs = [1]
; loops.
And don't get fooled by the fact that an actual solution was found! It still does not terminate.
#Luis: But how come? I'm getting baffled by this, the same thing is happening on ...
To see this, you need the notion of a failure-slice which helps to identify the responsible part in your program. With some falsework consisting of goals false the responsible part is exposed.
All unnecessary parts have been removed by false. What remains has to be changed somehow.
int_cset_(N,Acc,Acc) :- false, N #= 0.
int_cset_(N,Acc,Cs) :- N1 #= N-1, int_cset_(N1,[N|Acc],Cs), false.
int_cset(N,Cs) :- int_cset_(N,[],Cs), false.
?- int_cset(1, Cs), false.
loops.
Adding the redundant goal N1 #> 0
will avoid unnecessary non-termination.
This alone will not solve your problem since if N is not given, you will still encounter non-termination due to the following failure slice:
regions_ncolors(L,N) :-
colouring(L),
int_cset(N,Cs), false,
subset(L,Cs),
label(L).
In int_cset(N,Cs), Cs occurs for the first time and thus cannot influence termination (there is another reason too, its definition would ignore it as well..) and therefore only N has a chance to induce termination.
The actual solution has been already suggested by #TA_intern using length/2 which liberates one of such mode-infested chores.
So far, I have always taken steadfastness in Prolog programs to mean:
If, for a query Q, there is a subterm S, such that there is a term T that makes ?- S=T, Q. succeed although ?- Q, S=T. fails, then one of the predicates invoked by Q is not steadfast.
Intuitively, I thus took steadfastness to mean that we cannot use instantiations to "trick" a predicate into giving solutions that are otherwise not only never given, but rejected. Note the difference for nonterminating programs!
In particular, at least to me, logical-purity always implied steadfastness.
Example. To better understand the notion of steadfastness, consider an almost classical counterexample of this property that is frequently cited when introducing advanced students to operational aspects of Prolog, using a wrong definition of a relation between two integers and their maximum:
integer_integer_maximum(X, Y, Y) :-
Y >= X,
!.
integer_integer_maximum(X, _, X).
A glaring mistake in this—shall we say "wavering"—definition is, of course, that the following query incorrectly succeeds:
?- M = 0, integer_integer_maximum(0, 1, M).
M = 0. % wrong!
whereas exchanging the goals yields the correct answer:
?- integer_integer_maximum(0, 1, M), M = 0.
false.
A good solution of this problem is to rely on pure methods to describe the relation, using for example:
integer_integer_maximum(X, Y, M) :-
M #= max(X, Y).
This works correctly in both cases, and can even be used in more situations:
?- integer_integer_maximum(0, 1, M), M = 0.
false.
?- M = 0, integer_integer_maximum(0, 1, M).
false.
| ?- X in 0..2, Y in 3..4, integer_integer_maximum(X, Y, M).
X in 0..2,
Y in 3..4,
M in 3..4 ? ;
no
Now the paper Coding Guidelines for Prolog by Covington et al., co-authored by the very inventor of the notion, Richard O'Keefe, contains the following section:
5.1 Predicates must be steadfast.
Any decent predicate must be “steadfast,” i.e., must work correctly if its output variable already happens to be instantiated to the output value (O’Keefe 1990).
That is,
?- foo(X), X = x.
and
?- foo(x).
must succeed under exactly the same conditions and have the same side effects.
Failure to do so is only tolerable for auxiliary predicates whose call patterns are
strongly constrained by the main predicates.
Thus, the definition given in the cited paper is considerably stricter than what I stated above.
For example, consider the pure Prolog program:
nat(s(X)) :- nat(X).
nat(0).
Now we are in the following situation:
?- nat(0).
true.
?- nat(X), X = 0.
nontermination
This clearly violates the property of succeeding under exactly the same conditions, because one of the queries no longer succeeds at all.
Hence my question: Should we call the above program not steadfast? Please justify your answer with an explanation of the intention behind steadfastness and its definition in the available literature, its relation to logical-purity as well as relevant termination notions.
In 'The craft of prolog' page 96 Richard O'Keef says 'we call the property of refusing to give wrong answers even when the query has an unexpected form (typically supplying values for what we normally think of as inputs*) steadfastness'
*I am not sure if this should be outputs. i.e. in your query ?- M = 0, integer_integer_maximum(0, 1, M). M = 0. % wrong! M is used as an input but the clause has been designed for it to be an output.
In nat(X), X = 0. we are using X as an output variable not an input variable, but it has not given a wrong answer, as it does not give any answer. So I think under that definition it could be steadfast.
A rule of thumb he gives is 'postpone output unification until after the cut.' Here we have not got a cut, but we still want to postpone the unification.
However I would of thought it would be sensible to have the base case first rather than the recursive case, so that nat(X), X = 0. would initially succeed .. but you would still have other problems..
(Let me sneak that in within the wave of midterm questions.)
A common definition for the sum of two natural numbers is nat_nat_sum/3:
nat_nat_sum(0, N, N).
nat_nat_sum(s(M), N, s(O)) :-
nat_nat_sum(M, N, O).
Strictly speaking, this definition is too general, for we have now also success for
?- nat_nat_sum(A, B, unnatural_number).
Similarly, we get the following answer substitution:
?- nat_nat_sum(0, A, B).
A = B.
We interpret this answer substitution as including all natural numbers and do not care about other terms.
Given that, now lets consider its termination property. In fact, it suffices to consider the following failure slice. That is, not only will nat_nat_sum/3 not terminate, if this slice does not terminate. This time they are completely the same! So we can say iff.
nat_nat_sum(0, N, N) :- false.
nat_nat_sum(s(M), N, s(O)) :-
nat_nat_sum(M, N, O), false.
This failure slice now exposes the symmetry between the first and third argument: They both influence non-termination in exactly the same manner! So while they describe entirely different things — one a summand, the other a sum — they have exactly the same influence on termination. And the poor second argument has no influence whatsoever.
Just to be sure, not only is the failure slice identical in its common termination condition
(use cTI) which reads
nat_nat_sum(A,B,C)terminates_if b(A);b(C).
It also terminates exactly the same for those cases that are not covered by this condition, like
?- nat_nat_sum(f(X),Y,Z).
Now my question:
Is there an alternate definition of nat_nat_sum/3 which possesses the termination condition:
nat_nat_sum2(A,B,C) terminates_if b(A);b(B);b(C).
(If yes, show it. If no, justify why)
In other words, the new definition nat_nat_sum2/3 should terminate if already one of its arguments is finite and ground.
Fine print. Consider only pure, monotonic, Prolog programs. That is, no built-ins apart from (=)/2 and dif/2
(I will award a 200 bounty on this)
nat_nat_sum(0, B, B).
nat_nat_sum(s(A), B, s(C)) :-
nat_nat_sum(B, A, C).
?
Ok, seems its over. The solution I was thinking of was:
nat_nat_sum2(0, N,N).
nat_nat_sum2(s(N), 0, s(N)).
nat_nat_sum2(s(N), s(M), s(s(O))) :-
nat_nat_sum2(N, M, O).
But as I realize, that's just the same as #mat's one which is almost the same as #WillNess'es.
Is this really the better nat_nat_sum/3? The original's runtime is independent of B (if we ignore one (1) occurs check for the moment).
There is another downside of my solution compared to #mat's solution which naturally extends to nat_nat_nat_sum/3
nat_nat_nat_sum(0, B, C, D) :-
nat_nat_sum(B, C, D).
nat_nat_nat_sum(s(A), B, C, s(D)) :-
nat_nat_nat_sum2(B, C, A, D).
Which gives
nat_nat_nat_sum(A,B,C,D)terminates_if b(A),b(B);b(A),b(C);b(B),b(C);b(D).
(provable in the unfolded version
with cTI)
The obvious trick is to flip the arguments:
sum(0,N,N).
sum(N,0,N).
sum(s(A),B,s(C)):- sum(B,A,C) ; sum(A,B,C).
Take the following two definitions:
Definition 1:
add(n,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
Definition 2:
add(n,X,X).
add(s(X),Y,Z) :- add(X,s(Y),Z).
Definition 1 terminates for pattern add(-,-,+), whereas definition 2
does not terminate for pattern add(-,-,+). Look see:
Definition 1:
?- add(X,Y,s(s(s(n)))).
X = n,
Y = s(s(s(n))) ;
X = s(n),
Y = s(s(n)) ;
X = s(s(n)),
Y = s(n) ;
X = s(s(s(n))),
Y = n
?-
Definition 2:
?- add(X,Y,s(s(s(n)))).
X = n,
Y = s(s(s(n))) ;
X = s(n),
Y = s(s(n)) ;
X = s(s(n)),
Y = s(n) ;
X = s(s(s(n))),
Y = n ;
Error: Execution aborted since memory threshold exceeded.
add/3
add/3
?-
So I guess definition 1 is better than definition 2.
Bye
The term fib(N,F) is true when F is the Nth Fibonacci number.
The following Prolog code is generally working for me:
:-use_module(library(clpfd)).
fib(0,0).
fib(1,1).
fib(N,F) :-
N #> 1,
N #=< F + 1,
F #>= N - 1,
F #> 0,
N1 #= N - 1,
N2 #= N - 2,
F1 #=< F,
F2 #=< F,
F #= F1 + F2,
fib(N1,F1),
fib(N2,F2).
When executing this query (in SICStus Prolog), the first (and correct) match is found for N (rather instantly):
| ?- fib(X,377).
X = 14 ?
When proceeding (by entering ";") to see if there are any further matches (which is impossible by definition), it takes an enormous amount of time (compared to the first match) just to always reply with no:
| ?- fib(X,377).
X = 14 ? ;
no
Being rather new to Prolog, I tried to use the Cut-Operator (!) in various ways, but I cannot find a way to prevent the search after the first match. Is it even possible given the above rules? If yes, please let me know how :)
There are two parts to get what you want.
The first is to use
call_semidet/1
which ensures that there is exactly one answer. See links for an
implementation for SICStus, too. In the unlikely event of having more
than one answer, call_semidet/1 produces a safe error. Note that
once/1 and !/0 alone simply cut away whatever there has been.
However, you will not be very happy with call_semidet/1 alone. It
essentially executes a goal twice. Once to see if there is no more
than one answer, and only then again to obtain the first answer. So
you will get your answer much later.
The other part is to speed up your definition such that above will not
be too disturbing to you. The solution suggested by CapelliC changes
the algorithm altogether which is specific to your concrete function
but does not extend to any other function. But it also describes a
different relation.
Essentially, you found the quintessential parts already, you only need
to assemble them a bit differently to make them work. But, let's start
with the basics.
CLPFD as CLP(Z)
What you are doing here is still not that common to many Prolog
programmers. You use finite domain constraints for general integer
arithmetics. That is, you are using CLPFD as a pure substitute to the
moded expression evaluation found in (is)/2, (>)/2 and the
like. So you want to extend the finite domain paradigm which assumes
that we express everything within finite given intervals. In fact, it
would be more appropriate to call this extension CLP(Z).
This extension does not work in every Prolog offering finite
domains. In fact, there is only SICStus, SWI and YAP that correctly
handle the case of infinite intervals. Other systems might fail or
succeed when they rather should succeed or fail - mostly when integers
are getting too large.
Understanding non-termination
The first issue is to understand the actual reason why your original
program did not terminate. To this end, I will use a failure
slice. That
is, I add false goals into your program. The point being: if the
resulting program does not terminate then also the original program
does not terminate. So the minimal failure slice of your (presumed)
original program is:
fiborig(0,0) :- false.
fiborig(1,1) :- false.
fiborig(N,F) :-
N #> 1,
N1 #= N-1,
N2 #= N-2,
F #= F1+F2,
fiborig(N1,F1), false,
fiborig(N2,F2).
There are two sources for non-termination here: One is that for a given
F there are infinitely many values for F1 and F2. That can be
easily handled by observing that F1 #> 0, F2 #>= 0.
The other is more related to Prolog's execution mechanism. To
illustrate it, I will add F2 #= 0. Again, because the resulting
program does not terminate, also the original program will loop.
fiborig(0,0) :- false.
fiborig(1,1) :- false.
fiborig(N,F) :-
N #> 1,
N1 #= N-1,
N2 #= N-2,
F #= F1+F2,
F1 #> 0,
F2 #>= 0,
F2 #= 0,
fiborig(N1,F1), false,
fiborig(N2,F2).
So the actual problem is that the goal that might have 0 as result
is executed too late. Simply exchange the two recursive goals. And add
the redundant constraint F2 #=< F1 for efficiency.
fibmin(0,0).
fibmin(1,1).
fibmin(N,F) :-
N #> 1,
N1 #= N-1,
N2 #= N-2,
F1 #> 0,
F2 #>= 0,
F1 #>= F2,
F #= F1+F2,
fibmin(N2,F2),
fibmin(N1,F1).
On my lame laptop I got the following runtimes for fib(N, 377):
SICStus SWI
answer/total
fiborig: 0.090s/27.220s 1.332s/1071.380s
fibmin: 0.080s/ 0.110s 1.201s/ 1.506s
Take the sum of both to get the runtime for call_semidet/1.
Note that SWI's implementation is written in Prolog only, whereas
SICStus is partly in C, partly in Prolog. So when porting SWI's (actually #mat's) clpfd to
SICStus, it might be comparable in speed.
There are still many things to optimize. Think of indexing, and the
handling of the "counters", N, N1, N2.
Also your original program can be improved quite a bit. For example,
you are unnecessarily posting the constraint F #>= N-1 three times!
If you are only interested in the first solution or know that there is at most one solution, you can use once/1 to commit to that solution:
?- once(fib(X, 377)).
+1 for using CLP(FD) as a declarative alternative to lower-level arithmetic. Your version can be used in all directions, whereas a version based on primitive integer arithmetic cannot.
I played a bit with another definition, I wrote in standard arithmetic and translated to CLP(FD) on purpose for this question.
My plain Prolog definition was
fibo(1, 1,0).
fibo(2, 2,1).
fibo(N, F,A) :- N > 2, M is N -1, fibo(M, A,B), F is A+B.
Once translated, since it take too long in reverse mode (or doesn't terminate, don't know),
I tried to add more constraints (and moving them around) to see where a 'backward' computation terminates:
fibo(1, 1,0).
fibo(2, 2,1).
fibo(N, F,A) :-
N #> 2,
M #= N -1,
M #>= 0, % added
A #>= 0, % added
B #< A, % added - this is key
F #= A+B,
fibo(M, A,B). % moved - this is key
After adding B #< A and moving the recursion at last call, now it works.
?- time(fibo(U,377,Y)).
% 77,005 inferences, 0.032 CPU in 0.033 seconds (99% CPU, 2371149 Lips)
U = 13,
Y = 233 ;
% 37,389 inferences, 0.023 CPU in 0.023 seconds (100% CPU, 1651757 Lips)
false.
edit To account for 0 based sequences, add a fact
fibo(0,0,_).
Maybe this explain the role of the last argument: it's an accumulator.
I have got some values H, and I would like to find the maximum one using \+, how can i do it?
maxValue(X) :-
Get(Id, X),
\+( Get(Id, Y), X < Y ).
don't have a clue....please help, thanks!
Using negation is one way to find the maximum. And it really works.
Here is an example:
p(2).
p(1).
p(3).
?- p(X), \+ (p(Y), Y > X).
X = 3
But the complexity will be O(n*n) where n is
the number of facts. But the maximum can be
determined in O(n). So maybe the following is
more efficient for large fact bases:
:- dynamic(the_max/1).
update_max(X) :-
the_max(Y), X>Y, !, retract(the_max(Y)), assertz(the_max(X)).
update_max(_).
find_max(X) :-
assertz(the_max(0)),
(p(Y), update_max(Y), fail; true),
retract(the_max(X)).
?- find_max(X).
X = 3
But watch out, when you use it from multiple threads,
you need to adapt it a little, i.e. make the_max
thread local.
Best Regards
See also these questions/answers:
Prolog query to find largest element in database?
Max out of values defined by prolog clauses