| 1 | (******************************************************************************* |
|---|
| 2 | This program is copyrighted free software by Kento Emoto |
|---|
| 3 | <emoto[at]ipl.t.u-tokyo.ac.jp> developed under the collaborative |
|---|
| 4 | research on Fortress Programming Language between Sun Microsystems, |
|---|
| 5 | Inc. and the University of Tokyo. |
|---|
| 6 | |
|---|
| 7 | You can redistribute it and/or modify it under the following |
|---|
| 8 | BSD-style license or the Sun Contributor Agreement that Kento Emoto signed. |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | Copyright 2009 by Kento Emoto |
|---|
| 12 | All rights reserved. |
|---|
| 13 | |
|---|
| 14 | Redistribution and use in source and binary forms, with or without |
|---|
| 15 | modification, are permitted provided that the following conditions |
|---|
| 16 | are met: |
|---|
| 17 | |
|---|
| 18 | * Redistributions of source code must retain the above copyright |
|---|
| 19 | notice, this list of conditions and the following disclaimer. |
|---|
| 20 | * Redistributions in binary form must reproduce the above copyright |
|---|
| 21 | notice, this list of conditions and the following disclaimer |
|---|
| 22 | in the documentation and/or other materials provided with the |
|---|
| 23 | distribution. |
|---|
| 24 | * Neither the name of Kento Emoto nor the names of its |
|---|
| 25 | contributors may be used to endorse or promote products derived |
|---|
| 26 | from this software without specific prior written permission. |
|---|
| 27 | |
|---|
| 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|---|
| 29 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|---|
| 30 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|---|
| 31 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|---|
| 32 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|---|
| 33 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|---|
| 34 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
|---|
| 35 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|---|
| 36 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|---|
| 37 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|---|
| 38 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 39 | |
|---|
| 40 | |
|---|
| 41 | ******************************************************************************) |
|---|
| 42 | |
|---|
| 43 | (* |
|---|
| 44 | |
|---|
| 45 | This program is modified from the BiCGSTAB.fss to use zero-based |
|---|
| 46 | indexing and algebraic operations on vectors. It is important to use |
|---|
| 47 | vector operations for efficiency, as well as readability or |
|---|
| 48 | maintainability. |
|---|
| 49 | |
|---|
| 50 | This program is still naive because it has many code duplications and |
|---|
| 51 | naive codes for vector operations. You can improve readability and |
|---|
| 52 | reusability using nice notations provided by Fortress and its library. |
|---|
| 53 | |
|---|
| 54 | *) |
|---|
| 55 | |
|---|
| 56 | component BiCGSTAB2 |
|---|
| 57 | |
|---|
| 58 | export Executable |
|---|
| 59 | |
|---|
| 60 | run(args : String...) : () = do |
|---|
| 61 | println("BiCGSTAB") |
|---|
| 62 | testrun[\16,16,16\](); |
|---|
| 63 | (*testrun[\2,2,2\]();*) |
|---|
| 64 | end |
|---|
| 65 | |
|---|
| 66 | (* Makes sample matrix A and vector b s.t. the answer of A x = b is x = 1 . *) |
|---|
| 67 | initilization[\nat imax, nat jmax, nat kmax\]() = |
|---|
| 68 | do |
|---|
| 69 | (* those allocations of vectors should be factored out as calls of a function *) |
|---|
| 70 | Ap = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 71 | Ae = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 72 | Aw = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 73 | An = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 74 | As = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 75 | At = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 76 | Ab = array3[\RR64, imax, jmax, kmax\]() |
|---|
| 77 | Ap.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 2.0) |
|---|
| 78 | Ae.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 1.0) |
|---|
| 79 | Aw.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 1.0) |
|---|
| 80 | An.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 1.0) |
|---|
| 81 | As.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 1.0) |
|---|
| 82 | At.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 1.0) |
|---|
| 83 | Ab.fill(fn (i:ZZ32,j:ZZ32,k:ZZ32):RR64 => 1.0) |
|---|
| 84 | |
|---|
| 85 | for j <- 0#jmax do |
|---|
| 86 | for k <- 0#kmax do |
|---|
| 87 | Aw[0,j,k] := 0.0 |
|---|
| 88 | Ae[imax-1,j,k] := 0.0 |
|---|
| 89 | end |
|---|
| 90 | end |
|---|
| 91 | for i <- 0#imax do |
|---|
| 92 | for k <- 0#kmax do |
|---|
| 93 | As[i,0,k] := 0.0 |
|---|
| 94 | An[i,jmax-1,k] := 0.0 |
|---|
| 95 | end |
|---|
| 96 | end |
|---|
| 97 | for i <- 0#imax do |
|---|
| 98 | for j <- 0#jmax do |
|---|
| 99 | Ab[i,j,0] := 0.0 |
|---|
| 100 | At[i,j,kmax-1] := 0.0 |
|---|
| 101 | end |
|---|
| 102 | end |
|---|
| 103 | |
|---|
| 104 | (* PrintMatrix[\imax,jmax,kmax\](Ap, Ae, Aw, An, As, At, Ab) *) |
|---|
| 105 | |
|---|
| 106 | (* |
|---|
| 107 | oops! we cant use negative indices! ... nat is only for non-negative... |
|---|
| 108 | b = array1[\RR64, imax jmax kmax + 2 jmax imax\]().shift( - jmax imax) |
|---|
| 109 | c = array1[\RR64, imax jmax kmax + 2 jmax imax\]().shift( - jmax imax) |
|---|
| 110 | |
|---|
| 111 | i will shift them in the product loop. |
|---|
| 112 | *) |
|---|
| 113 | |
|---|
| 114 | b = array1[\RR64, (imax jmax kmax) + (2 jmax imax)\]() |
|---|
| 115 | x = array1[\RR64, (imax jmax kmax) + (2 jmax imax)\]() |
|---|
| 116 | |
|---|
| 117 | x.fill(fn (i:ZZ32):RR64 => 0.0) |
|---|
| 118 | b.fill(fn (i:ZZ32):RR64 => 0.0) |
|---|
| 119 | |
|---|
| 120 | for i <- 0#imax do |
|---|
| 121 | for j <- 0#jmax do |
|---|
| 122 | for k <- 0#kmax do |
|---|
| 123 | m = i + imax j + imax jmax k + imax jmax |
|---|
| 124 | b[m] := 2.0 |
|---|
| 125 | if (i>0) AND (i<imax-1) then |
|---|
| 126 | b[m] := b[m] + 2.0 |
|---|
| 127 | else |
|---|
| 128 | b[m] := b[m] + 1.0 |
|---|
| 129 | end |
|---|
| 130 | |
|---|
| 131 | if (j>0) AND (j<jmax-1) then |
|---|
| 132 | b[m] := b[m] + 2.0 |
|---|
| 133 | else |
|---|
| 134 | b[m] := b[m] + 1.0 |
|---|
| 135 | end |
|---|
| 136 | |
|---|
| 137 | if (k>0) AND (k<kmax-1) then |
|---|
| 138 | b[m] := b[m] + 2.0 |
|---|
| 139 | else |
|---|
| 140 | b[m] := b[m] + 1.0 |
|---|
| 141 | end |
|---|
| 142 | end |
|---|
| 143 | end |
|---|
| 144 | end |
|---|
| 145 | (* the answer of Ax=b is x = 1. *) |
|---|
| 146 | (Ap, Ae, Aw, An, As, At, Ab, b, x) |
|---|
| 147 | end |
|---|
| 148 | (* A sample driver for the BiCGSTAB method. *) |
|---|
| 149 | testrun[\nat imax, nat jmax, nat kmax\]() : () = |
|---|
| 150 | do |
|---|
| 151 | (Ap, Ae, Aw, An, As, At, Ab, b, x) = initilization[\imax, jmax, kmax\]() |
|---|
| 152 | (* |
|---|
| 153 | PrintVector[\imax, jmax, kmax\](b) |
|---|
| 154 | PrintMatrixVector[\imax, jmax, kmax\](Ap, Ae, Aw, An, As, At, Ab, b) |
|---|
| 155 | MatrixVectorProduct[\imax, jmax, kmax\](Ap, Ae, Aw, An, As, At, Ab, b, x) |
|---|
| 156 | PrintVector[\imax, jmax, kmax\](x) |
|---|
| 157 | *) |
|---|
| 158 | |
|---|
| 159 | st = nanoTime() |
|---|
| 160 | BiCGSTABband[\imax, jmax, kmax\](Ap,Ae,Aw,An,As,At,Ab,x,b) |
|---|
| 161 | et = nanoTime() |
|---|
| 162 | t = et - st |
|---|
| 163 | ss = t / 1000000000.0 |
|---|
| 164 | println("elapsed time " t " ns ( " ss " s)") |
|---|
| 165 | end |
|---|
| 166 | (* Note |
|---|
| 167 | b must be of [1-imax jamx : imax jmax kmax + imax jmax] for simplicity |
|---|
| 168 | oops! we cant use negative indices for arrays!!!!!! |
|---|
| 169 | ok. i will shift the indices by + imax jmax |
|---|
| 170 | |
|---|
| 171 | conditions for sentinels |
|---|
| 172 | Aw(1,_,_) = 0 |
|---|
| 173 | Ae(imax,_,_) = 0 |
|---|
| 174 | As(_,1,_) = 0 |
|---|
| 175 | An(_,jmax,_) = 0 |
|---|
| 176 | Ab(_,_,1) = 0 |
|---|
| 177 | At(_,_,kmax) = 0 |
|---|
| 178 | |
|---|
| 179 | *) |
|---|
| 180 | (* BiCGSTAB method for band matrix A and vector b. |
|---|
| 181 | This program uses zero-based indexing |
|---|
| 182 | to use algebraic operations of vectors in Fortress. |
|---|
| 183 | *) |
|---|
| 184 | BiCGSTABband[\nat imax, nat jmax, nat kmax\](Ap,Ae,Aw,An,As,At,Ab,x2,b2) : (ZZ32, RR64) = |
|---|
| 185 | do |
|---|
| 186 | (* those allocations of vectors should be factored out as calls of a function *) |
|---|
| 187 | x : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := x2 |
|---|
| 188 | b : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b2 |
|---|
| 189 | r : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 190 | r' : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 191 | p : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 192 | y : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 193 | e : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 194 | v : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 195 | c : Vector[\RR64,(imax jmax kmax) + (2 jmax imax)\] := b.copy() |
|---|
| 196 | (* we dont need so many iterations because the matrix is a band matrix. *) |
|---|
| 197 | itrmax = imax jmax kmax |
|---|
| 198 | er0 = 1.0 10^(-4) |
|---|
| 199 | |
|---|
| 200 | MatrixVectorProduct[\imax,jmax,kmax\](Ap,Ae,Aw,An,As,At,Ab,x,c) |
|---|
| 201 | |
|---|
| 202 | (* |
|---|
| 203 | PrintVector[\imax, jmax, kmax\](x) |
|---|
| 204 | PrintMatrixVector[\imax, jmax, kmax\](Ap, Ae, Aw, An, As, At, Ab, x) |
|---|
| 205 | PrintVector[\imax, jmax, kmax\](c) |
|---|
| 206 | PrintVector[\imax, jmax, kmax\](b) |
|---|
| 207 | *) |
|---|
| 208 | |
|---|
| 209 | r := b - c |
|---|
| 210 | c1 : RR64 := r DOT r |
|---|
| 211 | |
|---|
| 212 | label MainLoop |
|---|
| 213 | if (c1 < er0) then exit MainLoop with () end |
|---|
| 214 | p := r |
|---|
| 215 | r' := r |
|---|
| 216 | |
|---|
| 217 | (* |
|---|
| 218 | PrintVector[\imax, jmax, kmax\](p) |
|---|
| 219 | PrintVector[\imax, jmax, kmax\](r') |
|---|
| 220 | *) |
|---|
| 221 | it : ZZ32 := 1 |
|---|
| 222 | rr : RR64 := 0 |
|---|
| 223 | while it <= itrmax do |
|---|
| 224 | MatrixVectorProduct[\imax,jmax,kmax\](Ap,Ae,Aw,An,As,At,Ab,p,y) |
|---|
| 225 | c2 = r' DOT y |
|---|
| 226 | alp = c1 / c2 |
|---|
| 227 | e := r - alp y |
|---|
| 228 | MatrixVectorProduct[\imax,jmax,kmax\](Ap,Ae,Aw,An,As,At,Ab,e,v) |
|---|
| 229 | ev = e DOT v |
|---|
| 230 | vv = v DOT v |
|---|
| 231 | (* We get ev=vv=0 when imax=jmax=kmax=2. Thus, we need to avoid NaN. *) |
|---|
| 232 | c3 = if (vv=0) AND (ev=0) then 1 else ev / vv end |
|---|
| 233 | x := x + alp p + c3 e |
|---|
| 234 | r := e - c3 v |
|---|
| 235 | rr := r DOT r |
|---|
| 236 | println(it " residual = " rr) |
|---|
| 237 | if (rr < er0) then exit MainLoop with (it,rr) end |
|---|
| 238 | c1 := r' DOT r |
|---|
| 239 | |
|---|
| 240 | bet = c1 / (c2 c3) |
|---|
| 241 | p := r + bet (p - c3 y) |
|---|
| 242 | |
|---|
| 243 | it += 1 |
|---|
| 244 | end |
|---|
| 245 | (it,rr) |
|---|
| 246 | end MainLoop |
|---|
| 247 | end |
|---|
| 248 | |
|---|
| 249 | |
|---|
| 250 | (* A product of a 7-band matrix and a vector. *) |
|---|
| 251 | MatrixVectorProduct[\nat imax, nat jmax, nat kmax\] |
|---|
| 252 | (Ap, Ae, Aw, An, As, At, Ab, b, c) : () = |
|---|
| 253 | do |
|---|
| 254 | for k <- 0#kmax do |
|---|
| 255 | for j <- 0#jmax do |
|---|
| 256 | for i <- 0#imax do |
|---|
| 257 | m = i + imax j + imax jmax k + imax jmax |
|---|
| 258 | c[m] := Ap[i,j,k] b[m] + Aw[i,j,k] b[m - 1] + Ae[i,j,k] b[m + 1] + As[i,j,k] b[m - imax] + An[i,j,k] b[m + imax] + Ab[i,j,k] b[m - imax jmax] + At[i,j,k] b[m + imax jmax] |
|---|
| 259 | end |
|---|
| 260 | end |
|---|
| 261 | end |
|---|
| 262 | end |
|---|
| 263 | (* A pretty printer for a 7-band matrix.*) |
|---|
| 264 | PrintMatrix[\nat imax, nat jmax, nat kmax\] |
|---|
| 265 | (Ap, Ae, Aw, An, As, At, Ab) : () = |
|---|
| 266 | do |
|---|
| 267 | for k <- seq(0#kmax) do |
|---|
| 268 | for j <- seq(0#jmax) do |
|---|
| 269 | for i <- seq(0#imax) do |
|---|
| 270 | m = i + imax j + imax jmax k (* mth row *) |
|---|
| 271 | p : ZZ32 := 0 |
|---|
| 272 | while p < imax jmax kmax do |
|---|
| 273 | v = case p of |
|---|
| 274 | m => Ap[i,j,k] |
|---|
| 275 | m - 1 => Aw[i,j,k] |
|---|
| 276 | m + 1 => Ae[i,j,k] |
|---|
| 277 | m - imax => As[i,j,k] |
|---|
| 278 | m + imax => An[i,j,k] |
|---|
| 279 | m - imax jmax => Ab[i,j,k] |
|---|
| 280 | m + imax jmax => At[i,j,k] |
|---|
| 281 | else => 0.0 |
|---|
| 282 | end |
|---|
| 283 | print(v " ") |
|---|
| 284 | p += 1 |
|---|
| 285 | end |
|---|
| 286 | println() |
|---|
| 287 | end |
|---|
| 288 | end |
|---|
| 289 | end |
|---|
| 290 | end |
|---|
| 291 | |
|---|
| 292 | (* A pretty printer for a vector (an array). *) |
|---|
| 293 | PrintVector[\nat imax, nat jmax, nat kmax\] |
|---|
| 294 | (s, b) : () = |
|---|
| 295 | do |
|---|
| 296 | print(s " : ") |
|---|
| 297 | PrintVector[\imax, jmax, kmax\](b) |
|---|
| 298 | end |
|---|
| 299 | |
|---|
| 300 | (* A pretty printer for a vector (an array). *) |
|---|
| 301 | PrintVector[\nat imax, nat jmax, nat kmax\] |
|---|
| 302 | (b) : () = |
|---|
| 303 | do |
|---|
| 304 | for k <- seq(0#kmax) do |
|---|
| 305 | for j <- seq(0#jmax) do |
|---|
| 306 | for i <- seq(0#imax) do |
|---|
| 307 | m = i + imax j + imax jmax k + imax jmax (* mth row *) |
|---|
| 308 | print(b[m] " ") |
|---|
| 309 | end |
|---|
| 310 | end |
|---|
| 311 | end |
|---|
| 312 | println() |
|---|
| 313 | end |
|---|
| 314 | |
|---|
| 315 | (* A pretty printer for the pair of a 7-band matrix and a vector (an array). *) |
|---|
| 316 | PrintMatrixVector[\nat imax, nat jmax, nat kmax\] |
|---|
| 317 | (Ap, Ae, Aw, An, As, At, Ab, b) : () = |
|---|
| 318 | do |
|---|
| 319 | for k <- seq(0#kmax) do |
|---|
| 320 | for j <- seq(0#jmax) do |
|---|
| 321 | for i <- seq(0#imax) do |
|---|
| 322 | m = i + imax j + imax jmax k (* mth row *) |
|---|
| 323 | p : ZZ32 := 0 |
|---|
| 324 | while p < imax jmax kmax do |
|---|
| 325 | v = case p of |
|---|
| 326 | m => Ap[i,j,k] |
|---|
| 327 | m - 1 => Aw[i,j,k] |
|---|
| 328 | m + 1 => Ae[i,j,k] |
|---|
| 329 | m - imax => As[i,j,k] |
|---|
| 330 | m + imax => An[i,j,k] |
|---|
| 331 | m - imax jmax => Ab[i,j,k] |
|---|
| 332 | m + imax jmax => At[i,j,k] |
|---|
| 333 | else => 0.0 |
|---|
| 334 | end |
|---|
| 335 | print(v " ") |
|---|
| 336 | p += 1 |
|---|
| 337 | end |
|---|
| 338 | println(": " b[m + imax jmax]) |
|---|
| 339 | end |
|---|
| 340 | end |
|---|
| 341 | end |
|---|
| 342 | end |
|---|
| 343 | |
|---|
| 344 | |
|---|
| 345 | end |
|---|