github.com/gopherd/gonum@v0.0.4/mathext/internal/amos/amos_test.go (about) 1 // Copyright ©2016 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package amos 6 7 import ( 8 "math" 9 "runtime" 10 "strconv" 11 "testing" 12 13 "math/rand" 14 15 "github.com/gopherd/gonum/floats/scalar" 16 ) 17 18 type input struct { 19 x []float64 20 is []int 21 kode int 22 id int 23 yr []float64 24 yi []float64 25 n int 26 tol float64 27 } 28 29 func randnum(rnd *rand.Rand) float64 { 30 r := 2e2 // Fortran has infinite loop if this is set higher than 2e3 31 if rnd.Float64() > 0.99 { 32 return 0 33 } 34 return rnd.Float64()*r - r/2 35 } 36 37 func randInput(rnd *rand.Rand) input { 38 x := make([]float64, 8) 39 for j := range x { 40 x[j] = randnum(rnd) 41 } 42 is := make([]int, 3) 43 for j := range is { 44 is[j] = rnd.Intn(1000) 45 } 46 kode := rnd.Intn(2) + 1 47 id := rnd.Intn(2) 48 n := rnd.Intn(5) + 1 49 yr := make([]float64, n+1) 50 yi := make([]float64, n+1) 51 for j := range yr { 52 yr[j] = randnum(rnd) 53 yi[j] = randnum(rnd) 54 } 55 tol := 1e-14 56 57 return input{ 58 x, is, kode, id, yr, yi, n, tol, 59 } 60 } 61 62 const nInputs = 100000 63 64 func TestAiry(t *testing.T) { 65 t.Parallel() 66 rnd := rand.New(rand.NewSource(1)) 67 for i := 0; i < nInputs; i++ { 68 in := randInput(rnd) 69 zairytest(t, in.x, in.kode, in.id) 70 } 71 } 72 73 func TestZacai(t *testing.T) { 74 t.Parallel() 75 switch runtime.GOARCH { 76 case "arm64": 77 t.Skipf("skipping on GOARCH=%s", runtime.GOARCH) 78 } 79 rnd := rand.New(rand.NewSource(1)) 80 for i := 0; i < nInputs; i++ { 81 in := randInput(rnd) 82 zacaitest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) 83 } 84 } 85 86 func TestZbknu(t *testing.T) { 87 t.Parallel() 88 rnd := rand.New(rand.NewSource(1)) 89 for i := 0; i < nInputs; i++ { 90 in := randInput(rnd) 91 zbknutest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) 92 } 93 } 94 95 func TestZasyi(t *testing.T) { 96 t.Parallel() 97 rnd := rand.New(rand.NewSource(1)) 98 for i := 0; i < nInputs; i++ { 99 in := randInput(rnd) 100 zasyitest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) 101 } 102 } 103 104 func TestZseri(t *testing.T) { 105 t.Parallel() 106 switch runtime.GOARCH { 107 case "arm64": 108 t.Skipf("skipping on GOARCH=%s", runtime.GOARCH) 109 } 110 rnd := rand.New(rand.NewSource(1)) 111 for i := 0; i < nInputs; i++ { 112 in := randInput(rnd) 113 zseritest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) 114 } 115 } 116 117 func TestZmlri(t *testing.T) { 118 t.Parallel() 119 rnd := rand.New(rand.NewSource(1)) 120 for i := 0; i < nInputs; i++ { 121 in := randInput(rnd) 122 zmlritest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi, in.kode) 123 } 124 } 125 126 func TestZkscl(t *testing.T) { 127 t.Parallel() 128 rnd := rand.New(rand.NewSource(1)) 129 for i := 0; i < nInputs; i++ { 130 in := randInput(rnd) 131 zkscltest(t, in.x, in.is, in.tol, in.n, in.yr, in.yi) 132 } 133 } 134 135 func TestZuchk(t *testing.T) { 136 t.Parallel() 137 rnd := rand.New(rand.NewSource(1)) 138 for i := 0; i < nInputs; i++ { 139 in := randInput(rnd) 140 zuchktest(t, in.x, in.is, in.tol) 141 } 142 } 143 144 func TestZs1s2(t *testing.T) { 145 t.Parallel() 146 rnd := rand.New(rand.NewSource(1)) 147 for i := 0; i < nInputs; i++ { 148 in := randInput(rnd) 149 zs1s2test(t, in.x, in.is) 150 } 151 } 152 153 func zs1s2test(t *testing.T, x []float64, is []int) { 154 155 type data struct { 156 ZRR, ZRI, S1R, S1I, S2R, S2I float64 157 NZ int 158 ASCLE, ALIM float64 159 IUF int 160 } 161 162 input := data{ 163 x[0], x[1], x[2], x[3], x[4], x[5], 164 is[0], 165 x[6], x[7], 166 is[1], 167 } 168 169 zr := complex(input.ZRR, input.ZRI) 170 s1 := complex(input.S1R, input.S1I) 171 s2 := complex(input.S2R, input.S2I) 172 impl := func(input data) data { 173 s1, s2, nz, iuf := Zs1s2(zr, s1, s2, input.ASCLE, input.ALIM, input.IUF) 174 zrr := real(zr) 175 zri := imag(zr) 176 s1r := real(s1) 177 s1i := imag(s1) 178 s2r := real(s2) 179 s2i := imag(s2) 180 alim := input.ALIM 181 ascle := input.ASCLE 182 return data{zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf} 183 } 184 185 comp := func(input data) data { 186 zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf := 187 zs1s2Orig(input.ZRR, input.ZRI, input.S1R, input.S1I, input.S2R, input.S2I, input.NZ, input.ASCLE, input.ALIM, input.IUF) 188 return data{zrr, zri, s1r, s1i, s2r, s2i, nz, ascle, alim, iuf} 189 } 190 191 oi := impl(input) 192 oc := comp(input) 193 194 sameF64(t, "zs1s2 zrr", oc.ZRR, oi.ZRR) 195 sameF64(t, "zs1s2 zri", oc.ZRI, oi.ZRI) 196 sameF64(t, "zs1s2 s1r", oc.S1R, oi.S1R) 197 sameF64(t, "zs1s2 s1i", oc.S1I, oi.S1I) 198 sameF64(t, "zs1s2 s2r", oc.S2R, oi.S2R) 199 sameF64(t, "zs1s2 s2i", oc.S2I, oi.S2I) 200 sameF64(t, "zs1s2 ascle", oc.ASCLE, oi.ASCLE) 201 sameF64(t, "zs1s2 alim", oc.ALIM, oi.ALIM) 202 sameInt(t, "iuf", oc.IUF, oi.IUF) 203 sameInt(t, "nz", oc.NZ, oi.NZ) 204 } 205 206 func zuchktest(t *testing.T, x []float64, is []int, tol float64) { 207 YR := x[0] 208 YI := x[1] 209 NZ := is[0] 210 ASCLE := x[2] 211 TOL := tol 212 213 YRfort, YIfort, NZfort, ASCLEfort, TOLfort := zuchkOrig(YR, YI, NZ, ASCLE, TOL) 214 y := complex(YR, YI) 215 NZamos := Zuchk(y, ASCLE, TOL) 216 YRamos := real(y) 217 YIamos := imag(y) 218 ASCLEamos := ASCLE 219 TOLamos := TOL 220 221 sameF64(t, "zuchk yr", YRfort, YRamos) 222 sameF64(t, "zuchk yi", YIfort, YIamos) 223 sameInt(t, "zuchk nz", NZfort, NZamos) 224 sameF64(t, "zuchk ascle", ASCLEfort, ASCLEamos) 225 sameF64(t, "zuchk tol", TOLfort, TOLamos) 226 } 227 228 func zkscltest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64) { 229 ZRR := x[0] 230 ZRI := x[1] 231 FNU := x[2] 232 NZ := is[1] 233 ELIM := x[3] 234 ASCLE := x[4] 235 RZR := x[6] 236 RZI := x[7] 237 238 yrfort := make([]float64, len(yr)) 239 copy(yrfort, yr) 240 yifort := make([]float64, len(yi)) 241 copy(yifort, yi) 242 ZRRfort, ZRIfort, FNUfort, Nfort, YRfort, YIfort, NZfort, RZRfort, RZIfort, ASCLEfort, TOLfort, ELIMfort := 243 zksclOrig(ZRR, ZRI, FNU, n, yrfort, yifort, NZ, RZR, RZI, ASCLE, tol, ELIM) 244 245 yramos := make([]float64, len(yr)) 246 copy(yramos, yr) 247 yiamos := make([]float64, len(yi)) 248 copy(yiamos, yi) 249 ZRRamos, ZRIamos, FNUamos, Namos, YRamos, YIamos, NZamos, RZRamos, RZIamos, ASCLEamos, TOLamos, ELIMamos := 250 Zkscl(ZRR, ZRI, FNU, n, yramos, yiamos, RZR, RZI, ASCLE, tol, ELIM) 251 252 sameF64(t, "zkscl zrr", ZRRfort, ZRRamos) 253 sameF64(t, "zkscl zri", ZRIfort, ZRIamos) 254 sameF64(t, "zkscl fnu", FNUfort, FNUamos) 255 sameInt(t, "zkscl n", Nfort, Namos) 256 sameInt(t, "zkscl nz", NZfort, NZamos) 257 sameF64(t, "zkscl rzr", RZRfort, RZRamos) 258 sameF64(t, "zkscl rzi", RZIfort, RZIamos) 259 sameF64(t, "zkscl ascle", ASCLEfort, ASCLEamos) 260 sameF64(t, "zkscl tol", TOLfort, TOLamos) 261 sameF64(t, "zkscl elim", ELIMfort, ELIMamos) 262 263 sameF64SApprox(t, "zkscl yr", YRfort, YRamos, 1e-14) 264 sameF64SApprox(t, "zkscl yi", YIfort, YIamos, 1e-14) 265 } 266 267 func zmlritest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { 268 ZR := x[0] 269 ZI := x[1] 270 FNU := x[2] 271 KODE := kode 272 NZ := is[1] 273 274 yrfort := make([]float64, len(yr)) 275 copy(yrfort, yr) 276 yifort := make([]float64, len(yi)) 277 copy(yifort, yi) 278 ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort := 279 zmlriOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol) 280 281 yramos := make([]float64, len(yr)) 282 copy(yramos, yr) 283 yiamos := make([]float64, len(yi)) 284 copy(yiamos, yi) 285 ZRamos, ZIamos, FNUamos, KODEamos, Namos, YRamos, YIamos, NZamos, TOLamos := 286 Zmlri(ZR, ZI, FNU, KODE, n, yramos, yiamos, tol) 287 288 sameF64(t, "zmlri zr", ZRfort, ZRamos) 289 sameF64(t, "zmlri zi", ZIfort, ZIamos) 290 sameF64(t, "zmlri fnu", FNUfort, FNUamos) 291 sameInt(t, "zmlri kode", KODEfort, KODEamos) 292 sameInt(t, "zmlri n", Nfort, Namos) 293 sameInt(t, "zmlri nz", NZfort, NZamos) 294 sameF64(t, "zmlri tol", TOLfort, TOLamos) 295 296 sameF64S(t, "zmlri yr", YRfort, YRamos) 297 sameF64S(t, "zmlri yi", YIfort, YIamos) 298 } 299 300 func zseritest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { 301 ZR := x[0] 302 ZI := x[1] 303 FNU := x[2] 304 KODE := kode 305 NZ := is[1] 306 ELIM := x[3] 307 ALIM := x[4] 308 309 yrfort := make([]float64, len(yr)) 310 copy(yrfort, yr) 311 yifort := make([]float64, len(yi)) 312 copy(yifort, yi) 313 ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort, ELIMfort, ALIMfort := 314 zseriOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) 315 316 yramos := make([]float64, len(yr)) 317 copy(yramos, yr) 318 yiamos := make([]float64, len(yi)) 319 copy(yiamos, yi) 320 y := make([]complex128, len(yramos)) 321 for i, v := range yramos { 322 y[i] = complex(v, yiamos[i]) 323 } 324 z := complex(ZR, ZI) 325 326 NZamos := Zseri(z, FNU, KODE, n, y[1:], tol, ELIM, ALIM) 327 328 ZRamos := real(z) 329 ZIamos := imag(z) 330 FNUamos := FNU 331 KODEamos := KODE 332 Namos := n 333 TOLamos := tol 334 ELIMamos := ELIM 335 ALIMamos := ALIM 336 YRamos := make([]float64, len(y)) 337 YIamos := make([]float64, len(y)) 338 for i, v := range y { 339 YRamos[i] = real(v) 340 YIamos[i] = imag(v) 341 } 342 343 sameF64(t, "zseri zr", ZRfort, ZRamos) 344 sameF64(t, "zseri zi", ZIfort, ZIamos) 345 sameF64(t, "zseri fnu", FNUfort, FNUamos) 346 sameInt(t, "zseri kode", KODEfort, KODEamos) 347 sameInt(t, "zseri n", Nfort, Namos) 348 sameInt(t, "zseri nz", NZfort, NZamos) 349 sameF64(t, "zseri tol", TOLfort, TOLamos) 350 sameF64(t, "zseri elim", ELIMfort, ELIMamos) 351 sameF64(t, "zseri elim", ALIMfort, ALIMamos) 352 353 sameF64SApprox(t, "zseri yr", YRfort, YRamos, 1e-9) 354 sameF64SApprox(t, "zseri yi", YIfort, YIamos, 1e-10) 355 } 356 357 func zasyitest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { 358 ZR := x[0] 359 ZI := x[1] 360 FNU := x[2] 361 KODE := kode 362 NZ := is[1] 363 ELIM := x[3] 364 ALIM := x[4] 365 RL := x[5] 366 367 yrfort := make([]float64, len(yr)) 368 copy(yrfort, yr) 369 yifort := make([]float64, len(yi)) 370 copy(yifort, yi) 371 ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, RLfort, TOLfort, ELIMfort, ALIMfort := 372 zasyiOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, RL, tol, ELIM, ALIM) 373 374 yramos := make([]float64, len(yr)) 375 copy(yramos, yr) 376 yiamos := make([]float64, len(yi)) 377 copy(yiamos, yi) 378 ZRamos, ZIamos, FNUamos, KODEamos, Namos, YRamos, YIamos, NZamos, RLamos, TOLamos, ELIMamos, ALIMamos := 379 Zasyi(ZR, ZI, FNU, KODE, n, yramos, yiamos, RL, tol, ELIM, ALIM) 380 381 sameF64(t, "zasyi zr", ZRfort, ZRamos) 382 sameF64(t, "zasyi zr", ZIfort, ZIamos) 383 sameF64(t, "zasyi fnu", FNUfort, FNUamos) 384 sameInt(t, "zasyi kode", KODEfort, KODEamos) 385 sameInt(t, "zasyi n", Nfort, Namos) 386 sameInt(t, "zasyi nz", NZfort, NZamos) 387 sameF64(t, "zasyi rl", RLfort, RLamos) 388 sameF64(t, "zasyi tol", TOLfort, TOLamos) 389 sameF64(t, "zasyi elim", ELIMfort, ELIMamos) 390 sameF64(t, "zasyi alim", ALIMfort, ALIMamos) 391 392 sameF64SApprox(t, "zasyi yr", YRfort, YRamos, 1e-12) 393 sameF64SApprox(t, "zasyi yi", YIfort, YIamos, 1e-12) 394 } 395 396 func zbknutest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { 397 ZR := x[0] 398 ZI := x[1] 399 FNU := x[2] 400 KODE := kode 401 NZ := is[1] 402 ELIM := x[3] 403 ALIM := x[4] 404 405 yrfort := make([]float64, len(yr)) 406 copy(yrfort, yr) 407 yifort := make([]float64, len(yi)) 408 copy(yifort, yi) 409 ZRfort, ZIfort, FNUfort, KODEfort, Nfort, YRfort, YIfort, NZfort, TOLfort, ELIMfort, ALIMfort := 410 zbknuOrig(ZR, ZI, FNU, KODE, n, yrfort, yifort, NZ, tol, ELIM, ALIM) 411 412 yramos := make([]float64, len(yr)) 413 copy(yramos, yr) 414 yiamos := make([]float64, len(yi)) 415 copy(yiamos, yi) 416 ZRamos, ZIamos, FNUamos, KODEamos, Namos, YRamos, YIamos, NZamos, TOLamos, ELIMamos, ALIMamos := 417 Zbknu(ZR, ZI, FNU, KODE, n, yramos, yiamos, tol, ELIM, ALIM) 418 419 sameF64(t, "zbknu zr", ZRfort, ZRamos) 420 sameF64(t, "zbknu zr", ZIfort, ZIamos) 421 sameF64(t, "zbknu fnu", FNUfort, FNUamos) 422 sameInt(t, "zbknu kode", KODEfort, KODEamos) 423 sameInt(t, "zbknu n", Nfort, Namos) 424 sameInt(t, "zbknu nz", NZfort, NZamos) 425 sameF64(t, "zbknu tol", TOLfort, TOLamos) 426 sameF64(t, "zbknu elim", ELIMfort, ELIMamos) 427 sameF64(t, "zbknu alim", ALIMfort, ALIMamos) 428 429 sameF64SApprox(t, "zbknu yr", YRfort, YRamos, 1e-12) 430 sameF64SApprox(t, "zbknu yi", YIfort, YIamos, 1e-12) 431 } 432 433 func zairytest(t *testing.T, x []float64, kode, id int) { 434 ZR := x[0] 435 ZI := x[1] 436 KODE := kode 437 ID := id 438 439 AIRfort, AIIfort, NZfort, IERRfort := zairyOrig(ZR, ZI, ID, KODE) 440 AIRamos, AIIamos, NZamos, IERRamos := Zairy(ZR, ZI, ID, KODE) 441 442 sameF64Approx(t, "zairy air", AIRfort, AIRamos, 1e-12) 443 sameF64Approx(t, "zairy aii", AIIfort, AIIamos, 1e-12) 444 sameInt(t, "zairy nz", NZfort, NZamos) 445 sameInt(t, "zairy ierr", IERRfort, IERRamos) 446 } 447 448 func zacaitest(t *testing.T, x []float64, is []int, tol float64, n int, yr, yi []float64, kode int) { 449 ZR := x[0] 450 ZI := x[1] 451 FNU := x[2] 452 KODE := kode 453 NZ := is[1] 454 MR := is[2] 455 ELIM := x[3] 456 ALIM := x[4] 457 RL := x[5] 458 459 yrfort := make([]float64, len(yr)) 460 copy(yrfort, yr) 461 yifort := make([]float64, len(yi)) 462 copy(yifort, yi) 463 ZRfort, ZIfort, FNUfort, KODEfort, MRfort, Nfort, YRfort, YIfort, NZfort, RLfort, TOLfort, ELIMfort, ALIMfort := 464 zacaiOrig(ZR, ZI, FNU, KODE, MR, n, yrfort, yifort, NZ, RL, tol, ELIM, ALIM) 465 466 yramos := make([]float64, len(yr)) 467 copy(yramos, yr) 468 yiamos := make([]float64, len(yi)) 469 copy(yiamos, yi) 470 ZRamos, ZIamos, FNUamos, KODEamos, MRamos, Namos, YRamos, YIamos, NZamos, RLamos, TOLamos, ELIMamos, ALIMamos := 471 Zacai(ZR, ZI, FNU, KODE, MR, n, yramos, yiamos, RL, tol, ELIM, ALIM) 472 473 sameF64(t, "zacai zr", ZRfort, ZRamos) 474 sameF64(t, "zacai zi", ZIfort, ZIamos) 475 sameF64(t, "zacai fnu", FNUfort, FNUamos) 476 sameInt(t, "zacai kode", KODEfort, KODEamos) 477 sameInt(t, "zacai mr", MRfort, MRamos) 478 sameInt(t, "zacai n", Nfort, Namos) 479 sameInt(t, "zacai nz", NZfort, NZamos) 480 sameF64(t, "zacai rl", RLfort, RLamos) 481 sameF64(t, "zacai tol", TOLfort, TOLamos) 482 sameF64(t, "zacai elim", ELIMfort, ELIMamos) 483 sameF64(t, "zacai elim", ALIMfort, ALIMamos) 484 485 sameF64SApprox(t, "zacai yr", YRfort, YRamos, 1e-12) 486 sameF64SApprox(t, "zacai yi", YIfort, YIamos, 1e-12) 487 } 488 489 func sameF64(t *testing.T, str string, c, native float64) { 490 t.Helper() 491 if math.IsNaN(c) && math.IsNaN(native) { 492 return 493 } 494 if c == native { 495 return 496 } 497 cb := math.Float64bits(c) 498 nb := math.Float64bits(native) 499 t.Errorf("Case %s: Float64 mismatch. c = %v, native = %v\n cb: %v, nb: %v\n", str, c, native, cb, nb) 500 } 501 502 func sameF64Approx(t *testing.T, str string, c, native, tol float64) { 503 t.Helper() 504 if math.IsNaN(c) && math.IsNaN(native) { 505 return 506 } 507 if scalar.EqualWithinAbsOrRel(c, native, tol, tol) { 508 return 509 } 510 // Have a much looser tolerance for correctness when the values are large. 511 // Floating point noise makes the relative tolerance difference greater for 512 // higher values. 513 if c > 1e200 && scalar.EqualWithinAbsOrRel(c, native, 10, 10) { 514 return 515 } 516 cb := math.Float64bits(c) 517 nb := math.Float64bits(native) 518 t.Errorf("Case %s: Float64 mismatch. c = %v, native = %v\n cb: %v, nb: %v\n", str, c, native, cb, nb) 519 } 520 521 func sameInt(t *testing.T, str string, c, native int) { 522 t.Helper() 523 if c != native { 524 t.Errorf("Case %s: Int mismatch. c = %v, native = %v.", str, c, native) 525 } 526 } 527 528 func sameF64S(t *testing.T, str string, c, native []float64) { 529 t.Helper() 530 if len(c) != len(native) { 531 panic(str) 532 } 533 for i, v := range c { 534 sameF64(t, str+"_idx_"+strconv.Itoa(i), v, native[i]) 535 } 536 } 537 538 func sameF64SApprox(t *testing.T, str string, c, native []float64, tol float64) { 539 t.Helper() 540 if len(c) != len(native) { 541 panic(str) 542 } 543 for i, v := range c { 544 sameF64Approx(t, str+"_idx_"+strconv.Itoa(i), v, native[i], tol) 545 } 546 }