Asserting all different possibilities - prolog

I have this code which asserts fact based on lists of other facts, however I have difficulty doing 2 things:
First, I want it to assert all the different possible facts.
Second, I want it to be able to use lists of variable lengths. The code I have only works if the lists are exactly 2 and 4 of length, which works for testing but will not work in practice.
assert_test([Fact], [Z,Z2], [Y, Y2, Y3, Y4]) :-
Z,
Z2,
Y,
Y2,
Y3,
Y4,
assertz(Fact).
I really have no clue as to what kind of solution I need for my problems, I would really appreciate any pointer that could help me in the right direction.

This question isn't very clear, but it seems like you want to (a) call a number of goals passed in as a list, then (b) assert all those goals. I will answer under the assumption that this is true, although this operation as written is almost certainly not useful.
To call some variable V, you can just put V as a goal in your rule body, as you did, or you can apply the call/1 predicate to it, i.e., write call(V). Thus, to call a list of goals, you can do maplist(call, Goals).
Similarly, to assert a list of goals, you can do maplist(assertz, Goals).
So overall, here is one way of doing what you might want:
test_assert(Goals) :-
maplist(call, Goals),
maplist(assertz, Goals).
This applies to a list Goals of any length.
If your Prolog doesn't have an implementation of maplist/2 or you don't want to use it, you might instead write a recursive solution, something like:
test_assert([]).
test_assert([Goal|Goals]) :-
call(Goal),
assertz(Goal),
test_assert(Goals).
(None of this is tested.) Note that this interleaves the call and assert operations, so they are performed in a different order than in the approach using maplist/2.

Related

Prolog - Infinite loop with very basic rule definition

I was trying to practice Prolog, as suggested by my TA, I am trying to create the rule append3(A,B,C,D) which means D is the result of the append of A,B and C.
The definition of append(A,B,C) is given
append([],B,B).
append([X|A],B,[X|C]):-append(A,B,C).
So I simply wrote following, which makes sense to me, as the rule for append3
append3(A,B,C,D) :- append(A,B,X),append(X,C,D).
After, I tried some query, such as append3(A,B,C,[1,2,3]). Everything was fine in the beginning, it was giving me the right results. However, at one moment, I pressed ;, it went into an infinite loop trying to search another answer.
I am not really sure why this happens? I suppose that append3(A,B,C,D) is a very basic rule to define. Is there anything that I am missing or that I didn't consider?
How can I fix this problem?
Prolog's execution mechanism is pretty complex compared to command oriented programming languages a.k.a. imperative languages (short form: imps). Your TA has given you an excellent example where you can improve your mastery of Prolog.
First of all, you need to understand the termination behavior of append/3. The best way is via a failure-slice which helps you focus on the part that is relevant to termination. In this case it is:
append([],B,B) :- false.
append([X|A],B,[X|C]):-append(A,B,C), false.
This fragment or failure slice now terminates exactly in all cases where your original definition terminates! And since it is shorter, it makes understanding of termination a bit easier. Of course, this new program will no longer find answers like for append([a],[b],[a,b]) — it will fail in stead. But for termination alone it's perfect.
Now let's go through the arguments one by one:
argument needs to have a non-empty list element and will fail (and terminate) should the argument be [] or any other term. Non-termination may only occur with a partial list (that's a list with a variable instead of [] at the end like [a,b|L]) or just a variable.
argument is just the variable B. There is no way how this B might be different to any term. Thus, B has no influence on termination at all. It is termination neutral.
argument is essentially the same as the first argument. In fact, those arguments look quite symmetrical although they describe different things.
To summarize, if the first or the last argument is a (fully instantiated) list, append/3 will terminate.
Note that I just said if and not iff. After all, the first and third argument are a bit connected to each other via the variable X. Let's ignore that for this analysis.
Now, to a failure slice of your definition.
append3(A,B,C,D) :- append(A,B,X), false, append(X,C,D).
Note that D does no longer occur in the visible part! Therefore, the fourth argument has no influence on termination of this fragment. And since X occurs for the first time, only A has an influence on its termination. Therefore, if A is just a variable (or a partial list), the program will not terminate! No need to look any further. No need to look at screens full of traces.
To fix this for a query like your query append3(A,B,C,[1,2,3])., D has to influence the first goal somewhat.
One possible fix suggested by another answer would be to exchange the goals:
append3(A,B,C,D) :- append(X,C,D), false, append(A,B,X).
Let's look at the variables of append(X,C,D)! C is termination neutral, X occurs for the first time and thus has no influence on termination at all. Only D may make this goal terminate. And thus queries like append3([1],[2],[3], D) will now loop! What a bargain, exchanging non-termination in one case for another!
To make your program work for both cases, the first goal of append/3 must contain both D and at least one of A, B or C. Try to find it yourself! Here is the spoiler:
append3(A, B, C, D) :- append(A, BC, D), append(B, C, BC).
Now the first goal terminates if either A or D is a (fully instantiated) list. The second goal requires either B or BC to be a list. And BC comes from the first goal, which is a list if D is one.
Thus append3(A, B, C, D) terminates_if b(A), b(B) ; (D).
See another answer for more on termination, failure slices, and a technique I have not mentioned here, which is termination inference.
And, note that there are still more cases where the definitions terminate, although they are rather obscure like append([a|_],_,[b|_]) or append3([a|_],_,_,[b|_])) which both fail (and thus terminate) although they only have partial lists. Because of this it's terminates_if and not terminates_iff.
You need to flip the predicates append(A, B, X), append(X, C, D). Since all three variables A, B, and X are unbound in append(A, B, X) prolog tries to satisfy it and then constrain it with append(X, C, D) which will always fail after giving you existing solutions. So it enters an infinite loop.
Try just executing append(A, B, X). all of them unbound. Prolog should show you an infinite sequence of solutions, these fail in the next clause append(X, C, D).
Flip the predicates and you should be fine.
append3(A, B, C, D) :-
append(T, C, D),
append(A, B, T).

