Prolog:组合谓词失败
Prolog: combined predicate failed
作为初学者,我正在尝试解决矩阵问题,其中解决方案是矩阵中不同数字的求和或乘法。例如,[[14,_,_,_],[15,_,_,_],[28,_,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_sum
和 solve_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).
当我使用solve_row_sum_or_multiply([[14,_,_,_],[15,_,_,_],[28,_,_,_]],X)
时,它会给我可能的组合。然而,当 solve_row_sum_or_multiply([[14,_,_,_],[15,_,_,_],[28,_,1,_]],X)
时,它给了我错误,但那里有一个可能的解决方案,例如 [[14,7,2,1],[15,3,7,5],[28,4,1,7]]
.
我想知道哪里出了问题。非常感谢任何帮助!
编辑
问题在组合谓词内部,最好编写答案建议的谓词而不是嵌套的 if-then-else 谓词。
让我们回顾一下这段代码。
介绍码
:- use_module(library(clpfd)).
% ---
% Make sure you see all the information in a list printed at the
% toplevel, i.e. tell the toplevel to not elide large lists (print
% them in full, don't use '...')
% ---
my_print :-
Depth=100,
Options=[quoted(true), portray(true), max_depth(Depth), attributes(portray)],
set_prolog_flag(answer_write_options,Options),
set_prolog_flag(debugger_write_options,Options).
:- my_print.
multiply/2
重新编码 multiply/2
谓词,以便更容易阅读。添加测试代码以确保它确实按照我们的想法执行:
% ---
% Set up constraint: all the elements in List, multiplied
% together, must yield Result. If the List is empty, the
% Result must be 1.
% ---
multiply(Factors,Product):-
multiply_2(Factors,1,Product).
multiply_2([Factor|Factors],PartialProduct,Product):-
PartialProduct2 #= PartialProduct * Factor,
multiply_2(Factors,PartialProduct2,Product).
multiply_2([],Product,Product).
solve_multiply([Product|Factors]):-
Factors ins 1..9,
multiply(Factors,Product),
all_distinct(Factors).
% ---
% Testing
% ---
:- begin_tests(multiply).
test(1) :-
multiply([X,Y,Z],6),
[X,Y,Z] ins 1..9,
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1, 1, 6], [1, 2, 3]]).
test(2) :-
multiply([],Result),
assertion(Result == 1).
test(3) :-
multiply([X,Y],3),
[X,Y] ins 1..9,
X #=< Y,
bagof([X,Y],label([X,Y]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,3]]).
test(4) :-
solve_multiply([6,X,Y,Z]),
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]).
test(5) :-
solve_multiply([362880,F1,F2,F3,F4,F5,F6,F7,F8,F9]),
F1 #=< F2,
F2 #=< F3,
F3 #=< F4,
F4 #=< F5,
F5 #=< F6,
F6 #=< F7,
F7 #=< F8,
F8 #=< F9,
bagof([F1,F2,F3,F4,F5,F6,F7,F8,F9],label([F1,F2,F3,F4,F5,F6,F7,F8,F9]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,3,4,5,6,7,8,9]]).
test(6,fail) :-
solve_multiply([-1,X,Y,Z]).
:- end_tests(multiply).
solve_sum/1
总而言之,在简化和重新编码为 Prolog 的“模式匹配”风格而不是(因为想要一个更好的词)原始问题中使用的“Algol 调用风格”之后(这让我很困惑我不得不说)。
这看起来也不错。请注意,谓词 solve_sum/1
与 multiply/2
的论证风格完全不同 如果保持相同的调用约定,reader(和自己)会更好 - 也更容易。
solve_sum([Sum|Terms]):-
Terms ins 1..9,
all_distinct(Terms),
sum(Terms, #=, Sum).
% ---
% Testing
% ---
:- begin_tests(sum).
test(0) :-
solve_sum([0]).
test(1) :-
solve_sum([6,X,Y,Z]),
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1, 2, 3]]).
test(2) :-
solve_sum([9,X,Y,Z]),
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,6],[1,3,5],[2,3,4]]).
test(3,fail) :-
solve_sum([1,_X,_Y,_Z]).
:- end_tests(sum).
获得好的结果的打印谓词
Prolog 可以轻松地“即时”构建任意结构,只需准确规定结构的外观即可。
我们的“解决方案”是:
- 一个列表
- 列表中的每个元素都有一个“行”(代表其中一个表达式)
- 行中有一项:
row(Result,Op,RowValues)
其中 Result
是等式的左边,Op
是 add
或 [=24 之一=] 和 RowValues
是一个列表,其中包含为方程中的值找到的值。
print_solution([]).
print_solution([Labeling|Labelings]) :-
format("---~n"),
print_rows_of_solution(Labeling),
format("---~n"),
print_solution(Labelings).
print_rows_of_solution([]).
print_rows_of_solution([row(Result,Op,RowValues)|Rows]) :-
print_row(Result,RowValues,Op),
print_rows_of_solution(Rows).
print_row(Result,[RowEntry|RowEntries],Op) :-
format("~q = ~q",[Result,RowEntry]),
print_row_2(RowEntries,Op).
print_row_2([RowEntry|RowEntries],Op) :-
((Op == mult) -> OpChar = '*'
; (Op == add) -> OpChar = '+'
; OpChar = '?'),
format(" ~q ~q",[OpChar,RowEntry]),
print_row_2(RowEntries,Op).
print_row_2([],_) :-
format("~n").
solve_row_sum_or_multiply/2
这已被修改为还收集在第二个参数(列表)中选择的操作。
请注意,“矩阵上的 maplist-all-distinct”没有在这里完成,因为这似乎是错误的。
solve_row_sum_or_multiply([],[]).
solve_row_sum_or_multiply([Row|MoreRows],[mult|Ops]) :-
Row = [X|_Xs],
X >= 25,
solve_multiply(Row), % we now have imposed a product constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
solve_row_sum_or_multiply([Row|MoreRows],[add|Ops]) :-
Row = [X|_Xs],
X < 25,
solve_sum(Row), % we now have imposed a sum constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
solve_row_sum_or_multiply([Row|MoreRows],[mult|Ops]) :-
Row = [X|_Xs],
X < 25,
solve_multiply(Row), % alternatively, we now have imposed a product constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
最后是“主要”谓词
在trial_run/1
中我们规定除了X32
之外的所有变量都是不同的并且X32
是1。如果X32
在“不同的集合”中,none 的变量可以取值 1 - 在这种情况下没有解决方案。
我们还进行了排序以仅获得一组“规范”解决方案:
我们使用bagof/3
:
收集了所有可能的解决方案和标签
trial_run(Solutions) :-
all_distinct([X11,X12,X13,X21,X22,X23,X31,X33]),
X32=1,
X11 #=< X12, X12 #=< X13,
X21 #=< X22, X22 #=< X23,
X31 #=< X33,
% multiple solutions solving x labeling may exist; collect them all
bagof(
[
row(14,Op1,[X11,X12,X13]),
row(15,Op2,[X21,X22,X23]),
row(28,Op3,[X31,X32,X33])
],
(
solve_row_sum_or_multiply( [[14,X11,X12,X13],[15,X21,X22,X23],[28,X31,X32,X33]], [Op1,Op2,Op3] ),
label([X11,X12,X13,X21,X22,X23,X31,X32,X33])
),
Solutions).
有用吗?
显然是的,只有一种解决方案:
?- trial_run(Solutions),print_solution(Solutions).
---
14 = 2 + 3 + 9
15 = 1 + 6 + 8
28 = 4 * 1 * 7
---
Solutions = [[row(14,add,[2,3,9]),row(15,add,[1,6,8]),row(28,mult,[4,1,7])]].
作为初学者,我正在尝试解决矩阵问题,其中解决方案是矩阵中不同数字的求和或乘法。例如,[[14,_,_,_],[15,_,_,_],[28,_,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_sum
和 solve_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).
当我使用solve_row_sum_or_multiply([[14,_,_,_],[15,_,_,_],[28,_,_,_]],X)
时,它会给我可能的组合。然而,当 solve_row_sum_or_multiply([[14,_,_,_],[15,_,_,_],[28,_,1,_]],X)
时,它给了我错误,但那里有一个可能的解决方案,例如 [[14,7,2,1],[15,3,7,5],[28,4,1,7]]
.
我想知道哪里出了问题。非常感谢任何帮助!
编辑
问题在组合谓词内部,最好编写答案建议的谓词而不是嵌套的 if-then-else 谓词。
让我们回顾一下这段代码。
介绍码
:- use_module(library(clpfd)).
% ---
% Make sure you see all the information in a list printed at the
% toplevel, i.e. tell the toplevel to not elide large lists (print
% them in full, don't use '...')
% ---
my_print :-
Depth=100,
Options=[quoted(true), portray(true), max_depth(Depth), attributes(portray)],
set_prolog_flag(answer_write_options,Options),
set_prolog_flag(debugger_write_options,Options).
:- my_print.
multiply/2
重新编码 multiply/2
谓词,以便更容易阅读。添加测试代码以确保它确实按照我们的想法执行:
% ---
% Set up constraint: all the elements in List, multiplied
% together, must yield Result. If the List is empty, the
% Result must be 1.
% ---
multiply(Factors,Product):-
multiply_2(Factors,1,Product).
multiply_2([Factor|Factors],PartialProduct,Product):-
PartialProduct2 #= PartialProduct * Factor,
multiply_2(Factors,PartialProduct2,Product).
multiply_2([],Product,Product).
solve_multiply([Product|Factors]):-
Factors ins 1..9,
multiply(Factors,Product),
all_distinct(Factors).
% ---
% Testing
% ---
:- begin_tests(multiply).
test(1) :-
multiply([X,Y,Z],6),
[X,Y,Z] ins 1..9,
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1, 1, 6], [1, 2, 3]]).
test(2) :-
multiply([],Result),
assertion(Result == 1).
test(3) :-
multiply([X,Y],3),
[X,Y] ins 1..9,
X #=< Y,
bagof([X,Y],label([X,Y]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,3]]).
test(4) :-
solve_multiply([6,X,Y,Z]),
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]).
test(5) :-
solve_multiply([362880,F1,F2,F3,F4,F5,F6,F7,F8,F9]),
F1 #=< F2,
F2 #=< F3,
F3 #=< F4,
F4 #=< F5,
F5 #=< F6,
F6 #=< F7,
F7 #=< F8,
F8 #=< F9,
bagof([F1,F2,F3,F4,F5,F6,F7,F8,F9],label([F1,F2,F3,F4,F5,F6,F7,F8,F9]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,3,4,5,6,7,8,9]]).
test(6,fail) :-
solve_multiply([-1,X,Y,Z]).
:- end_tests(multiply).
solve_sum/1
总而言之,在简化和重新编码为 Prolog 的“模式匹配”风格而不是(因为想要一个更好的词)原始问题中使用的“Algol 调用风格”之后(这让我很困惑我不得不说)。
这看起来也不错。请注意,谓词 solve_sum/1
与 multiply/2
的论证风格完全不同 如果保持相同的调用约定,reader(和自己)会更好 - 也更容易。
solve_sum([Sum|Terms]):-
Terms ins 1..9,
all_distinct(Terms),
sum(Terms, #=, Sum).
% ---
% Testing
% ---
:- begin_tests(sum).
test(0) :-
solve_sum([0]).
test(1) :-
solve_sum([6,X,Y,Z]),
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1, 2, 3]]).
test(2) :-
solve_sum([9,X,Y,Z]),
X #=< Y, Y #=< Z,
bagof([X,Y,Z],label([X,Y,Z]),Bag),
sort(Bag,BagS),
assertion(BagS == [[1,2,6],[1,3,5],[2,3,4]]).
test(3,fail) :-
solve_sum([1,_X,_Y,_Z]).
:- end_tests(sum).
获得好的结果的打印谓词
Prolog 可以轻松地“即时”构建任意结构,只需准确规定结构的外观即可。
我们的“解决方案”是:
- 一个列表
- 列表中的每个元素都有一个“行”(代表其中一个表达式)
- 行中有一项:
row(Result,Op,RowValues)
其中Result
是等式的左边,Op
是add
或 [=24 之一=] 和RowValues
是一个列表,其中包含为方程中的值找到的值。
print_solution([]).
print_solution([Labeling|Labelings]) :-
format("---~n"),
print_rows_of_solution(Labeling),
format("---~n"),
print_solution(Labelings).
print_rows_of_solution([]).
print_rows_of_solution([row(Result,Op,RowValues)|Rows]) :-
print_row(Result,RowValues,Op),
print_rows_of_solution(Rows).
print_row(Result,[RowEntry|RowEntries],Op) :-
format("~q = ~q",[Result,RowEntry]),
print_row_2(RowEntries,Op).
print_row_2([RowEntry|RowEntries],Op) :-
((Op == mult) -> OpChar = '*'
; (Op == add) -> OpChar = '+'
; OpChar = '?'),
format(" ~q ~q",[OpChar,RowEntry]),
print_row_2(RowEntries,Op).
print_row_2([],_) :-
format("~n").
solve_row_sum_or_multiply/2
这已被修改为还收集在第二个参数(列表)中选择的操作。
请注意,“矩阵上的 maplist-all-distinct”没有在这里完成,因为这似乎是错误的。
solve_row_sum_or_multiply([],[]).
solve_row_sum_or_multiply([Row|MoreRows],[mult|Ops]) :-
Row = [X|_Xs],
X >= 25,
solve_multiply(Row), % we now have imposed a product constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
solve_row_sum_or_multiply([Row|MoreRows],[add|Ops]) :-
Row = [X|_Xs],
X < 25,
solve_sum(Row), % we now have imposed a sum constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
solve_row_sum_or_multiply([Row|MoreRows],[mult|Ops]) :-
Row = [X|_Xs],
X < 25,
solve_multiply(Row), % alternatively, we now have imposed a product constraint on the current Row
solve_row_sum_or_multiply(MoreRows,Ops).
最后是“主要”谓词
在trial_run/1
中我们规定除了X32
之外的所有变量都是不同的并且X32
是1。如果X32
在“不同的集合”中,none 的变量可以取值 1 - 在这种情况下没有解决方案。
我们还进行了排序以仅获得一组“规范”解决方案:
我们使用bagof/3
:
trial_run(Solutions) :-
all_distinct([X11,X12,X13,X21,X22,X23,X31,X33]),
X32=1,
X11 #=< X12, X12 #=< X13,
X21 #=< X22, X22 #=< X23,
X31 #=< X33,
% multiple solutions solving x labeling may exist; collect them all
bagof(
[
row(14,Op1,[X11,X12,X13]),
row(15,Op2,[X21,X22,X23]),
row(28,Op3,[X31,X32,X33])
],
(
solve_row_sum_or_multiply( [[14,X11,X12,X13],[15,X21,X22,X23],[28,X31,X32,X33]], [Op1,Op2,Op3] ),
label([X11,X12,X13,X21,X22,X23,X31,X32,X33])
),
Solutions).
有用吗?
显然是的,只有一种解决方案:
?- trial_run(Solutions),print_solution(Solutions).
---
14 = 2 + 3 + 9
15 = 1 + 6 + 8
28 = 4 * 1 * 7
---
Solutions = [[row(14,add,[2,3,9]),row(15,add,[1,6,8]),row(28,mult,[4,1,7])]].