Prolog - dividing a list in N parts - list

I'm trying to write a predicate that divides a list into N parts.
This is what I have so far.
partition(1, List, List).
partition(N, List, [X,Y|Rest]):-
chop(List, X, Y),
member(NextToChop, [X,Y]), %Choose one of the new parts to chop further.
NewN is N-1,
partition(NewN, NextToChop, Rest).
chop(List, _, _):-
length(List, Length),
Length < 2, %You can't chop something that doesn't have at least 2 elements
fail,!.
chop(List, Deel1, Deel2):-
append(Deel1, Deel2, List),
Deel1 \= [],
Deel2 \= [].
The idea is to keep chopping parts of the list into two other parts until I have N pieces.
I have mediocre results with this approach:
?- partition(2, [1,2,3,4], List).
List = [[1], [2, 3, 4], 1] ;
List = [[1], [2, 3, 4], 2, 3, 4] ;
List = [[1, 2], [3, 4], 1, 2] ;
List = [[1, 2], [3, 4], 3, 4] ;
List = [[1, 2, 3], [4], 1, 2, 3] ;
List = [[1, 2, 3], [4], 4] ;
false.
So I get what I want, but I get it two times and there are some other things attached.
When dividing into 3 parts things get worse:
?- partition(3, [1,2,3,4], List).
List = [[1], [2, 3, 4], [2], [3, 4], 2] ;
List = [[1], [2, 3, 4], [2], [3, 4], 3, 4] ;
List = [[1], [2, 3, 4], [2, 3], [4], 2, 3] ;
List = [[1], [2, 3, 4], [2, 3], [4], 4] ;
List = [[1, 2], [3, 4], [1], [2], 1] ;
List = [[1, 2], [3, 4], [1], [2], 2] ;
List = [[1, 2], [3, 4], [3], [4], 3] ;
List = [[1, 2], [3, 4], [3], [4], 4] ;
List = [[1, 2, 3], [4], [1], [2, 3], 1] ;
List = [[1, 2, 3], [4], [1], [2, 3], 2, 3] ;
List = [[1, 2, 3], [4], [1, 2], [3], 1, 2] ;
List = [[1, 2, 3], [4], [1, 2], [3], 3] ;
false.
Another idea is using prefix but I don't know how that would really work. To use that I should be able to let Prolog know that it needs to take a prefix that's not too short and not too long either, so I don't take a prefix that's too long so there's nothing left for a next recursion step.
Can anyone point me in the right direction?
Little clarification: the predicate should return all posibilities of dividing the list in N parts (not including empty lists).

When describing relations that involve lists, DCGs are often very useful. Consider:
list_n_parts(List, N, Parts) :-
length(Parts, N),
phrase(parts(Parts), List).
parts([]) --> [].
parts([Part|Parts]) --> part(Part), parts(Parts).
part([P|Ps]) --> [P], list(Ps).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Sample query:
?- list_n_parts([1,2,3,4], 2, Ps).
Ps = [[1], [2, 3, 4]] ;
Ps = [[1, 2], [3, 4]] ;
Ps = [[1, 2, 3], [4]] ;
false.

Here is the basic way I'd use to implement that (using append/2 and length/2) :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List).
Now, that doesn't totally complies to your expectations : it allows for [].
One idea to fix that is to use a maplist call to format the Resulting list beforehand :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
using copy_term/2, the maplist/2 call looks like :
maplist(copy_term([_|_]), Result),
using functor/3 (credits to #false), it would look like :
maplist(functor('.', 2), Result),
using lambda.pl you could write :
maplist(\[_|_]^true, Result),
since the '\' already performs a term copy (thanks #false).
The only thing left is the append/2 call:
append(Result, List).
Another idea would be to use forall/2 filtering (maybe simpler to get, but worse in complexity) :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List),
forall(member(X, Result), X \= []).
etc...

Related

How to get all elements in a nested list where the first element of each list is a particular number?

I'm new to Prolog and I am having trouble with recursion and nested lists.
I want a predicate called getCommon(Number, List, X) which does the following:
getCommon(2, [[2,3], [2,5], [3,5]], X).
X = [[2,3], [2,5]].
I tried this but it returns an empty list and I am very confused as to why:
getCommon(_,[],_).
getCommon(Elem, [PointsH|PointsT], CommonPoints):-
nth0(0, PointsH, CurrElem),
(CurrElem = Elem -> append(CommonPoints,[PointsH],NewCommonPoints) ;append(CommonPoints,[],NewCommonPoints)),
getCommon(Elem, PointsT, NewCommonPoints).
Your code does not work because the recursion base case is not well defined and also because predicate append/3 is not properly used. Try the following code:
get_common(_, [], []).
get_common(K, [[K,Y]|Points], [[K,Y]|Rest]) :-
get_common(K, Points, Rest).
get_common(K, [[X,_]|Points], Rest) :-
dif(K,X),
get_common(K, Points, Rest).
Examples:
?- get_common(2, [[2,3], [3,2], [2,5], [3,7]], Common).
Common = [[2, 3], [2, 5]] ;
false.
?- get_common(3, [[2,3], [3,2], [2,5], [3,7]], Common).
Common = [[3, 2], [3, 7]] ;
false.
?- get_common(2, [[2,3], [K,2], [2,5], [3,7]], Common).
K = 2,
Common = [[2, 3], [2, 2], [2, 5]] ;
Common = [[2, 3], [2, 5]],
dif(K, 2) ;
false.

