prolog, probably some race condition - prolog

just to practice prolog, I am solving a few puzzles using it and I ran into some very weird behavior of prolog.
The full code may be found here https://github.com/bibiki/AdventOfCode2022/blob/main/day14/solution.pl
The interesting part is this
start_a_grid( Xlength, Ylength, Result ) :-
give_me( Ylength, air, Row ),
give_me( Xlength, Row, Result ).
give_me( 0, V, [] ).
give_me( N, V, [V|Rest] ) :-
write(N), nl,
N1 is N - 1,
give_me(N1, V, Rest).
Now, if I run start_a_grid(535, 169, Grid) it works fine, I get a Grid. If, I however, run start_a_grid(535, 169, Cave), input(Lines), init(Lines, Cave, Initialized). then N in my give_me predicate goes below 0. From my experiemnts, it is the inclusion of init predicate in my query that causes the problem.
start_a_grid(13, 11, Cave), sample_lines(Lines), init(Lines, Cave, Initialized) works perfectly fine.
My swipl version is 'SWI-Prolog version 8.4.2 for x86_64-linux'. Am I missing something or is this rather a bug in my swipl version? Thanks in advance for your answers.

Related

Tree methods going on infinite loop

So all of my tree code is not working properly when I instantiate my integer variables. Here's an example of what I mean:
% relates a tree and the numbe of nodes in that tree(order)
tree_order(empty,0).
tree_order(tree(_, Left_Subtree, Right_Subtree), Order) :-
Order #> 0,
Order #= Left_Subtree_Order + Right_Subtree_Order + 1,
tree_order(Left_Subtree, Left_Subtree_Order), tree_order(Right_Subtree, Right_Subtree_Order).
I'm not actually using that but here's my definition of a tree:
% Definition of a Binary Tree
tree(empty).
tree(tree(_, Left_Subtree, Right_Subtree)) :-
tree(Left_Subtree), tree(Right_Subtree).
So if run the following query tree_order(Tree, 2). it gives me a solution then when it backtracks it goes on an infinite loop. It's honestly baffling me, because I've run the program in my head a thousand times and I still can't find an answer.
One possibility is that Prolog is adding infinitely many nodes to the left of the tree and it doesn't realize that it actually leads to the tree having order greater than 2.
But if that's the case, how can I tell prolog to stop adding more than 2 nodes to the tree? I've thought about using CLP but the only methods I know reason about numerical domains and lists but not predicates.
Thanks in advance!
The reason for non-termination of tree_order(T, 2). is the following failure-slice:
tree_order(empty,0) :- false.
tree_order(tree(_, Left_Subtree, Right_Subtree), Order) :-
Order #> 0,
Order #= Left_Subtree_Order + Right_Subtree_Order + 1,
tree_order(Left_Subtree, Left_Subtree_Order), false,
tree_order(Right_Subtree, Right_Subtree_Order).
?- tree_order(T, 2).
loops.
In order to make this terminating, you need to specialize this program somehow. Like by adding T = tree(_,empty,empty) in front of the query.
Or by adding the redundant constraint Right_Subtree_Order #>=0.
Note that strictly speaking, this is no longer an example of finite domains but rather (potentially) infinite domains. Not all clpfd implementations support this. SICStus, Scryer, and SWI do support it. But only in Scryer and SWI does unification of such terms always terminate.
Better to constraint every free variable involved:
/* File: tree_order.pl
Author: Carlo,,,
Created: Oct 19 2021
Purpose: https://stackoverflow.com/q/69623834/874024
*/
:- module(tree_order,
[tree_order/2
]).
:- use_module(library(clpfd)).
% relates a tree and the number of nodes in that tree(order)
tree_order(empty, 0).
tree_order(tree(_, Left_Subtree, Right_Subtree), Order) :-
% Order #> 0, implicit given the following 3 constraints
Left_Subtree_Order #>= 0,
Right_Subtree_Order #>= 0,
Order #= Left_Subtree_Order + Right_Subtree_Order + 1,
tree_order(Left_Subtree, Left_Subtree_Order),
tree_order(Right_Subtree, Right_Subtree_Order).
yields
[debug] ?- tree_order(T,2).
T = tree(_, empty, tree(_, empty, empty)) ;
T = tree(_, tree(_, empty, empty), empty) ;
false.

Steadfastness: Definition and its relation to logical purity and termination

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

CLP Prolog - Logic Programming

