############################################################################ # # File: matrix.icn # # Subject: Procedures for matrix manipulation # # Authors: Stephen B. Wampler and Ralph E. Griswold # # Date: December 2, 2000 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # This file contains procedures for matrix manipulation. # ############################################################################ # # Links: lu # ############################################################################ link lu procedure matrix_width(M) return *M[1] end procedure matrix_height(M) return *M end procedure write_matrix(file, M, x, s) local r, c, row, col r := matrix_height(M) c := matrix_width(M) if /x then { # packed, no punctuation every row := 1 to r do { every col := 1 to c do { writes(file, M[row][col], s) } write(file) } } else { every row := 1 to r do { writes(file, "[") every col := 1 to c do { writes(file, M[row][col], ", ") } write(file, "]") } } end procedure copy_matrix(M) local M1, n, i n := *M M1 := list(n) every i := 1 to n do M1[i] := copy(M[i]) return M1 end procedure create_matrix(n, m, x) local M M := list(n) every !M := list(m, x) return M end procedure identity_matrix(n, m) local r, c, M M := create_matrix(n, m, 0) every r := 1 to n do { every c := 1 to m do { if r = c then M[r][c] := 1 } } return M end procedure add_matrix(M1, M2) local M3, r, c, n, m if ((n := *M1) ~= *M2) | ((m := *M1[1]) ~= *M2[1]) then stop("*** incorrect matrix sizes") M3 := create_matrix(n, m) every r := 1 to n do every c := 1 to m do M3[r][c] := M1[r][c] + M2[r][c] return M3 end procedure mult_matrix(M1, M2) local M3, r, c, n, k if (n := *M1[1]) ~= *M2 then stop("*** incorrect matrix sizes") M3 := create_matrix(*M1,*M2[1]) every r := 1 to *M1 do { every c := 1 to *M2[1] do { M3[r][c] := 0 every k := 1 to n do { M3[r][c] +:= M1[r][k] * M2[k][c] } } } return M3 end procedure invert_matrix(M) local M1, Y, I, d, i, n, B, j n := *M if n ~= *M[1] then stop("*** matrix not square") M1 := copy_matrix(M) Y := identity_matrix(n, n) I := list(n, 0) # index vector # First perform LH decomposition on M1 (which changes it and produces # an index vector, I. d := lu_decomp(M1, I) | stop("*** singular matrix") every j := 1 to n do { B := list(n) # work on columns every i := 1 to n do B[i] := Y[i][j] lu_back_sub(M1, I, B) # does not change M1 or I every i := 1 to n do # put column in result Y[i][j] := B[i] } return Y end procedure determinant(M) local M1, I, result, i, n n := *M if n ~= *M[1] then stop("*** matrix not square") M1 := copy_matrix(M) I := list(n, 0) # not used but required by lu_decomp() result := lu_decomp(M1, I) | stop("*** singular matrix") every i := 1 to n do # determinant is produce of diagonal result *:= M1[i][i] # elements of the decomposed matrix return result end