Prevent backtracking of function - prolog

Is it possible to specify to not backtrack a certain function? For example with the following code the somestatisticalfunction could be assumed to always be correct, and does not need to be backtracked. So when backtracking I would want Prolog to only backtrack the dosomethingelse(Output) and length(Ls, Size).
f(Ls) :-
length(Ls, Size),
somestatisticsalfunction(Size, Output), % Don't backtrack this
dosomethingelse(Output).

Instead of:
somestatisticsalfunction(Size, Output),
use:
once(somestatisticsalfunction(Size, Output)),
to succeed at most once. See https://www.swi-prolog.org/pldoc/man?predicate=once/1
I would also look at improving somestatisticsalfunction to prevent unwanted choicepoints.

Related

Why does my list reversal only work correctly in one direction?

I have produced the following code.
list_reverse([],[]).
list_reverse([X],[X]).
list_reverse(Ls,[R|Rs]) :-
last_elem(Ls,R),
without_last_elem(Ls,Next),
list_reverse(Next,Rs).
last_elem([E],E).
last_elem([_|Xs],E) :-
last_elem(Xs,E).
without_last_elem([X,_|[]],[X|[]]).
without_last_elem([X|T0],[X|T1]) :-
without_last_elem(T0,T1).
Swipl:
?- list_reverse([1,2,3],X).
X = [3, 2, 1] ;
false.
This is exactly what I want.
However if I go in the opposite direction I get success, followed by non-termination.
?- list_reverse(X,[1,2,3]).
X = [3, 2, 1] ;
C-c C-cAction (h for help) ? a
abort
% Execution Aborted
What I am struggling to understand is why I first get a correct solution for X. Is my program correct or not?
I am not worried about reversing a list as much as I am about this pattern of getting a correct solution followed by non-termination. It is a pattern I have already come across a few times.
I am [worried] about this pattern of getting a correct solution followed by non-termination.
This is due to the very specific notion of (universal) termination in Prolog. In other programming languages termination is a much simpler beast (still an undecidable beast nevertheless). If, say, a function returns then it terminates (for that case). But in Prolog, producing an answer is not the end as there might be further solutions or just an unproductive loop. In fact, it's best not to consider your query ?- list_reverse(X,[1,2,3]). but rather the following instead.
?- list_reverse(X,[1,2,3]), false.
In this manner all distracting answers are turned off. The only purpose of this query is now either to show termination or non-termination.
After that,
you can either try to follow Prolog's precise execution path but that is as insightful as staring into a car's gearbox when you are lost (the gears caused you to move into the place where you are lost thus they are somehow the cause...). Or, you take a step back, and consider related program fragments (called slices) that share certain properties with your original program. For termination, a failure-slice helps you to better understand what is at stake. In your case consider:
list_reverse([],[]) :- false.
list_reverse([X],[X]) :- false.
list_reverse(Ls,[R|Rs]) :-
last_elem(Ls,R), false,
without_last_elem(Ls,Next),
list_reverse(Next,Rs).
last_elem([E],E) :- false.
last_elem([_|Xs],E) :-
last_elem(Xs,E), false.
?- list_reverse(X,[1,2,3]), false.
Since this failure slice does not terminate, also your original program doesn't terminate! And, it is much easier to reason here in this smaller fragment. If you want to fix the problem, you need to modify something in the visible part. Otherwise you will keep being stuck in a loop.
Note that none of the facts is part of the loop. Thus they are irrelevant for non-termination.
Also note that in list_reverse/2 the variable Rs is never used in the visible part. Thus Rs has no influence on termination! Please note that this is a proof of that property already. Does this mean that the second argument of list_reverse/2 has no influence on termination? What do you think?
The last_elem/2 can keep constructing larger lists, that all should be rejected. But you thus get stuck in an infinite loop.
We can make a function that works with accumulator, and iterates over both the two lists concurrently. That means that once the left or right list is exhausted, no more recursive calls will be made:
reverse(L1, L2) :-
reverse(L1, [], L2, L2).
reverse([], L, L, []).
reverse([H|T], L1, R, [_|T2]) :-
reverse(T, [H|L1], R, T2).
Here the [H|T] and [_|T2] pattern thus both pop the first item of the list, and we only match if both lists are exhausted.

