在prolog中转置矩阵

时间:2017-03-28 19:58:11

标签: matrix prolog

我想在prolog转置一个矩阵,例如 [[1,2,3],[1,2,3],[1,2,3]]应该成为 [[1,1,1],[2,2,2],[3,3,3]]

以下是我所做的:

%transpose(M,T)
transpose([],[]).
transpose(M,[H|T]):-row(H,M,M1),transpose(M1,T).

%row(H, M, M1).
row([],[],[]).
row([H|Tt] , [[H|T1]|T] , [T1|Z]) :- row(Tt,T,Z).

M要转置T的位置。 行谓词(不确定谓词和函数之间的差异)得到M中每个子列表的头部,因此我可以获得新的转置矩阵T的整个第一行。 我分别测试了行,它给出了正确的结果。但是,当我尝试transpose时,我只会错误地发现错误。没有任何反应,打印出新矩阵T的信息。

任何人都可以帮助我吗?问题在于我构建程序的方式吗?或者我期望的结果确实只有true/false,如果是这样,如何获得新矩阵?谢谢:))

3 个答案:

答案 0 :(得分:2)

首先,关于术语的注释:函数的一个特征是每个输入与恰好一个输出相关。另一方面,关系可以适用于多个这样的组合。 Prolog谓词在他们的论点之间引发了关系,并且在回溯时会出现多个答案。

关于你的具体问题,@ lurker已经给出了一些可靠的建议。

然而,正如您已经注意到的,Prolog中的跟踪变得非常复杂,因此我想通过在Prolog中解释声明性调试的一些原则来补充潜伏者所写的内容。

从本质上讲,我们的目标是让我们的问题更简单而不是更难。我们从您为您发布的计划提及的案例开始:

?- transpose([[1,2,3],[1,2,3],[1,2,3]], Ls).
false.

从逻辑上讲,关系太具体失败应该持有的情况下保留。

要找到此问题的原因,我们可以使用文本或图形跟踪器逐步完成精确的执行细节,并尝试跟踪所有细节。这非常困难,所以我建议您首先尝试找一个更简单的案例仍然失败。

我将通过概括查询来完成此操作。有几种方法可以做到这一点。例如,我可以使用 fresh 变量代替具体整数:

?- transpose([[_,_,_],[_,_,_],[_,_,_]], Ls).
false.

啊哈,所以我们发现了一个更为笼统的案例仍然失败。只要这种情况失败,更具体的情况肯定失败,因为我们推理的是单调逻辑程序。 / p>

所以,新问题是:为什么这个更通用的查询失败了?为了找到原因,我们可以简单地进一步概括查询。例如,我们可以将此概括为以下情况,而不是推理每个包含3个元素的列表,其中两个列表被推广为“多个元素”:

?- transpose([[_|_],[_|_],[_,_,_]], Ls).
false.

我们发现这个更通用的查询仍然失败。我们甚至可以进一步概括:

?- transpose([_,_,[_,_,_]], Ls).
false.

仍然失败!请注意,我们也可以把它放得太远。例如:

?- transpose([_,_,_], Ls).
nontermination

在这里,我们遇到了一个完全不同的问题,与程序的终止属性有关。但是,在我们的案例中,我们希望找到意外失败的原因,因此我们回到上面的案例:

?- transpose([_,_,[_,_,_]], Ls).
false.

此时,没有更多要概括,因此我们可以现在调用此简化查询的跟踪器。

但是,我们也可以继续朝不同的方向发展:并非每个测试用例都需要概括。我们还可以提出一个完全不同的情况,例如只有两个(而不是三个)元素的列表:

?- transpose([_,[_,_,_]], Ls).
false

啊哈,所以这个失败了,即使它应该成功!

即使是更简单的案例呢?

?- transpose([[_,_,_]], Ls).
false.

进一步说:

?- transpose([[_,_]], Ls).
false.

更进一步:

?- transpose([[_]], Ls).
false.

这些查询的每个 应该成功,但失败

为什么?

要查找原因,请考虑基础逻辑程序的。例如,让我们采取一个最简单的查询,我们发现应该成功,但不会:?- transpose([[_]], _).

我使用以下定义来概括原始程序的约束(=目标)

:- op(920,fy, *).
*_.

例如,我们可以概括 row/3,如下所示:

row([], [], []).
row([H|Tt], [[H|T1]|T], [T1|Z]) :-
        * row(Tt,T,Z).

即使使用row/3这个更为通用的版本,我们也会得到:

?- transpose([[_]], Ls).
false.

这意味着:要使此查询成功,您必须在代码中添加其他子句(使其更通用)或更改剩余片段。< / p>

