计数 Dijkstra 守卫如何在 Prolog 中对执行进行排序

Posted

技术标签:

【中文标题】计数 Dijkstra 守卫如何在 Prolog 中对执行进行排序【英文标题】:How count Dijkstra guards sort executions in Prolog 【发布时间】:2021-02-11 19:30:41 【问题描述】:

我没有在 Dijsktras “if fi”中找到 Prolog 剪辑,因为他 says “否则将选择具有真正保护的任意保护列表来执行。”。因此,他的构造不会像 Prolog 剪辑那样选择第一个匹配项:

if Cond1 -> Action11, .., Action1n1
[] Cond2 -> Action21, .., Action2n2
...
[] Condm -> Actionm1, .., Actionmn2
if

“do od”结构中是否可能有一个 Prolog 剪辑,只要保护列表的至少一个条件为真,它就会循环?或者也许在 Prolog 中实现它的其他方法,我假设循环可以转换为递归调用。那么我们如何在 Prolog 中对 q1,q2,q3,q4 进行排序:

do q1 > q2 -> q1,q2 := q2,q1
[] q2 > q3 -> q2,q3 := q3,q2
[] q3 > q4 -> q3,q4 := q4,q3
od

对于输入7,11,5,3,Prolog 程序将有多少个非确定性执行路径(即 Prolog 解决方案)都提供相同的答案?

【问题讨论】:

"一个带有true 保护的任意保护列表将被选择执行"并且所有其他的都被丢弃,即被选中的被提交到,我一直想。如果我必须实现它,我会生成所有分支的警卫,在一些超时间隔检查它们,一旦一个或多个成功,我会随机选择其中一个,杀死所有其余的,然后继续优胜者。即承诺。无论如何,这是我的理解。 (或者超时也应该是随机的?) 这似乎是一个“概率”执行模型,这不是标准 Prolog 提供的,即使有延迟(延迟的谓词一旦满足“冻结”条件就开始执行)。我似乎记得 Parlog 或者 Concurrent Prolog 可以并行计算守卫 - 但是启动和协调即使是低开销线程的开销也使得这不切实际。 【参考方案1】:

我认为你可以这样做:

do([Q1,Q2,Q3,Q4], [swap(Q1,Q2)|P], S) :-
    Q1 > Q2,
    do([Q2,Q1,Q3,Q4], P, S).

do([Q1,Q2,Q3,Q4], [swap(Q2,Q3)|P], S) :-
    Q2 > Q3,
    do([Q1,Q3,Q2,Q4], P, S).

do([Q1,Q2,Q3,Q4], [swap(Q3,Q4)|P], S) :-
    Q3 > Q4,
    do([Q1,Q2,Q4,Q3], P, S).

do([Q1,Q2,Q3,Q4], [], [Q1,Q2,Q3,Q4]) :- % termination state
    Q1 =< Q2,
    Q2 =< Q3,
    Q3 =< Q4.

执行:

?- do([7,11,5,3],P,S).
P = [swap(11, 5), swap(7, 5), swap(11, 3), swap(7, 3), swap(5, 3)],
S = [3, 5, 7, 11] ;
P = [swap(11, 5), swap(11, 3), swap(7, 5), swap(7, 3), swap(5, 3)],
S = [3, 5, 7, 11] ;
P = [swap(11, 5), swap(11, 3), swap(5, 3), swap(7, 3), swap(7, 5)],
S = [3, 5, 7, 11] ;
P = [swap(5, 3), swap(11, 3), swap(7, 3), swap(11, 5), swap(7, 5)],
S = [3, 5, 7, 11] ;
P = [swap(5, 3), swap(11, 3), swap(11, 5), swap(7, 3), swap(7, 5)],
S = [3, 5, 7, 11] ;
false.

【讨论】:

不错,一些不确定的执行跟踪!【参考方案2】:

如果我们假设没有保护计算可以发散,我认为以下表示与问题中的排序示例相同的计算:

dgsort([A,B,C,D],R):-
  ( A > B -> X1 = [1]    ; X1 = [] ),
  ( B > C -> X2 = [2|X1] ; X2 = X1 ),
  ( C > D -> X3 = [3|X2] ; X3 = X2 ),
  (   X3 = [] -> R = [A,B,C,D]
  ;   random_member( X, X3),
      (  X =:= 1 -> dgsort([B,A,C,D],R)
      ;  X =:= 2 -> dgsort([A,C,B,D],R)
      ;  X =:= 3 -> dgsort([A,B,D,C],R) )).

