【问题标题】:List as graph in prolog在序言中以图表形式列出
【发布时间】:2012-03-20 10:41:20
【问题描述】:

我正在尝试生成从矩阵中的一个元素到另一个元素的所有可能的“方式”,主要条件说矩阵中的元素只有在元素共享至少一个角时才能与其他元素连接,因此在该矩阵中

[[1,2,3]
 [5,4,6]
 [8,9,7]]

1 只能与 2,4,5 连接,但 4 与所有元素连接。是否可以在不使用吸引的情况下将该列表表示为图形?或者也许我可以找到更简单的方法来做到这一点


感谢所有回答。 好的,我提出:-) 现在有了谓词,我生成了所有“边”,但我无法在任何地方使用它们,我不知道如何使用这种模式 ([row:R1,column:C1,value:V1], [row:R2,column:C2,value:V2]) 添加到每个单元格的累加器(列表)信息中。

【问题讨论】:

  • 你的问题到底是什么?是如何在图中通过谓词转换这个矩阵?是如何使用图形来查找所有路径吗?只是关于这个矩阵还是关于在图中转换矩阵的一般问题?

标签: prolog logic


【解决方案1】:

这是一个需要考虑的(冗长但简单的)解决方案。

首先,它有助于有一个辅助谓词从矩阵中的Row,Col 位置检索元素作为列表列表,例如:

get_matrix_entry_nth0(RowInd, ColInd, Matrix, Entry) :-
    nth0(RowInd, Matrix, Row),
    nth0(ColInd, Row, Entry).

其次,它还可以帮助使用该谓词来定义相对于由RowCol 索引的条目在方向方面,例如:

up_left_entry(R-C, Matrix, E) :-
    PrevR is R - 1,
    PrevC is C - 1,
    get_matrix_entry_nth0(PrevR, PrevC, Matrix, E).

up_entry(R-C, Matrix, E) :-
    PrevR is R - 1,
    get_matrix_entry_nth0(PrevR, C, Matrix, E).

up_right_entry(R-C, Matrix, E) :-
    PrevR is R - 1,
    NextC is C + 1,
    get_matrix_entry_nth0(PrevR, NextC, Matrix, E).

right_entry(R-C, Matrix, E) :-
    NextC is C + 1,
    get_matrix_entry_nth0(R, NextC, Matrix, E).

down_right_entry(R-C, Matrix, E) :-    
    NextR is R + 1,
    NextC is C + 1,
    get_matrix_entry_nth0(NextR, NextC, Matrix, E).

down_entry(R-C, Matrix, E) :-
    NextR is R + 1,
    get_matrix_entry_nth0(NextR, C, Matrix, E).

down_left_entry(R-C, Matrix, E) :-    
    NextR is R + 1,
    PrevC is C - 1,
    get_matrix_entry_nth0(NextR, PrevC, Matrix, E).

left_entry(R-C, Matrix, E) :-
    PrevC is C - 1,
    get_matrix_entry_nth0(R, PrevC, Matrix, E).

有了这些辅助谓词,解决方案就相当简单了:

matrix_path([R|Rs], P) :-
    % determine rows, cols
    length([R|Rs], Rows),
    length(R, Cols),
    % defer to matrix_path/4 to compute all paths starting with 0,0
    matrix_path(0-0, Rows-Cols, [R|Rs], P).

matrix_path/2 是程序的入口点。这个单子句谓词预先确定给定矩阵中的行数和列数,并将处理推迟到matrix_path/4,它从0,0(左上角)元素开始计算。

matrix_path(R-C, Rows-Cols, Matrix, P) :-
    C >= Cols, !,
    % end of column, proceed to next row
    NextRow is R + 1,
    NextRow < Rows,
    matrix_path(NextRow-0, Rows-Cols, Matrix, P).

matrix_path/4的第一个子句检查列数是否超过;如果是这样,则使用剪切(!)来排除下面的子句,并在下一行重新开始计算并将列索引重置为 0。

