Related
this is my code, I don't understand why this does not look like what I thought
com([],[]).
com([H|T1],[H|T2]):-
com(T1,T2).
com([_|T1],T2):-
com(T1,T2).
three([X1,X2|T]) :-
X2 is X1 + 1,
(
T = []
; three([X2|T])
).
then I tried "findall(Tests, (com([6,7,8,8,9],Tests),three(Tests),Length(Test,N)), N>=3,Alltests)", this is to find all possible cases that continuous number with at least length 3,
'com' return all the tests
'three' is to find all continuous number with at least length 3.
but, the results were wrong.
[trace] findall(..,....,[[6, 7, 8, 9], [6, 7, 8], [6, 7, 8], [7, 8, 9]])
why I just got one [6,7,8,9] and [7,8,9], it should return both I think
findall(Tests, (com([6,7,8,8,9],Tests),three(Tests),Length(Test,N)), N>=3,Alltests)
You have Test instead of Tests here, so it's a different variable.
And Length with a capital needs to be length
And you have N>=3 outside the () so you are using findall/4 instead of findall/3.
With those changes, it seems to work for me:
?- findall(Tests, (com([6,7,8,8,9],Tests),three(Tests),length(Tests,N), N>=3),Alltests).
Alltests = [[6, 7, 8, 9], [6, 7, 8], [6, 7, 8, 9], [6, 7, 8], [7, 8, 9], [7, 8, 9]]
Everything seems to work alright:
?- com([6,7,8,8,9],Tests), three(Tests), length(Tests,N), N >= 3.
N = 4, Tests = [6,7,8,9]
; N = 3, Tests = [6,7,8]
; N = 4, Tests = [6,7,8,9]
; N = 3, Tests = [6,7,8]
; N = 3, Tests = [7,8,9]
; N = 3, Tests = [7,8,9]
; false.
Tip: always do the pure parts first; aggregate later.
Just wanted to give an easy way to define three/1
three(Lst) :-
LstDigits = [1, 2, 3, 4, 5, 6, 7, 8, 9],
between(3, 9, Len),
length(Lst, Len),
append([_, Lst, _], LstDigits).
Result in swi-prolog:
?- three(L).
L = [1,2,3] ;
L = [2,3,4] ;
L = [3,4,5] ;
L = [4,5,6] ;
L = [5,6,7] ;
L = [6,7,8] ;
L = [7,8,9] ;
L = [1,2,3,4] ;
L = [2,3,4,5] ;
etc.
Basically what I want to achieve is :
Given a list of domain Variables set these Variables with a domain relative to a List of Numbers. Example:
......
List=[A1,A2,A3],
domain(List,1,5],
setDomain(List,[1,2]),
labeling([],List).
Result:
A1=1, A2=1, A3=1 or
A1=1, A2=1, A3=2 or
A1=1, A2=2, A3=1
and so on...
What I have tried:
setDomain(List,ListIntegers):-
element(X, List, Element),
member(Element,ListIntegers),
main(List):-
List=[A1,A2,A3],
domain(List,1,5],
setDomain(List,[1,2]),
labeling([],List).
but not success...
Can anyone help understand how can I accomplish this?
In your solution, you're using labeling/2 but haven't defined its arguments using CLP(FD), so it doesn't do anything for you. It's not very clear from your question or simple example, but it sounds like you want a list of a given length whose elements are each taken from a domain consisting of an arbitrary list of elements?
You could do so with something like this:
member_(List, Element) :- member(Element, List).
domain_list(Length, Domain, List) :-
length(List, Length),
maplist(member_(Domain), List).
This would give:
6 ?- domain_list(3, [1,3], L).
L = [1, 1, 1] ;
L = [1, 1, 3] ;
L = [1, 3, 1] ;
L = [1, 3, 3] ;
L = [3, 1, 1] ;
L = [3, 1, 3] ;
L = [3, 3, 1] ;
L = [3, 3, 3].
7 ?-
This also works for any kind of elements:
7 ?- domain_list(3, [tom, a(b)], L).
L = [tom, tom, tom] ;
L = [tom, tom, a(b)] ;
L = [tom, a(b), tom] ;
L = [tom, a(b), a(b)] ;
L = [a(b), tom, tom] ;
L = [a(b), tom, a(b)] ;
L = [a(b), a(b), tom] ;
L = [a(b), a(b), a(b)].
8 ?-
If you wanted to use CLP(FD), you'd need to keep a couple of things in mind. CLP(FD) is for integer domains, and CLP(FD) has its own way of specifying domains, which is not in list form.
For instance, if you wanted a list of length N whose elements were in the domain described by [1,2,3,5,6,8], you would write it as:
length(List, N),
List ins 1..3 \/ 5..6 \/ 8,
label(List).
Which would result in, for example:
2 ?- length(List, 3), List ins 1..3 \/ 5..6 \/ 8, label(List).
List = [1, 1, 1] ;
List = [1, 1, 2] ;
List = [1, 1, 3] ;
List = [1, 1, 5] ;
List = [1, 1, 6] ;
List = [1, 1, 8] ;
List = [1, 2, 1] ;
List = [1, 2, 2]
...
Using ECLiPSe Prolog you can write:
:-lib(fd).
applyDomain([],_).
applyDomain([H|T],D):-
var_fd(H,D),
applyDomain(T,D).
domainList(ListDomain,LengthList,ListOutput):-
length(ListOutput,LengthList),
list_to_dom(ListDomain,Domain),
applyDomain(ListOutput,Domain).
Query:
?- domainList([2,3,5,7,8],5,L).
L = [_530{[2, 3, 5, 7, 8]}, _547{[2, 3, 5, 7, 8]}, _564{[2, 3, 5, 7, 8]}, _581{[2, 3, 5, 7, 8]}, _598{[2, 3, 5, 7, 8]}]
Yes (0.00s cpu)
The output means that each variable (in this case _530, _547 and so on) in the list L has the specified domain {[2, 3, 5, 7, 8]}. If you want to label the list you can simply add
labeling(ListOutput).
as last line of domainList/3 and you get:
?- domainList([2, 3, 5, 7, 8], 5, L).
L = [2, 2, 2, 2, 2]
Yes (0.00s cpu, solution 1, maybe more)
L = [2, 2, 2, 2, 3]
Yes (0.00s cpu, solution 2, maybe more)
L = [2, 2, 2, 2, 5]
Yes (0.00s cpu, solution 3, maybe more)
and so on... If you want that all the list will be different, just add
alldifferent(ListOutput),
before labeling/1, and you'll get
?- domainList([2, 3, 5, 7, 8], 5, L).
L = [2, 3, 5, 7, 8]
Yes (0.00s cpu, solution 1, maybe more)
L = [2, 3, 5, 8, 7]
Yes (0.00s cpu, solution 2, maybe more)
L = [2, 3, 7, 5, 8]
Yes (0.00s cpu, solution 3, maybe more)
I usually don't use SWI prolog for clpfd problems, so i don't know if there is a similar solution in SWI...
i can create a list from 0 to N and permutation it. But how can i make it into matrix and permutation each line just from matrix(2,L).
add(X,L,[X|L]).
add(X,[L|H],[L|R]):- add(X,H,R).
permut([],[]).
permut([L|H],R):- permut(H,R1),add(L,R1,R).
permutations(L,R):- findall(P,permut(L,P),R).
do_list(N, L) :- do_list1(N, [], L).
do_list1(0, L, L) :- !.
do_list1(N, R, L) :- N > 0,
N1 is N-1,
do_list1(N1, [N|R], L).
matrix(N,L):-
do_list(N,R),
permut(R,L).
not sure about your request. Here is a possible answer based on builtins...
3 ?- [user].
|: matrix(N, Mat) :- length(Rows, N), maplist(numlist(1,N), Rows), maplist(permutation, Rows, Mat).
% user://1 compiled 0.01 sec, 2 clauses
true.
4 ?- matrix(3, M).
M = [[1, 2, 3], [1, 2, 3], [1, 2, 3]] ;
M = [[1, 2, 3], [1, 2, 3], [1, 3, 2]] ;
M = [[1, 2, 3], [1, 2, 3], [2, 1, 3]] ;
M = [[1, 2, 3], [1, 2, 3], [2, 3, 1]] ;
...
I'm trying to figure out how to generate a list of sets, where each set has a length of N and the sum of each set is X.
I found this code:
num_split(0,[]).
num_split(N, [X | List]):-
between(1,N,X),
plus(X,Y,N),
num_split(Y,List).
And I can use that to get a list of sets with sum X:
num_split(6,List),length(List,5).
List = [1, 1, 1, 1, 2] ;
List = [1, 1, 1, 2, 1] ;
List = [1, 1, 2, 1, 1] ;
List = [1, 2, 1, 1, 1] ;
List = [2, 1, 1, 1, 1] ;
false.
The problem is that those are all permutations, and I'm looking for combinations. The output I'm looking for should be something like get_combos(Sum,Length,List):
get_combos(6,2,List).
List = [5,1];
List = [4,2];
List = [3,3];
false.
Any pointers?
If you have access to a CLP(FD) library, you can use this code:
:- [library(clpfd)].
get_combos(Sum, Length, List) :-
length(List, Length),
List ins 1 .. Sum,
% all_distinct(List), not really useful here
sum(List, #=, Sum),
chain(List, #<),
label(List).
test:
?- get_combos(10,3,L).
L = [1, 2, 7] ;
L = [1, 3, 6] ;
L = [1, 4, 5] ;
L = [2, 3, 5] ;
Maybe I misunderstood your question. Use this chain
...
chain(List, #=<),
....
to get possible duplicates values:
?- get_combos(10,3,L).
L = [1, 1, 8] ;
L = [1, 2, 7] ;
L = [1, 3, 6] ;
L = [1, 4, 5] ;
L = [2, 2, 6] ;
L = [2, 3, 5] ;
L = [2, 4, 4] ;
L = [3, 3, 4] ;
false.
Enforce an "equal or greater" restriction between successive values in the array.
You can add it on as another predicate:
is_combination([]).
is_combination([_]).
is_combination([A,B|List]) :- A =< B, is_combination([B|List]).
get_combos(Sum, Length, List) :-
num_split(Sum, Length, List),
is_combination(List).
Unfortunately, tacking it on the end of the num_split/3 does not necessarily increase its performance, so adding it directly into the algorithm would be marginally better:
get_combos(_, 0, []).
get_combos(Sum, 1, [Sum]).
get_combos(Sum, Length, [A, B|List]) :-
between(1, Sum, A),
plus(A, NextSum, Sum),
plus(1, NextLength, Length),
get_combos(NextSum, NextLength, [B|List]),
A =< B.
I'm not sure just how much more performance this gets, as the comparison has to be after the recursion, due to the less-than-or-equals operator (=<) requiring both operands to be fully instantiated for it to work.
I was trying to write predicate divide(L,Len,Slist) which will be true when Slist can unify with a List of length Len allocated from List L. for example
divide([1,2,3,4,5,6,7],3,Slist).
Should give such answers
Slist=[1,2,3];
Slist=[2,3,4];
Slist=[3,4,5];
Slist=[4,5,6];
Slist=[5,6,7];
But i couldn't find a better way then length(X,Len), sublist(L,X). but it does work too slow.
How should look divide predicate?
Alternatively you could use DCG as mentionned by #false in this great answer:
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
divide(List, Length, Result) :-
length(Result, Length),
phrase((seq(_), seq(Result), seq(_)), List).
sublist/2 doesn't seems to work as expected:
?- [library(dialect/sicstus/lists)].
% library(dialect/sicstus/lists) compiled into sicstus_lists 0,00 sec, 14 clauses
true.
?- L=[1,2,3,4,5,6], length(T, 3),sublist(T,L).
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 3] ;
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 4] ;
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 5] ;
....
You could use append/3 instead:
?- L=[1,2,3,4,5,6], length(T, 3), append(_, Q, L), append(T, _, Q).
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 3],
Q = [1, 2, 3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = [2, 3, 4],
Q = [2, 3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = [3, 4, 5],
Q = [3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = Q, Q = [4, 5, 6] ;
false.
I don't think it's very fast, just essential...