mljistcart
mljistcart

Reputation: 45

Prolog constraint logic programming - How to set a domain on a List of Domain Variables given a List of Integers?

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?

Upvotes: 1

Views: 2499

Answers (2)

lurker
lurker

Reputation: 58324

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

Upvotes: 2

damianodamiano
damianodamiano

Reputation: 2662

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

Upvotes: 1

Related Questions