Prolog : get the opposite result - prolog

I have the following code :
neighbor(C1, C2, [C1, C2|L]).
neighbor(C1, C2, [C2, C1|L]).
neighbor(C1, C2, [H|L]) :- neighbor(C1, C2, L).
not_neighbors(C5, C2, E, R) :-
not_neighbor(C5, C2, E).
not_neighbors(C5, C2, E, R) :-
not_neighbor(C5, C2, R).
/* THIS DON'T WORK */
not_neighbor(C5, C2, E) :-
\+ neighbor(C5, C2, E).
Or :
same_position(I, J, [I|U], [J|V]).
same_position(I, J, [M|U], [N|V]) :-
I \== M, % optimisation
J \== N, % optimisation
same_position(I, J, U, V).
/* THIS DON'T WORK */
not_under(C4, C1, R, E) :-
\+ same_position(C4, C1, R, E).
I know the problem is the negation and I want to get the opposite result of same_position for example.
M. #CapelliC suggested me to use dif/2 but I don't know how to apply this on my specific example.

Let us first think logically about what it means to be "neighbours" in a list: In what cases are A and B neighbouring elements in a list?
Answer: If the list is of the form [...,X,Y,...] and at least one of the following holds:
A = X and B = Y
A = Y and B = X.
In logical terms: ( A = X ∧ B = Y) ∨ (A = Y ∧ B = X).
We want to state the opposite of this, which is the negated formula:
¬ ( ( A = X ∧ B = Y) ∨ (A = Y ∧ B = X) ) ≡
≡ ¬ ( A = X ∧ B = Y) ∧ ¬ (A = Y ∧ B = X) ≡
≡ (¬ A = X ∨ ¬ B = Y) ∧ (¬ A = Y ∨ ¬ B = X) ≡
≡ (A ≠ X ∨ B ≠ Y) ∧ (A ≠ Y ∨ B ≠ X)
Who would have thought that De Morgan's laws had any practical application, right?
To state X ≠ Y in Prolog, we use the powerful dif/2 constraint, exactly as #CapelliC has already suggested. dif/2 is true iff its arguments are different terms. It is a pure predicate and works correctly in all directions. If your Prolog system does not yet provide it, make sure to let your vendor know that you need it! Until then, you can approximate it with iso_dif/2, if necessary.
In Prolog, the above thus becomes:
( dif(A, X) ; dif(B, Y) ), ( dif(A, Y) ; dif(B, X) )
because (',')/2 denotes conjunction, and (;)/2 denotes disjunction.
So we have:
not_neighbours(_, _, []).
not_neighbours(_, _, [_]).
not_neighbours(A, B, [X,Y|Rest]) :-
( dif(A, X) ; dif(B, Y) ),
( dif(A, Y) ; dif(B, X) ),
not_neighbours(A, B, [Y|Rest]).
A few test cases make us more confident about the predicate's correctness:
?- not_neighbours(a, b, [a,b]).
false.
?- not_neighbours(A, B, [A,B]).
false.
?- not_neighbours(A, B, [_,A,B|_]).
false.
?- not_neighbours(A, B, [_,B,A|_]).
false.
?- not_neighbours(a, b, [_,a,c,_]).
true .
Note that this definition works correctly also if all arguments are variables, which we call the most general case.
A drawback of this solution is that (;)/2 creates many alternatives, and many of them do not matter at all. We can make this significantly more efficient by another algebraic equivalence that lets us get rid of unneeded alternatives:
¬ A ∨ B ≡ A → B
So, in our case, we can write (¬ A = X ∨ ¬ B = Y) as A = X →B≠Y.
We can express implication in Prolog with the powerful if_/3 meta-predicate:
impl(A, B) :- if_(A, B, true).
And so we can declaratively equivalently write our solution as:
not_neighbours(_, _, []).
not_neighbours(_, _, [_]).
not_neighbours(A, B, [X,Y|Rest]) :-
impl(A=X, dif(B, Y)),
impl(B=X, dif(A, Y)),
not_neighbours(A, B, [Y|Rest]).
Sample query:
?- not_neighbours(a, b, [x,y]).
true ;
false.
And a more general case:
?- not_neighbours(a, b, [X,Y]).
X = a,
dif(Y, b) ;
X = b,
dif(Y, a) ;
dif(X, b),
dif(X, a) ;
false.
You can use this predicate for checking and generating answers. Try for example iterative deepening to fairly enumerate all answers:
?- length(Ls, _), not_neighbours(A, B, Ls).
Remarkably, pure logical reasoning has thus led us to a general and efficient Prolog program.
dif/2 may at first appear unusual to you, because it appeared in the very first Prolog system and was then for a time ignored by some vendors. Nowadays, dif/2 is becoming available (again) in an increasing number of implementations as an important built-in predicate that allows you to declaratively state that two terms are different. The massive confusion that its impure alternatives usually cause in Prolog courses can be avoided with dif/2.

