このディレクトリの索引
http://hibari.2ch.net/test/read.cgi/tech/1320365280/477
#  [1] 授業単元:C言語 
#  [2] 問題文:3*3の逆行列Aをもとめよ 
#  http://ime.nu/ideone.com/erZBk 
#  

'3*3の逆行列Aをもとめよ'(_a,_逆行列A) :-
        var(_a),
        '3行3列の行列aを入力'(_a),
        正方行列の逆行列(_a,_逆行列A).
'3*3の逆行列Aをもとめよ'(_a,_逆行列A) :-
        \+(var(_a)),
        正方行列の逆行列(_a,_逆行列A).

正方行列の逆行列(_正方行列,_正方行列の逆行列) :-
        余因子行列(_正方行列,_余因子行列),
        転置(_余因子行列,_チルダ余因子行列),
        行列式の値(_正方行列,_正方行列の行列式の値),
        チルダ余因子行列を正方行列の行列式の値で割る(_チルダ余因子行列,_正方行列の行列式の値,_正方行列の逆行列).

チルダ余因子行列を正方行列の行列式の値で割る([],_,[]).
チルダ余因子行列を正方行列の行列式の値で割る(_チルダ余因子行列,_正方行列の行列式の値,_正方行列の逆行列) :-
        _チルダ余因子行列 = [_行_1|R1],
        行列要素の割り算(_行_1,_正方行列の行列式の値,_行_2),
        _正方行列の逆行列 = [_行_2|R2],
        チルダ余因子行列を正方行列の行列式の値で割る(R1,_正方行列の行列式の値,R2).

行列要素の割り算([],_,[]).
行列要素の割り算([_被除数|R1],_除数,[N2|R2]) :-
        約分(_被除数/_除数,N2),
        行列要素の割り算([N1|R1],D,[N2|R2]).

約分(B / A,V) :-
        \+(integer(B)),
        V is B / A,!.
約分(B / A,V) :-
        \+(integer(A)),
        V is B / A,!.
約分(B / A,X) :-
        最大公約数(B,A,C),
        _分子 is B // C,
        _分母 is A // C,
        約分の二(_分子,_分母,X),!.

約分の二(_分子,1,_分子) :- !.
約分の二(_分子,1.0,_分子) :- !.
約分の二(_分子,_分母,_分子 / _分母).

'余因子行列で行列値|a|を求める'(_a,_行列式_aの値) :-
        余因子行列(_n,_a,_余因子行列),
        _a = [_aの第一行|_],
        _余因子行列 = [_余因子行列の第一行|_],
        二つのならびの積の和(_aの第一行,_余因子行列の第一行,_行列式_aの値).

余因子行列(_n,_正方行列,_余因子行列) :-
        length(_余因子行列,_n),
        findall(L,(
                    nth1(_i,_余因子行列,L),
                    余因子行列の要素が余因子である(_n,_正方行列,_i,L)), 
                _余因子行列).

余因子行列の要素が余因子である(_n,_正方行列,_i,L) :-
        length(L,_n),
        findall(_余因子,(
                    nth1(_j,L,_余因子),
                    余因子(_n,_正方行列,_i,_j,_余因子)),
                L).

行列式の値(_正方行列,_i,_n,_行列式の値) :-
        findsum(W,(
                    'n次正方行列の要素を列・行取り出す'(_n,_正方行列,_i,_j,_正方行列の要素),
                    余因子(_n,_正方行列,_i,_j,_余因子),
                    W is _正方行列の要素 * _余因子),
                _行列式の値).

余因子(_n,_正方行列,_i,_j,_余因子) :-
        'n次正方行列から、第i行と第j列を取り除いた正方行列(n-1次正方行列の行列式に、(-1)のi+j乗をかけたものを、Aの(i,j)余因子といい、Cijで表します。'(_n,_正方行列,_i,_j,_余因子).

'n次正方行列から、第i行と第j列を取り除いた正方行列(n-1次正方行列の行列式に、(-1)のi+j乗をかけたものを、Aの(i,j)余因子といい、Cijで表します。'(_n,_正方行列,_i,_j,_余因子) :-
        '正方行列から第i行と第j列を取り除く'(_正方行列,_i,_j,_n_1次正方行列),
        'i,jから乗数を得る'(_i,_j,_乗数),
        二つの対角要素の積を得る(_n,_n_1次正方行列,_右下がり対角要素の積,_右上がり対角要素の積),        
        _余因子 is _乗数 * (_右下がり対角要素の積-_右上がり対角要素の積).

'正方行列から第i行と第j列を取り除く'(_正方行列,_i,_j,_n_1次正方行列) :-
        '第何行を取り除く'(_正方行列,_i,_第i行が取り除かれた行列),
        転置(_第i行が取り除かれた行列,_転置された第i行が取り除かれた行列),
        '第何行を取り除く'(_転置された第i行が取り除かれた行列,_j,_転置された第i行第j列が取り除かれた行列),
        転置(_転置された第i行第j列が取り除かれた行列,_n_1次正方行列).

'第何行を取り除く'(_正方行列,_第何行,_第i行が取り除かれた行列) :-
        append(L0,[L|R],_正方行列),
        length([_|L0],_第何行),
        append(L0,R,_第i行が取り除かれた行列).

二つの対角要素の積を得る(_n,_正方行列,_右下がり対角要素の積,_右上がり対角要素の積) :-
        二つの対角要素を得る(_n,_正方行列,_右下がり対角要素ならび,_右上がり対角要素ならび),
        対角要素の掛算(_右下がり対角要素ならび,_右下がり対角要素の積),
        対角要素の掛算(_右上がり対角要素ならび,_右上がり対角要素の積).


二つの対角要素を得る(_n,_正方行列,_右下がり対角要素ならび,_右上がり対角要素ならび) :-
        右下がり対角要素ならび(_n,_正方行列,_右下がり対角要素ならび),
        右上がり対角要素ならび(_n,_正方行列,_右上がり対角要素ならび).        

右下がり対角要素ならび(_n,_正方行列,_右下がり対角要素ならび) :-
        findall(V,(
                    nth1(_nth1,_正方行列,L),
                    nth1(_nth1,L,V)),
                _右下がり対角要素ならび).

右上がり対角要素ならび(_n,_正方行列,_右上がり対角要素ならび) :-
        findall(V,(
                    append(_,[L|R],_正方行列),
                    length([_|R],_nth1),
                    nth1(_nth1,L,V)),
                _右上がり対角要素ならび),!.

'i,jから乗数を得る'(_i,_j,(-1)) :-
        1 is (_i + _j) mod 2,!.
'i,jから乗数を得る'(_i,_j,1) :-
        0 is (_i + _j) mod 2,!.

対角要素の掛算([],1).
対角要素の掛算([A|R],X) :-
        対角要素の掛算(R,Y),
        X is A * Y.