I am now quite a while trying to figure out what my mistake is, but I am not able to.
Task:
We have to figure out how to find three permutations of a List containing 9 elements in the form of List of Lists. Each List of Lists should contain three sublists, each containing three elements. But no element is allowed to be together with another element in two different sublists.
The following output for the three permutations A, B, C with the given List= [1,2,3,4,5,6,7,8,9] could be:
predicate(A, B, C , [1,2,3,4,5,6,7,8,9]).
A = [[1,2,3],[4,5,6],[7,8,9]],
B = [[1,4,7],[2,5,8],[3,6,9]],
C = [[1,5,9],[2,6,7],[3,4,8]].
My Code so far (first my helper predicates) :
To split a list into a List of Lists ( N is always 3 ):
split_list(List, N, Splitted_List) :-
split_helper(List, N, [], Splitted_List).
split_helper([], _, Acc, Acc).
split_helper(List, N, Acc, Splitted_List) :-
my_append(H, T, List),
my_length(H, N),
split_helper(T, N, [H|Acc], Splitted_List).
A possible query:
split_list([1,2,3,4,5,6,7,8,9], 3, X).
X = [[1,2,3],[4,5,6],[7,8,9]].
To check wether all sublists of a List of lists contains at most one same element:
max_one_common_element(List1, List2) :-
max_one_common_element(List1, List2, 0).
max_one_common_element([], _, Count) :-
Count =< 1.
max_one_common_element([H|T], List2, Count) :-
(my_member(H, List2) ->
NewCount is Count + 1,
max_one_common_element(T, List2, NewCount)
;
max_one_common_element(T, List2, Count)
).
A possible query:
max_one_common_element([[1,2,3],[4,5,6],[7,8,9]], [[1,4,7],[2,5,8],[3,6,9]]).
True.
To change order of sublists, for comparing purposes (important later on):
swap_lists(List, Result):-
select(Selected, List, Rest),
append(Rest, [Selected], Result).
A possible query:
swap_list([[1,2,3],[4,5,6],[7,8,9]], X).
X = [[4,5,6],[7,8,9],[1,2,3]].
My main predicate, which instantiates A, B and C. The one making me issues is C, A and B are properly instantiated.
I was thinking to take all permutations of the input List and check with max_one_common_element/2 wether each sublists has at most one common element.
Since max_one_common_element/2 is only able to check both lists at the current index ( e.g. [[1,2],[3,4]], [[3,4],[1,2]] would return True, even though it is False) my idea was to change the order of the sublists from A and B two times and check again with C after the first and second change, so all 3 sublists of A and B should be covered.
main_predicate(A, B, C, List):-
/* instantiates A as the input list but seqmented */
split_list(List, 3 , A),
/* instantiates B as a permutation of A, taking every nth element in a sublist*/
%This part is unimportant since it works properly
/* instantiates C as a permutation from the input list, test that each Sub-List contains at most one same element */
permutation(List, Permuted),
split_list(Permuted, Size, Dessert),
max_one_common_element(A, C),
max_one_common_element(A, C),
/* first swap A and B two times */
swap_lists(A, A1),
swap_lists(A1, A2),
swap_lists(B, B1),
swap_lists(B1, B2),
/* Check again with C */
max_one_common_element(A1, C),
max_one_common_element(A2, C),
max_one_common_element(B1, C),
max_one_common_element(B2, C).
When I make a query of:
predicate(A, B ,C, [1,2,3,4,5,6,7,8,9] ).
My output is:
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ,
B = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ,
C = [[7, 8, 9], [4, 5, 6], [1, 2, 3]] .
Prolog just do not seem to consider every call of max_one_common_element/2. Since deleting some seem to change the output, but in my mind I have considered all cases and everything should be fine. I also considered changing max_one_common_element/2, but nothing works.
Thank you really much for your help in advance.
Controlling the backtracking was interesting (to enforce comb_available over all the solution sublists):
:- dynamic used/2.
list_perm3(SubLen, L, P) :-
length(L, Len),
int_div_lt_plus1(Len, SubLen, SegLen),
retractall(used(_, _)),
% Work with instantiated, unique list
int_list_wrap(L, LN),
list_perm3_loop(LN, SubLen, SegLen, PN),
% Map to elements in original list
perm_lists_wrap(PN, L, P).
int_list_wrap(L, LN) :-
int_list_wrap_(L, 1, LN).
int_list_wrap_([], _, []).
int_list_wrap_([H|T], I, [i(I, H)|LN]) :-
I1 is I + 1,
int_list_wrap_(T, I1, LN).
% Can contain sublists
perm_lists_wrap([], _, []).
perm_lists_wrap([[]|T], L, [[]|P]) :-
perm_lists_wrap(T, L, P).
perm_lists_wrap([[H|R]|T], L, [E|P]) :-
% Is a sublist
perm_lists_wrap([H|R], L, E),
perm_lists_wrap(T, L, P).
% Using i/2 for first-argument indexing
perm_lists_wrap([i(_, E)|T], L, [E|P]) :-
perm_lists_wrap(T, L, P).
int_div_lt_plus1(Int, Div, Mod) :-
divmod(Int, Div, Mod0, Rem),
( Rem =:= 0
-> Mod is Mod0
% If doesn't divide cleanly, add 1
; Mod is Mod0 + 1
).
list_perm3_loop(L, SubLen, SegLen, P) :-
% Keeping backtracking to this top-level
(list_perm3_(L, SubLen, SegLen, P) -> true ; !, fail).
list_perm3_loop(L, SubLen, SegLen, P) :-
list_perm3_loop(L, SubLen, SegLen, P).
list_perm3_(L, SubLen, SegLen, P) :-
length(P, SegLen),
perm3_segments(P, SubLen, L),
assert_used(P).
assert_used([]).
assert_used([H|T]) :-
% Assert the used pairs, to prevent reuse
forall(
( select(E1, H, H0),
member(E2, H0)
),
assert(used(E1, E2))
),
assert_used(T).
perm3_segments([], _, []).
perm3_segments([H|T], SubLen, L) :-
perm3(L, H, SubLen, R),
perm3_segments(T, SubLen, R).
perm3(L, P, SubLen, R) :-
length(L, LLen),
PLen is min(LLen, SubLen),
length(P, PLen),
perm3_(P, L, [], R).
perm3_([], R, _, R).
perm3_([H|T], L, P, R) :-
select(H, L, L0),
comb_available(P, H),
perm3_(T, L0, [H|P], R).
comb_available([], _).
comb_available([H|T], E) :-
\+ used(E, H),
comb_available(T, E).
Results in swi-prolog:
?- list_perm3(3, [1,2,3,4,5,6,7,8,9], P).
P = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ;
P = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] ;
P = [[1, 5, 9], [2, 6, 7], [3, 4, 8]] ;
P = [[1, 6, 8], [2, 4, 9], [3, 5, 7]] ;
false.
To take the first 3:
?- once(findnsols(3, P, list_perm3(3, [1,2,3,4,5,6,7,8,9], P), [A,B,C])).
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
B = [[1, 4, 7], [2, 5, 8], [3, 6, 9]],
C = [[1, 5, 9], [2, 6, 7], [3, 4, 8]].
Example of handling vars and leftover sublists:
?- list_perm3(3, [1,2,3,Four,5,6,7,8,9,Ten,Eleven], P).
P = [[1, 2, 3], [Four, 5, 6], [7, 8, 9], [Ten, Eleven]] ;
P = [[1, Four, 7], [2, 5, 8], [3, 6, Ten], [9, Eleven]] ;
P = [[1, 5, 9], [2, Four, Ten], [3, 7, Eleven], [6, 8]] ;
P = [[1, 6, Eleven], [3, Four, 8], [5, 7, Ten], [2, 9]] ;
false.
I managed to come up with my own solution:
make_dessert(Starter, Main, Dessert, List_of_Persons, Size):-
permutation(List_of_Persons, Permuted),
split_list(Permuted, Size, Dessert),
at_most_one_common(Starter, Dessert),
at_most_one_common(Main, Dessert).
split_list(List, N, Splitted_List) :-
split_helper(List, N, [], Splitted_List).
split_helper([], _, Acc, Acc).
split_helper(List, N, Acc, Splitted_List) :-
append(H, T, List),
length(H, N),
split_helper(T, N, [H|Acc], Splitted_List).
at_most_one_common([], _).
at_most_one_common([H|T], List2) :-
check_list(H, List2),
at_most_one_common(T, List2).
check_list(_, []).
check_list(X, [H|T]) :-
intersection(X, H, Z),
length(Z, L),
L =< 1,
check_list(X, T).
I forgot to mention that I receive bonus points for keeping the inferences as low as possible. As my program is not as efficient as #brebs 's, I would really appreciate a few tipps from you to lower these. I am maybe also considering starting a new question regarding this case later on.
For my assignment I need to create a list of all the possible shifts (rotations) of another list in prolog. For example,
Prototype: all_shifts(+A,-R,+L,+S) *S will always start at 1*
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]].
Currently, I have a program that shifts it to the left once.
one_shift(A, R) :-
rotate(left, A, R).
rotate(left, [H|T], L) :- append(T, [H], L).
However, I need to create another program in which the final result (R) contains all of the possible shifts. Recursion in prolog is really beginning to confuse me, but I'm pretty sure that's whats required. Any help would be really appreciated.
Stay logically pure using same_length/2 and append/3!
list_rotations(Es, Xss) :-
same_length(Es, [_|Xss]),
rotations_of(Xss, Es).
rotations_of([], _Es).
rotations_of([Xs|Xss], Es) :-
same_length([_|Xss], Suffix),
same_length(Es, Xs),
append(Suffix, Prefix, Xs),
append(Prefix, Suffix, Es),
rotations_of(Xss, Es).
Sample query:
?- list_rotations([A,B,C,D], Xss).
Xss = [[B,C,D,A],
[C,D,A,B],
[D,A,B,C]]. % succeeds deterministically
A solution to your problem could be:
rotatelist([H|T], R) :- append(T, [H], R).
rotate(L,LO,LL):-
rotatelist(L,L1),
\+member(L1,LO),!,
append([L1],LO,L2),
rotate(L1,L2,LL).
rotate(_,L,L).
?- rotate([1,2,3,4],[],L).
L = [[1, 2, 3, 4], [4, 1, 2, 3], [3, 4, 1, 2], [2, 3, 4, 1]]
Simply rotates the list and checks if this list has already been inserted in the output list. If not the recursion continues, otherwise it returns the list in L. I've inserted the cut ! just to have only the list with all the possible rotations. If you want generate also the other lists just remove it...
If instead you want a solution with the prototype you provide, it could be:
rotatelist([H|T], R) :- append(T, [H], R).
all_shifts(_,[],I,I).
all_shifts(L,Result,Len,I):-
I < Len,
rotatelist(L,LO),
I1 is I+1,
all_shifts(LO,R1,Len,I1),
append([LO],R1,Result).
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
The idea is basically the same as before... Note that this second solution is not tail recursive.
I want to create an intersection of lists of lists in prolog. (Matrix, with lists as cells)
I have to handle only the case, when number of rows and columns are the same (Rectangular). The lists are ordered, and does not contain any duplicate elements (they are ord_sets).
How could I do that?
Example: (3 rows, 3 columns)
A:
[[[1,2],[3,2,1],[3,4,5]],
[[1,2],[3,2,1],[3,4,5]],
[[1,2],[3,2,1],[3,4,5]]]
B:
[[[1],[3,2,1],[3,4,5]],
[[1,2],[2,1],[3,4]],
[[1,2],[3,2,1],[3,9,10,4,5]]]
C:
[[[1],[3,2,1],[3,4,5]],
[[1,2],[2,1],[3,4]],
[[1,2],[3,2,1],[3,4,5]]]
Thank you for the help!
Most Prolog interpreters already have a predicate to calculate the intersection between two lists: intersection/3. For example:
?- intersection([3,2,1], [3,9,10,4,5], R).
R = [3].
We can use maplist/3 to process an entire row of such lists:
?- maplist(intersection, [[1,2],[3,2,1],[3,4,5]], [[1],[3,2,1],[3,4,5]], C).
C = [[1], [3, 2, 1], [3, 4, 5]].
And by using another maplist/3 we process the matrices:
?- maplist(maplist(intersection),[[[1,2],[3,2,1],[3,4,5]], [[1,2],[3,2,1],[3,4,5]], [[1,2],[3,2,1],[3,4,5]]], [[[1],[3,2,1],[3,4,5]],[[1,2],[2,1],[3,4]],[[1,2],[3,2,1],[3,9,10,4,5]]], C).
C = [[[1], [3, 2, 1], [3, 4, 5]], [[1, 2], [2, 1], [3, 4]], [[1, 2], [3, 2, 1], [3, 4, 5]]].
So we can do the processing with:
intersect_matrix(A, B, C) :-
maplist(maplist(intersection), A, B, C).
Let's say you have a list in Prolog such as: [3,4,2,2,1,4]. How would one go about generating a list of lists of all possible patterns that start at the first element of the list, then either go to the i + 2th element, or the i + 3rd element, and so on from there.
Example:
Say I have [3,4,2,2,1,4,8].
I want to be able to generate a list of lists such as:
[[3,2,1,8], [3,2,4], [3,2,8]]
I.e. all possibilities of either every other element or every i+3 element, or any other combination, such as i+2,i+3,i+2,i+2, etc.
I've implemented my own version of a powerset, but I can't seem to figure out where to start.
gen([], []).
gen([A], [A]).
gen([A, _ | T], [A | Xs]) :- gen(T, Xs).
gen([A, _, _ | T], [A | Xs]) :- gen(T, Xs).
results in
?- gen([3,4,2,2,1,4,8], X).
X = [3, 2, 1, 8] ;
X = [3, 2, 1] ;
X = [3, 2, 4] ;
X = [3, 2, 4] ;
X = [3, 2, 8] ;
false.
You can use findall/3 to get all results
?- findall(X, gen([3,4,2,2,1,4,8], X), Z).
Z = [[3, 2, 1, 8], [3, 2, 1], [3, 2, 4], [3, 2, 4], [3, 2, 8]].