If you want to generate the not-neighbors, \+ won't do as it is by definition semidet and never binds a variable. You need something that
constructs answers. One option is to generate all pairs and then use your \+ neighbor(...) to filter the non-neighbors. A direct constructive approach isn't that hard either, although the need to have both orderings complicate the code a little:
not_neighbor(C1, C2, List) :-
append(_, [C10,_|Postfix], List),
member(C20, Postfix),
swap(C1,C2, C10,C20).
swap(X,Y, X,Y).
swap(X,Y, Y,X).
See http://swish.swi-prolog.org/p/njssKnba.pl

Related

Remove invariants from some prolog list?

I am searching some predicate:
reduce_2n_invariant(+I, +F, -O)
based on:
some input list I
some input operator F of form fx,
which generates some output list O, that satisfies following general condition:
∀x:(x ∈ O ↔ ∀ n ∈ ℕ ∀ y ∈ O: x ≠ F(F(...F(y)...)),
whereby F is applied 2 times n times to y.
Is their some easy way to do that with swi-prolog?
E.g. the list
l = [a, b, f(f(a)), f(f(c)), f(f(f(a))), f(f(f(f(a)))), f(b),f(f(b))]
with operator f should result in:
O = [a, b, f(f(c)), f(f(f(a))), f(b)]
My code so far:
invariant_2(X, F, Y) :-
Y = F(F(X)).
invariant_2(X, F, Y) :-
Y = F(F(Z)), invariant_2(X, F, Z).
reduce_2n_invariant(LIn, F, LOut) :-
findall(X, (member(X, LIn), forall(Y, (member(Y, LIn), not(invariant(Y,F,X))))), LOut).
leads to an error message:
/test.pl:2:5: Syntax error: Operator expected
/test.pl:4:5: Syntax error: Operator expected
after calling:
invariant_2(a,f,f(f(a))).
The error message is due to the fact that Prolog does not accept terms with variable functors. So, for example, the goal Y2 = F(F(Y0)) should be encoded as Y2 =.. [F,Y1], Y1 =.. [F,Y0]:
?- F = f, Y2 = f(f(f(a))), Y2 =.. [F,Y1], Y1 =.. [F,Y0].
F = f,
Y2 = f(f(f(a))),
Y1 = f(f(a)),
Y0 = f(a).
A goal of the form Term =.. List (where the ISO operator =.. is called univ) succeeds if List is a list whose first item is the functor of Term and the remaining items are the arguments of Term. Using this operator, the predicate invariant_2/3 can be defined as follows:
invariant_2(X, F, Y2) :-
( Y2 =.. [F, Y1],
Y1 =.. [F, Y0]
-> invariant_2(X, F, Y0)
; Y2 = X ).
Examples:
?- invariant_2(a, f, f(f(a))).
true.
?- invariant_2(a, f, f(f(f(a)))).
false.
?- invariant_2(g(a), f, f(f(g(a)))).
true.
?- invariant_2(g(a), f, f(f(f(g(a))))).
false.
The specification of reduce_2n_invariant/3 is not very clear to me, because it seems that the order in which the input list items are processed may change the result obtained. Anyway, I think you can do something like this:
reduce_2n_invariant(Lin, F, Lout) :-
reduce_2n_invariant_loop(Lin, F, [], Lout).
reduce_2n_invariant_loop([], _, Lacc, Lout) :-
reverse(Lacc, Lout).
reduce_2n_invariant_loop([X|Xs], F, Lacc, Lout) :-
( forall(member(Y, Lacc), not(invariant_2(Y, F, X)))
-> Lacc1 = [X|Lacc]
; Lacc1 = Lacc ),
reduce_2n_invariant_loop(Xs, F, Lacc1, Lout).
Example:
?- reduce_2n_invariant([a,b,f(f(a)),f(f(c)),f(f(f(a))),f(f(f(f(a)))),f(b),f(f(b))], f, Lout).
Lout = [a, b, f(f(c)), f(f(f(a))), f(b)].
#slago beat me by a few minutes but since I've already written it, I'll still post it:
I'm shying away from the findall because the negation of the invariant is very hard to express directly. In particular, terms compared by the invariant must be ground for my implementation (e.g. [f(a), f(g(f(a)))] should not lose any terms but [f(a), f(f(f(a)))] should reduce to [f(a)] which means that the base case of the definition can't just pattern match on the shape of the parameter in the case two terms are not in this relation).
The other problem was already explained, in that F=f, X=F(t) is not syntactically correct and we need the meta-logical =.. to express this.
term_doublewrapped_in(X, Y, Fun) :-
Y =.. [Fun, T],
T =.. [Fun, X].
term_doublewrapped_in(X, Y, Fun) :-
Y =.. [Fun, T],
T =.. [Fun, Z],
term_doublewrapped_in(X, Z, Fun).
Apart from term_doublewrapped_in not necessarily terminating when the second parameter contains variables, it might also give rise to false answers due to the occurs check being disabled by default:
?- term_doublewrapped_in(X, f(X), F).
X = f(X), % <-- cyclic term here
F = f ;
% ...
Therefore the groundness condition is actually required for the soundness of this procedure.
I just lifted this notion to lists:
anymember_doublewrapped_in(Terms, X, F) :-
member(T, Terms),
term_doublewrapped_in(T,X,F).
and wrapped it into a variant of filter/3 that negates the predicate given:
functor_list_reduced_acc(_F, _L, [], []).
functor_list_reduced_acc(F, L, R, [X|Xs]) :-
anymember_doublewrapped_in(L, X, F)
-> functor_list_reduced_acc(F, L, R, Xs)
; ( R = [X|Rs], functor_list_reduced_acc(F, L, Rs, Xs) ).
functor_list_reduced(F,L,R) :-
functor_list_reduced_acc(F,L,R,L).
I first tried using partiton/4 to do the same but then we would need to include library(lambda) or a similar implementation to make dynamically instantiate the invariant to the correct F and list element.

