限制 Prolog 中的搜索 - Magic Square

2023-12-21

我想用 Prolog 程序求解最完美幻方。

维基页面:https://en.wikipedia.org/wiki/Most-perfect_magic_square 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]]).

我确认,有 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_sum and square_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).

Now diag_sum and square_sum_x将使用未绑定(但受约束)的变量进行调用C1 and C2, 分别。这可以!这就是您使用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]] .
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

限制 Prolog 中的搜索 - Magic Square 的相关文章

  • 如何以最小化每个分区总和的最大值的方式对整数数组进行分区?

    输入是正整数或空整数的数组 A 和另一个整数 K 我们应该将 A 划分为 K 个连续元素块 我所说的 划分 是指 A 的每个元素都属于某个块 并且 2 个不同的块不包含任何共同元素 我们将块的总和定义为该块的元素的总和 目标是在 K 个块中
  • Haar级联正例图像大小调整

    我正在迈出第一步 为自定义对象识别创建 haar 级联 我花了时间获取大量数据并编写了一些预处理脚本以将视频转换为帧 我的下一步是裁剪感兴趣的对象 以创建一些积极的训练示例 我有几个问题 我确实在网上寻找答案 我有点困惑 我读到我应该致力于
  • 找到一个恰好出现了 N/2 次的数字

    这是我的面试问题之一 给定一个包含 N 个元素的数组以及元素出现的位置正好 N 2次 其余 N 2 个元素是unique 您如何找到运行时间更好的元素 请记住 元素未排序 您可以假设 N 是偶数 例如 input array 10 2 3
  • 在 O(n) 时间内对列表中的数字方块进行排序?

    给定一个按排序顺序排列的整数列表 例如 9 2 0 2 3 我们必须对每个元素进行平方并按排序顺序返回结果 所以 输出将是 0 4 4 9 81 我可以找出两种方法 O NlogN 方法 我们将每个元素的平方插入哈希集中 然后将元素复制到列
  • 如何让 Prolog 解释你的结果超出真实的陈述

    我有以下事实和规则 flight sea msp flight msp jfk route A B flight A B route B A flight A B route A C flight A B flight B C 当查询rou
  • 具有最小刻度的图表的漂亮标签算法

    我需要手动计算图表的刻度标签和刻度范围 我知道漂亮刻度的 标准 算法 参见 我也知道这个Java实现 http erison blogspot nl 2011 07 algorithm for optimal scaling on char
  • 沿着长数据序列在固定大小的移动窗口中查找中值

    给定一个数据序列 可能有重复项 一个固定大小的移动 窗口 从数据开始处每次迭代时移动窗口 序列 使得 1 从窗口中删除最旧的数据元素并添加新数据 元素被推入窗口 2 求每次移动时窗口内数据的中位数 以下帖子没有帮助 有效地找到随机序列的中值
  • 从数字列表中生成所有唯一对,n 选择 2

    我有一个元素列表 假设是整数 我需要进行所有可能的两对比较 我的方法是 O n 2 我想知道是否有更快的方法 这是我在java中的实现 public class Pair public int x y public Pair int x i
  • 地形/山地算法未按预期工作

    我想使用一个非常基本的原理创建一个上面有山的地形 如以下高度图所示 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0
  • 将 X 插入到排序列表中的正确位置

    在序言中 如何将 X 插入到排序列表中的正确位置 我的尝试 insert X Y Rest X Y Rest X lt Y insert X Rest BiggerRest 您的方向是正确的 但您需要解决这三个问题 insert X X i
  • 如何发现“贪婪”算法?

    我正在读一本关于 贪婪 算法 但我很难发现它们解决真正的 顶级程序员 问题 If I know给定的问题可以用 贪婪 算法来解决 因此编写解决方案非常容易 然而 如果我没有被告知这个问题是 贪婪的 我就无法发现它 用 贪婪 算法解决的问题有
  • Java中获取集合的幂集

    的幂集为 1 2 3 is 2 3 2 3 1 2 1 3 1 2 3 1 假设我有一个Set在爪哇中 Set
  • 将两个大数作为字符串相除,而不使用java中的Bignumbers

    我需要在不使用 Biginteger 的情况下划分两个大整数 因为数字不能存储在原始类型中 因为我需要从给定的字符串中逐个字符地执行此操作 我已经创建了一个名为 BigNumber 的类 用这个类我可以 Add multiply 比较两个内
  • 在内存有限的二叉树中查找第一个 null

    我有一个二叉树 其中每个节点都可以有一个值 我想找到树中值为空并且最接近根的节点 如果有两个节点到根的距离相同 则任意一个都可以 我需要最小化对二叉树的读取访问次数 假设工作内存仅限于 k 个节点 深度 k 的 DFS 是详尽的 但除非我首
  • 根据对象变量搜索对象列表

    我有一个对象列表 这些对象具有三个变量 ID 名称和值 这个列表中可能有很多对象 我需要根据ID或Name找到一个对象 并更改值 例子 class objec public string Name public int UID public
  • 对产品列表进行分类的算法? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个代表或多或少相同的产品的列表 例如 在下面的列表中 它们都是希捷硬盘 希捷硬盘 500Go 适用于笔记本电脑的希捷硬盘 120
  • 归并排序究竟进行了多少次比较?

    我读到 在实践中 快速排序比合并排序快得多 其原因是隐藏常量 那么 随机快速排序复杂度的解是2nlnn 1 39nlogn 这意味着快速排序中的常数是1 39 但是合并排序呢 归并排序中的常数是什么 让我们看看能否解决这个问题 在合并排序中
  • 使用按键重新排列字符串

    我想使用Pythonrandomly根据给定的键重新排列字符串的各个部分 我还想用相同的密钥恢复原始字符串 def rearrange key data pass def restore key rearranged data pass 效
  • 平均值大于或等于 k ​​的最长连续子数组

    考虑一个包含 N 个整数的数组 找到最长的连续子数组 使其元素的平均值大于 或等于 给定数字 k 显而易见的答案具有 O n 2 复杂度 我们可以做得更好吗 我们可以通过在 O n 时间内从所有值中减去 k 将这个问题简化为 sum gt
  • MySQL - 通过部分单词匹配和相关性评分进行高效搜索(全文)

    如何进行 MySQL 搜索 既匹配部分单词 又提供准确的相关性排序 SELECT name MATCH name AGAINST math IN BOOLEAN MODE AS relevance FROM subjects WHERE M

随机推荐