Hi, I’m a Prolog learner, so my code can not be very efficient. I’m stuck on a little problem in Prolog which seems doable. Here is the problem :
I have two basis [i0,j0,k0]
and [i1,j1,k1]
. Then we have an orthogonal constraint between all elements of the same basis (i0
is orthogonal to j0
, j0
is orthogonal to k0
, and k0
is orthogonal to i0
, and the same for the vectors of the second basis).
I would like to find the set of new orthogonal constraint to add between elements of the first basis and the second one such that the two basis are aligned/equal. Then it could be interesting to find the minimal number of constraints (which seems to be 3 when you think about it).
Here is my attempt:
:- dynamic ortho_constraint/2.
basis([i0,j0,k0]).
basis([i1,j1,k1]).
ortho(X,Y) :- ortho_constraint(X,Y); ortho_constraint(Y,X).
ortho(X,Y) :- basis(B), permutation(B,[X,Y,_]).
collin(X,Y) :-
dif(X,Y), % fail fast principle
basis(B1), basis(B2), dif(B1,B2),
permutation([E1,E2,X],B1), member(Y,B2),
ortho(E1,Y), ortho(E2,Y).
equal(B1,B2) :-
B1 = B2;
length(B1,3), length(B2,3),
maplist(collin, B1, B2).
In this code I defined basis/1
the predicate to define a base. Then ortho/2
is true when it exists a base B in which X
and Y
are vectors, or when it exists a dynamically added ortho_constraint/2
between the two vectors.
The first problem occurs in collin/2
. It’s defined on the fact that two vectors X
and Y
are collinear iif it exists two different basis B1=[E1,E2,X]
and B2=[_,_,Y]
(possibly with a permutation) such that ortho(E1,Y)
and ortho(E2,Y)
are true.
When I query that, with some dynamic constraints added and that I want to get all X
and Y
such that collin(X,Y)
is true, I get :
?- asserta(ortho_constraint(i1,k0)), asserta(ortho_constraint(j1,k0)), asserta(ortho_constraint(j1,i0)), collin(X,Y), retractall(ortho_constraint(_,_)).
X = j0,
Y = j1 ;
false.
But for instance :
?- asserta(ortho_constraint(i1,k0)), asserta(ortho_constraint(j1,k0)), asserta(ortho_constraint(j1,i0)), collin(k0,k1), retractall(ortho_constraint(_,_)).
false.
?- asserta(ortho_constraint(i1,k0)), asserta(ortho_constraint(j1,k0)), asserta(ortho_constraint(j1,i0)), collin(k1,k0), retractall(ortho_constraint(_,_)).
true .
collin/2
seems to depends on the order of the arguments even if I pay attention to not impose the basis in which X
and Y
belong, and we are not able to query all answers since {X=k1, Y=k0} should at least appear in the answers of collin(X,Y)
…
Also, collin/2
has to be true between two vectors of two different basis if the two others vectors of the two different basis are already collinear (i0 // i1 and j0 // j1 => k0 // k1), but I am not able to express this rule without falling into an infinite recursion …
Can you help me to code a better version of collin/2
?
At this point I will also be able to simplify equal/2
as when two vectors of two basis are collinear, it implies that the third vectors of the two basis are also collinear one to another ;).
Then I would like to formulate my query to answer my problem. The goal is to generate a list L
of all possible pairs X-Y
such that X
is a member of B1
and Y
is a member of B2
, and then generate a powerset P
from this list. This represents all the possible constraints we have to test in our problem. Then, for a list of constraint T
in the powerset P
, we define the constraints which are in T
and we check that the two basis are equals, just before removing the dynamically added constraints.
powerset([], []).
powerset([_|T], P) :- powerset(T,P).
powerset([H|T], [H|P]) :- powerset(T,P).
solution(T,B1,B2) :-
basis(B1), basis(B2), dif(B1,B2),
findall(PS, (setof(X-Y, (member(X,B1), member(Y,B2)), L), powerset(L,PS)), P),
member(T,P), forall(member(X-Y,T), asserta(ortho_constraint(X,Y))),
equal(B1,B2), retractall(ortho_constraint(_,_)).
If you think that my query could be expressed in a simpler/clearer way, please notice me. I have 260 results and when I order them I have :
?- setof(Len-T, (solution(T, [i0,j0,k0],[i1,j1,k1]), length(T,Len)), Z), keysort(Z, S).
S = [
1-[j0-i1],
2-[i0-i1, j0-i1],
2-[i0-j1, k0-i1],
2-[i0-k1, j0-k1],
2-[j0-i1, k0-i1],
3-[i0-i1, i0-j1, k0-i1],
3-[i0-i1, i0-k1, j0-k1],
3-[i0-i1, j0-i1, k0-i1],
[...]
So some problems with lists of size 1 and 2 which are clearly not solutions of my problem, but the rest “seems” correct …
Thanks in advance
Teusner