| 1 | (******************************************************************************* |
|---|
| 2 | Copyright 2009 Sun Microsystems, Inc., |
|---|
| 3 | 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
|---|
| 4 | All rights reserved. |
|---|
| 5 | |
|---|
| 6 | U.S. Government Rights - Commercial software. |
|---|
| 7 | Government users are subject to the Sun Microsystems, Inc. standard |
|---|
| 8 | license agreement and applicable provisions of the FAR and its supplements. |
|---|
| 9 | |
|---|
| 10 | Use is subject to license terms. |
|---|
| 11 | |
|---|
| 12 | This distribution may include materials developed by third parties. |
|---|
| 13 | |
|---|
| 14 | Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered |
|---|
| 15 | trademarks of Sun Microsystems, Inc. in the U.S. and other countries. |
|---|
| 16 | ******************************************************************************) |
|---|
| 17 | |
|---|
| 18 | component conjGrad |
|---|
| 19 | import Sparse.{...} |
|---|
| 20 | export Executable |
|---|
| 21 | |
|---|
| 22 | mkMatrix[\nat n\]() : RR64[n,n] = do |
|---|
| 23 | (* We generate a symmetric positive-definite matrix by generating |
|---|
| 24 | a lower-triangular positive matrix and multiplying by its |
|---|
| 25 | transpose. *) |
|---|
| 26 | lambda_inv = - 4 n / log n |
|---|
| 27 | rt2 = SQRT 2 |
|---|
| 28 | row(i:ZZ32):SparseVector[\RR64,n\] = do |
|---|
| 29 | mem0 = array[\(ZZ32,RR64)\](n-i) |
|---|
| 30 | j : ZZ32 := i |
|---|
| 31 | o : ZZ32 := 0 |
|---|
| 32 | while (j < n) do |
|---|
| 33 | mem0[o] := (j,random(rt2)) |
|---|
| 34 | (* Approximate Bernoulli interarrival with Poisson *) |
|---|
| 35 | ii = 1 + narrow |\lambda_inv log random(1.0)/| |
|---|
| 36 | j += ii |
|---|
| 37 | o += 1 |
|---|
| 38 | end |
|---|
| 39 | SparseVector[\RR64,n\](trim(mem0,o)) |
|---|
| 40 | end |
|---|
| 41 | l = Csr[\RR64,n,n\](array1[\SparseVector[\RR64,n\],n\](row)) |
|---|
| 42 | (* We multiply by the transpose and hope the result is positive-definite. |
|---|
| 43 | It will be with high probability. *) |
|---|
| 44 | l l.t() |
|---|
| 45 | end |
|---|
| 46 | |
|---|
| 47 | mkVector[\nat n\]() : RR64[n] = do |
|---|
| 48 | f(i): RR64 = random(4.0)-2.0 |
|---|
| 49 | array1[\RR64,n\](f) |
|---|
| 50 | end |
|---|
| 51 | |
|---|
| 52 | testSparse[\nat n\](A: Csr[\RR64,n,n\]) = do |
|---|
| 53 | D = matrix[\RR64,n,n\]().assign(A) |
|---|
| 54 | if D=/=A then |
|---|
| 55 | println("FAIL: dense =/= sparse" // "D" D // "A" A) |
|---|
| 56 | else |
|---|
| 57 | println("dense OK") |
|---|
| 58 | end |
|---|
| 59 | A2 = identity[\Csr[\RR64,n,n\]\](A A.t()) |
|---|
| 60 | D2 = D D.t() |
|---|
| 61 | if D2=/=A2 then |
|---|
| 62 | println("FAIL: dense^2 =/= sparse^2" // "D^2" D2 // "A^2" A2) |
|---|
| 63 | else |
|---|
| 64 | println("dense^2 OK") |
|---|
| 65 | end |
|---|
| 66 | v = mkVector[\n\]() |
|---|
| 67 | Av = A v |
|---|
| 68 | Dv = D v |
|---|
| 69 | (* Small variations may occur based on summation order for dot |
|---|
| 70 | product. *) |
|---|
| 71 | if ||Dv - Av|| > 0.000000000001 then |
|---|
| 72 | println("Fail: Dv =/= Av" // "Dv = " Dv // "Av = " Av) |
|---|
| 73 | else |
|---|
| 74 | println("Dv OK") |
|---|
| 75 | end |
|---|
| 76 | end |
|---|
| 77 | |
|---|
| 78 | (************************************************************) |
|---|
| 79 | |
|---|
| 80 | (* conjGrad returns the approximate solution z to the linear equation: |
|---|
| 81 | * A z = x |
|---|
| 82 | * along with the approximate cartesian error of the solution. This |
|---|
| 83 | * method is considered superior to LU decomposition when A is |
|---|
| 84 | * sparse, symmetric, and positive-definite. *) |
|---|
| 85 | conjGrad[\Elt extends Number, nat N, |
|---|
| 86 | Vec extends Vector[\Elt,N\], |
|---|
| 87 | Mat extends Matrix[\Elt,N,N\]\] |
|---|
| 88 | (A: Mat, x: Vec): (Vec, RR64) = do |
|---|
| 89 | cgit_max = 25 |
|---|
| 90 | z: Vec := x.replica[\Elt\]().fill(0) |
|---|
| 91 | r: Vec := x |
|---|
| 92 | p: Vec := r |
|---|
| 93 | rho: Elt := r DOT r |
|---|
| 94 | for j <- seq(1#cgit_max) do |
|---|
| 95 | q = A p |
|---|
| 96 | alpha = rho / (p DOT q) |
|---|
| 97 | z += alpha p |
|---|
| 98 | rho0 = rho |
|---|
| 99 | r -= alpha q |
|---|
| 100 | rho := r DOT r |
|---|
| 101 | beta = rho / rho0 |
|---|
| 102 | p := r + beta p |
|---|
| 103 | println("Iter " j " alpha = " alpha // "z" z) |
|---|
| 104 | end |
|---|
| 105 | (z, ||x - A z||) |
|---|
| 106 | end |
|---|
| 107 | |
|---|
| 108 | (************************************************************) |
|---|
| 109 | |
|---|
| 110 | run():() = do |
|---|
| 111 | testSparse(mkMatrix[\16\]()) |
|---|
| 112 | A = mkMatrix[\50\]() |
|---|
| 113 | v = mkVector[\50\]() |
|---|
| 114 | println(A) |
|---|
| 115 | println("v" v) |
|---|
| 116 | (s,e) = conjGrad[\RR64,50,Vector[\RR64,50\],Matrix[\RR64,50,50\]\](A,v) |
|---|
| 117 | println("s" s) |
|---|
| 118 | println("Error = " e) |
|---|
| 119 | end |
|---|
| 120 | |
|---|
| 121 | end |
|---|