计算决定因素时的无限循环

时间:2018-04-12 14:48:47

标签: postscript algebra matrix-inverse determinants

我担心我违反规则永远不会尽可能巧妙地编写代码。当尝试使用LaPlace扩展计算8x8矩阵的行列式时,我发生了无限递归。

程序尝试对圆进行投影变换,投影由4个源点和4个目标点定义。

基本思想来自this page,它显示了用于求解投影矩阵系数的8x8矩阵。然后我尝试从维基百科中的定义实现所需的函数。

xform.ps(对matmul transpose函数使用G library

%!
errordict/rangecheck{pstack()= countexecstack array execstack == quit}put
errordict/dictstackoverflow{countexecstack array execstack dup length 21 sub 20 getinterval == quit}put
4(G/G)run <<

/main {
    300 400  100  0 360 arc  flattenpath

    100 100  500 100  500 500  100 500
    200 200  300 200  300 300  200 300  xformpath

    stroke
}

/xformpath {
    10 dict begin
        {mul neg}
        { *- v3 u3  v2 u2  v1 u1  v0 u0
             y3 x3  y2 x2  y1 x1  y0 x0 }{exch def}forall

        [
            [ x0  y0  1   0   0   0   x0 u0 *-  y0 u0 *- ]
            [ x1  y1  1   0   0   0   x1 u1 *-  y1 u1 *- ]
            [ x2  y2  1   0   0   0   x2 u2 *-  y2 u2 *- ]
            [ x3  y3  1   0   0   0   x3 u3 *-  y3 u3 *- ]
            [ 0   0   0   x0  y0  1   x0 v0 *-  y0 v0 *- ]
            [ 0   0   0   x1  y1  1   x1 v1 *-  y1 v1 *- ]
            [ 0   0   0   x2  y2  1   x2 v2 *-  y2 v2 *- ]
            [ 0   0   0   x3  y3  1   x3 v3 *-  y3 v3 *- ]
        ]
        invertmat
        [ u0 u1 u2 u3 v0 v1 v2 v3 ] transpose
        matmul
        massage-vector-into-matrix
        /P exch def

        [
            { project2 /moveto cvx }
            { project2 /lineto cvx }
            {}
            { /closepath cvx } pathforall
        ] cvx
        newpath exec

    end
}

/massage-vector-into-matrix {
    transpose 0 get
    dup 0 3 getinterval exch
    dup 3 3 getinterval exch
    6 2 getinterval aload pop 1  3 array astore
    3 array astore
}

/project2 {
    hom P matmul het
}

/hom { % x y  ->  [ x y 1 ]
    1  3 array astore
}

/het { % [ x y w ]  ->  x/w y/w
    aload pop dup 3 1 roll div 3 1 roll div exch
}

/invertmat {
    dup  det 1 exch div  dup dup 3 array astore exch
    adjugate  { { mul } sop } vop
}

/det {
    << exch
        /A exch
    >> begin
        A length 2 eq {
            aload pop
            aload pop /d exch def /c exch def
            aload pop /b exch def /a exch def
            a d mul b c mul sub
        }{
            /M A length def  % LaPlace expansion on first column
            /N A 0 get length def
            0
            0 1 M _1 { /i exch def
                i 0 A minor
                i 2 mod 1 eq { neg } if
                add
            } for
        } ifelse
    end
}

/adjugate {
    cofactor transpose
}

/cofactor {
    << exch
        /A exch
        /M 1 index       length
        /N 3 index 0 get length
    >> begin
        [
            0 1 M _1 { /i exch def
                [
                    0 1 N _1 { /j exch def
                        i j A minor
                        i j add 2 mod 1 eq { neg } if       
                    } for
                ]
            } for
        ]
    end
}

/minor {
    3 dict begin
        dup length exch
        dup 0 get length exch
        {A N M n m}{exch def}forall
        [
            0 1 M _1 { /i exch def
                [
                    0 1 N _1 { /j exch def
                        m i eq  n j eq  or  not {
                            A i get j get
                        } if
                    } for
                ]
            } for
        ]

        det
    end
}

/_1 { 1 sub }

>> begin main

错误是/ dictstackoverflow。倾倒execstack的尾部给出了这个:

[--%for_pos_int_continue-- {i 2 mod 1 eq {neg} if add} {end} {end} 1 1 7 
{/i exch def i 0 A minor i 2 mod 1 eq {neg} if add} --%for_pos_int_continue-- 
{i 2 mod 1 eq {neg} if add} {end} {end} 1 1 7 {/i exch def i 0 A minor i 
2 mod 1 eq {neg} if add} --%for_pos_int_continue-- {i 2 mod 1 eq {neg} if 
add} {end} {A length 2 eq {aload pop aload pop /d exch def /c exch def aload 
pop /b exch def /a exch def a d mul b c mul sub} {/M A length def /N A 0 ge
t length def 0 0 1 M _1 {/i exch def i 0 A minor i 2 mod 1 eq {neg} if add} 
for} ifelse end}]

任何人都可以发现我做错了什么,或者是否有更简单的方法来计算未成年人和决定因素,从而更清楚地避免我的问题?

1 个答案:

答案 0 :(得分:0)

我找到了一个似乎有效的决定因素的功能。当然,它使用LaPlace扩展。但是,通过展开第一列,可以使用getinterval提取所有部分行。所以它在没有做双环的情况下组装了第一列的未成年人,这似乎更容易阅读。

%!
%errordict/rangecheck{pstack()= countexecstack array execstack == quit}put
4(G/G)run
/block { << exch {} forall >> begin main } def
{ %block

main {
    [[3 8][4 6]] determinant ==
    [[ 12 2 3 ][4 5 6][7 8 9]] determinant ==
    [[ 1 0 0 ][0 1 0][0 0 1]] determinant ==
    [[6 1 1][4 -2 5][2 8 7]] determinant ==
    [[1 2 1 0][0 3 1 1][-1 0 3 1][3 1 2 0]] determinant ==
    quit
}

determinant {
    dup length 3 le {
        dup length 0 eq {
            pop 0
        }{
        dup length 1 eq {
            0 get
        }{
        dup length 2 eq {
            aload pop aload pop 3 2 roll aload pop % c d a b
            4 -1 roll mul neg % d a -bc
            3 1 roll mul add % ad-bc
        }{
            dup 1 get 1 2 getinterval 1 index 2 get 1 2 getinterval 2 array astore determinant
            1 index 0 get 0 get mul exch
            dup 0 get 1 2 getinterval 1 index 2 get 1 2 getinterval 2 array astore determinant
            1 index 1 get 0 get mul neg exch
            dup 0 get 1 2 getinterval 1 index 1 get 1 2 getinterval 2 array astore determinant
            exch 2 get 0 get mul  add add
        }ifelse }ifelse }ifelse
    }{
        %dup ==()=
        dup { 0 get } map exch
        { 1  1 index length 1 sub  getinterval } map  % [ ai0 ] [ ai1..n ]
        [ exch
          0  1  2 index length 1 sub { % [ ... ai1..n  i
              2 copy  2 copy  0 exch getinterval 3 1 roll  % [ ... a i a0..11..n ai1..n i
              1 add  1 index length 1 index sub  getinterval
              combine 3 1 roll pop
          } for pop ] %   pstack()=
        { determinant } map % dup ==()=
        { mul } vop
        aload length 1 sub { sub } repeat  %  -+-+ == -(-(-(-)))
    } ifelse
}

combine {
    %    exch [ exch {}forall counttomark 2 add -1 roll {}forall ]
    2 copy length exch length add array
    dup 0 4 index putinterval
    dup 4 -1 roll length 4 -1 roll putinterval
}

map {
    [ 3 1 roll forall ]
}

} block