Prolog - deconstructing goals into individual facts and arithmetic - prolog

I'm attempting to write a small program that breaks up a given goal into all its smallest parts and eventually evaluates them. So far I have:
alien(X) :- fromMars(X), fromSaturn(X); fromJupiter(X), X = 'john'.
fromMars(john).
fromSaturn(john).
fromJupiter(john).
test(true) :- !.
test((Goal1,Goal2)) :- test(Goal1), test(Goal2).
test((Goal1;Goal2)) :- test(Goal1), test(Goal2).
test(X = Y) :- call(X = Y).
test(Goal) :- clause(Goal,Body),test(Body).
As far as I can tell so far, this will recursively inspect rules using clause/2 e.g. if I call test(alien(john)). . When it reaches the point that Body contains only facts such as fromMars(X), fromSaturn(X); fromJupiter(X), X = 'john' it will split those using the test((Goal1,Goal2)) :- and test((Goal1;Goal2)) :- rules, eventually reaching singular facts. When passed a singular fact, clause/2 will instantiate Body to true if it can be solved.
Problems arise with arithmetic. In the above program, eventually there will be the singular goal X = 'john' This causes an error with clause/2 (private procedure?). I introduced the rule test(X = Y) :- to catch this case so I can deal with it another way. However what I really want is a rule that will catch all arithmetic. Obviously I cant write a rule in the style of test(X = Y) :- to catch all possible types of arithmetic.
My goal is to eventually write an abductive meta-interpeter that can handle any type of rule thrown at it.
Let me know if none of this makes any sense and I'll try to clarify :)

meta interpreters it's one of the 'strong points' of Prolog. See this page from Markus Triska about this interesting theme.
As Little Booby Tables advised, you can capture arithmetic with something simple as
test(X is Y) :- X is Y.
BTW I think you have a typo here
test((Goal1;Goal2)) :- test(Goal1), test(Goal2).
should be
test((Goal1;Goal2)) :- test(Goal1) ; test(Goal2).
EDIT: working with operators can be generalized, if required. Just an example of the builtins required:
?- X = (1+2), X =.. [F, A, B], current_op(U, V, F).
X = 1+2,
F = (+),
A = 1,
B = 2,
U = 200,
V = fy .

Related

Non-termination of common reverse/2 implementation, and better solutions?

