Прологическое программирование логики ограничений - Как установить домен в списке переменных домена с учетом списка целых чисел?

В основном то, что я хочу достичь, это:

Учитывая список доменных переменных, установите эти переменные с доменом относительно списка номеров. Пример:

......

List=[A1,A2,A3],
domain(List,1,5],
setDomain(List,[1,2]),
labeling([],List). 

Результат:

A1=1, A2=1, A3=1 or
A1=1, A2=1, A3=2 or
A1=1, A2=2, A3=1

и так далее...

Что я пробовал:

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

но не успех...

Может кто-нибудь помочь понять, как я могу это сделать?

2 ответа

Решение

В вашем решении вы используете labeling/2 но не определили его аргументы с помощью CLP(FD), поэтому он ничего не делает для вас. Это не очень ясно из вашего вопроса или простого примера, но звучит так, как будто вы хотите получить список заданной длины, каждый элемент которого взят из домена, состоящего из произвольного списка элементов?

Вы можете сделать это примерно так:

member_(List, Element) :- member(Element, List).

domain_list(Length, Domain, List) :-
    length(List, Length),
    maplist(member_(Domain), List).

Это дало бы:

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

Это также работает для любого вида элементов:

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

Если вы хотите использовать CLP(FD), вам нужно помнить пару вещей. CLP(FD) предназначен для целочисленных доменов, а CLP (FD) имеет свой собственный способ указания доменов, который отсутствует в форме списка.

Например, если вы хотели список длины N чьи элементы были в домене, описанном [1,2,3,5,6,8], вы бы написали это как:

length(List, N),
List ins 1..3 \/ 5..6 \/ 8,
label(List).

В результате чего, например:

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

Используя ECLiPSe Prolog, вы можете написать:

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

Запрос:

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

Вывод означает, что каждая переменная (в данном случае _530, _547 и так далее) в списке L имеет указанный домен {[2, 3, 5, 7, 8]}, Если вы хотите пометить список, вы можете просто добавить

labeling(ListOutput).

как последняя строка domainList/3 и вы получите:

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

и так далее... Если вы хотите, чтобы весь список был другим, просто добавьте

alldifferent(ListOutput),

до labeling/1и вы получите

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

Я обычно не использую пролог SWI для clpfd проблемы, так что я не знаю, есть ли подобное решение в SWI...

Другие вопросы по тегам