matrix_path(R-C, _, Matrix, adj(S, T)) :-
    % get this entry
    get_matrix_entry_nth0(R, C, Matrix, S),
    % get each adjacent entry
    (   up_left_entry(R-C, Matrix, T)
    ;   up_entry(R-C, Matrix, T)
    ;   up_right_entry(R-C, Matrix, T)
    ;   right_entry(R-C, Matrix, T)
    ;   down_right_entry(R-C, Matrix, T)
    ;   down_entry(R-C, Matrix, T)
    ;   down_left_entry(R-C, Matrix, T)
    ;   left_entry(R-C, Matrix, T)
    ).

matrix_path/4 的第二个子句只是尝试从给定条目中检索所有可能的“路径”。有些可能会失败(例如在第一行查找),但 Prolog 会回溯以找到所有有效的解决方案。

matrix_path(R-C, Rows-Cols, Matrix, P) :-
    % get the entry for the next column in this row
    NextC is C + 1,
    matrix_path(R-NextC, Rows-Cols, Matrix, P).

matrix_path/4 的最后一个子句只是相对于同一行的下一列中的项目转移处理。

运行一个简单的例子:

?- matrix_path([[1,2],[3,4]], P).
P = adj(1, 2) ;
P = adj(1, 4) ;
P = adj(1, 3) ;
P = adj(2, 4) ;
P = adj(2, 3) ;
P = adj(2, 1) ;
P = adj(3, 1) ;
P = adj(3, 2) ;
P = adj(3, 4) ;
P = adj(4, 1) ;
P = adj(4, 2) ;
P = adj(4, 3) ;
false.

请注意,如果您希望所有相邻对立即不回溯,请将调用包装在 findall/2 中,如下所示:

?- findall(P, matrix_path([[1,2],[3,4]], P), Ps).
Ps = [adj(1, 2), adj(1, 4), adj(1, 3), adj(2, 4), adj(2, 3), adj(2, 1), adj(3, 1), adj(3, 2), adj(..., ...)|...].

【讨论】:

    【解决方案2】:

    使用 Prolog 回溯可以轻松完成有限集的枚举:

    adjacent_pos((R,C), (Ra,Ca)) :-
         (R > 1, Ra is R-1 ; Ra is R ; Ra is R+1),
         (C > 1, Ca is C-1 ; Ca is C ; Ca is C+1),
         once(Ra \= R ; Ca \= C).
    

    使用配对的 nth1/3 我们可以访问一个单元格:

    cell(Mat, (R,C), Cell) :-
         nth1(R, Mat, Row),
         nth1(C, Row, Cell).
    

    所以,在 NxM 个不同元素的矩阵中:

    adjacent(Mat, Elem, Adj) :-
         cell(Mat, Pe, Elem),
         adjacent_pos(Pe, Pa),
         cell(Mat, Pa, Adj).
    

    简单测试:

    test :-
       M = [[1,2,3],
            [5,4,6],
            [8,9,7]],
       findall(A, adjacent(M,1,A), L1), writeln(L1),
       findall(A, adjacent(M,4,A), L4), writeln(L4).
    

    产量:

    ?- test.
    [2,5,4]
    [1,2,3,5,6,8,9,7]
    true.
    

    请注意,测试 R &gt; 1C &gt; 1 可以避免,要求 nth1/3 未能通过“带外”测试。上限也是如此,实际上省略了,另外还有一个好处是我们不限于预定义的矩阵大小。

    【讨论】:

    • 非常感谢!但是如何记住所有生成的连接?没有递归对我来说有点难以弄清楚
    • 您可以断言它们,这是一种简单的记忆形式。对于更具体的问题,请详细编辑您的问题,以便我们为您提供帮助。
    猜你喜欢
    • 2014-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-26
    相关资源
    最近更新 更多