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 :) )