we have a list of list think an example ?- solve([[40,A,B],[30,B],[60,A,B,C]]),label([A,B,C]). will succeed with replacing B=30,A=10 and C=20.
The constraint with this example is A+B=40, A+B+C=60 and generally every variable are in between 0 and 100. Every list must begin with a constant and it includes at least one variable.
:- use_module(library(clpfd)).
sum([],0). % if the list is empty.
sum([X|XS],Z) :-
sum(XS,Z1),
X in 0..100,
Z #= X+Z1.
solveOne([Const|Var]) :-
sum(Var,Const).
solve([]). % if the list of list is also empty
solve([First|Others]) :-
solveOne(First),
solve(Others).
I am a bit skeptic the idea of base case,facts. Because every list must include at list one variable according to constraints, on the other hand we think about the "empty list" situation.?
First, the obvious problem: you define both a solve/2 and a solve/1 predicate (solve([],0)). The ",0" is probably unwanted.
Apart from that, if you have only a constant, like [X], then solveOne succeeds only if X is zero; otherwise, it fails according to sum([],0). So, in a sense, you indirectly check that you can have at least one variable if you assume your sum is always strictly positive.
In order to explicitely check that there is effectively at least one variable, then you can modify solveOne as follows:
solveOne([Const,V1|Vars]) :-
sum([V1|Vars], Const).
#coredump answer should put you on right track. If you are interested in writing lean code, consider this more succint definition (tested in SWI-Prolog)
solve(L) :- maplist(solveOne, L).
solveOne([C|Vs]) :- Vs ins 0..100, sum(Vs, #=, C).
?- solve([[40,A,B],[30,B],[60,A,B,C]]).
A = 10,
B = 30,
C = 20.

Prolog - converting succ representation into decimal

This is my code:
numeral(0).
numeral(succ(X)) :- numeral(X).
convertToD(A,0).
convertToD(succ(S), Y) :- numeral(S), Y1 is Y-1, convertToD(S, Y1).
Why does this give me such an output?
convertTo(succ(succ(0)), N).
N = 0 ;
ERROR: convertTo/2: Arguments are not sufficiently instantiated
Well, you're getting more than one answer because of this:
convertToD(A,0).
What you mean to have here is convertToD(0, 0), because otherwise you're saying "convertToD is true between anything and 0" when you mean "convertToD is 0 for 0." This is also why Prolog thinks you have multiple results.
Having given it some thought and noticed a question this question is a duplicate of, I see what you were trying to accomplish with the second clause. What you're trying to do is emulate the clpfd solution from there in ordinary Prolog. With clpfd:
convertToD(succ(S), Y) :- numeral(S), Y0 #= Y-1, convertToD(S, Y0).
A straightforward copy of that into vanilla Prolog gets us your code here, but what doesn't happen is all the magic clpfd brings to the table. Without clpfd, it's very difficult to make a predicate that works for any instantiation combination and never loops. One thing that helps is to move the arithmetic last:
convertToD(succ(S), Y) :- numeral(S), convertToD(S, Y1), succ(Y1, Y).
This gets us a predicate with all the desirable properties, except it loops here:
?- convertToD(X, 3).
X = s(s(s(0))) ;
^CAction (h for help) ? abort
I've messed with this with when/2 and var/1/nonvar/1 and haven't been able to solve that little problem.

how to run suspended goals in prolog with constraints

I am trying to solve a specific problem using prologs constraint solvers, and I'm stuck :D
A more general version of my problem requirement is the like this:
:- lib(ic).:- lib(ic).
solve( [A1*X+B1*Y=C1, A2*X+B2*Y=C2] ):-
X::[0..999],
Y::[0..999],
X #\= 0,
Y #\= 0,
A1*X+B1*Y#=C1, % line1
A2*X+B2*Y#=C2. % line2
And this is the query/goal I use:
solve( [2*X+3*Y=5, 3*X+2*Y=5] ).
And the program will compute the values of X and Y (in this case X=1, Y=1 is the solution).
What I am thinking is, what if the number of arguments in the goal/query can vary..in this case, my prolog program needs to have a dynamic suspended goals in place of lines commented with %line1 and %line2..
Question is, how do i make these expressions delayed..? I do not want to hard code these in the problem and think that only two expressions will be passed over through the goal..
Hope the question is clear.
Thanks.
I think you mean something like:
:- lib(ic).
solve([]).
solve([Eq | Eqs]) :-
term_variables(Eq, Vars),
Vars :: [0..999],
( foreach(Var, Vars) do Var #\= 0 ),
Eq = (Lhs = Rhs),
Eq0 = (Lhs #= Rhs),
call(Eq0),
solve(Eqs).
Note that this is ECLiPSe-CLP specific code (the foreach-loop which could be translated to a recursive helper predicate, of course, and the IC library).
Also note that call(Eq0) and writing just Lhs #= Rhs should have the same effect (afaik). But when the variables in Lhs #= Rhs are solver variables, that seems not to the case, at least I encountered such a problem some months ago using lib(cplex).

Resources