The unification algorithm in Prolog

I'm trying to program the unification algorithm in Prolog to verify if two expressions can unify by returning boolean True/False:
EDIT.
I found this implementation usefull:
from: http://kti.mff.cuni.cz/~bartak/prolog/data_struct.html
unify(A,B):-
atomic(A),atomic(B),A=B.
unify(A,B):-
var(A),A=B. % without occurs check
unify(A,B):-
nonvar(A),var(B),A=B. % without occurs check
unify(A,B):-
compound(A),compound(B),
A=..[F|ArgsA],B=..[F|ArgsB],
unify_args(ArgsA,ArgsB).
unify_args([A|TA],[B|TB]):-
unify(A,B),
unify_args(TA,TB).
unify_args([],[]).```
Here is a partial implementation of something like the Martelli and Montanari unification algorithm described at https://en.wikipedia.org/wiki/Unification_(computer_science)#A_unification_algorithm. The comments for each part refer to the corresponding rewrite rule from the algorithm. Note that there is no need for an explicit conflict rule, we can just fail if no other rule applies.
% assuming a universe with function symbols g/2, p/2, q/2
% identical terms unify (delete rule)
unify(X, Y) :-
X == Y,
!.
% a variable unifies with anything (eliminate rule)
unify(X, Y) :-
var(X),
!,
X = Y.
% an equation Term = Variable can be solved as Variable = Term (swap rule)
unify(X, Y) :-
var(Y),
!,
unify(Y, X).
% given equal function symbols, unify the arguments (decompose rule)
unify(g(A, B), g(X, Y)) :-
unify(A, X),
unify(B, Y).
unify(p(A, B), p(X, Y)) :-
unify(A, X),
unify(B, Y).
unify(q(A, B), q(X, Y)) :-
unify(A, X),
unify(B, Y).
Examples:
?- unify(q(Y,g(a,b)), p(g(X,X),Y)).
false.
?- unify(q(Y,g(a,b)), q(g(X,X),Y)).
false.
?- unify(q(Y,g(a,a)), q(g(X,X),Y)).
Y = g(a, a),
X = a.
One or two things remain for you to do:
Generalize the decompose rule to deal with arbitrary terms. You might find the =.. operator useful. For example:
?- Term = r(a, b, c), Term =.. FunctorAndArgs, [Functor | Args] = FunctorAndArgs.
Term = r(a, b, c),
FunctorAndArgs = [r, a, b, c],
Functor = r,
Args = [a, b, c].
You will need to check if two terms have the same functor and the same number of arguments, and whether all corresponding pairs of arguments unify.
Find out if your professor would like you to implement the occurs check, and if yes, implement it.

Brute-force Prolog SAT solver for boolean formulas

I'm trying to write an algorithm that naively looks for models of a boolean formula (NNF, but not CNF).
The code I have can check an existing model, but it'll fail (or not finish) when asked to find models, seemingly because it generates infinitely many solutions for member(X, Y) along the lines of [X|_], [_,X|_], [_,_,X|_]...
What I have so far is this:
:- op(100, fy, ~).
:- op(200, xfx, /\).
:- op(200, xfx, \/).
:- op(300, xfx, =>).
:- op(300, xfx, <=>).
formula(X) :- atom(X).
formula(~X) :- formula(X).
formula(X /\ Y) :- formula(X), formula(Y).
formula(X \/ Y) :- formula(X), formula(Y).
formula(X => Y) :- formula(X), formula(Y).
formula(X <=> Y) :- formula(X), formula(Y).
model(1, _).
model(X, F) :- atom(X), member([X, 1], F).
model(~X, F) :- atom(X), member([X, 0], F). % NNF
model(A /\ B, F) :- model(A, F), model(B, F).
model(A \/ B, F) :- (model(A, F); model(B, F)).
model(A => B, F) :- model(~A \/ B, F).
model(A <=> B, F) :- model((A => B) /\ (B => A), F).
sat(A) :- model(A, F), \+ (member([X, 1], F), member([X, 0], F)).
%%% examples:
% formula(~(~ (a /\ b) \/ (c => d))).
% model(a, [[a,1]]).
Is there a better data structure for F, or some other way the partially-instantiated lists can be cut off?
Edit: Added definitions and examples.
Use clpb!
:- use_module(library(clpb)).
Sample query using sat/1:
?- sat(~(~ (A * B) + (C * D))).
A = B, B = 1, sat(1#C*D).
Some variables (A and B) already have been bound to exactly one Boolean value (in above query), but search is not yet complete (which is indicated by residual goals).
To trigger the smart brute-force enumeration of all solutions use labeling/1 like so:
?- sat(~(~ (A * B) + (C * D))), labeling([A,B,C,D]).
A = B, B = 1, C = D, D = 0
; A = B, B = D, D = 1, C = 0
; A = B, B = C, C = 1, D = 0.
I solved it by writing a generate_model predicate that created a pre-defined list with exactly one element for each variable:
generate_model([], []).
generate_model([X|T], [[X,_]|T2]) :- generate_model(T, T2).
sat(A) :-
var_list(A, Vars),
generate_model(Vars, F),
model(A, F).
Do I understand you, that you are happy with a single model. You
don't need labeling or sat_count. Here is an alternative model finder, that is similar to yours, but will only return consistent models.
Since it finds counter models, you need to supply the negation of the formula to find a model. The predicate maze/3 was developed as a negative implementation of the positive predicate proof/2:
% Find a counter model.
% maze(+Norm,+List,-List)
maze(or(A,_),L,_) :- member(A,L), !, fail.
maze(or(A,B),L,R) :- !, inv(A,C), maze(B,[C|L],R).
maze(and(A,_),L,R) :- maze(A,L,R), !.
maze(and(_,B),L,R) :- !, maze(B,L,R).
maze(A,L,_) :- member(A,L), !, fail.
maze(A,L,M) :- oneof(L,B,R), connective(B), !,
inv(A,C), inv(B,D), maze(D,[C|R],M).
maze(A,L,[B|L]) :- inv(A,B).
It can find counter models to all of the following fallacies:
Affirming a Disjunct: (p v q) & p => ~q.
Affirming the Consequent: (p => q) & q => p.
Commutation of Conditionals: (p => q) => (q => p).
Denying a Conjunct: ~(p & q) & ~p => q.
Denying the Antecedent: (p => q) & ~p => ~q.
Improper Transposition: (p => q) => (~p => ~q).
Here is an example run:
Jekejeke Prolog 2, Runtime Library 1.2.5
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- negcase(_,N,F), norm(F,G), maze(G,[],L),
write(N), write(': '), sort(L,R), write(R), nl, fail; true.
Affirming a Disjunct: [pos(p),pos(q)]
Affirming the Consequent: [neg(p),pos(q)]
Commutation of Conditionals: [neg(p),pos(q)]
Denying a Conjunct: [neg(p),neg(q)]
Denying the Antecedent: [neg(p),pos(q)]
Improper Transposition: [neg(p),pos(q)]
Interestingly the thing is much faster than CLP(B). Here are some timings running the same problem in CLP(B) and with maze:
?- time((between(1,1000,_), negcaseclp(_,N,F,L),
sat(~F), once(labeling(L)), fail; true)).
% Up 296 ms, GC 3 ms, Thread Cpu 250 ms (Current 01/27/18 00:34:20)
Yes
?- time((between(1,1000,_), negcase(_,_,F),
norm(F,G), maze(G,[],_), fail; true)).
% Up 82 ms, GC 0 ms, Thread Cpu 78 ms (Current 01/27/18 00:30:21)
Yes

Difference between X\=Y and dif(X,Y)

What is the difference between this:
X \= Y
and this piece of code:
dif(X, Y)
I thought that they should behave the same, but they do not. Here's the example:
n_puta(L, N, X) :- nputa(L, N, 0, X).
nputa([], N, C, _) :- N = C.
nputa([G|R], N, C, X) :- G = X, nputa(R, N, Y, X), C is Y - 1.
nputa([G|R], N, C, X) :- dif(G,X), nputa(R, N, C, X).
And here are some calls:
?- n_puta([a,a,b,b,b], 2, X).
X = a ;
false.
?- n_puta([a,a,b,a,b,b], 3, X).
X = a ;
X = b ;
false.
X should be the atom that occurs exactly N times in the list L. If I replace dif(G, X) with G \= X, I don't get the expected result. Can someone tell me what is the difference between these two operators? Can I use anything else except dif(G, X)?
This example works prefectly in SWI-Prolog, but doesn't work in Amzi! Prolog.
dif/2 and (\=)/2 are the same as long as their arguments are ground. But only dif/2 is a pure relation that works correctly also with variables and can be used in all directions. Your example clearly shows that you should use dif/2 in this case, because you use your predicate not only to test, but also to generate solutions. The most widely used Prolog systems all provide dif/2.

Don't repeat solutions in Prolog

Suppose you have a database with the following content:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
So a and b are sons of d and c. Now you want to know, given a bigger database, who is brother to who. A solution would be:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
The problem with this is that if you ask "brother(X, Y)." and start pressing ";" you'll get redundant results like:
X = a, Y = b;
X = b, Y = a;
X = a, Y = b;
X = b, Y = a;
I can understand why I get these results but I am looking for a way to fix this. What can I do?
Prolog will always try to find every possible solution available for your statements considering your set of truths. The expansion works as depth-first search:
son(a, d).
son(b, d).
son(a, c).
son(b, c).
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y.
brother(X, Y)
_______________________|____________________________ [son(X, P)]
| | | |
X = a, P = d X = b, P = d X = a, P = c X = a, P = b
| | | |
| ... ... ...
|
| (X and P are already defined for this branch;
| the algorithm now looks for Y's)
|__________________________________________ [son(Y, d)]
| |
son(a, d) -> Y = a son(b, d) -> Y = b
| |
| | [X \= Y]
X = a, Y = a -> false X = a, Y = b -> true
|
|
solution(X = a, Y = b, P = d)
But, as you can see, the expansion will be performed in all the branches, so you'll end up with more of the same solution as the final answer. As pointed by #Daniel Lyons, you may use the setof built-in.
You may also use the ! -- cut operator -- that stops the "horizontal" expansion, once a branch has been found to be valid, or add some statement that avoids the multiple solutions.
For further information, take a look at the Unification algorithm.
First, I would advise against updating the Prolog database dynamically. For some reasons, consider the article
"How to deal with the Prolog dynamic database?".
You could use a combination of the builtin setof/3 and member/2, as #DanielLyons has suggested in his answer.
As yet another alternative, consider the following query which uses setof/3 in a rather unusual way, like this:
?- setof(t,brother(X,Y),_).
X = a, Y = b ;
X = b, Y = a.
You can eliminate one set with a comparison:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
X = a,
Y = b ;
false.
Since X and Y will be instantiated both ways, requiring X be less than Y is a good way to cut the solutions in half.
Your second problem is that X and Y are brothers by more than one parent. The easiest solution here would be to make your rules more explicit:
mother(a, d).
mother(b, d).
father(a, c).
father(b, c).
brother(X, Y) :-
mother(X, M), mother(Y, M),
father(X, F), father(Y, F),
X \= Y, X #< Y.
?- brother(X, Y).
X = a,
Y = b ;
false.
This method is very specific to this particular problem, but the underlying reasoning is not: you had two copies because a and b are "brothers" by c and also by d—Prolog was right to produce that solution twice because there was a hidden variable being instantiated to two different values.
A more elegant solution would probably be to use setof/3 to get the solutions. This can work even with your original code:
?- setof(X-Y, (brother(X, Y), X #< Y), Brothers).
Brothers = [a-b].
The downside to this approach is that you wind up with a list rather than Prolog generating different solutions, though you can recover that behavior with member/2.
This should work. But I think it can be improved (I am not a Prolog specialist):
brother(X, Y) :-
son(X, P1),
son(Y, P1),
X #< Y,
(son(X, P2), son(Y, P2), P1 #< P2 -> false; true).
If you're using Strawberry Prolog compiler,you won't get all the answers by typing this:
?- brother(X, Y),
write(X), nl,
write(Y), nl.
In order to get all the answers write this:
?- brother(X, Y),
write(X), nl,
write(Y), nl,
fail.
I hope it helps you.:)
I got to an answer.
% Include the dictionary
:- [p1]. % The dictionary with sons
:- dynamic(found/2).
brother(X, Y) :-
% Get two persons from the database to test
son(X, P),
son(Y, P),
% Test if the two persons are different and were not already used
testBrother(X, Y).
% If it got here it's because there is no one else to test above, so just fail and retract all
brother(_, _) :-
retract(found(_, _)),
fail.
testBrother(X, Y) :-
X \= Y,
\+found(X, Y),
\+found(Y, X),
% If they were not used succed and assert what was found
assert(found(X, Y)).
It always returns fails in the end but it succeeds with the following.
brother(X, Y). % Every brother without repetition
brother('Urraca', X). % Every brother of Urraca without repetition
brother('Urraca', 'Sancho I'). % True, because Urraca and Sancho I have the same father and mother. In fact, even if they only had the same mother or the same father it would return true. A little off context but still valid, if they have three or more common parents it would still work
It fails with the following:
brother(X, X). % False because it's the same person
brother('Nope', X). % False because not is not even in the database
brother('Nope', 'Sancho I'). % False, same reason
So like this I can, for example, ask: brother(X, Y), and start pressing ";" to see every brother and sister without any repetition.
I can also do brother(a, b) and brother(b, a), assuming a and b are persons in the database. This is important because some solutions would use #< to test things and like so brother(b, a) would fail.
So there it is.

Resources