/*
    Triangularize a given matrix (Gaussian elimination) (for B-Prolog).
    by Neng-Fa Zhou, Feb. 16, 2010
*/
triangle_matrix(Matrix):-
    foreach(I in 1..Matrix^length-1,
          [Row,J],                              % Row and J are local
          (select_nonzero_row(I,I,Matrix,J)->
              (I\==J->(Row @= Matrix[I],        % swap row I and J
                   Matrix[I] @:= Matrix[J],
                   Matrix[J] @:= Row)
                ;
                    true
                ),
               foreach(K in I+1..Matrix^length,trans_row(I,K,Matrix))
            ;
               true
             )).
           
% select a row J where  Matrix[J,I] is not zero
select_nonzero_row(I,J0,Matrix,J):-
    Matrix[J0,I]=\=0,!,J=J0.
select_nonzero_row(I,J0,Matrix,J):-
    J0 < Matrix^length,
    J1 is J0+1,
    select_nonzero_row(I,J1,Matrix,J).

% transform row K to make Matrix[K,I] zero
trans_row(I,K,Matrix):-
    Matrix[K,I]=:=0,!.   % is already zero
trans_row(I,K,Matrix):-
    foreach(J in I+1..Matrix[K]^length,
          [NewCoe],
          (NewCoe is Matrix[K,J]/Matrix[K,I]-Matrix[I,J]/Matrix[I,I],
           Matrix[K,J] @:= NewCoe)),
    Matrix[K,I] @:= 0.

test:-
    matrix(Ls),
    lists_to_matrix(Ls,Matrix),
    triangle_matrix(Matrix),
    matrix_to_lists(Matrix,Ls1),
    foreach(L in Ls1, writeln(L)),
    nl,nl,
    fail.

lists_to_matrix(Ls,Matrix):-
    NRows is Ls^length,
    NCols is Ls[1]^length,
    new_array(Matrix,[NRows,NCols]),
    foreach(I in 1..NRows, J in 1..NCols,
          Matrix[I,J] is Ls[I,J]).
    
matrix_to_lists(Matrix,Ls):-
    Ls @= [Row : I in 1..Matrix^length,[Row], 
	         (Row @=[Matrix[I,J] : J in 1..Matrix[I]^length])].	    

matrix(M):-
    M=[[1,1,1,0],
       [1,-2,2,4],
       [1,2,-1,2]].

matrix(M):-
    M=[[2,1,-1,8],
       [-3,-1,2,-11],
       [-2,1,2,-3]].

matrix(M):-
    M=[[2,-3,-1,2,3,4],
       [4,-4,-1,4,11,4],
       [2,-5,-2,2,-1,9],
       [0,2,1,0,4,-5]].


    


