首页 文章

在prolog中转置矩阵

提问于
浏览
0

我想在 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 时,我只得到'false'并且没有任何反应,没有打印新矩阵 T 的信息 .

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

3 回答

  • 1

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

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

    但是,正如您已经注意到的那样,Prolog中的跟踪很快变得非常复杂,因此我想通过在Prolog中解释 declarative debugging 的一些原则来补充潜伏者所写的内容 .

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

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

    从逻辑上讲,这种关系是 too specific :它无法在它应该持有的情况下持有 .

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

    我将通过 generalizing 查询来完成此操作 . 有几种方法可以做到这一点 . 例如,我可以使用新的变量而不是具体的整数:

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

    啊哈,所以我们发现了一个更加普遍的案例,但仍然失败了 . 只要这种情况失败,更具体的情况肯定也会失败,因为我们正在推理 puremonotonic 逻辑程序 .

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

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

    我们看到这个更通用的查询 still fails . 我们甚至可以进一步概括:

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

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

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

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

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

    在这一点上,没有更多的概括,所以我们现在可以在这个简化的查询上调用跟踪器 .

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

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

    啊哈,所以这也失败了,尽管它应该成功!

    甚至更简单的情况呢?

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

    并进一步:

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

    甚至进一步:

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

    这些查询中的每一个都应该成功,但都会失败 .

    为什么?

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

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

    : - op(920,fy,*) .

    • _ .

    例如,我们可以 generalize row/3 如下:

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

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

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

    这意味着:要使此查询成功,您必须向代码添加其他子句(使其更通用)或 change the remaining fragment .

    像潜伏者一样,我也把剩下的作为锻炼 .

  • 0

    Prolog只有谓词而不是函数 . 谓词定义了一个关系,并且通常不被认为是"doing something",就像它“定义一些东西一样 . 你的 row/3 实际上定义了它的3个参数之间的关系.3个参数的相关性在于第1和第3个列表的元素是第二个列表的参数的头部和尾部 . 我将显示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
    
  • 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 .
    
        ?-
    

相关问题