Prolog:组合谓词失败

Prolog:组合谓词失败,prolog,predicate,clpfd,Prolog,Predicate,Clpfd,作为一个初学者,我试图解决一个矩阵问题,其中的解决方案是矩阵中不同数字的求和或乘法。例如,[[14,15,15,28,1,1]]。谓词应该根据矩阵生成解决方案。然而,我遇到了一个问题,我的组合谓词失败了,但它们都独立地成功了 我把问题分解为求和和乘法。因此,使用clpfd库和一些谓词求和: removeHead([Head|Tail],Tail). get_head_element([],_). get_head_element([Head|Rest],Head). solve_sum(Ro

作为一个初学者,我试图解决一个矩阵问题,其中的解决方案是矩阵中不同数字的求和或乘法。例如,
[[14,15,15,28,1,1]]
。谓词应该根据矩阵生成解决方案。然而,我遇到了一个问题,我的组合谓词失败了,但它们都独立地成功了

我把问题分解为求和和乘法。因此,使用clpfd库和一些谓词求和:

removeHead([Head|Tail],Tail).

get_head_element([],_).
get_head_element([Head|Rest],Head).

solve_sum(Row,RestRow):-
    get_head_element(Row, Goal),
    removeHead(Row,RestRow),
    RestRow ins 1..9,
    all_distinct(RestRow),
    sum(RestRow, #=, Goal).
对于乘法:

multiply(List,Result):-
    multiply(List,1,Result).

multiply([Element|RestList],PrevResult,Result):-
    NextResult #= PrevResult * Element,
    multiply(RestList,NextResult, Result).

multiply([], Result, Result).

solve_multiply(Row,RestRow):-
    get_head_element(Row, Goal),
    removeHead(Row,RestRow),
    RestRow ins 1..9,
    multiply(RestRow,Goal),
    all_distinct(RestRow).
solve\u sum
solve\u multiply
都适用于一行,但这里我将这两个谓词结合起来:

solve_row_sum_or_multiply([],_).

solve_row_sum_or_multiply([HeadRow|Matrix],Solution):-
maplist(all_distinct,Matrix),
get_head_element(HeadRow,Goal),
( Goal >= 25
-> solve_multiply(HeadRow,Solution),
   write(Solution)
; ( solve_sum(HeadRow,Solution),
    write(Solution)
    ; solve_multiply(HeadRow,Solution),
    write(Solution))
),solve_row_sum_or_multiply(Matrix,Solution).
当我使用
求解行和或乘法([[14,[u,[u,[u,[u,]15,[u,[u,[u,]28,[u,[u,[u,[u,]X)
,它会给出可能的组合。然而,当
求解行和或乘法([[14,7,2,1],[15,28,1,1],[X])
时,它给了我错误的答案,但是有一个可能的答案,比如
[[14,7,2,1],[15,3,7,5],[28,4,1,7]

我想知道可能出了什么问题。非常感谢您的帮助

编辑


问题出在组合谓词内部,最好编写答案建议的谓词,而不是嵌套的if-then-else谓词。

让我们回顾一下这段代码

介绍代码

:-使用_模块(库(clpfd))。
% ---
%请确保在打印的列表中看到所有信息
%toplevel,即告诉toplevel不要删除大列表(打印
%请完整填写,不要使用“…”)
% ---
我的照片:-
深度=100,
选项=[引用(真实)、描绘(真实)、最大深度(深度)、属性(描绘)],
设置prolog标志(应答、写入选项、选项),
设置prolog标志(调试器写入选项,选项)。
:-我的照片。
乘/2

重新编码
乘法/2
谓词,以便更容易读取。添加测试代码,以确保其实际执行我们认为的功能:

%---
%设置约束:列表中的所有元素,相乘
%共同努力,必须取得成果。如果列表为空,则
%结果必须是1。
% ---
乘(因子、乘积):-
乘以2(因子,1,乘积)。
乘| 2([因子|因子]、部分积、积):-
PartialProduct2#=PartialProduct*因子,
乘以2(因子,部分乘积2,乘积)。
乘2([],积,积)。
求|乘([积|因子]):-
因子1..9,
乘以(因子、乘积),
所有的(因素)都是不同的。
% ---
%测试
% ---
:-开始测试(乘法)。
测试(1):-
相乘([X,Y,Z],6),
[X,Y,Z]ins 1..9,
X#=
求和/1

总而言之,在简化并重新编码为Prolog的“模式匹配”风格,而不是(因为缺少更好的词)“Algol调用风格”之后,正如在原始问题中使用的那样(我不得不说这让我非常困惑)

这个看起来也不错。请注意,谓词
solve_sum/1
在参数样式上与
multiply/2
有很大不同,如果保持相同的调用约定,则会更好,对读者(和自己)也更容易

solve_sum([sum|Terms]):-
第1至9条中的术语,
所有不同的(术语),
总和(术语,#=,总和)。
% ---
%测试
% ---
:-开始测试(总和)。
测试(0):-
求和([0])。
测试(1):-
求和([6,X,Y,Z]),
X#=
打印谓词以获得良好的结果

Prolog使“动态”构造任意结构变得容易,只需精确规定结构的外观即可

我们的“解决方案”是:

  • 单子
  • 列表中的每个元素都有一个“行”(代表一个表达式)
  • 行a项:
    row(Result,Op,RowValues)
    其中
    Result
    是等式的左侧,
    Op
    add
    mult
    中的一个,而
    RowValues
    是等式中的值列表
print_解决方案([])。
打印溶液([标签]):-
格式(“--~n”),
打印溶液的行(标签),
格式(“--~n”),
打印溶液(标签)。
打印解决方案([])的行。
打印解决方案的行([行(结果、操作、行值)|行]:-
打印行(结果、行值、操作),
打印溶液的行数。
打印行(结果,[RowEntry | RowEntries],Op):-
格式(“~q=~q”,[Result,RowEntry]),
打印第2行(第2行,Op)。
打印第2行([RowEntry | RowEntries],Op):-
((Op==mult)->OpChar='*'
;(Op==add)->OpChar='+'
;OpChar='?'),
格式(“~q~q”,[OpChar,RowEntry]),
打印第2行(第2行,Op)。
打印第2行([],):-
格式