如何防止Prolog回溯到它不应该回溯的地方';T

如何防止Prolog回溯到它不应该回溯的地方';T,prolog,clpfd,Prolog,Clpfd,我正在尝试解决一个CSP问题,我需要向调酒师分发鸡尾酒,这样每个调酒师最多只能有一杯鸡尾酒,所有鸡尾酒都由调酒师提供。我通过创建一个clpfd变量列表来解决这个问题,首先给出所有调酒师的完整域,然后删除所有不知道如何制作鸡尾酒的调酒师。 我的代码可以工作,但有一个问题:太慢了。如果我查看分析器,remove_domain会被调用2000次(对于我给程序的输入),而它的Redo statistic大于100000。 我需要在其中一个函数(或两者)中更改什么,以便prolog不需要回溯 produc

我正在尝试解决一个CSP问题,我需要向调酒师分发鸡尾酒,这样每个调酒师最多只能有一杯鸡尾酒,所有鸡尾酒都由调酒师提供。我通过创建一个clpfd变量列表来解决这个问题,首先给出所有调酒师的完整域,然后删除所有不知道如何制作鸡尾酒的调酒师。
我的代码可以工作,但有一个问题:太慢了。如果我查看分析器,remove_domain会被调用2000次(对于我给程序的输入),而它的Redo statistic大于100000。 我需要在其中一个函数(或两者)中更改什么,以便prolog不需要回溯

produce_domains(_,_,[],[]) :- !.
produce_domains(Bartenders,NBartenders,[Cocktail|Cocktails],[Var|Vars]) :-
    Var in 1..NBartenders,
    remove_domain(Bartenders,NBartenders,Cocktail,Var),!,
    produce_domains(Bartenders,NBartenders,Cocktails,Vars),!.

remove_domain([],0,_,_) :- !.
remove_domain([Bartender|Bartenders],NBartenders,Cocktail,Var) :-
    (\+ member(Cocktail,Bartender) -> Var #\= NBartenders;!),!,
    NNBartenders is NBartenders - 1,
    remove_domain(Bartenders,NNBartenders,Cocktail,Var),!.

我已经读过了,但是我使用的是最新的Windows版本的SWI Prolog(5.10.5),所以这不应该是这里的问题。

您不需要那么多
/0
:Prolog通常可以判断谓词是确定性的

首先让我提供以下版本的代码。它使用的名称关系更密切,不包含
/0
,并使用高阶谓词缩短代码

:- use_module(library(clpfd)).

bartenders_cocktails_variables(Bs, Cs, Vs) :-
        length(Bs, LBs),
        maplist(bartenders_cocktail_variable(Bs, LBs), Cs, Vs).

bartenders_cocktail_variable(Bs, N, C, V) :-
        V in 1..N,
        foldl(compatible_bartender(C,V), Bs, 1, _).

compatible_bartender(C, V, Cs, N0, N1) :-
        (   member(C, Cs) -> true
        ;   V #\= N0
        ),
        N1 #= N0 + 1.
请注意,我是向上计数,而不是向下计数,以列举调酒师(这只是他们能够混合的鸡尾酒列表),因为这似乎更自然。我还可以通过简单地切换if-then-else的分支来省略
(\+)/1

示例查询,显示谓词在此用例中是确定性的:

?- bartenders_cocktails_variables([[a,b],[a,b],[x,y]], [x,a,b], Vars).
Vars = [3, _G1098, _G1101],
_G1098 in 1..2,
_G1101 in 1..2.
我们看到:鸡尾酒
x
必须由第三个调酒师等混合


我认为您的程序的这一部分可能不是您描述的缓慢性能的原因。也许你的程序的其他部分(无意中)是不确定的?可能尝试不同的标签策略或其他限制?如果您发布更多内容,我们可能会为您提供更多帮助。

Cuts与CLP(FD)不协调。尝试在没有成员、\+等的情况下重新表述您的问题。。。(也许所有的不同都有帮助)有一个小问题:swi prolog 5.10.5中不存在foldl。。。所以现在我注意到我对使用最新的Windows版本的评论是不正确的,但是我自己在那里放了一个foldl的实现。现在调酒师\u cocktails\u变量被调用的次数正好正确(每次订单调用一次),但它需要60%的计算时间。其他40%在clfpd中:全部不同。这60%中的39%是对clfpd的调用:\\=/2。关于比例:相容性调酒师在剖析器中有270万个调用和410万个重做。如果不是这样的话,考虑在兼容约束被声明之后(即,在<代码> ButtRelsSkCaldAsTysAsvs/3 )之后,张贴<代码> AlxDistabdie/1 ,从那时起,人们已经知道了更多的事情,
所有的/1
都需要做更少的工作。此外,您可以考虑建立一个域(如<代码> 1 \ 3 / 7…9代码/代码>),而不是为每个变量张贴一个<代码> /2 < /C>约束,而不是张贴一个<代码> /2 < /Cult>约束,然后考虑几个不一致性。你可以很容易地调整compatible_Bartener/5来为每一种鸡尾酒构建一个合适的域。事实上,整个程序中只有一个完全不同的域,所以这是正确的。我曾经尝试过建立域名,但这个例子不起作用:好吧,我之前的评论太快了:我确实建立了域名,而不是将其分解,现在程序稍微快了一点。但还是不够快,无法完成任务。