The following is a standard textbook definition of reverse(X,Y) which is true if the list Y is the reverse of the list X. The code is often used to introduce or illustrate the use of an accumulator.
% recursive definition
step([], L2, L2).
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]).
% convenience property around step/3
reverse(X, Y) :- step(X, Y, []).
The following query works as expcted.
?- reverse([1,2,3], Y).
Y = [3,2,1]
But the following fails after it prompts to search for more solutions after the first one.
?- reverse(X, [1,2,3]).
X = [3,2,1]
Stack limit (0.2Gb) exceeded
Stack sizes: local: 3Kb, global: 0.2Gb, trail: 0Kb
Stack depth: 4,463,497, last-call: 100%, Choice points: 12
...
Questions:
What is the choice point prolog is going back to?
Is this called non-termination? I am not familiar with prolog terminology.
Is there a better way to define reverse(X,Y) such that it is reversible, in the sense that both of the above queries work and terminate?
I have found that using a cut step([], L2, L2):- !. appears to work, but this seems like we've waded into procedural programming and have drifted far away from declarative logic programming. Is this a fair judgement?
1mo, frankly I do not know what kind of choicepoint is responsible. This is a notion far too low level to be of direct relevance. And there are better techniques to understand the problem, in particular failure slices.
2do, the problem here is called (universal) non-termination. But note how you found it: You got an answer and then only when demanding the next answer Prolog looped. This can be even worse, like looping only after the n-th answer. The easiest way to spot all kinds of non-termination is to just add false to the query. If G_0 terminates universally also G_0, false terminates (and fails).
3tio, yes there is. But first, try to understand why your original program looped. The best is to add some falsework into your program. By adding goals false we obtain a failure-slice. And if we find such a slice that already does not terminate then also the original program does not terminate. (No further analysis required!1) Here is the one of relevance:
step([], L2, L2) :- false.
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]), false.
reverse(X, Y) :- step(X, Y, []), false.
?- reverse(X, [1,2,3]), false.
loops.
So we need to understand only that visible part! As promised, there is now not a single choicepoint present.
Just look at the head of step/3! There, only the first argument insists on some specific term, but the second and third do not insist on anything. Therefore the second and third argument cannot influence termination. They are termination neutral. And thus, only the first argument of reverse/2 will influence termination.
To fix this, we need to somehow get the second argument of reverse/2 into a relevant position in step. The simplest way is to add another argument. And, if we are at it, we may realize that both arguments of reverse/2 are of the same length, thus:
step([], L2, L2, []).
step([H1|T1], X, L2, [_|Y]) :- step(T1, X, [H1|L2], Y).
reverse(X, Y) :- step(X, Y, [], Y).
?- reverse(X, [1,2,3]), false.
false.
?- reverse([1,2,3], Y), false.
false.
?- reverse(X,Y).
X = [], Y = []
; X = [_A], Y = [_A]
; X = [_A,_B], Y = [_B,_A]
; X = [_A,_B,_C], Y = [_C,_B,_A]
; ... .
4to, don't believe the tale of the green cut! They are so rare. Most good cuts are placed together with a guard that ensures that the cut is safe. See how your cut wreaked havoc:
?- X = [a], reverse(X,Y).
X = "a", Y = "a". % nice
?- reverse(X,Y), X = [a].
false, unexpected.
?- reverse(L,[]).
L = [].
?- L = [_|_], reverse(L,[]).
loops, unexpected.
So sometimes the program will fail incorrectly, and the looping is still present. Hardly an improvement.
1 Assuming that we use the pure monotonic subset of Prolog
Yes, you have correctly noted that this predicate does not terminate when you pass a variable in the first argument. It also does not terminate if the first argument is a partial list.
The first witness that you reported comes from the fact step([], L2, L2)., which is clearly the base case for your recursion/induction. When you ask the Prolog engine for additional witnesses, it proceeds by trying to do so using the induction rule step([H1|T1], X, L2) :- step(T1, X, [H1|L2]). Note that your implementation here is defined recursively on the first argument, and so this unifies the unbound first argument with [H1|T1], and then makes a recursive call with T1 as the first argument, which then unifies with a fresh [H1|T1], which makes a recursive call... This is the cause of the infinite loop you're observing.
Yes.
Often times with nontermination issues, it's helpful to understand Prolog's execution model. That doesn't necessarily mean we can't come up with a "pure logic" solution, though. In this case, the query doesn't terminate if the first argument is a partial list, so we simply need to ensure that the first argument has a fixed length. What should its length be? Well, since we're reversing a list it should be the same as the other list. Try out this definition instead:
reverse(X, Y) :- same_length(X, Y), step(X, Y, []).
This solves the problem for both of the queries you posed. As an added bonus, it's actually possible to pose the "most general query" and get a sensible infinite sequence of results with this definition:
?- reverse(X, Y).
X = Y, Y = [] ;
X = Y, Y = [_] ;
X = [_A, _B],
Y = [_B, _A] ;
X = [_A, _B, _C],
Y = [_C, _B, _A] ;
X = [_A, _B, _C, _D],
Y = [_D, _C, _B, _A] ;
...
As far as I know, there isn't really a clear way to describe Prolog's cut operator in the language of first order logic. All of the literature I've read on the topic describe it operationally within the context of Prolog's execution model — by this I mean that its semantics are defined in terms of choice points/backtracking rather than propositions and logical connectives. That being said, it's hard to write Prolog code that is fast or has good termination properties without being aware of the execution model, and "practical" Prolog programs often use it for this reason (look up "Prolog red and green cuts"). I think your judgement that the cut is "procedural" is on the right track, but personally I think it's still a valuable tool when used appropriately.
swi-prolog added an extra argument to fix such termination:
?- reverse(L, [1,2,3]).
L = [3,2,1].

Prolog - How to separate atoms from expression involving predicates?