How do I make a rule fail without proving that something is false?

I am trying to make an invert/2. I want it to ignore the order of its arguments, so that you don't need to worry about which half of the inversion is the one you know, and so that you don't have to repeat yourself when stating inversions as facts. I currently have
invert(Left, Right) :-
call_with_depth_limit(invert(Right, Left), 1, Result),
Result \= depth_limit_exceeded.
as the first invert rule. This mostly works, but if invert(a, b)., then ?- invert(b, X). gives both X = a and false, which is not what I want at all.
There are two things I'd consider. First, make sure that the predicate you create for establishing the symmetry of the relationship in your facts has a different name than your facts. Having the name be the same usually leads to issues such as infinite recursion. Secondly, if the facts are under your control to declare, be consistent about whether the facts explicitly declare the symmetrical case or not. If they do, then you don't need the extra predicate. If they don't, then you need an extra predicate.
For example, with symmetries explicitly declared:
opposite(a, b).
opposite(b, a).
opposite(c, d).
opposite(d, c).
You don't need an extra predicate to get the symmetrical solutions for opposite.
An example where the symmetries are not explicitly declared:
opposite(a, b).
opposite(c, d).
inverted(X, Y) :- opposite(X, Y).
inverted(X, Y) :- opposite(Y, X).
In this case, querying inverted/2 instead of opposite/2 will handle the symmetry in the relationships.

Prolog and limitations of backtracking

This is probably the most trivial implementation of a function that returns the length of a list in Prolog
count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
one thing about Prolog that I still cannot wrap my head around is the flexibility of using variables as parameters.
So for example I can run count([a, b, c], 3). and get true. I can also run count([a, b], X). and get an answer X = 2.. Oddly (at least for me) is that I can also run count(X, 3). and get at least one result, which looks something like X = [_G4337877, _G4337880, _G4337883] ; before the interpreter disappears into an infinite loop. I can even run something truly "flexible" like count(X, A). and get X = [], A = 0 ; X = [_G4369400], A = 1., which is obviously incomplete but somehow really nice.
Therefore my multifaceted question. Can I somehow explain to Prolog not to look beyond first result when executing count(X, 3).? Can I somehow make Prolog generate any number of solutions for count(X, A).? Is there a limitation of what kind of solutions I can generate? What is it about this specific predicate, that prevents me from generating all solutions for all possible kinds of queries?
This is probably the most trivial implementation
Depends from viewpoint: consider
count(L,C) :- length(L,C).
Shorter and functional. And this one also works for your use case.
edit
library CLP(FD) allows for
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).
?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(further) answering to comments
It was clearly sarcasm
No, sorry for giving this impression. It was an attempt to give you a synthetic answer to your question. Every details of the implementation of length/2 - indeed much longer than your code - have been carefully weighted to give us a general and efficient building block.
There must be some general concept
I would call (full) Prolog such general concept. From the very start, Prolog requires us to solve computational tasks describing relations among predicate arguments. Once we have described our relations, we can query our 'knowledge database', and Prolog attempts to enumerate all answers, in a specific order.
High level concepts like unification and depth first search (backtracking) are keys in this model.
Now, I think you're looking for second order constructs like var/1, that allow us to reason about our predicates. Such constructs cannot be written in (pure) Prolog, and a growing school of thinking requires to avoid them, because are rather difficult to use. So I posted an alternative using CLP(FD), that effectively shields us in some situation. In this question specific context, it actually give us a simple and elegant solution.
I am not trying to re-implement length
Well, I'm aware of this, but since count/2 aliases length/2, why not study the reference model ? ( see source on SWI-Prolog site )
The answer you get for the query count(X,3) is actually not odd at all. You are asking which lists have a length of 3. And you get a list with 3 elements. The infinite loop appears because the variables B and U in the first goal of your recursive rule are unbound. You don't have anything before that goal that could fail. So it is always possible to follow the recursion. In the version of CapelliC you have 2 goals in the second rule before the recursion that fail if the second argument is smaller than 1. Maybe it becomes clearer if you consider this slightly altered version:
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :-
T #> 0,
U #= T - 1,
count(B, U).
Your query
?- count(X,3).
will not match the first rule but the second one and continue recursively until the second argument is 0. At that point the first rule will match and yield the result:
X = [_A,_B,_C] ?
The head of the second rule will also match but its first goal will fail because T=0:
X = [_A,_B,_C] ? ;
no
In your above version however Prolog will try the recursive goal of the second rule because of the unbound variables B and U and hence loop infinitely.

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.