像潜伏者一样,我也将剩下的作为练习。

答案 1 :(得分:1)

Prolog只有谓词而不是功能谓词定义了一种关系,并且通常不被认为是&#34;做某事&#34;尽可能地定义一些东西。你的row/3实际上定义了它的3个参数之间的关系。 3个参数的相关之处在于第1和第3个列表的元素是第2个列表的参数的头部和尾部。我将展示3个不同的查询,说明:

| ?- row([a,b,c], L, M).

L = [[a|A],[b|B],[c|C]]
M = [A,B,C]

yes
| ?- row(A, [[a,b,c],[d,e,f],[g,h,i]], L).

A = [a,d,g]
L = [[b,c],[e,f],[h,i]] ? ;

no
| ?- row(A, B, [[a,b],[c,d],[e,f]]).

A = [C,D,E]
B = [[C,a,b],[D,c,d],[E,e,f]] ? ;

no
| ?- 

功能不会以这种方式运行。你也可以看到,知道这种关系,这个名字有点泛泛。 row并未真正充分描述这种关系。也许它可以被称为heads_and_tails/3,也许可以交换第一和第二个参数。

transpose/2谓词失败的原因是它会递归到空列表列表(如果是3行矩阵,则为[[], [], []]),但是transpose/2个基数案例基于[]

<小时/> 让我们看看评论中建议的transpose([], [])的基本情况,代之以:

transpose([[] | _], []).

以下示例查询结果:

| ?- transpose([[a,b,c],[d,e,f]], T).

T = [[a,d],[b,e],[c,f]] ? ;

no
| ?- transpose([[a,b,c],[d,e,f], [a]], T).

no
| ?- transpose(T, [[a,b,c],[d,e,f]]).

T = [[a,d],[b,e|_],[c,f|_]] ? ;

no

第二个查询的结果不正确。根据此谓词的逻辑,解决此问题的一种方法是将基本案例从transpose([], [])更改为此:

transpose(Empty, []) :- maplist(=([]), Empty).

这会导致谓词产生以下结果:

| ?- transpose(T, [[a,b,c],[d,e,f]]).

T = [[a,d],[b,e],[c,f]] ? a

no
| ?- transpose([[a,b,c],[d,e,f]], T).

T = [[a,d],[b,e],[c,f]] ? a

no

答案 2 :(得分:-1)

事实证明,之前的解决方案是不充分的,因为它只是对逻辑关系的描述。

除了关系规范之外,还需要对事实进行迭代,然后根据关系进行处理。

在以下程序中,foreach用于生成事实。

在swipl上测试。

示例查询遵循该程序。

    */

    (
        program(INPUT_VECTOR,OUTPUT_VECTOR)
    )
    :-
    (
        (
            (
                INPUT_TRUTH_GOAL
            )
            =
            (
                item(INPUT_VECTOR,J_INDEX,K_INDEX,ITEM)
            )
        )
        ,
        (
            (
                OUTPUT_TRUTH_GOAL
            )
            =
            (
                item(OUTPUT_VECTOR,K_INDEX,J_INDEX,ITEM)
            )
        )
        ,
        (
            (
                nonvar(INPUT_VECTOR)
            )
            *->
            (
                once(foreach(INPUT_TRUTH_GOAL,OUTPUT_TRUTH_GOAL))
            )
            ;
            (
                (
                    nonvar(OUTPUT_VECTOR)
                )
                *->
                (
                    once(foreach(OUTPUT_TRUTH_GOAL,INPUT_TRUTH_GOAL))
                )
            )
        )
    )
    .

    (
        item(VECTOR,J_INDEX,K_INDEX,ITEM)
    )
    :-
    (
        (
            nth1(J_INDEX,VECTOR,SUBVECTOR)
        )
        ,
        (
            nth1(K_INDEX,SUBVECTOR,ITEM)
        )
    )
    .

    /*

测试:

三个测试查询证明该程序基本适合:

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

    ?-
    program([[1,2,3],[4,5,6],[7,8,9]],OUTPUT_VECTOR)
    .
    OUTPUT_VECTOR = [[1, 4, 7|_830], [2, 5, 8|_962], [3, 6, 9|_1100]|_356]  .

    ?-
    program(INPUT_VECTOR,[[1,4,7],[2,5,8],[3,6,9]])
    .
    INPUT_VECTOR = [[1, 2, 3|_560], [4, 5, 6|_626], [7, 8, 9|_698]|_350]    .

    ?-

不幸的是,该计划未能通过坚定的测试:

    ?-
    program(INPUT_VECTOR,OUTPUT_VECTOR)
    ,
    INPUT_VECTOR = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    .

    false .

    ?-