我想解决以下问题。
我有2个(或更多)矩阵; a和b。
每个矩阵都有列,行和值(利润)。
我想使用prolog从2个不同的矩阵中找到2列的组合,这将为我提供最多的正利润。
即。矩阵A中的ColumnX +矩阵B中的ColumnY,然后我计算结果列中具有正数的值的数量。 I.E.我添加了同一行的值。
我把下面的代码放到我迄今为止尝试的代码(以及它的链接),但是我的函数 count_profits(ColA,ColB,P)没有返回预期的结果。以下查询应返回 P = 2 ,但返回 P = 1 。
count_profits(66,65.5,P).
目前我正在为每个要使用的矩阵提供列索引。最终我想要一个名为 best_profit(ColA,ColB)的函数,它应该给我矩阵A中的列和矩阵B中的列,这样可以在组合时产生最多的正结果。根据我的测试数据,如果我是正确的话,这应该导致 ColA = 66 和 ColB = 65.5 。
% Data sets
% a(Column, Row, Profit)
% b(Column, Row, Profit)
a(65, 66, -0.82).
a(65, 65.5, -1.32).
a(65, 65, -1.82).
a(65.5, 66, -1.07).
a(65.5, 65.5, -1.57).
a(65.5, 65, -1.57).
a(66, 66, -1.3).
a(66, 65.5, -1.3).
a(66, 65, -1.3).
b(65, 66, -1).
b(65, 65.5, -0.5).
b(65, 65, 1.72).
b(65.5, 66, -0.5).
b(65.5, 65.5, 1.48).
b(65.5, 65, 1.48).
b(66, 66, 1.25).
b(66, 65.5, 1.25).
b(66, 65, 1.25).
min_row(Row) :-
a(Col, Row, _),
\+ (a(_,Row2,_), Row2 < Row),!.
max_row(Row) :-
a(Col, Row, _),
\+ (a(_,Row2,_), Row2 > Row),!.
is_profit(ColA, ColB, Row, P) :-
a(ColA, Row, Profit1),
b(ColB, Row, Profit2),
Profit is Profit1 + Profit2,
( Profit > 0 -> P is 1 ; P is 0),!.
count_profits(ColA, ColB, Row1, P) :-
max_row(Row),
Row1 =:= Row,
is_profit(ColA, ColB, Row1, P).
count_profits(ColA, ColB, Row1, P) :-
a(ColA,Row2,_),
Row2 > Row1,
count_profits(ColA, ColB, Row2, P2),
is_profit(ColA, ColB, Row1, P1),
P is P1+P2.
count_profits(ColA, ColB, P) :-
min_row(Row1),
count_profits(ColA, ColB, Row1, P),!.
更新1:
以下是我在我的示例prolog代码中尝试使用的数据的直观表示:
答案 0 :(得分:5)
我给你一些构建块来解决这个任务。
首先,让我们决定推理理性数字。请避免乱七八糟的浮点数字,这会给你带来无穷无尽的问题。
要了解Prolog中的有理数,请查看 CLP(Q),约束解析有理数。
在您的情况下,使用涉及浮点数的矩阵启动。让我们首先使用更方便的表示法,例如:
matrix(a, [[-0.82,-1.07,-1.3], [-1.32,-1.57,-1.3], [-1.82,-1.57,-1.3]]). matrix(b, [[-1,-0.5,1.25], [-0.5,1.48,1.25], [1.72,1.48,1.25]]).
您可以使用所有解决方案谓词,例如setof/3
和findall/3
将当前演示文稿转换为行 。
如前所述,我们首先将转换为有理数,以消除后续步骤中的许多问题。顺便说一下,即使您目前拥有的数字也完全无法保证!另外,在您的情况下,我们主要对列感兴趣,因此我们可以转置矩阵,并使用rationalize/1
来获取列列表有理数:
:- use_module(library(clpq)). :- use_module(library(clpfd)). to_rational(F, R) :- R is rationalize(F). rational_columns(Name, Cols) :- matrix(Name, Rows), transpose(Rows, Cols0), maplist(maplist(to_rational), Cols0, Cols).
让我们看看到目前为止的情况:
?- rational_columns(a, Cols). Cols = [[-41 rdiv 50, -33 rdiv 25, -91 rdiv 50], [-107 rdiv 100, -157 rdiv 100, -157 rdiv 100], [-13 rdiv 10, -13 rdiv 10, -13 rdiv 10]].
继续,让我们定义添加列的含义:
column_column_plus(As, Bs, Ps) :- maplist(addition, As, Bs, Ps). addition(A, B, Sum) :- { Sum = A + B }.
这使用CLP(Q)约束来定义列表的元素添加。它可以在所有方向使用!
使用这些构建块,我们已经可以描述我们感兴趣的列组合:
combination_number(A-B, N) :- rational_columns(a, ACs), rational_columns(b, BCs), member(A, ACs), member(B, BCs), column_column_plus(A, B, Ps), include(<(0), Ps, Gs0), Gs0 = [_|_], length(Gs0, N).
解决方案可以在回溯中找到:
?- combination_number(Cs, N). Cs = [-41 rdiv 50, -33 rdiv 25, -91 rdiv 50]-[-1 rdiv 2, 37 rdiv 25, 37 rdiv 25], N = 1 ; Cs = [-41 rdiv 50, -33 rdiv 25, -91 rdiv 50]-[5 rdiv 4, 5 rdiv 4, 5 rdiv 4], N = 1 ; Cs = [-107 rdiv 100, -157 rdiv 100, -157 rdiv 100]-[-1, -1 rdiv 2, 43 rdiv 25], N = 1 ; Cs = [-107 rdiv 100, -157 rdiv 100, -157 rdiv 100]-[5 rdiv 4, 5 rdiv 4, 5 rdiv 4], N = 1 ; Cs = [-13 rdiv 10, -13 rdiv 10, -13 rdiv 10]-[-1, -1 rdiv 2, 43 rdiv 25], N = 1 ; Cs = [-13 rdiv 10, -13 rdiv 10, -13 rdiv 10]-[-1 rdiv 2, 37 rdiv 25, 37 rdiv 25], N = 2 ; false.
要选择最佳组合,您可以将findall/3
与keysort/2
结合使用:
?- findall(N-Cs, combination_number(Cs, N), NCs0), keysort(NCs0, NCs), last(NCs, Best).
产量:
Best = 2-([-13 rdiv 10, -13 rdiv 10, -13 rdiv 10]-[-1 rdiv 2, 37 rdiv 25, 37 rdiv 25]).