Prolog: Redundant results in clauses involving anonymous variables

Consider the following Prolog program.
a(X) :- b(_), c(X).
b(1).
b(2).
b(3).
c(1).
Running the query:
a(X).
in SWI-Prolog, we get three results, all X = 1.
Given that we do not care about the anonymous variable, what is preventing SWI-Prolog to return a single result? Why isn't this optimization performed?
Thanks
Well for Prolog the underscore is simply an anonymous variable. So the a/1 predicate is equivalent to:
a(X) :-
b(Y),
c(X).
Now it may look useless to backtrack over the b(Y) clause, since once it is satisfied, the Y is nowhere used, and thus should not have impact on the rest of the program. Furthermore Y has no effect on X so b(Y) should not have the slightest influence on X.
In real Prolog however, there are some things that might have impact:
the b/1 predicate might perform I/O. Say that the predicate is implemented as:
b(a) :-
print(a).
b(a) :-
print(b).
then it will print a in the first branch and b in the second one.
b/1 might raise an exception in a second, third, ... path. In which case we probably want to handle the error;
b/1 might use asserta/1, assertz/1, etc. and alter the program. It might for instance add facts for c/1 such that in the second run c/1 has other results.
A lot of Prolog interpreters have a non-backtrackable store such that the different backtracking paths, can share information with each other.
other coding facilities such that the outcome of b/1 might have impact on c/1.
You can avoid this backtracking over b/1 by using the once/1 meta-predicate. For instance:
a(X) :-
once(b(_)),
c(X).

Do I need "base step" to make a recursion on Prolog?

I'm learning Prolog at my university and I'm stuck with a question. Note that I'm a newbie in Prolog and I don't even know the correct spelling of Prolog elements.
I need to define a recursive rule in my .pl file and I don't know if I need a "base step" on my rule. Check my rule:
recur_disciplinas(X, Y) :- requisito(X, Y).
recur_disciplinas(X, Y) :- requisito(X, Z), recur_disciplinas(Z, Y).
This is working, but couldn't I do something like the following?
recur_disciplinas(X, Y) :- requisito(X, Z), recur_disciplinas(Z, Y).
What happens when I declare the same "rule name" (recur_disciplinas(X,Y) :-) two times? Occurs somewhat like an overwrite?
I'm currently using swi-prolog. Thank you so much, guys!
The best way how to understand Prolog rules is to look at the :- operator which is a 1970ies rendering of an arrow (yes, the assignment operator := in Pascal was meant as an arrow, too). So you look what is there on the right-hand side and say: Provided all that is true, I can conclude what is on the left-hand side. So you are reading right-to-left with your rule:
recur_disciplinas(X, Y) :- requisito(X, Z), recur_disciplinas(Z, Y).
% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ read
You say: provided there is some X, Y and Z such that the right-hand is true, we can conclude that recur_disciplians(X, Y) holds. Now, lets generalize this by removing requisito(X, Z). What is left now is:
recur_disciplinas(X, Y) :- /******/ recur_disciplinas(Z, Y).
So you can conclude from recur_disciplinas(Z, Y) that recur_disciplinas(X, Y) holds. But you have nothing to start with that conclusion! So effectively this means that there is no solution to this relation at all.
Its like saying, provided I can fly, I will fly like a bird.
Maybe that is true, but as long as you do not fly, it is all in vain.
See this answer how to permit to express your relation more compactly. A goal closure(requisito, X, Y) suffices! And it would even deal with potential loops.
As a side remark, I suspect that recur is some verb, even an imperative. Right? Try to avoid imperatives for relations. Imperatives are good for changing things. Like "switch on the light" which changes the world from a world with a light switched off to one where it is switched on. Imperatives are good for telling a mindless entity what to do. If you rather want to reason about things, imperatives are just malaprop. Focus instead on what should be the case and what not.
If you have a rule name more than one time, it creates an or-branch in your control flow. Prolog will try to unify the first clause. If it will fail, it will try the second clause, and the third, etc.
In the code above, the recur_disciplinas rule will first try to find a matching requisito. If it will fail, it will try to find a requisito-of-a-requisito, transitively, and recursively.
If you don't put a base clause, Prolog will always try the recursive clause, thus it may enter an infinite loop.
Writing base conditions is not unique to Prolog. It is the same with every language that allows recursion. If there is no halting condition, your function will enter an infinite loop.
Consider this equivalent procedural pseudo-code:
def find_disciplinas(X, Y):
if find_requisito(X,Y): # halting condition
return (X, Y)
else: # recursive call
for all Z such that find_requisito(X, Z):
return find_disciplinas(X, Z)
if your "requisito" records include a cycle, and you remove the halting condition, the above procedure will loop indefinitely.
Here we say recur_disciplinas/2 is a predicate with two arguments, and you have asked about whether two clauses (rules) for the predicate are necessary.
As the other Answers have said, one needs a "base case" in recursion so that the recursion terminates, as is usually desirable! The most common arrangement is like your first example: the first rule is the terminating condition (base case) and the second rule is the recursive step (induction case). Someone reading your code will likely find this arrangement familiar and easy to understand.
However the base case and the recursion step MAY be combined into a single rule, and this is sometimes useful. For example, we could use the OR syntax:
recur_disciplinas(X, Y) :-
requisito(X, Y) ; ( requisito(X, Z), recur_disciplinas(Z, Y) ).
Here ; means OR, and this single rule produces essentially the same search for solutions as your original two-rule version.
It is also possible that there can be multiple base cases, each with their own rules or written into a more complicated "combination" rule. As with any programming discipline, clarity and correctness should be prized over mere brevity in code.
In some unusual circumstances it can be advantageous to position the recursive step as the first rule, and move the base case (or cases) into following rules. This would require extra care to ensure the termination condition will always be reached, since it is unlikely you want code that can loop endlessly. The Prolog engine always starts with the first rule when a predicate is invoked; the following rules are tried only once the first rule fails.

