diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/math/linalg.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/math/linalg.b')
| -rw-r--r-- | appl/math/linalg.b | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/appl/math/linalg.b b/appl/math/linalg.b new file mode 100644 index 00000000..5477c4ca --- /dev/null +++ b/appl/math/linalg.b @@ -0,0 +1,197 @@ +implement LinAlg; + +include "sys.m"; +sys: Sys; +print: import sys; + +include "math.m"; +math: Math; +ceil, fabs, floor, Infinity, log10, pow10, sqrt: import math; +dot, gemm, iamax: import math; + +include "linalg.m"; + +# print a matrix in MATLAB-compatible format +printmat(label:string, a:array of real, lda, m, n:int) +{ + if(m>30 || n>10) + return; + if(sys==nil){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + } + print("%% %d by %d matrix\n",m,n); + print("%s = [",label); + for(i:=0; i<m; i++){ + print("%.4g",a[i]); + for(j:=1; j<n; j++) + print(", %.4g",a[i+lda*j]); + if(i==m-1) + print("]\n"); + else + print(";\n"); + } +} + + +# Constant times a vector plus a vector. +daxpy(da:real, dx:array of real, dy:array of real) +{ + n := len dx; + gemm('N','N',n,1,n,da,nil,0,dx,n,1.,dy,n); +} + +# Scales a vector by a constant. +dscal(da:real, dx:array of real) +{ + n := len dx; + gemm('N','N',n,1,n,0.,nil,0,nil,0,da,dx,n); +} + +# gaussian elimination with partial pivoting +# dgefa factors a double precision matrix by gaussian elimination. +# dgefa is usually called by dgeco, but it can be called +# directly with a saving in time if rcond is not needed. +# (time for dgeco) = (1 + 9/n)*(time for dgefa) . +# on entry +# a REAL precision[n][lda] +# the matrix to be factored. +# lda integer +# the leading dimension of the array a . +# n integer +# the order of the matrix a . +# on return +# a an upper triangular matrix and the multipliers +# which were used to obtain it. +# the factorization can be written a = l*u where +# l is a product of permutation and unit lower +# triangular matrices and u is upper triangular. +# ipvt integer[n] +# an integer vector of pivot indices. +# info integer +# = 0 normal value. +# = k if u[k][k] .eq. 0.0 . this is not an error +# condition for this subroutine, but it does +# indicate that dgesl or dgedi will divide by zero +# if called. use rcond in dgeco for a reliable +# indication of singularity. +dgefa(a:array of real, lda, n:int, ipvt:array of int): int +{ + if(sys==nil){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + } + info := 0; + nm1 := n - 1; + if(nm1 >= 0) + for(k := 0; k < nm1; k++){ + kp1 := k + 1; + ldak := lda*k; + + # find l = pivot index + l := iamax(a[ldak+k:ldak+n]) + k; + ipvt[k] = l; + + # zero pivot implies this column already triangularized + if(a[ldak+l]!=0.){ + + # interchange if necessary + if(l!=k){ + t := a[ldak+l]; + a[ldak+l] = a[ldak+k]; + a[ldak+k] = t; + } + + # compute multipliers + t := -1./a[ldak+k]; + dscal(t,a[ldak+k+1:ldak+n]); + + # row elimination with column indexing + for(j := kp1; j < n; j++){ + ldaj := lda*j; + t = a[ldaj+l]; + if(l!=k){ + a[ldaj+l] = a[ldaj+k]; + a[ldaj+k] = t; + } + daxpy(t,a[ldak+k+1:ldak+n],a[ldaj+k+1:ldaj+n]); + } + }else + info = k; + } + ipvt[n-1] = n-1; + if(a[lda*(n-1)+(n-1)] == 0.) + info = n-1; + return info; +} + + +# dgesl solves the double precision system +# a * x = b or trans(a) * x = b +# using the factors computed by dgeco or dgefa. +# on entry +# a double precision[n][lda] +# the output from dgeco or dgefa. +# lda integer +# the leading dimension of the array a . +# n integer +# the order of the matrix a . +# ipvt integer[n] +# the pivot vector from dgeco or dgefa. +# b double precision[n] +# the right hand side vector. +# job integer +# = 0 to solve a*x = b , +# = nonzero to solve trans(a)*x = b where +# trans(a) is the transpose. +# on return +# b the solution vector x . +# error condition +# a division by zero will occur if the input factor contains a +# zero on the diagonal. technically this indicates singularity +# but it is often caused by improper arguments or improper +# setting of lda. +dgesl(a:array of real, lda, n:int, ipvt:array of int, b:array of real, job:int) +{ + nm1 := n - 1; + if(job == 0){ # job = 0 , solve a * x = b + # first solve l*y = b + if(nm1 >= 1) + for(k := 0; k < nm1; k++){ + l := ipvt[k]; + t := b[l]; + if(l!=k){ + b[l] = b[k]; + b[k] = t; + } + daxpy(t,a[lda*k+k+1:lda*k+n],b[k+1:n]); + } + + # now solve u*x = y + for(kb := 0; kb < n; kb++){ + k = n - (kb + 1); + b[k] = b[k]/a[lda*k+k]; + t := -b[k]; + daxpy(t,a[lda*k:lda*k+k],b[0:k]); + } + }else{ # job = nonzero, solve trans(a) * x = b + # first solve trans(u)*y = b + for(k := 0; k < n; k++){ + t := dot(a[lda*k:lda*k+k],b[0:k]); + b[k] = (b[k] - t)/a[lda*k+k]; + } + + # now solve trans(l)*x = y + if(nm1 >= 1) + for(kb := 1; kb < nm1; kb++){ + k = n - (kb+1); + b[k] += dot(a[lda*k+k+1:lda*k+n],b[k+1:n]); + l := ipvt[k]; + if(l!=k){ + t := b[l]; + b[l] = b[k]; + b[k] = t; + } + } + } +} |