If I’ve an expression:
x + y * (-z)
How to I separate them to form a list of [x,y,z]?
My idea:
split2(X, [X]) :-
X \= +(_,_),
*(_,_),
-(_).
split2(X + Y, [H|T]) :-
split2(X,[H]),
split2(Y, T).
(Repeat for * and -).
Somehow it only works for simple case(involving 2 terms or only one predicate), but not complicated one.
Can someone tells me what’s wrong with my idea?
Follows a solution using DCGs that doesn't require a grammar rule per arithmetic operator and that takes full advantage of first-argument indexing (thus avoiding spurious choice-points or ugly cuts in the grammar rules):
split(Expression, Atomics) :-
Expression =.. [Functor| Args],
phrase(split_atomics(Args, Functor), Atomics).
split_atomics([], Atomic) -->
[Atomic].
split_atomics([Head| Tail], _) -->
split_list([Head| Tail]).
split_list([]) -->
[].
split_list([Head| Tail]) -->
{Head =.. [Functor| Args]},
split_atomics(Args, Functor),
split_list(Tail).
Sample calls:
| ?- split((x + y * (-z)), Atomics).
Atomics = [x, y, z]
yes
| ?- split((x + 3 * (-2)), Atomics).
Atomics = [x, 3, -2]
yes
Your predicates are pretty mixed up. For starters, you're using X \= _+_ to prevent the other rule from matching; instead you should use atomic(X). You're then saying _*_, -_ which is not clearly saying anything in particular except that certain anonymous variables... exist? Anyway, the rest of the first clause is erroneous for one reason or another.
Your second clause is off to a decent start, but I think you are avoiding a use of append/3 here for no particular reason. In the head, you are expecting H to be an atom, but then with the first term in the body you're forcing H to be a singleton list. What if X = a*b? You'd expect split2(a*b,[a,b]) to unify.
You're not far from where you need to be though. This is probably your general pattern:
split2(X, [X]) :- atomic(X).
split2(-X, Result) :- split2(X, Result).
split2(X+Y, Result) :-
split2(X, XVars),
split2(Y, YVars),
append(XVars, YVars, Result).
Continue the pattern for your other operators.
Can someone tells me what's wrong with my idea?
What you are doing is too complicated, that's what's wrong. If you really have as input a valid compound term, and what you need to get out of it is a list of the atomic sub-terms, then, here is what you might want to try:
expression_atoms(E) -->
{ compound(E),
E =.. [_Name|Args]
},
!,
expression_list_atoms(Args).
expression_atoms(E) -->
{ atomic(E)
},
!,
[E].
expression_list_atoms([E|Es]) -->
expression_atoms(E),
expression_list_atoms(Es).
expression_list_atoms([]) --> [].
(Ninja edit: see the solution by Paulo Moura for a cleaner implementation of the same idea.)
The only reason why this is a DCG and not a normal predicate is that I am too lazy to figure out how to do the appends properly.
Here is a small test:
?- X = x + y * (-z).
X = x+y* -z.
?- X = x + y * (-z), write_canonical(X).
+(x,*(y,-(z)))
X = x+y* -z.
?- X = x + y * (-z), write_canonical(X), phrase(expression_atoms(X), Atoms).
+(x,*(y,-(z)))
X = x+y* -z,
Atoms = [x, y, z].
In the last query, you can see the atoms extracted from the expression.
As you see, this solution doesn't care about the names of the compound terms. This happens in line 3 of the listing:
E =.. [_Name|Args]
So you can throw anything at it and it will still "work":
?- phrase(expression_atoms(
the(naked, truth(about(our(waitresses))), is(that(they(only(flirt, with, you))), to(get(a(better(tip('!')))))))),
Atoms).
Atoms = [naked, waitresses, flirt, with, you, !].
If you want this to fail for anything else but a predefined list of operators with a given arity, then you'd have to put a bit more code in there.

Prolog addition on wrapped values

