Prolog约束逻辑编程 - 如何在给定整数列表的情况下在域变量列表上设置域?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Prolog约束逻辑编程 - 如何在给定整数列表的情况下在域变量列表上设置域?相关的知识,希望对你有一定的参考价值。

基本上我想要实现的是:

给定域变量列表,将这些变量设置为相对于数字列表的域。例:

......

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

但没有成功......

任何人都可以帮助理解我如何实现这一目标?

答案

在您的解决方案中,您使用的是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中的每个变量(在本例中为_547L等)具有指定的域{[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 prolog来解决clpfd问题,所以我不知道SWI中是否有类似的解决方案......

以上是关于Prolog约束逻辑编程 - 如何在给定整数列表的情况下在域变量列表上设置域?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Prolog 优化约束逻辑编程中的寻路

Prolog:获取包含给定整数的子列表

列表替换中的 Prolog 元素

使用Prolog的CLPFD基于约束结果生成列表

Prolog 匹配 vs miniKanren 统一

Java的嵌入式Prolog解释器/编译器