Compare results return from a query

When I run a query, it can return zero, one or more than one results. How can I "save" these results so that I can compare them later, or how can I compare them on the fly?
For example, I have these facts:
father(john, mark).
father(john, michael).
age(michael, 10).
age(mark, 12).
Now if I run a query like this
?- father(john, X).
it will return mark and michael, but how can I compare the age of mark and michael? In fact, how can I even know that the query will return more than one results?
The idea is that I want to get the eldest son of a father
What you're running into here is the fact that on backtracking, Prolog releases the variable bindings it found when it produced the previous result. This feature causes a lot of consternation in the early days, so know that you're not alone, we were all there once.
The first thing you should do is try to let go of the need to tell Prolog how to get the result, and instead focus on telling Prolog how to distinguish the result you want logically. This is logic programming, after all. :) When you say "how can I compare the age of mark and michael?" you're hiding the real question behind the assumption that once you know how to hold onto things you can find the answer yourself. But you don't want to find the answer yourself, you want Prolog to find it!
Let's take an example. Say you want to find out who is the youngest child of whom. You can do this logically:
?- father(Father, Child),
age(Child, YoungestAge),
\+ (father(Father, Child2),
age(Child2, Younger),
Younger < YoungestAge).
Father = john,
Child = michael,
YoungestAge = 10.
This would be inefficient with a large database, unfortunately, since Prolog will have to search every age/2 fact to find all the children of a particular parent. Presumably Prolog will index these predicates and that may be enough to save us depending on how you use it, but it doesn't look like a strategy you can apply universally. But you can't beat the logical reading of this query: supposing I have a father Father of child Child, and supposing that Child's age is YoungestAge, there is no Child2 of this same Father whose age is Younger than YoungestAge.
Frequently, you do need all the solutions, and for that there are three predicates: setof/3, bagof/3 and findall/3. They all have basically the same API with slightly different semantics. For instance, if you want all the children for a parent, you can use setof to get them:
?- setof(Child, father(john, Child), Children).
Children = [mark, michael].
You'll need a bigger fact database to see the effect of the differences between the two, but that's a different question. In short, setof/3 will get you a sorted list of unique answers whereas bagof/3 will get you an unsorted list with all the answers. findall/3 does the same thing, with a difference in the way it treats variables. In my experience, setof/3 and findall/3 tend to be used a lot more than bagof/3.
If the work you're doing necessitates it, or if efficiency demands it, you can use these meta-predicates to find all the possible solutions and walk through the list doing whatever processing you need to do.
As for the question "how can I even know that the query will return more than one result?" the answer is basically you can generate them all and see how many you had (findall(..., Answers), length(Answers, Count)) or you can use once/1 to ensure that you get a single solution. once is great for making non-deterministic predicates deterministic; the effect is basically the same as putting a cut right after the clause. For instance:
?- father(john, X).
X = mark ;
X = michael.
?- once(father(john, X)).
X = mark.
?- father(john, X), !.
X = mark.
In general it is recommended that you use once/1 over explicit cuts, if possible.
Let me know if this helps.
just a footnote on Daniel answer:
eldest(Father, Child) :-
findall(A/C, (father(Father, C), age(C, T), A is -T), L),
sort(L, [_/Child|_]).
I used the trick of negating the age to get the list in reverse order.
Here a 'one liner', does just the same as above:
eldest(Father, Child) :-
setof(A/C, T^(father(Father, C), age(C, T), A is -T), [_/Child|_]).
edit if your Prolog has library(aggregate), there is a cleaner way to get the result:
eldest(Father, Child) :-
aggregate(max(A, C), (father(Father, C), age(C, A)), max(_, Child)).

Resources