【问题标题】:Using Prolog & CLP(R) for a system of constraints将 Prolog 和 CLP(R) 用于约束系统
【发布时间】:2017-05-08 07:25:14
【问题描述】:

我希望使用 Prolog 生成满足约束系统的随机向量。

例如,我们的用户可能会在运行时向我们的软件提供以下信息:

给定一个向量<x1, x2, x3, ... x30>,我们可能有两个约束:

x1 > x2 + x3 + x4
x5 <= sin(x6 + x7)

我想做的是生成一个大致遵循以下形式的 Prolog 程序:

:- random(0.0, 1.0, X1)
:- random(0.0, 1.0, X2)
#...
# its also concievable that the bounds are different than 0 to 1
:- random(0.0, 1.0, X30)

clp(r) :- constraints { 
   X1 > X2 + X3 + X4,
   X5 <= sin(X6 + X7)   
}

?- [ X1, X2, X3, X4, ... X30 ]

这将在 30 维空间中均匀地输出一个随机向量。

这对 Prolog 可行吗?

还有消耗该输出的问题。我想做的是拨打next() 重新生成一个新向量。具体来说,我需要避免重新编译,因为我希望能够每秒生成大约 10,000 个这些向量。我能达到这种性能水平吗?

我希望在 JVM 上使用嵌入式(进程内)SWI-Prolog 实例,我们的其余软件都在该实例上运行。这样就够了吗?

【问题讨论】:

    标签: random prolog constraints clp clpr


    【解决方案1】:

    没关系!

    该方法原则上是可以的,个人认为 Prolog 是此类任务的不错选择。

    但是,您需要解决一些微妙的问题。

    首先,让我们正确理解 CLP(R) 的语法

    向量([X1,X2,X3,X4,X5,X6,X7]):- { X1 > X2 + X3 + X4, X5 =

    特别注意=&lt; 的使用以及{}/1 的正确使用来表示CLP(R) 约束。标记 &lt;= 在 Prolog 算术中被避开,因为它看起来像一个 箭头,在证明者中通常表示 蕴涵

    这足以获得第一个答案,即使它们尚未实例化为具体的解决方案

    ?- 向量(Ls)。 Ls = [_1028,_1034,_1040,_1046,_1052,_1058,_1064], {_1046=_1028-_1034-_1040-_1088, _1088>0.0}, {_1052-sin(_1058+_1064)=

    使用random/1 我们可以将随机浮点数从(0,1) 分配给任何变量。例如:

    ?- 向量([A,B,C,D,E,F,G]), 随机(A), 随机(B)。 A = 0.33797712696696053, B = 0.7039688010209147, {D= -0.3659916740539542-C-_894, _894>0.0}, {E-sin(F+G)=

    这解决了任务的一部分。但是,这种方法在以下情况下会失败:

    ?- 向量([A,B,C,D,E,F,G]), 随机(A), 随机(B), 随机(C), 随机(D)。 错误。

    这里,(确定性!)随机数生成冲突与约束。有几种方法可以解决这个问题。在我展示它们之前,让我们将变量约束到所需的间隔,例如使用以下定义:

    zero_to_one(X) :- { 0 =

    我们可以简单地将此约束声明为一个附加要求:

    ?- 向量([A,B,C,D,E,F,G]), maplist(zero_to_one, [A,B,C,D,E,F,G]), 随机(A), 随机(B), 随机(C)。

    这又产生了false

    方法1:更多相同

    解决上述问题的一种方法是简单地重复随机分配,直到在回溯中找到解决方案:

    ?- 向量([A,B,C,D,E,F,G]), maplist(zero_to_one, [A,B,C,D,E,F,G]), 随机(A), 随机(B), 重复, 随机(C)。 A = 0.9433451780634803, B = 0.15859272177823736, C = 0.706502025956454, {D>=0.0,_2064=0.07825043032878898-D,D=0.0, E==0.0, F==0.0, G=

    因此,我们离具体的解决方案又近了一步,我们的意思是向量的完整实例化。缺点非常明显:在极端情况下,我们将永远以这种方式找到有效的分配。如果运气稍好一点,可能需要 许多 次尝试才能为单个 附加 变量找到具体值。

    方法二:最大化或最小化

    解决此问题的另一种方法是使用 CLP(R) 的 maximize/1 和/或 minimize/1 来使用约束求解器本身来获得具体的解决方案。这仅适用于 线性 约束,甚至不适用于所有这些约束。例如,考虑以下查询:

    ?- { X = sin(Y) }, 地图列表(zero_to_one,[X,Y]), 最大化(X)。 错误。

    甚至:

    ?- { X 错误。

    虽然相反:

    ?- { X =X = 1.0 .

    现在,让我们使用以下技巧摆脱所有非线性约束:我们只需将随机浮点数分配给X6X7,例如:

    ?- 向量(Ls), Ls = [A,B,C,D,E,F,G], 地图列表(zero_to_one,Ls), 随机(F),随机(G)

    在此基础上,我们可以写:

    ?- 向量(Ls), Ls = [A,B,C,D,E,F,G], 地图列表(zero_to_one,Ls), 随机(F),随机(G), 最大化(A),最小化(B+C+D+E)。 Ls = [1.0, 0.0, 0.0, 0.0, 0.0, 0.9702069686491169, 0.13220925936558517], A = 1.0, B = C, C = D, D = E, E = 0.0, F = 0.9702069686491169, G = 0.13220925936558517。

    因此,我们得到了一个满足所有约束并具有一些随机分量的具体解决方案。

    结束语

    首先,重复一遍,我认为 Prolog 是此类任务的不错选择。约束求解器的修剪可以帮助消除大部分搜索空间,约束求解器本身可以帮助您通过最小化和最大化获得具体的解决方案。其次,还有几个问题需要牢记:

    • 首先,以这种方式(通过任何一种方法)生成的解决方案不是随机的,因为每个解决方案同样可能。相反,可能存在比其他解决方案更有可能出现的解决方案集群。
    • 如上所示,方程可能需要一些额外的推理和实验,以将它们简化为线性方程并应用适用的优化方向。 Prolog 非常适合这种推理,您可以使用它轻松尝试不同的策略。
    • 您可能必须在随机化和确定性优化之间找到一个有效的折衷方案,以实例化剩余的向量分量。权衡还可能取决于向量组件的纠缠。

    最后,一个非常重要的评论:隐式随机状态与我们期望的逻辑关系的属性背道而驰,因为它们会导致您的谓词在后续调用中表现得非常不同,从而进行调试和系统测试一个噩梦。因此,我强烈建议您为 随机种子 做准备,或通过代码携带随机数生成器的显式状态。这将帮助您更好地理解程序的行为并使其完全具有确定性。您可以稍后改变种子以生成不同的解决方案集合。

    【讨论】:

    • so minimizemaximize 即使在本身不需要最小化和最大化的情况下?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    相关资源
    最近更新 更多