Implementing often-occuring determinism patterns in Prolog

When programming in Prolog I often write predicates whose behavior should be semi-deterministic when called with all arguments instantiated (and whose behavior should be non-deterministic otherwise).
A concrete use case for this is my predicate walk/3, which implements graph walks. Since multiple paths can exist between two vertices, the instantiation (+,+) gives multiple choicepoints after true. These are, however, quite useless. Calling code must explicitly use once/1 for performance reasons.
%! walk(+Graph:ugraph, +StartVertex, +EndVertex) is semidet.
%! walk(+Graph:ugraph, -StartVertex, +EndVertex) is nondet.
%! walk(+Graph:ugraph, +StartVertex, -EndVertex) is nondet.
%! walk(+Graph:ugraph, -StartVertex, -EndVertex) is nondet.
Semi-determinism can be forced by the use of once/1 in the calling context, but I want to implement semi-determinism as a property of the predicate walk/3, and not as something that has to be treated specially every time it is called.
In addition to concerns over code aesthetics, the calling context need not always know whether its call to walk/3 is semi-deterministic or not. For example:
%! cycle(+Graph:ugraph, +Vertex) is semidet.
%! cycle(+Graph:ugraph, -Vertex) is nondet.
cycle(Graph, Vertex):-
walk(Graph, Vertex, Vertex).
I have come up with the following solution, which does produce the correct behavior.
walk_wrapper(Graph, Start, End):-
call_ground_as_semidet(walk(Graph, Start, End)).
:- meta_predicate(call_ground_as_semidet(0)).
call_ground_as_semidet(Goal):-
ground(Goal), !,
Goal, !.
call_ground_as_semidet(Goal):-
Goal.
However, this solution has deficiencies:
It's not generic enough, e.g. sometimes ground should be nonvar.
It is not stylistic, requiring an extra predicate wrapper every time it is used.
It may also be slightly inefficient.
My question is: are there other ways in which often-occurring patterns of (non-)determinism, like the one described here, can be generically/efficiently/stylistically programmed in Prolog?
You should experiment with double negation as failure. Yes a ground goal can only be true or false, so it should not leave any choice points. Lets assume we have an acyclic graph, to make matters simple:
If I use this code:
edge(a, b). edge(a, c).
edge(a, d). edge(b, c).
edge(c, d). edge(c, e).
edge(d, e).
path(X,X).
path(X,Y) :- edge(X,Z), path(Z,Y).
The Prolog system will now leave choice points for closed queries:
?- path(a, e).
true ;
true ;
true ;
true ;
true ;
false.
In my opinion the recommended approach, to eliminate these
choice points and nevertheless have a multi-moded predicate,
is to use so called meta-programming in Prolog.
meta-programming is also sometimes derogeratively called
non-logical programming, since it is based on non-logical
predicates such as ground/1, !/0 or (+)/1. But lets call
it meta-programming when declarativity is not impacted.
You could write a wrapper smart/1 as follows, doing the
same as your call_ground_as_semidet/1, but with a small nuance:
smart(G) :- ground(G), !, \+ \+ G.
smart(G) :- G.
The Prolog system will not anymore leave a choice point for closed queries:
?- smart(path(a,e)).
true.
The advantage of \+ \+ over once, is that the former does
not only leave no choice points, but also removes the trail. It
is sometimes called the garbage collection meta-predicate of Prolog.
Not an answer but too long for a comment. Keep in mind I am not sure I understand exactly, so I want to re-state your question first.
To take your graph example. You want to be able to ask the following questions using the same call of the same predicate.
Given a graph,
Question 1: is vertex B reachable from vertex A (somehow)? - yes or no
Question 2: which vertices are reachable from A? - enumerate by backtracking
Question 3: from which vertices is B reachable? - enumerate by backtracking
Question 4: which A and B exist for which B is reachable from A? - enumerate by backtracking
And I might be wrong here, but it seems that answering Question 1 and Question 2 might employ a different search strategy than answering Question 3?
More generally, you want to have a way of saying: if I have a yes-or-no question, succeed or fail. Otherwise, enumerate answers.
Here comes my trouble: what are you going to do with the two different types of answers? And what are the situations in which you don't know in advance which type of answer you need? (If you do know in advance, you can use once(goal), as you said yourself.)
PS:
There is obviously setof/3, which will fail if there are no answers, or collect all answers. Are there situations in which you want to know some of the answers but you don't want to collect all of them? Is this an efficiency concern because of the size and number of the answers?
Not an answer but an advice.
Maybe I missunderstood your question. I think you are trying to address performance issues by forcing a predicate to be non-deterministic. That question is pointless: if p(X) is non-deterministic (multiple solutions), then p(X),! is deterministic (first solution only).
You should not address performance issues by altering program logic or predicate reversibility. I suggest a different approach:
First, take advantage of prolog indexing. For example:
cycle(+Graph:ugraph, +Vertex)
is NOT the same (in terms of performance) as:
cycle(+Vertex, +Graph:ugraph)
You should find documentation on prolog indexing (and performance impact) on the Web.
Second, write multiple implementations for the same problem. Each one will optimize performance for a different case. Then, write a predicate that chooses the best implementation for each case.