I wrote a test program with bindings (facts) between atoms and numbers.
bind(a, 3).
bind(b, 4).
bind(c, 5).
As part of a toy interpreter, I want to be able to perform additions on these atoms using Prolog's native arithmetic operators. For instance, I want to be able to run this query:
% val(X) is the value bound to X
?- X is val(a) + val(b).
X = 7.
However, I'm struggling to find a way to allow this addition. My first approach would have been this one:
% val(X, Y): Y is the value bound to X
val(X, Y) :- bind(X, Y).
% Make val an arithmetic function
:- arithmetic_function(val/1).
However, arithmetic_function/1 is no longer part of Prolog (or at least SWI-Prolog says it's deprecated), so I can't use it. Then I believed the best solution would be to overload the + operator to take this into account:
% val(X, Y): Y is the value bound to X
val(val(X), Y) :- bind(X, Y).
% Overload the + operator
+(val(_X, XVal), val(_Y, YVal)) :- XVal + YVal.
But here I've got my syntax all messed up because I don't really know how to overload a native arithmetic operation. When I type in the sample query from before, SWI-Prolog says ERROR: Arithmetic: ``val(a)' is not a function.
Would you have hints about a possible solution or a better approach or something I missed?
From the docs, I tought you should use function_expansion/3.
But I'm unable to get it to work, instead, goal_expansion could do, but isn't very attractive... for instance, if you save the following definitions in a file bind.pl (just to say)
:- module(bind, [test/0]).
:- dynamic bind/2.
bind(a, 3).
bind(b, 4).
bind(c, 5).
% :- multifile user:goal_expansion/2.
user:goal_expansion(val(X), Y) :- bind(X, Y).
user:goal_expansion(X is Y, X is Z) :- expand_goal(Y, Z).
user:goal_expansion(X + Y, U + V) :- expand_goal(X, U), expand_goal(Y, V).
test :-
X is val(a) + val(b), writeln(X).
and consult it, you can run your test:
?- test.
7
edit
after Paulo suggestion, here is an enhanced solution, that should work for every binary expression.
user:goal_expansion(X is Y, X is Z) :- expr_bind(Y, Z).
expr_bind(val(A), V) :- !, bind(A, V).
expr_bind(X, Y) :-
X =.. [F, L, R], % get operator F and Left,Right expressions
expr_bind(L, S), % bind Left expression
expr_bind(R, T), % bind Right expression
Y =.. [F, S, T]. % pack bound expressions back with same operator
expr_bind(X, X). % oops, I forgot... this clause allows numbers and variables
having defined user as target module for goal_expansion, it works on the CLI:
?- R is val(a)*val(b)-val(c).
R = 7.
edit
now, let's generalize to some other arithmetic operators, using the same skeleton expr_bind uses for binary expressions:
user:goal_expansion(X, Y) :-
X =.. [F,L,R], memberchk(F, [is, =<, <, =:=, >, >=]),
expr_bind(L, S),
expr_bind(R, T),
Y =.. [F, S, T].
and unary operators (I cannot recall no one apart minus, so I show a simpler way than (=..)/2):
...
expr_bind(-X, -Y) :- expr_bind(X, Y).
expr_bind(X, X).
Now we get
?- -val(a)*2 < val(b)-val(c).
true.
One way to do it is using Logtalk parametric objects (Logtalk runs on SWI-Prolog and 11 other Prolog systems; this makes this solution highly portable). The idea is to define each arithmetic operation as a parametric object that understands an eval/1 message. First we define a protocol that will be implemented by the objects representing the arithmetic operations:
:- protocol(eval).
:- public(eval/1).
:- end_protocol.
The basic parametric object understands val/1 and contains the bind/2 table:
:- object(val(_X_), implements(eval)).
eval(X) :-
bind(_X_, X).
bind(a, 3).
bind(b, 4).
bind(c, 5).
:- end_object.
I exemplify here only the implementation for arithmetic addition:
:- object(_X_ + _Y_, implements(eval)).
eval(Result) :-
_X_::eval(X), _Y_::eval(Y),
Result is X + Y.
:- end_object.
Sample call (assuming the entities above are saved in an eval.lgt file):
% swilgt
...
?- {eval}.
% [ /Users/pmoura/Desktop/eval.lgt loaded ]
% (0 warnings)
true.
?- (val(a) + val(b))::eval(R).
R = 7.
This can be an interesting solution if you plan to implement more functionality other than expression evaluation. E.g. a similar solution but for symbolic differentiation of arithmetic expressions can be found at:
https://github.com/LogtalkDotOrg/logtalk3/tree/master/examples/symdiff
This solution will also work in the case of runtime generated expressions (term-expansion based solutions usually only work at source file compile time and at the top-level).
If you're only interested in expression evaluation, Capelli's solution is more compact and retains is/2 for evaluation. It can also be made more portable if necessary using Logtalk's portable term-expansion mechanism (but note the caveat in the previous paragraph).
This is perhaps not exactly what I was looking for, but I had an idea:
compute(val(X) + val(Y), Out) :-
bind(X, XVal),
bind(Y, YVal),
Out is XVal + YVal.
Now I can run the following query:
?- compute(val(a) + val(c), Out).
Out = 8.
Now I need to define compute for every arithmetic operation I'm interested in, then get my interpreter to run expressions through it.

Prolog - Backtracking through a set of dynamic options

I'm trying to trigger backtracking on a goal but in a dynamic way, if it's possible. To better exemplify my issue let's say we have the following PROLOG code:
num(1).
num(2).
num(3).
num(4).
num(5).
Then I head to SWI-Prolog and call: num(X). This triggers backtracking looking for all solutions, by typing ; .
What I would like is to remove those facts (num(1),num(2), etc) and replace that code with something thata generates those facts dynamically. Is there any way in which I can achieve this? Someting of the sorts,maybe?
num(X):- for X in 1..5
that yields the same solutions as the code above?
As far as I know, the findall predicate returns a list, which is not what I'm looking for. I would like to backtrack through all answers and look through them using ; in the console.
Yes there is, and you were already very close!
:- use_module(library(clpfd)).
num(X) :-
X in 1..5.
?- num(X).
X in 1..5.
?- num(X), X #>3.
X in 4..5.
?- num(X), labeling([], [X]).
X = 1
; X = 2
; X = 3
; X = 4
; X = 5.
SWI-Prolog has the (non-ISO) predicate between/3 for that:
num(X) :- between(1, 5, X).
You can implement the predicate (for other Prologs and for further tweaking) like this:
between2(A, A, A) :- !. % green cut
between2(A, B, A) :- A < B.
between2(A, B, C) :-
A < B,
A1 is A + 1,
between2(A1, B, C).
The signature for both between/3 and between2/3 is (+From,+To,?X). It means that the From and To must be bound and X can be either bound or not. Also note that From and To must be integers such that From <= To. (Oh, and these integers must be written using Arabic numerals with an optional plus or minus sign before. And using ASCII. Is something non-obvious still missed? And the integers must not be too large or too small, although SWI-Prolog is usually compiled with unbounded integer support, so both between(1, 100000000000000000000000000000000000000000000, X) and between2(1, 100000000000000000000000000000000000000000000, X) usually work.)

Can't show the second answer in Prolog

sisters(mary,catherine).
sisters(catherine,mary).
brothers(john,simone).
brothers(simone,john).
marriage(john,mary,2010).
marriage(mary,john,2010).
marriage(kate,simone,2009).
marriage(simone,kate,2009).
marriage(catherine,josh,2011).
marriage(josh,catherine,2011).
birth(mary,johnny).
birth(mary,peter).
birth(catherine,william).
birth(kate,betty).
givebirthyear(mary,peter,2015).
givebirthyear(mary,johnny,2012).
givebirthyear(catherine,william,2012).
givebirthyear(kate,betty,2011).
siblings(X,Y) :-
birth(Parent,X),
birth(Parent,Y).
cousins(X,Y) :-
birth(Xparent,X),
birth(Yparent,Y),
sisters(Xparent,Yparent).
cousins(X,Y) :-
X \= Y,
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
I don' know what's happening in my code. When I input
cousins(betty,johnny).
and
cousins(william,johnny).
The prolog says true. But when I entered
cousins(S,johnny).
THe prolog says S = william but didn't show me that S = betty. I don't really know what's happening. Need help.
Here is the prolog result I got.
?- cousins(S,johnny).
S = william ;
false.
?- cousins(betty,johnny).
true.
?- cousins(william,johnny).
true .
The problem
The reason this happens is because
X \= Y,
actually means:
\+(X = Y).
now \+ or not in Prolog has some weird behaviour compared to the logical not. \+ means negation as finite failure. This means that \+(G) is considered to be true in case Prolog queries G, and can not find a way to satisfy G, and that G is finite (eventually the quest to satisfy G ends).
Now if we query \+(X = Y), Prolog will thus aim to unify X and Y. In case X and Y are (ungrounded) variables, then X can be equal to Y. As a result X \= Y fails in case X and Y are free variables.
So basically we can either use another predicate that for instance puts a constraint on the two variables that is triggered when the variables are grounded, or we can reorder the body of the clause, such that X and Y are already grounded before we call X \= Y.
If we can make for instance the assumption that X and Y will be grounded after calling birth/2, we can reorder the clause to:
cousins(X,Y) :-
birth(Xmom,X),
birth(Ymom,Y),
X \= Y,
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Prolog has however a predicate dif/2 that puts a constraint on the two variables, and from the moment the two are grounded, it will fail if the two are equal. So we can use it like:
cousins(X,Y) :-
dif(X,Y),
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Making things simpler
That being said, I think you make the program too complex. We can start with a few definitions:
two people are slibings/2 if they are brothers/2 or sisters/2.
slibings(X,Y) :-
brothers(X,Y).
slibings(X,Y) :-
sisters(X,Y).
It is however possible that brothers/2 and sisters/2 do not provide all information. Two people are also slibings if they have the same mother (we will assume that people do not divorce here, or at least not give birth to other children after they remarry).
slibings(X,Y) :-
dif(X,Y),
birth(Mother,X),
birth(Mother,Y).
a parent/2 of a person is the mother of the person or the father (the person that married the mother).
So we can write:
parent(Mother,X) :-
birth(Mother,X).
parent(Father,X) :-
birth(Mother,X),
marriage(Father,Mother,_).
based on your example, the marriage/3 predicate is bidirectional: in case marriage(X,Y,Z)., then there is also a fact marriage(Y,X,Z)..
And now we can define:
two people are cousins if there parents are slibings:
cousins(X,Y) :-
parent(MF1,X),
parent(MF2,Y),
slibings(MF1,MF2).
and that's it.

Resources