Prolog intersection list of lists

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

Generate Successive Number Pairs - Prolog

I have some code that takes a given list of pairs of numbers and solves for chains of 7. However, it takes an obnoxious amount of time to solve for even one (well, i haven't solved for 1 yet and it has been a large amount of time). I was wondering if there was a better/more efficient way of coding this.
Here's what I did, with out the numbers in the list "L". (the list looks like such: L= [[1,2],[2,3],...])
length(L,LEN),
interval(N1,1,LEN),
interval(N2,1,LEN),
interval(N3,1,LEN),
interval(N4,1,LEN),
interval(N5,1,LEN),
interval(N6,1,LEN),
interval(N7,1,LEN),
nth1(N1,L,A),
nth1(N2,L,B),
nth1(N3,L,C),
nth1(N4,L,D),
nth1(N5,L,E),
nth1(N6,L,F),
nth1(N7,L,G),
nth1(2,A,A2),
nth1(1,B,B1),
A2 = B1,
nth1(2,B,B2),
nth1(1,C,C1),
B2 = C1,
nth1(2,C,C2),
nth1(1,D,D1),
C2 = D1,
nth1(2,D,D2),
nth1(1,E,E1),
D2 = E1,
nth1(2,E,E2),
nth1(1,F,F1),
E2 = F1,
nth1(2,F,F2),
nth1(1,G,G1),
F2 = G1,
nth1(2,G,G2),
nth1(1,A,A1),
G2 = A1,
R = (A,B,C,D,E,F,G).
If I understand your intention correctly, you can write this shorter as
use_module(library(clpfd)).
q(L,R) :-
[A,B,C,D,E,F,G] ins 1 .. 7,
R = [[A,B],[B,C],[C,D],[D,E],[E,F],[F,G],[G,A]],
permutation(L, R),
label([A,B,C,D,E,F,G]).
Example:
3 ?- q([[1,7],[2,3],[5,4],[3,1],[7,6],[6,5],[4,2]],X).
X = [[1, 7], [7, 6], [6, 5], [5, 4], [4, 2], [2, 3], [3, 1]] ;
X = [[2, 3], [3, 1], [1, 7], [7, 6], [6, 5], [5, 4], [4, 2]] ;
X = [[5, 4], [4, 2], [2, 3], [3, 1], [1, 7], [7, 6], [6, 5]] ;
X = [[3, 1], [1, 7], [7, 6], [6, 5], [5, 4], [4, 2], [2, 3]] ;
X = [[7, 6], [6, 5], [5, 4], [4, 2], [2, 3], [3, 1], [1, 7]] ;
X = [[6, 5], [5, 4], [4, 2], [2, 3], [3, 1], [1, 7], [7, 6]] ;
X = [[4, 2], [2, 3], [3, 1], [1, 7], [7, 6], [6, 5], [5, 4]] ;
false.
But your question is really unclear.
update: We can create the kind of lists we use above, of any length, with
vars(N, Vars):-
length(Vars, N).
pairs(Vars, N, Pairs):- % assuming vars(N, Vars)
N #> 0,
append(Vars,[A],[A|B]), % |B| = N
maplist( pair, Vars, B, Pairs).
pair( A, B, [A,B]).
Such that q/2 can be generalized as
gen_q(L,R) :-
length( L, N),
vars( N, Vars),
Vars ins 1 .. N,
pairs( Vars, N, R),
permutation(L, R),
label(Vars).
But computational feasibility of this for larger inputs is another matter entirely. The brute force of permutation/2 may have to be replaced with something more specific.
Also, the N results produced comprise a clear pattern; there's no need to re-enter the search to produce them all after the first one is found.

Prolog: Generating Every Possibility of a List Given a Pattern

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]].

Permutation Prolog

I am trying to make a list*list of all permutations from 1 to N
Example: perm(3, X). -> X = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
I am instead getting
X = [1, 2, 3]
X = [1, 3, 2]
X = [2, 1, 3]
X = [2, 3, 1]
X = [3, 1, 2]
X = [3, 2, 1]
and having to keep hitting next. My question is how would I put all values of X into a list like the example run that I want. Here is my existing code:
permHelp([],[]).
permHelp(List,[H|Finish]):-delete(H,List,Rest),permHelp(Rest,Finish).
delete(X,[X|T],T).
delete(X,[H|T],[H|NT]):-delete(X,T,NT).
createList(0, L, L) :- !.
createList(N, R, L) :- N > 0, N1 is N-1, createList(N1, [N|R], L).
perm(N, X):- createList(N, [], L), permHelp(L, X).
perm(N, X):-
createList(N, [], L),
list_allperms(L, X).
With list_allperms/2 defined in another answer.
What you call permHelp should rather be called permutation.