【问题标题】:Restrict search in Prolog - Magic Sqare在 Prolog - Magic Square 中限制搜索
【发布时间】:2022-01-16 15:48:47
【问题描述】:

我想用 Prolog 程序解决最完美的魔方。

维基页面:https://en.wikipedia.org/wiki/Most-perfect_magic_square

当我输入查询“magic_square(4, [[7, 12, 1, 14], [2, 13, 8, 11], [16, 3, 10, 5], [9, 6, 15 , 4]])。” (这是一个有效的魔方)我的程序返回 true。所以我假设我的规则基础是正确的。

很遗憾,如果未知的值超过 9 个,则需要很长时间才能找到解决方案。

我需要帮助来限制我的搜索,以便程序在合理的时间内找到解决方案。理想情况下,它还应该适用于 12 x 12 网格(以及其他 4 的倍数)并且没有给出值:magic_square(12, Matrix)。

非常感谢!

这是我的代码:

:- use_module(library(clpfd)).

diag2_sum(0, _, _, _).
diag2_sum(I0, C1, Row1, Row3) :-
    I0 > 0,
    nth1(I0,Row1,A),
    (I0 =:= 2 -> I2 = 4 ; I2 is mod(I0 + 2,4)),
    nth1(I2,Row3,B),
    C1 =:= A + B,
    I1 is I0 - 1,
    diag2_sum(I1, C1, Row1, Row3).

diag_sum([_,_], _, _).
diag_sum([Row1|Tail], C1, N) :-
    nth1(2,Tail,Row3),
    diag2_sum(N, C1, Row1,Row3),
    diag_sum(Tail, C1, N).

square_sum_x(_, _, _, 0).
square_sum_x(Row1, Row2, C2, I0) :-
    (I0 =:= 3 -> I2 = 4 ; I2 is mod(I0 + 1,4)),
    nth1(I0,Row1,Elem1),
    nth1(I2,Row1,Elem2),
    nth1(I0,Row2,Elem3),
    nth1(I2,Row2,Elem4),
    C2 =:= Elem1 + Elem2 + Elem3 + Elem4,
    I1 is I0 - 1,
    square_sum_x(Row1, Row2, C2, I1).


square_sum_y(_, _, 0, _).
square_sum_y(Matrix, C2, I0, N) :-
    (I0 =:= 3 -> I2 = 4 ; I2 is mod(I0 + 1,4)),
    nth1(I0,Matrix,Row1),
    nth1(I2,Matrix,Row2),
    
    square_sum_x(Row1,Row2, C2, N),
    I1 is I0 - 1,
    square_sum_y(Matrix, C2, I1, N).

magic_square(N, Matrix) :-
    Nmax is N * N,
    C1 is Nmax + 1,
    C2 is C1 * 2,
    write(C1),nl,write(C2),nl,
    length(Matrix, N),
    maplist(same_length(Matrix), Matrix),
    append(Matrix, Vs),
    Vs ins 1..Nmax, all_different(Vs),
    maplist(label, Matrix),
    %write(Matrix),nl,
    diag_sum(Matrix, C1, N),
    square_sum_y(Matrix, C2, N, N).

% some queries i tryed out:
% magic_square(4, [[7, 12, 1, 14], [2, 13, 8, 11], [16, 3, 10, 5], [9, 6, 15, 4]]).    
% magic_square(4, [[7, 12, 1, 14], [2, 13, 8, B4], [C1, C2, C3, C4], [D1, D2, D3, D4]]).
% magic_square(4, [[7, A2, A3, 14], [2, B2, 8, B4], [C1, C2, 10, C4], [D1, D2, D3, 4]]).

【问题讨论】:

  • clpfd 可能会有所帮助 - 例如“magic_square.pl”hakank.org/swi_prolog
  • 我只是忘记粘贴了....我编辑了我的帖子。谢谢

标签: algorithm search prolog breadth-first-search perfect-square


【解决方案1】:

我确认有 10 个孔的查询似乎需要很长时间,即使有 9 个孔,它在 SWI-Prolog 中也不是很快:

?- time(magic_square(4, [[_, _, _, _], [_, _, 8, 11], [_, _, 10, 5], [_, 6, 15, 4]])).
17
34
% 88,086,790 inferences, 3.449 CPU in 3.449 seconds (100% CPU, 25543070 Lips)
true .