cmets: "一个带有true 保护的任意 保护列表将被选择 执行" 并且所有其他的被丢弃,即被选择的一个 致力于,我一直认为。因此,如果我必须实现它,我会生成所有分支的警卫,在一些超时间隔检查它们,一旦一个或多个成功,我就会随机选择其中一个,杀死所有其余的,然后继续赢家。即承诺。无论如何,这是我的理解。 (或者超时也应该是随机的?)

我还认为 do-od 构造通过相同的机制选择了真正的守卫。即“至少一个”,我们不在乎哪个。如果我们假设所有守卫计算都终止,我们可以执行所有这些,随机选择获胜者,然后继续执行它的操作。上面的代码就是这样做的。


要找出执行路径的数量,我们需要将 random_member 更改为 member,通过 findall 运行谓词并测量结果列表的长度:

dgsortn([A,B,C,D],R):-
  ( A > B -> X1 = [1]    ; X1 = [] ),
  ( B > C -> X2 = [2|X1] ; X2 = X1 ),
  ( C > D -> X3 = [3|X2] ; X3 = X2 ),
  (   X3 = [] -> R = [A,B,C,D]
  ;   member( X, X3),
      (  X =:= 1 -> dgsortn([B,A,C,D],R)
      ;  X =:= 2 -> dgsortn([A,C,B,D],R)
      ;  X =:= 3 -> dgsortn([A,B,D,C],R) )).

运行成功5次:

9 ?- dgsortn( [7,11,5,3], R).
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11].

我们还可以添加一个计数器来查看生成每个解决方案所采取的步骤数。

【讨论】:

( X =:= 1 -> sort([B,A,C,D],R) ?? 为什么不使用 dgsort?输入有多少种不同的执行路径 [7, 11,5,3]. 我认为 pick_randomly 将是 SWI-Prolog 中的 random_member/2,这是确定性的。而如果random_member/2被non-deterministic member/2替换,可以统计所有可能的执行路径吗? 是的,这是在最后一次编辑中。感谢 random_member 参考,也会编辑它。 有趣,使用 member/2 时没有最后选择点!不像我的解决方案。列表构建做了一种选择点前瞻。 我只是做了最简单的事情。 :)【参考方案3】:

我直接解决了计数问题并提出了这个解决方案。它的缺点是否定失败会重新评估条件。

sortloop([Q1,Q2,Q3,Q4], R) :- Q1 > Q2, sortloop([Q2,Q1,Q3,Q4], R).
sortloop([Q1,Q2,Q3,Q4], R) :- Q2 > Q3, sortloop([Q1,Q3,Q2,Q4], R).
sortloop([Q1,Q2,Q3,Q4], R) :- Q3 > Q4, sortloop([Q1,Q2,Q4,Q3], R).
sortloop([Q1,Q2,Q3,Q4], [Q1,Q2,Q3,Q4]) :- \+ Q1 > Q2, \+ Q2 > Q3, \+ Q3 > Q4.

但它显示有 5 个执行路径:

?- sortloop([7,11,5,3], R).
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
false.

但是我们可以改进条件只评估一次吗?我想到的是软剪辑(*-&gt;)/2,因为动作列表不会中止:

sortloop2([Q1,Q2,Q3,Q4], R) :-
  ((Q1 > Q2, sortloop2([Q2,Q1,Q3,Q4], R);
    Q2 > Q3, sortloop2([Q1,Q3,Q2,Q4], R);
    Q3 > Q4, sortloop2([Q1,Q2,Q4,Q3], R)) *-> true; R=[Q1,Q2,Q3,Q4]).

软切割解决方案给出了相同的结果:

?- sortloop2([7,11,5,3], R).
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
false.

但是没有一个解决方案使用 Prolog 剪辑来替换 Dijkstra 守卫中条件和动作列表之间的箭头。情况有点复杂。

编辑 12.02.2021: 如果有人好奇这 5 条路径作为 DAG 的样子:

【讨论】:

以上是关于计数 Dijkstra 守卫如何在 Prolog 中对执行进行排序的主要内容,如果未能解决你的问题,请参考以下文章

最短路 P1144 最短路计数Dijkstra堆优化/SPFA

最短路 P1144 最短路计数Dijkstra堆优化/SPFA

P1144 最短路计数 题解 最短路应用题

如何在Java中使用Prolog?

如何在PHP中使用Prolog?

如何在 SWI-Prolog 上设置闹钟?