What does this line of code do exactly? (Prolog)

My lecturer gave us this sample program to look at the code, while I understood the recursive function on a whole the was this one line I couldn't quite grasp the meaning of
all_different([H | T]) :- member(H, T), !, fail.
extracted from the recursive function:
all_different([H | T]) :- member(H, T), !, fail.
all_different([_ | T]) :- all_different(T).
all_different([_]).
all I understood about it is that it splits a list into a Head H and a Tail T and checks if H is contained in T...My question is, what is it that "!" and "fail" do?
These things are pretty fundamental to Prolog.
fail is essential. It forces Prolog to consider the current branch a failure and initiates backtracking.
The ! is called "the cut." It commits Prolog to the current branch. Or, it prunes the trail of choice points under the current rule.
Taken in conjunction, in Prolog-ese, this says "If the head of the list is present in the tail of the list, there is no need to look for any additional answers, and fail." Thus, if any element of the list is present in the remainder of the list, you'll get an immediate failure with no chance of backtracking. This isn't actually all that dire, it just means that Prolog won't waste any more time trying to figure out if the list is "all_different." Backtracking will resume at the call site normally.
It's important that these go in this order. If you tried to cut after the fail, you'd never make it to the cut, because backtracking would already have begun. If you omit the cut, the predicate will return true if there is any sublist of the list which satisfies the property. This is guaranteed to be the case for any non-empty list by the last clause, which asserts that a list with one element satisfies the property. If you omit the fail, you're just going to get one success for each element of the list that is in a sublist, plus one for the tail. I encourage you to try playing around with the predicate, making these changes and seeing the effects, because it will go a long way to illustrating the purpose of the cut and fail.

Resources