那么那个时间去哪儿了?让我们使用 SWI-Prolog 的分析器:

?- profile(magic_square(4, [[_, _, _, _], [_, _, 8, 11], [_, _, 10, 5], [_, 6, 15, 4]])).
17
34
true.

这将打开一个 GUI 窗口。如果我们点击谓词列表中的magic_square/2,我们会看到:

注意__aux_maplist/2_label+0/1 的行:94.7% 的执行时间都花在了那里!这是您的 maplist(label, Matrix) 行,您在到达有趣的部分之前就被卡住了,其中 diag_sumsquare_sum_y 谓词实际上定义了幻方是什么。

基本上,通过发布all_different(Vs) 并立即对其进行标记,您是在要求 Prolog 枚举可以填补输入项中的空白的不同数字的所有排列。此类排列的数量以及您的执行时间呈指数增长。

在知道所有约束之前,您不应该以这种方式使用标签。标记应该是您在谓词中做的最后一件事,或者更好的是,它应该由与您定义容器的谓词不同的谓词来完成。

所以你可以这样设置:

% "Core relation" defining the shape of the solution and constraints.
magic_square_(N, Matrix) :-
    Nmax is N * N,
    C1 is Nmax + 1,
    C2 is C1 * 2,
    write(C1),nl,write(C2),nl,
    length(Matrix, N),
    maplist(same_length(Matrix), Matrix),
    append(Matrix, Vs),
    Vs ins 1..Nmax, all_different(Vs),
    diag_sum(Matrix, C1, N),
    square_sum_y(Matrix, C2, N, N).

magic_square(N, Matrix) :-
    magic_square_(N, Matrix),
    maplist(label, Matrix).

现在 diag_sumsquare_sum_x 将分别使用未绑定(但受约束)变量 C1C2 调用。这可以!这就是您使用 CLP(FD) 时想要的!但是您需要将这些变量的数值相等目标从 =:=(需要基本值)更改为 #=(实际上适用于约束变量)。

现在您可以快速使用 9 个变量:

?- Matrix = [[_, _, _, _], [_, _, 8, 11], [_, _, 10, 5], [_, 6, 15, 4]], time(magic_square(4, Matrix)).
17
34
% 8,473 inferences, 0.006 CPU in 0.006 seconds (100% CPU, 1506518 Lips)
Matrix = [[7, 12, 1, 14], [2, 13, 8, 11], [16, 3, 10, 5], [9, 6, 15, 4]] ;
% 33 inferences, 0.000 CPU in 0.000 seconds (91% CPU, 749778 Lips)
false.

还有 10:

?- Matrix = [[_, _, _, _], [_, _, 8, 11], [_, _, 10, 5], [_, _, 15, 4]], time(magic_square(4, Matrix)).
17
34
% 8,933 inferences, 0.002 CPU in 0.002 seconds (100% CPU, 4338676 Lips)
Matrix = [[7, 12, 1, 14], [2, 13, 8, 11], [16, 3, 10, 5], [9, 6, 15, 4]] .

还有更多:

?- Matrix = [[_, _, _, _], [_, _, 8, _], [_, _, 10, _], [_, _, _, 4]], time(magic_square(4, Matrix)).
17
34
% 24,710 inferences, 0.009 CPU in 0.009 seconds (99% CPU, 2658996 Lips)
Matrix = [[7, 2, 11, 14], [12, 13, 8, 1], [6, 3, 10, 15], [9, 16, 5, 4]] .

【讨论】:

  • 非常感谢您的详细回答。我会在晚上看看这个。谢谢!
  • 您是否尝试过生成 8x8 幻方?因为我无法生成大于 4x4 的魔方。我根据您的回答中的建议更新了我的问题中的代码,并对其进行了一些更改,因此它应该适用于更高维度的幻方。但显然它不是出于某种原因。
  • 请不要更改您的问题以包含答案。您的问题文本不再有意义,因为您现在可以快速实施!我将撤消您的更改。如果您有新问题,请提交新问题
  • 我现在创建了一个新问题:stackoverflow.com/questions/70746559/…
猜你喜欢
  • 1970-01-01
  • 2016-02-11
  • 1970-01-01
  • 2018-08-03
  • 2012-07-27
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多