我是Prolog的新手,目前正致力于一个简单的约束编程问题。所以我有四个实数A,B,C,D具有这样的属性 A + B + C + d = A B C * D = 7.11 由于使用整数更容易,我尝试了以下实现:
:- use_module(library(clpfd)).
grocery(Vars):-
Vars=[A,B,C,D],
X #= 100 * A,
Y #= 100 * B,
Z #= 100 * C,
W #= 100 * D,
X+Y+Z+W #= 711,
X*Y*Z*W #= 71100000000.
由于以上将给出部分解决的答案,我尝试将关键字label(Vars)
放在最后。但这导致我执行grocery(V)
生成
ERROR: Arguments are not sufficiently instantiated.
虽然grocery([V])
会给我一个false
。任何人都可以启发我如何做标签?感谢
编辑:我之前没有把调用放到库clpfd
答案 0 :(得分:3)
您正面临两个问题,我想分别讨论 :
如你所说,我们得到:
?- grocery(Vs), label(Vs). ERROR: Arguments are not sufficiently instantiated
标记要求所有要标记的变量都具有有限域。在您的情况下,label/1
会引发instantiation-error,因为某些变量的域仍为无限:
?- grocery([A,B,C,D]). A in inf.. -1\/1..sup, 100*A#=_9006, _9006 in inf.. -100\/100..sup, _9006+_9084+_9078+_9072#=711, _9006*_9084#=_9102, _9084 in inf.. -100\/100..sup, 100*B#=_9084, _9102 in inf.. -1\/1..sup, _9102*_9078#=_9222, _9078 in inf.. -100\/100..sup, 100*C#=_9078, C in inf.. -1\/1..sup, _9222 in -71100000000.. -1\/1..71100000000, _9222*_9072#=71100000000, _9072 in -71100000000.. -100\/100..71100000000, 100*D#=_9072, D in -711000000.. -1\/1..711000000, B in inf.. -1\/1..sup.
唯一的机会就是创建一个合适的专业化程序,其中变量以有限域结束。写[Vs]
代替Vs
显然不是解决方案:
?- grocery(Vs), label([Vs]). ERROR: Type error: `integer' expected, found `[_8206,_9038,_8670,_8930]' (a list)
这是因为label/1
要求其参数为有限域变量列表,不 列表列表。
合适的专业化的一个例子可能是:
?- grocery(Vs), Vs ins 0..sup, label(Vs). false.
生成的程序无解决方案,但至少我们知道肯定没有解决方案,因为没有更多的实例化错误。
我们因此得出了第二个,而不是独立的问题:为什么这个结果程序没有解决方案?
使用像Prolog这样的逻辑编程语言的一个主要优点是它可以应用声明性调试方法,例如 GUPU 中所示。
与GUPU一样,使用以下定义概括目标:
:- op(920,fy, *). *_.
例如,我们可以概括您计划的最后一个目标:
grocery(Vars):- Vars = [A,B,C,D], X #= 100 * A, Y #= 100 * B, Z #= 100 * C, W #= 100 * D, X+Y+Z+W #= 711, *X*Y*Z*W #= 71100000000.
结果程序显然比原始程序更通用,因为我们从纯和单调中删除了约束 Prolog程序。
现在,我们仍然可以获得前面的查询:
?- grocery(Vs), Vs ins 0..sup, label(Vs). false.
现在我们知道了:即使是更通用的程序也没有解决方案。
如果您希望在这种情况下解决方案,则必须更改剩余程序的部分以更正公式中的错误。
有关此方法的详细信息,请参阅program-slicing和logical-purity。