I am quite new in the Prolog magical universe, but it seems to be very powerful to solve my 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
).
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).
I have working a start of code (but you can give me tips and tricks to have a more efficient code) but then I'm stuck when I need to express the goal of my problem ...
Let's define define ortho/1
such that all the elements in the list given to ortho are ortho one to another. Then we could define our two basis:
ortho([i0,j0,k0]).
ortho([i1,j1,k1]).
I add then the following rule to deduce ortho([X,Y])
from ortho([X,Y,Z])
predicates:
ortho(L) :- ortho(B), unique(L), unordered_subset(B,L).
This could be explained as we need to find an existing basis B
such that L
is a sublist of B
and all elements of L
are distinct. Some tests are leading to:
?- ortho([i0,j0]).
true.
?- ortho([k0,i0]).
true.
?- ortho([i0,i0]).
false.
Here is the implementation of unique/1
, subset/2
and unordered_subset/2
I used in my program (Found on StackOverflow, don't know if there is better but it seems to work).
% unique/1 detect list formed by unique elements
unique([]).
unique([X|Xs]) :- \+ memberchk(X, Xs), unique(Xs).
% subset/2 (set, subset) true if subset is a subset of set in the same order
subset([], []).
subset([E|Tail], [E|NTail]):-
subset(Tail, NTail).
subset([_|Tail], NTail):-
subset(Tail, NTail).
% unordered_subset/2 (set, subset) true if subset is a subset of set
unordered_subset(Set, SubSet):-
length(Set, LSet),
between(0,LSet, LSubSet),
length(NSubSet, LSubSet),
permutation(SubSet, NSubSet),
subset(Set, NSubSet).
The finality is to see if the two basis are equal. To do so, I defined equal/2
and collin/2
such that:
% collin/2 check the collinearity of two vectors
collin(A,B) :-
ortho([X,Y,A]), ortho([X,B]), ortho([Y,B]).
% equal/2 check basis equals
equal([],[]).
equal([H1|T1],[H2|T2]) :-
collin(H1,H2),
equal(T1,T2).
collin/2
is based on the fact that two vectors A
and B
are collinear if it exists X
and Y
such that [X,Y,A]
is a basis and X
and Y
are both orthogonal to B
. And equal/2
is the fact that two basis are equal if the vectors taken in the good order are collinear. (By commutativity Prolog should be able to find this good order).
To find a solution to my problem, I think there is something about finding a list of pairs T
of length N
, with N as low as possible, such that for all pair P=X-Y
in T, ortho(X,Y)
implies equal([i0,j0,k0], [i1,j1,k1])
.
Could you help me to express this rule ? (And eventually to have a better code :) )