github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/floats/floats_test.go (about) 1 // Copyright ©2013 The Gonum Authors. All rights reserved. 2 // Use of this code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package floats 6 7 import ( 8 "fmt" 9 "math" 10 "strconv" 11 "testing" 12 13 "golang.org/x/exp/rand" 14 15 "github.com/jingcheng-WU/gonum/floats/scalar" 16 ) 17 18 const ( 19 EqTolerance = 1e-14 20 Small = 10 21 Medium = 1000 22 Large = 100000 23 Huge = 10000000 24 ) 25 26 func areSlicesEqual(t *testing.T, truth, comp []float64, str string) { 27 if !EqualApprox(comp, truth, EqTolerance) { 28 t.Errorf(str+". Expected %v, returned %v", truth, comp) 29 } 30 } 31 32 func areSlicesSame(t *testing.T, truth, comp []float64, str string) { 33 ok := len(truth) == len(comp) 34 if ok { 35 for i, a := range truth { 36 if !scalar.EqualWithinAbsOrRel(a, comp[i], EqTolerance, EqTolerance) && !scalar.Same(a, comp[i]) { 37 ok = false 38 break 39 } 40 } 41 } 42 if !ok { 43 t.Errorf(str+". Expected %v, returned %v", truth, comp) 44 } 45 } 46 47 func Panics(fun func()) (b bool) { 48 defer func() { 49 err := recover() 50 if err != nil { 51 b = true 52 } 53 }() 54 fun() 55 return 56 } 57 58 func TestAdd(t *testing.T) { 59 t.Parallel() 60 a := []float64{1, 2, 3} 61 b := []float64{4, 5, 6} 62 c := []float64{7, 8, 9} 63 truth := []float64{12, 15, 18} 64 n := make([]float64, len(a)) 65 66 Add(n, a) 67 Add(n, b) 68 Add(n, c) 69 areSlicesEqual(t, truth, n, "Wrong addition of slices new receiver") 70 Add(a, b) 71 Add(a, c) 72 areSlicesEqual(t, truth, n, "Wrong addition of slices for no new receiver") 73 74 // Test that it panics 75 if !Panics(func() { Add(make([]float64, 2), make([]float64, 3)) }) { 76 t.Errorf("Did not panic with length mismatch") 77 } 78 } 79 80 func TestAddTo(t *testing.T) { 81 t.Parallel() 82 a := []float64{1, 2, 3} 83 b := []float64{4, 5, 6} 84 truth := []float64{5, 7, 9} 85 n1 := make([]float64, len(a)) 86 87 n2 := AddTo(n1, a, b) 88 areSlicesEqual(t, truth, n1, "Bad addition from mutator") 89 areSlicesEqual(t, truth, n2, "Bad addition from returned slice") 90 91 // Test that it panics 92 if !Panics(func() { AddTo(make([]float64, 2), make([]float64, 3), make([]float64, 3)) }) { 93 t.Errorf("Did not panic with length mismatch") 94 } 95 if !Panics(func() { AddTo(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { 96 t.Errorf("Did not panic with length mismatch") 97 } 98 } 99 100 func TestAddConst(t *testing.T) { 101 t.Parallel() 102 s := []float64{3, 4, 1, 7, 5} 103 c := 6.0 104 truth := []float64{9, 10, 7, 13, 11} 105 AddConst(c, s) 106 areSlicesEqual(t, truth, s, "Wrong addition of constant") 107 } 108 109 func TestAddScaled(t *testing.T) { 110 t.Parallel() 111 s := []float64{3, 4, 1, 7, 5} 112 alpha := 6.0 113 dst := []float64{1, 2, 3, 4, 5} 114 ans := []float64{19, 26, 9, 46, 35} 115 AddScaled(dst, alpha, s) 116 if !EqualApprox(dst, ans, EqTolerance) { 117 t.Errorf("Adding scaled did not match") 118 } 119 short := []float64{1} 120 if !Panics(func() { AddScaled(dst, alpha, short) }) { 121 t.Errorf("Doesn't panic if s is smaller than dst") 122 } 123 if !Panics(func() { AddScaled(short, alpha, s) }) { 124 t.Errorf("Doesn't panic if dst is smaller than s") 125 } 126 } 127 128 func TestAddScaledTo(t *testing.T) { 129 t.Parallel() 130 s := []float64{3, 4, 1, 7, 5} 131 alpha := 6.0 132 y := []float64{1, 2, 3, 4, 5} 133 dst1 := make([]float64, 5) 134 ans := []float64{19, 26, 9, 46, 35} 135 dst2 := AddScaledTo(dst1, y, alpha, s) 136 if !EqualApprox(dst1, ans, EqTolerance) { 137 t.Errorf("AddScaledTo did not match for mutator") 138 } 139 if !EqualApprox(dst2, ans, EqTolerance) { 140 t.Errorf("AddScaledTo did not match for returned slice") 141 } 142 AddScaledTo(dst1, y, alpha, s) 143 if !EqualApprox(dst1, ans, EqTolerance) { 144 t.Errorf("Reusing dst did not match") 145 } 146 short := []float64{1} 147 if !Panics(func() { AddScaledTo(dst1, y, alpha, short) }) { 148 t.Errorf("Doesn't panic if s is smaller than dst") 149 } 150 if !Panics(func() { AddScaledTo(short, y, alpha, s) }) { 151 t.Errorf("Doesn't panic if dst is smaller than s") 152 } 153 if !Panics(func() { AddScaledTo(dst1, short, alpha, s) }) { 154 t.Errorf("Doesn't panic if y is smaller than dst") 155 } 156 } 157 158 func TestArgsort(t *testing.T) { 159 t.Parallel() 160 s := []float64{3, 4, 1, 7, 5} 161 inds := make([]int, len(s)) 162 163 Argsort(s, inds) 164 165 sortedS := []float64{1, 3, 4, 5, 7} 166 trueInds := []int{2, 0, 1, 4, 3} 167 168 if !Equal(s, sortedS) { 169 t.Error("elements not sorted correctly") 170 } 171 for i := range trueInds { 172 if trueInds[i] != inds[i] { 173 t.Error("inds not correct") 174 } 175 } 176 177 inds = []int{1, 2} 178 if !Panics(func() { Argsort(s, inds) }) { 179 t.Error("does not panic if lengths do not match") 180 } 181 } 182 183 func TestCount(t *testing.T) { 184 t.Parallel() 185 s := []float64{3, 4, 1, 7, 5} 186 f := func(v float64) bool { return v > 3.5 } 187 truth := 3 188 n := Count(f, s) 189 if n != truth { 190 t.Errorf("Wrong number of elements counted") 191 } 192 } 193 194 func TestCumProd(t *testing.T) { 195 t.Parallel() 196 s := []float64{3, 4, 1, 7, 5} 197 receiver := make([]float64, len(s)) 198 result := CumProd(receiver, s) 199 truth := []float64{3, 12, 12, 84, 420} 200 areSlicesEqual(t, truth, receiver, "Wrong cumprod mutated with new receiver") 201 areSlicesEqual(t, truth, result, "Wrong cumprod result with new receiver") 202 CumProd(receiver, s) 203 areSlicesEqual(t, truth, receiver, "Wrong cumprod returned with reused receiver") 204 205 // Test that it panics 206 if !Panics(func() { CumProd(make([]float64, 2), make([]float64, 3)) }) { 207 t.Errorf("Did not panic with length mismatch") 208 } 209 210 // Test empty CumProd 211 emptyReceiver := make([]float64, 0) 212 truth = []float64{} 213 CumProd(emptyReceiver, emptyReceiver) 214 areSlicesEqual(t, truth, emptyReceiver, "Wrong cumprod returned with empty receiver") 215 } 216 217 func TestCumSum(t *testing.T) { 218 t.Parallel() 219 s := []float64{3, 4, 1, 7, 5} 220 receiver := make([]float64, len(s)) 221 result := CumSum(receiver, s) 222 truth := []float64{3, 7, 8, 15, 20} 223 areSlicesEqual(t, truth, receiver, "Wrong cumsum mutated with new receiver") 224 areSlicesEqual(t, truth, result, "Wrong cumsum returned with new receiver") 225 CumSum(receiver, s) 226 areSlicesEqual(t, truth, receiver, "Wrong cumsum returned with reused receiver") 227 228 // Test that it panics 229 if !Panics(func() { CumSum(make([]float64, 2), make([]float64, 3)) }) { 230 t.Errorf("Did not panic with length mismatch") 231 } 232 233 // Test empty CumSum 234 emptyReceiver := make([]float64, 0) 235 truth = []float64{} 236 CumSum(emptyReceiver, emptyReceiver) 237 areSlicesEqual(t, truth, emptyReceiver, "Wrong cumsum returned with empty receiver") 238 } 239 240 func TestDistance(t *testing.T) { 241 t.Parallel() 242 norms := []float64{1, 2, 4, math.Inf(1)} 243 slices := []struct { 244 s []float64 245 t []float64 246 }{ 247 { 248 nil, 249 nil, 250 }, 251 { 252 []float64{8, 9, 10, -12}, 253 []float64{8, 9, 10, -12}, 254 }, 255 { 256 []float64{1, 2, 3, -4, -5, 8}, 257 []float64{-9.2, -6.8, 9, -3, -2, 1}, 258 }, 259 } 260 261 for j, test := range slices { 262 tmp := make([]float64, len(test.s)) 263 for i, L := range norms { 264 dist := Distance(test.s, test.t, L) 265 copy(tmp, test.s) 266 Sub(tmp, test.t) 267 norm := Norm(tmp, L) 268 if dist != norm { // Use equality because they should be identical. 269 t.Errorf("Distance does not match norm for case %v, %v. Expected %v, Found %v.", i, j, norm, dist) 270 } 271 } 272 } 273 274 if !Panics(func() { Distance([]float64{}, norms, 1) }) { 275 t.Errorf("Did not panic with unequal lengths") 276 } 277 } 278 279 func TestDiv(t *testing.T) { 280 t.Parallel() 281 s1 := []float64{5, 12, 27} 282 s2 := []float64{1, 2, 3} 283 ans := []float64{5, 6, 9} 284 Div(s1, s2) 285 if !EqualApprox(s1, ans, EqTolerance) { 286 t.Errorf("Div doesn't give correct answer") 287 } 288 s1short := []float64{1} 289 if !Panics(func() { Div(s1short, s2) }) { 290 t.Errorf("Did not panic with unequal lengths") 291 } 292 s2short := []float64{1} 293 if !Panics(func() { Div(s1, s2short) }) { 294 t.Errorf("Did not panic with unequal lengths") 295 } 296 } 297 298 func TestDivTo(t *testing.T) { 299 t.Parallel() 300 s1 := []float64{5, 12, 27} 301 s1orig := []float64{5, 12, 27} 302 s2 := []float64{1, 2, 3} 303 s2orig := []float64{1, 2, 3} 304 dst1 := make([]float64, 3) 305 ans := []float64{5, 6, 9} 306 dst2 := DivTo(dst1, s1, s2) 307 if !EqualApprox(dst1, ans, EqTolerance) { 308 t.Errorf("DivTo doesn't give correct answer in mutated slice") 309 } 310 if !EqualApprox(dst2, ans, EqTolerance) { 311 t.Errorf("DivTo doesn't give correct answer in returned slice") 312 } 313 if !EqualApprox(s1, s1orig, EqTolerance) { 314 t.Errorf("S1 changes during multo") 315 } 316 if !EqualApprox(s2, s2orig, EqTolerance) { 317 t.Errorf("s2 changes during multo") 318 } 319 DivTo(dst1, s1, s2) 320 if !EqualApprox(dst1, ans, EqTolerance) { 321 t.Errorf("DivTo doesn't give correct answer reusing dst") 322 } 323 dstShort := []float64{1} 324 if !Panics(func() { DivTo(dstShort, s1, s2) }) { 325 t.Errorf("Did not panic with s1 wrong length") 326 } 327 s1short := []float64{1} 328 if !Panics(func() { DivTo(dst1, s1short, s2) }) { 329 t.Errorf("Did not panic with s1 wrong length") 330 } 331 s2short := []float64{1} 332 if !Panics(func() { DivTo(dst1, s1, s2short) }) { 333 t.Errorf("Did not panic with s2 wrong length") 334 } 335 } 336 337 func TestDot(t *testing.T) { 338 t.Parallel() 339 s1 := []float64{1, 2, 3, 4} 340 s2 := []float64{-3, 4, 5, -6} 341 truth := -4.0 342 ans := Dot(s1, s2) 343 if ans != truth { 344 t.Errorf("Dot product computed incorrectly") 345 } 346 347 // Test that it panics 348 if !Panics(func() { Dot(make([]float64, 2), make([]float64, 3)) }) { 349 t.Errorf("Did not panic with length mismatch") 350 } 351 } 352 353 func TestEquals(t *testing.T) { 354 t.Parallel() 355 s1 := []float64{1, 2, 3, 4} 356 s2 := []float64{1, 2, 3, 4} 357 if !Equal(s1, s2) { 358 t.Errorf("Equal slices returned as unequal") 359 } 360 s2 = []float64{1, 2, 3, 4 + 1e-14} 361 if Equal(s1, s2) { 362 t.Errorf("Unequal slices returned as equal") 363 } 364 if Equal(s1, []float64{}) { 365 t.Errorf("Unequal slice lengths returned as equal") 366 } 367 } 368 369 func TestEqualApprox(t *testing.T) { 370 t.Parallel() 371 s1 := []float64{1, 2, 3, 4} 372 s2 := []float64{1, 2, 3, 4 + 1e-10} 373 if EqualApprox(s1, s2, 1e-13) { 374 t.Errorf("Unequal slices returned as equal for absolute") 375 } 376 if !EqualApprox(s1, s2, 1e-5) { 377 t.Errorf("Equal slices returned as unequal for absolute") 378 } 379 s1 = []float64{1, 2, 3, 1000} 380 s2 = []float64{1, 2, 3, 1000 * (1 + 1e-7)} 381 if EqualApprox(s1, s2, 1e-8) { 382 t.Errorf("Unequal slices returned as equal for relative") 383 } 384 if !EqualApprox(s1, s2, 1e-5) { 385 t.Errorf("Equal slices returned as unequal for relative") 386 } 387 if EqualApprox(s1, []float64{}, 1e-5) { 388 t.Errorf("Unequal slice lengths returned as equal") 389 } 390 } 391 392 func TestEqualFunc(t *testing.T) { 393 t.Parallel() 394 s1 := []float64{1, 2, 3, 4} 395 s2 := []float64{1, 2, 3, 4} 396 eq := func(x, y float64) bool { return x == y } 397 if !EqualFunc(s1, s2, eq) { 398 t.Errorf("Equal slices returned as unequal") 399 } 400 s2 = []float64{1, 2, 3, 4 + 1e-14} 401 if EqualFunc(s1, s2, eq) { 402 t.Errorf("Unequal slices returned as equal") 403 } 404 if EqualFunc(s1, []float64{}, eq) { 405 t.Errorf("Unequal slice lengths returned as equal") 406 } 407 } 408 409 func TestEqualsRelative(t *testing.T) { 410 t.Parallel() 411 equalityTests := []struct { 412 a, b float64 413 tol float64 414 equal bool 415 }{ 416 {1000000, 1000001, 0, true}, 417 {1000001, 1000000, 0, true}, 418 {10000, 10001, 0, false}, 419 {10001, 10000, 0, false}, 420 {-1000000, -1000001, 0, true}, 421 {-1000001, -1000000, 0, true}, 422 {-10000, -10001, 0, false}, 423 {-10001, -10000, 0, false}, 424 {1.0000001, 1.0000002, 0, true}, 425 {1.0000002, 1.0000001, 0, true}, 426 {1.0002, 1.0001, 0, false}, 427 {1.0001, 1.0002, 0, false}, 428 {-1.000001, -1.000002, 0, true}, 429 {-1.000002, -1.000001, 0, true}, 430 {-1.0001, -1.0002, 0, false}, 431 {-1.0002, -1.0001, 0, false}, 432 {0.000000001000001, 0.000000001000002, 0, true}, 433 {0.000000001000002, 0.000000001000001, 0, true}, 434 {0.000000000001002, 0.000000000001001, 0, false}, 435 {0.000000000001001, 0.000000000001002, 0, false}, 436 {-0.000000001000001, -0.000000001000002, 0, true}, 437 {-0.000000001000002, -0.000000001000001, 0, true}, 438 {-0.000000000001002, -0.000000000001001, 0, false}, 439 {-0.000000000001001, -0.000000000001002, 0, false}, 440 {0, 0, 0, true}, 441 {0, -0, 0, true}, 442 {-0, -0, 0, true}, 443 {0.00000001, 0, 0, false}, 444 {0, 0.00000001, 0, false}, 445 {-0.00000001, 0, 0, false}, 446 {0, -0.00000001, 0, false}, 447 {0, 1e-310, 0.01, true}, 448 {1e-310, 0, 0.01, true}, 449 {1e-310, 0, 0.000001, false}, 450 {0, 1e-310, 0.000001, false}, 451 {0, -1e-310, 0.1, true}, 452 {-1e-310, 0, 0.1, true}, 453 {-1e-310, 0, 0.00000001, false}, 454 {0, -1e-310, 0.00000001, false}, 455 {math.Inf(1), math.Inf(1), 0, true}, 456 {math.Inf(-1), math.Inf(-1), 0, true}, 457 {math.Inf(-1), math.Inf(1), 0, false}, 458 {math.Inf(1), math.MaxFloat64, 0, false}, 459 {math.Inf(-1), -math.MaxFloat64, 0, false}, 460 {math.NaN(), math.NaN(), 0, false}, 461 {math.NaN(), 0, 0, false}, 462 {-0, math.NaN(), 0, false}, 463 {math.NaN(), -0, 0, false}, 464 {0, math.NaN(), 0, false}, 465 {math.NaN(), math.Inf(1), 0, false}, 466 {math.Inf(1), math.NaN(), 0, false}, 467 {math.NaN(), math.Inf(-1), 0, false}, 468 {math.Inf(-1), math.NaN(), 0, false}, 469 {math.NaN(), math.MaxFloat64, 0, false}, 470 {math.MaxFloat64, math.NaN(), 0, false}, 471 {math.NaN(), -math.MaxFloat64, 0, false}, 472 {-math.MaxFloat64, math.NaN(), 0, false}, 473 {math.NaN(), math.SmallestNonzeroFloat64, 0, false}, 474 {math.SmallestNonzeroFloat64, math.NaN(), 0, false}, 475 {math.NaN(), -math.SmallestNonzeroFloat64, 0, false}, 476 {-math.SmallestNonzeroFloat64, math.NaN(), 0, false}, 477 {1.000000001, -1.0, 0, false}, 478 {-1.0, 1.000000001, 0, false}, 479 {-1.000000001, 1.0, 0, false}, 480 {1.0, -1.000000001, 0, false}, 481 {10 * math.SmallestNonzeroFloat64, 10 * -math.SmallestNonzeroFloat64, 0, true}, 482 {1e11 * math.SmallestNonzeroFloat64, 1e11 * -math.SmallestNonzeroFloat64, 0, false}, 483 {math.SmallestNonzeroFloat64, -math.SmallestNonzeroFloat64, 0, true}, 484 {-math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64, 0, true}, 485 {math.SmallestNonzeroFloat64, 0, 0, true}, 486 {0, math.SmallestNonzeroFloat64, 0, true}, 487 {-math.SmallestNonzeroFloat64, 0, 0, true}, 488 {0, -math.SmallestNonzeroFloat64, 0, true}, 489 {0.000000001, -math.SmallestNonzeroFloat64, 0, false}, 490 {0.000000001, math.SmallestNonzeroFloat64, 0, false}, 491 {math.SmallestNonzeroFloat64, 0.000000001, 0, false}, 492 {-math.SmallestNonzeroFloat64, 0.000000001, 0, false}, 493 } 494 for _, ts := range equalityTests { 495 if ts.tol == 0 { 496 ts.tol = 1e-5 497 } 498 if equal := scalar.EqualWithinRel(ts.a, ts.b, ts.tol); equal != ts.equal { 499 t.Errorf("Relative equality of %g and %g with tolerance %g returned: %v. Expected: %v", 500 ts.a, ts.b, ts.tol, equal, ts.equal) 501 } 502 } 503 } 504 505 func TestEqualLengths(t *testing.T) { 506 t.Parallel() 507 s1 := []float64{1, 2, 3, 4} 508 s2 := []float64{1, 2, 3, 4} 509 s3 := []float64{1, 2, 3} 510 if !EqualLengths(s1, s2) { 511 t.Errorf("Equal lengths returned as unequal") 512 } 513 if EqualLengths(s1, s3) { 514 t.Errorf("Unequal lengths returned as equal") 515 } 516 if !EqualLengths(s1) { 517 t.Errorf("Single slice returned as unequal") 518 } 519 if !EqualLengths() { 520 t.Errorf("No slices returned as unequal") 521 } 522 } 523 524 func eqIntSlice(one, two []int) string { 525 if len(one) != len(two) { 526 return "Length mismatch" 527 } 528 for i, val := range one { 529 if val != two[i] { 530 return "Index " + strconv.Itoa(i) + " mismatch" 531 } 532 } 533 return "" 534 } 535 536 func TestFind(t *testing.T) { 537 t.Parallel() 538 s := []float64{3, 4, 1, 7, 5} 539 f := func(v float64) bool { return v > 3.5 } 540 allTrueInds := []int{1, 3, 4} 541 542 // Test finding first two elements 543 inds, err := Find(nil, f, s, 2) 544 if err != nil { 545 t.Errorf("Find first two: Improper error return") 546 } 547 trueInds := allTrueInds[:2] 548 str := eqIntSlice(inds, trueInds) 549 if str != "" { 550 t.Errorf("Find first two: " + str) 551 } 552 553 // Test finding no elements with non nil slice 554 inds = []int{1, 2, 3, 4, 5, 6} 555 inds, err = Find(inds, f, s, 0) 556 if err != nil { 557 t.Errorf("Find no elements: Improper error return") 558 } 559 str = eqIntSlice(inds, []int{}) 560 if str != "" { 561 t.Errorf("Find no non-nil: " + str) 562 } 563 564 // Test finding first two elements with non nil slice 565 inds = []int{1, 2, 3, 4, 5, 6} 566 inds, err = Find(inds, f, s, 2) 567 if err != nil { 568 t.Errorf("Find first two non-nil: Improper error return") 569 } 570 str = eqIntSlice(inds, trueInds) 571 if str != "" { 572 t.Errorf("Find first two non-nil: " + str) 573 } 574 575 // Test finding too many elements 576 inds, err = Find(inds, f, s, 4) 577 if err == nil { 578 t.Errorf("Request too many: No error returned") 579 } 580 str = eqIntSlice(inds, allTrueInds) 581 if str != "" { 582 t.Errorf("Request too many: Does not match all of the inds: " + str) 583 } 584 585 // Test finding all elements 586 inds, err = Find(nil, f, s, -1) 587 if err != nil { 588 t.Errorf("Find all: Improper error returned") 589 } 590 str = eqIntSlice(inds, allTrueInds) 591 if str != "" { 592 t.Errorf("Find all: Does not match all of the inds: " + str) 593 } 594 } 595 596 func TestHasNaN(t *testing.T) { 597 t.Parallel() 598 for i, test := range []struct { 599 s []float64 600 ans bool 601 }{ 602 {}, 603 { 604 s: []float64{1, 2, 3, 4}, 605 }, 606 { 607 s: []float64{1, math.NaN(), 3, 4}, 608 ans: true, 609 }, 610 { 611 s: []float64{1, 2, 3, math.NaN()}, 612 ans: true, 613 }, 614 } { 615 b := HasNaN(test.s) 616 if b != test.ans { 617 t.Errorf("HasNaN mismatch case %d. Expected %v, Found %v", i, test.ans, b) 618 } 619 } 620 } 621 622 func TestLogSpan(t *testing.T) { 623 t.Parallel() 624 receiver1 := make([]float64, 6) 625 truth := []float64{0.001, 0.01, 0.1, 1, 10, 100} 626 receiver2 := LogSpan(receiver1, 0.001, 100) 627 tst := make([]float64, 6) 628 for i := range truth { 629 tst[i] = receiver1[i] / truth[i] 630 } 631 comp := make([]float64, 6) 632 for i := range comp { 633 comp[i] = 1 634 } 635 areSlicesEqual(t, comp, tst, "Improper logspace from mutator") 636 637 for i := range truth { 638 tst[i] = receiver2[i] / truth[i] 639 } 640 areSlicesEqual(t, comp, tst, "Improper logspace from returned slice") 641 642 if !Panics(func() { LogSpan(nil, 1, 5) }) { 643 t.Errorf("Span accepts nil argument") 644 } 645 if !Panics(func() { LogSpan(make([]float64, 1), 1, 5) }) { 646 t.Errorf("Span accepts argument of len = 1") 647 } 648 } 649 650 func TestLogSumExp(t *testing.T) { 651 t.Parallel() 652 s := []float64{1, 2, 3, 4, 5} 653 val := LogSumExp(s) 654 // http://www.wolframalpha.com/input/?i=log%28exp%281%29+%2B+exp%282%29+%2B+exp%283%29+%2B+exp%284%29+%2B+exp%285%29%29 655 truth := 5.4519143959375933331957225109748087179338972737576824 656 if math.Abs(val-truth) > EqTolerance { 657 t.Errorf("Wrong logsumexp for many values") 658 } 659 s = []float64{1, 2} 660 // http://www.wolframalpha.com/input/?i=log%28exp%281%29+%2B+exp%282%29%29 661 truth = 2.3132616875182228340489954949678556419152800856703483 662 val = LogSumExp(s) 663 if math.Abs(val-truth) > EqTolerance { 664 t.Errorf("Wrong logsumexp for two values. %v expected, %v found", truth, val) 665 } 666 // This case would normally underflow 667 s = []float64{-1001, -1002, -1003, -1004, -1005} 668 // http://www.wolframalpha.com/input/?i=log%28exp%28-1001%29%2Bexp%28-1002%29%2Bexp%28-1003%29%2Bexp%28-1004%29%2Bexp%28-1005%29%29 669 truth = -1000.54808560406240666680427748902519128206610272624 670 val = LogSumExp(s) 671 if math.Abs(val-truth) > EqTolerance { 672 t.Errorf("Doesn't match for underflow case. %v expected, %v found", truth, val) 673 } 674 // positive infinite case 675 s = []float64{1, 2, 3, 4, 5, math.Inf(1)} 676 val = LogSumExp(s) 677 truth = math.Inf(1) 678 if val != truth { 679 t.Errorf("Doesn't match for pos Infinity case. %v expected, %v found", truth, val) 680 } 681 // negative infinite case 682 s = []float64{1, 2, 3, 4, 5, math.Inf(-1)} 683 val = LogSumExp(s) 684 truth = 5.4519143959375933331957225109748087179338972737576824 // same as first case 685 if math.Abs(val-truth) > EqTolerance { 686 t.Errorf("Wrong logsumexp for values with negative infinity") 687 } 688 } 689 690 func TestMaxAndIdx(t *testing.T) { 691 t.Parallel() 692 for _, test := range []struct { 693 in []float64 694 wantIdx int 695 wantVal float64 696 desc string 697 }{ 698 { 699 in: []float64{3, 4, 1, 7, 5}, 700 wantIdx: 3, 701 wantVal: 7, 702 desc: "with only finite entries", 703 }, 704 { 705 in: []float64{math.NaN(), 4, 1, 7, 5}, 706 wantIdx: 3, 707 wantVal: 7, 708 desc: "with leading NaN", 709 }, 710 { 711 in: []float64{math.NaN(), math.NaN(), math.NaN()}, 712 wantIdx: 0, 713 wantVal: math.NaN(), 714 desc: "when only NaN elements exist", 715 }, 716 { 717 in: []float64{math.NaN(), math.Inf(-1)}, 718 wantIdx: 1, 719 wantVal: math.Inf(-1), 720 desc: "leading NaN followed by -Inf", 721 }, 722 { 723 in: []float64{math.NaN(), math.Inf(1)}, 724 wantIdx: 1, 725 wantVal: math.Inf(1), 726 desc: "leading NaN followed by +Inf", 727 }, 728 } { 729 ind := MaxIdx(test.in) 730 if ind != test.wantIdx { 731 t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx) 732 } 733 val := Max(test.in) 734 if !scalar.Same(val, test.wantVal) { 735 t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal) 736 } 737 } 738 if !Panics(func() { MaxIdx([]float64{}) }) { 739 t.Errorf("Expected panic with zero length") 740 } 741 } 742 743 func TestMinAndIdx(t *testing.T) { 744 t.Parallel() 745 for _, test := range []struct { 746 in []float64 747 wantIdx int 748 wantVal float64 749 desc string 750 }{ 751 { 752 in: []float64{3, 4, 1, 7, 5}, 753 wantIdx: 2, 754 wantVal: 1, 755 desc: "with only finite entries", 756 }, 757 { 758 in: []float64{math.NaN(), 4, 1, 7, 5}, 759 wantIdx: 2, 760 wantVal: 1, 761 desc: "with leading NaN", 762 }, 763 { 764 in: []float64{math.NaN(), math.NaN(), math.NaN()}, 765 wantIdx: 0, 766 wantVal: math.NaN(), 767 desc: "when only NaN elements exist", 768 }, 769 { 770 in: []float64{math.NaN(), math.Inf(-1)}, 771 wantIdx: 1, 772 wantVal: math.Inf(-1), 773 desc: "leading NaN followed by -Inf", 774 }, 775 { 776 in: []float64{math.NaN(), math.Inf(1)}, 777 wantIdx: 1, 778 wantVal: math.Inf(1), 779 desc: "leading NaN followed by +Inf", 780 }, 781 } { 782 ind := MinIdx(test.in) 783 if ind != test.wantIdx { 784 t.Errorf("Wrong index "+test.desc+": got:%d want:%d", ind, test.wantIdx) 785 } 786 val := Min(test.in) 787 if !scalar.Same(val, test.wantVal) { 788 t.Errorf("Wrong value "+test.desc+": got:%f want:%f", val, test.wantVal) 789 } 790 } 791 if !Panics(func() { MinIdx([]float64{}) }) { 792 t.Errorf("Expected panic with zero length") 793 } 794 } 795 796 func TestMul(t *testing.T) { 797 t.Parallel() 798 s1 := []float64{1, 2, 3} 799 s2 := []float64{1, 2, 3} 800 ans := []float64{1, 4, 9} 801 Mul(s1, s2) 802 if !EqualApprox(s1, ans, EqTolerance) { 803 t.Errorf("Mul doesn't give correct answer") 804 } 805 s1short := []float64{1} 806 if !Panics(func() { Mul(s1short, s2) }) { 807 t.Errorf("Did not panic with unequal lengths") 808 } 809 s2short := []float64{1} 810 if !Panics(func() { Mul(s1, s2short) }) { 811 t.Errorf("Did not panic with unequal lengths") 812 } 813 } 814 815 func TestMulTo(t *testing.T) { 816 t.Parallel() 817 s1 := []float64{1, 2, 3} 818 s1orig := []float64{1, 2, 3} 819 s2 := []float64{1, 2, 3} 820 s2orig := []float64{1, 2, 3} 821 dst1 := make([]float64, 3) 822 ans := []float64{1, 4, 9} 823 dst2 := MulTo(dst1, s1, s2) 824 if !EqualApprox(dst1, ans, EqTolerance) { 825 t.Errorf("MulTo doesn't give correct answer in mutated slice") 826 } 827 if !EqualApprox(dst2, ans, EqTolerance) { 828 t.Errorf("MulTo doesn't give correct answer in returned slice") 829 } 830 if !EqualApprox(s1, s1orig, EqTolerance) { 831 t.Errorf("S1 changes during multo") 832 } 833 if !EqualApprox(s2, s2orig, EqTolerance) { 834 t.Errorf("s2 changes during multo") 835 } 836 MulTo(dst1, s1, s2) 837 if !EqualApprox(dst1, ans, EqTolerance) { 838 t.Errorf("MulTo doesn't give correct answer reusing dst") 839 } 840 dstShort := []float64{1} 841 if !Panics(func() { MulTo(dstShort, s1, s2) }) { 842 t.Errorf("Did not panic with s1 wrong length") 843 } 844 s1short := []float64{1} 845 if !Panics(func() { MulTo(dst1, s1short, s2) }) { 846 t.Errorf("Did not panic with s1 wrong length") 847 } 848 s2short := []float64{1} 849 if !Panics(func() { MulTo(dst1, s1, s2short) }) { 850 t.Errorf("Did not panic with s2 wrong length") 851 } 852 } 853 854 func TestNearestIdx(t *testing.T) { 855 t.Parallel() 856 for _, test := range []struct { 857 in []float64 858 query float64 859 want int 860 desc string 861 }{ 862 { 863 in: []float64{6.2, 3, 5, 6.2, 8}, 864 query: 2, 865 want: 1, 866 desc: "Wrong index returned when value is less than all of elements", 867 }, 868 { 869 in: []float64{6.2, 3, 5, 6.2, 8}, 870 query: 9, 871 want: 4, 872 desc: "Wrong index returned when value is greater than all of elements", 873 }, 874 { 875 in: []float64{6.2, 3, 5, 6.2, 8}, 876 query: 3.1, 877 want: 1, 878 desc: "Wrong index returned when value is greater than closest element", 879 }, 880 { 881 in: []float64{6.2, 3, 5, 6.2, 8}, 882 query: 2.9, 883 want: 1, 884 desc: "Wrong index returned when value is less than closest element", 885 }, 886 { 887 in: []float64{6.2, 3, 5, 6.2, 8}, 888 query: 3, 889 want: 1, 890 desc: "Wrong index returned when value is equal to element", 891 }, 892 { 893 in: []float64{6.2, 3, 5, 6.2, 8}, 894 query: 6.2, 895 want: 0, 896 desc: "Wrong index returned when value is equal to several elements", 897 }, 898 { 899 in: []float64{6.2, 3, 5, 6.2, 8}, 900 query: 4, 901 want: 1, 902 desc: "Wrong index returned when value is exactly between two closest elements", 903 }, 904 { 905 in: []float64{math.NaN(), 3, 2, -1}, 906 query: 2, 907 want: 2, 908 desc: "Wrong index returned when initial element is NaN", 909 }, 910 { 911 in: []float64{0, math.NaN(), -1, 2}, 912 query: math.NaN(), 913 want: 0, 914 desc: "Wrong index returned when query is NaN and a NaN element exists", 915 }, 916 { 917 in: []float64{0, math.NaN(), -1, 2}, 918 query: math.Inf(1), 919 want: 3, 920 desc: "Wrong index returned when query is +Inf and no +Inf element exists", 921 }, 922 { 923 in: []float64{0, math.NaN(), -1, 2}, 924 query: math.Inf(-1), 925 want: 2, 926 desc: "Wrong index returned when query is -Inf and no -Inf element exists", 927 }, 928 { 929 in: []float64{math.NaN(), math.NaN(), math.NaN()}, 930 query: 1, 931 want: 0, 932 desc: "Wrong index returned when query is a number and only NaN elements exist", 933 }, 934 { 935 in: []float64{math.NaN(), math.Inf(-1)}, 936 query: 1, 937 want: 1, 938 desc: "Wrong index returned when query is a number and single NaN precedes -Inf", 939 }, 940 } { 941 ind := NearestIdx(test.in, test.query) 942 if ind != test.want { 943 t.Errorf(test.desc+": got:%d want:%d", ind, test.want) 944 } 945 } 946 if !Panics(func() { NearestIdx([]float64{}, 0) }) { 947 t.Errorf("Expected panic with zero length") 948 } 949 } 950 951 func TestNearestIdxForSpan(t *testing.T) { 952 t.Parallel() 953 for i, test := range []struct { 954 length int 955 lower float64 956 upper float64 957 value float64 958 idx int 959 }{ 960 { 961 length: 13, 962 lower: 7, 963 upper: 8.2, 964 value: 6, 965 idx: 0, 966 }, 967 { 968 length: 13, 969 lower: 7, 970 upper: 8.2, 971 value: 10, 972 idx: 12, 973 }, 974 { 975 length: 13, 976 lower: 7, 977 upper: 8.2, 978 value: 7.19, 979 idx: 2, 980 }, 981 { 982 length: 13, 983 lower: 7, 984 upper: 8.2, 985 value: 7.21, 986 idx: 2, 987 }, 988 { 989 length: 13, 990 lower: 7, 991 upper: 8.2, 992 value: 7.2, 993 idx: 2, 994 }, 995 { 996 length: 13, 997 lower: 7, 998 upper: 8.2, 999 value: 7.151, 1000 idx: 2, 1001 }, 1002 { 1003 length: 13, 1004 lower: 7, 1005 upper: 8.2, 1006 value: 7.249, 1007 idx: 2, 1008 }, 1009 { 1010 length: 4, 1011 lower: math.Inf(-1), 1012 upper: math.Inf(1), 1013 value: math.Copysign(0, -1), 1014 idx: 0, 1015 }, 1016 { 1017 length: 5, 1018 lower: math.Inf(-1), 1019 upper: math.Inf(1), 1020 value: 0, 1021 idx: 2, 1022 }, 1023 { 1024 length: 5, 1025 lower: math.Inf(-1), 1026 upper: math.Inf(1), 1027 value: math.Inf(-1), 1028 idx: 0, 1029 }, 1030 { 1031 length: 5, 1032 lower: math.Inf(-1), 1033 upper: math.Inf(1), 1034 value: math.Inf(1), 1035 idx: 3, 1036 }, 1037 { 1038 length: 4, 1039 lower: math.Inf(-1), 1040 upper: math.Inf(1), 1041 value: 0, 1042 idx: 2, 1043 }, 1044 { 1045 length: 4, 1046 lower: math.Inf(-1), 1047 upper: math.Inf(1), 1048 value: math.Inf(1), 1049 idx: 2, 1050 }, 1051 { 1052 length: 4, 1053 lower: math.Inf(-1), 1054 upper: math.Inf(1), 1055 value: math.Inf(-1), 1056 idx: 0, 1057 }, 1058 { 1059 length: 5, 1060 lower: math.Inf(1), 1061 upper: math.Inf(1), 1062 value: 1, 1063 idx: 0, 1064 }, 1065 { 1066 length: 5, 1067 lower: math.NaN(), 1068 upper: math.NaN(), 1069 value: 1, 1070 idx: 0, 1071 }, 1072 { 1073 length: 5, 1074 lower: 0, 1075 upper: 1, 1076 value: math.NaN(), 1077 idx: 0, 1078 }, 1079 { 1080 length: 5, 1081 lower: math.NaN(), 1082 upper: 1, 1083 value: 0, 1084 idx: 4, 1085 }, 1086 { 1087 length: 5, 1088 lower: math.Inf(-1), 1089 upper: 1, 1090 value: math.Inf(-1), 1091 idx: 0, 1092 }, 1093 { 1094 length: 5, 1095 lower: math.Inf(-1), 1096 upper: 1, 1097 value: 0, 1098 idx: 4, 1099 }, 1100 { 1101 length: 5, 1102 lower: math.Inf(1), 1103 upper: 1, 1104 value: math.Inf(1), 1105 idx: 0, 1106 }, 1107 { 1108 length: 5, 1109 lower: math.Inf(1), 1110 upper: 1, 1111 value: 0, 1112 idx: 4, 1113 }, 1114 { 1115 length: 5, 1116 lower: 100, 1117 upper: math.Inf(-1), 1118 value: math.Inf(-1), 1119 idx: 4, 1120 }, 1121 { 1122 length: 5, 1123 lower: 100, 1124 upper: math.Inf(-1), 1125 value: 200, 1126 idx: 0, 1127 }, 1128 { 1129 length: 5, 1130 lower: 100, 1131 upper: math.Inf(1), 1132 value: math.Inf(1), 1133 idx: 4, 1134 }, 1135 { 1136 length: 5, 1137 lower: 100, 1138 upper: math.Inf(1), 1139 value: 200, 1140 idx: 0, 1141 }, 1142 { 1143 length: 5, 1144 lower: -1, 1145 upper: 2, 1146 value: math.Inf(-1), 1147 idx: 0, 1148 }, 1149 { 1150 length: 5, 1151 lower: -1, 1152 upper: 2, 1153 value: math.Inf(1), 1154 idx: 4, 1155 }, 1156 { 1157 length: 5, 1158 lower: 1, 1159 upper: -2, 1160 value: math.Inf(-1), 1161 idx: 4, 1162 }, 1163 { 1164 length: 5, 1165 lower: 1, 1166 upper: -2, 1167 value: math.Inf(1), 1168 idx: 0, 1169 }, 1170 { 1171 length: 5, 1172 lower: 2, 1173 upper: 0, 1174 value: 3, 1175 idx: 0, 1176 }, 1177 { 1178 length: 5, 1179 lower: 2, 1180 upper: 0, 1181 value: -1, 1182 idx: 4, 1183 }, 1184 } { 1185 if idx := NearestIdxForSpan(test.length, test.lower, test.upper, test.value); test.idx != idx { 1186 t.Errorf("Case %v mismatch: Want: %v, Got: %v", i, test.idx, idx) 1187 } 1188 } 1189 if !Panics(func() { NearestIdxForSpan(1, 0, 1, 0.5) }) { 1190 t.Errorf("Expected panic for short span length") 1191 } 1192 } 1193 1194 func TestNorm(t *testing.T) { 1195 t.Parallel() 1196 s := []float64{-1, -3.4, 5, -6} 1197 val := Norm(s, math.Inf(1)) 1198 truth := 6.0 1199 if math.Abs(val-truth) > EqTolerance { 1200 t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) 1201 } 1202 // http://www.wolframalpha.com/input/?i=%28%28-1%29%5E2+%2B++%28-3.4%29%5E2+%2B+5%5E2%2B++6%5E2%29%5E%281%2F2%29 1203 val = Norm(s, 2) 1204 truth = 8.5767126569566267590651614132751986658027271236078592 1205 if math.Abs(val-truth) > EqTolerance { 1206 t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) 1207 } 1208 // http://www.wolframalpha.com/input/?i=%28%28%7C-1%7C%29%5E3+%2B++%28%7C-3.4%7C%29%5E3+%2B+%7C5%7C%5E3%2B++%7C6%7C%5E3%29%5E%281%2F3%29 1209 val = Norm(s, 3) 1210 truth = 7.2514321388020228478109121239004816430071237369356233 1211 if math.Abs(val-truth) > EqTolerance { 1212 t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) 1213 } 1214 1215 //http://www.wolframalpha.com/input/?i=%7C-1%7C+%2B+%7C-3.4%7C+%2B+%7C5%7C%2B++%7C6%7C 1216 val = Norm(s, 1) 1217 truth = 15.4 1218 if math.Abs(val-truth) > EqTolerance { 1219 t.Errorf("Doesn't match for inf norm. %v expected, %v found", truth, val) 1220 } 1221 } 1222 1223 func TestProd(t *testing.T) { 1224 t.Parallel() 1225 s := []float64{} 1226 val := Prod(s) 1227 if val != 1 { 1228 t.Errorf("Val not returned as default when slice length is zero") 1229 } 1230 s = []float64{3, 4, 1, 7, 5} 1231 val = Prod(s) 1232 if val != 420 { 1233 t.Errorf("Wrong prod returned. Expected %v returned %v", 420, val) 1234 } 1235 } 1236 1237 func TestReverse(t *testing.T) { 1238 t.Parallel() 1239 for _, s := range [][]float64{ 1240 {0}, 1241 {1, 0}, 1242 {2, 1, 0}, 1243 {3, 2, 1, 0}, 1244 {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, 1245 } { 1246 Reverse(s) 1247 for i, v := range s { 1248 if v != float64(i) { 1249 t.Errorf("unexpected values for element %d: got:%v want:%v", i, v, i) 1250 } 1251 } 1252 } 1253 } 1254 1255 func TestSame(t *testing.T) { 1256 t.Parallel() 1257 s1 := []float64{1, 2, 3, 4} 1258 s2 := []float64{1, 2, 3, 4} 1259 if !Same(s1, s2) { 1260 t.Errorf("Equal slices returned as unequal") 1261 } 1262 s2 = []float64{1, 2, 3, 4 + 1e-14} 1263 if Same(s1, s2) { 1264 t.Errorf("Unequal slices returned as equal") 1265 } 1266 if Same(s1, []float64{}) { 1267 t.Errorf("Unequal slice lengths returned as equal") 1268 } 1269 s1 = []float64{1, 2, math.NaN(), 4} 1270 s2 = []float64{1, 2, math.NaN(), 4} 1271 if !Same(s1, s2) { 1272 t.Errorf("Slices with matching NaN values returned as unequal") 1273 } 1274 s1 = []float64{1, 2, math.NaN(), 4} 1275 s2 = []float64{1, math.NaN(), 3, 4} 1276 if Same(s1, s2) { 1277 t.Errorf("Slices with unmatching NaN values returned as equal") 1278 } 1279 } 1280 1281 func TestScale(t *testing.T) { 1282 t.Parallel() 1283 s := []float64{3, 4, 1, 7, 5} 1284 c := 5.0 1285 truth := []float64{15, 20, 5, 35, 25} 1286 Scale(c, s) 1287 areSlicesEqual(t, truth, s, "Bad scaling") 1288 } 1289 1290 func TestScaleTo(t *testing.T) { 1291 t.Parallel() 1292 s := []float64{3, 4, 1, 7, 5} 1293 sCopy := make([]float64, len(s)) 1294 copy(sCopy, s) 1295 c := 5.0 1296 truth := []float64{15, 20, 5, 35, 25} 1297 dst := make([]float64, len(s)) 1298 ScaleTo(dst, c, s) 1299 if !Same(dst, truth) { 1300 t.Errorf("Scale to does not match. Got %v, want %v", dst, truth) 1301 } 1302 if !Same(s, sCopy) { 1303 t.Errorf("Source modified during call. Got %v, want %v", s, sCopy) 1304 } 1305 if !Panics(func() { ScaleTo(dst, 0, []float64{1}) }) { 1306 t.Errorf("Expected panic with different slice lengths") 1307 } 1308 } 1309 1310 func TestSpan(t *testing.T) { 1311 t.Parallel() 1312 receiver1 := make([]float64, 5) 1313 truth := []float64{1, 2, 3, 4, 5} 1314 receiver2 := Span(receiver1, 1, 5) 1315 areSlicesEqual(t, truth, receiver1, "Improper linspace from mutator") 1316 areSlicesEqual(t, truth, receiver2, "Improper linspace from returned slice") 1317 receiver1 = make([]float64, 6) 1318 truth = []float64{0, 0.2, 0.4, 0.6, 0.8, 1.0} 1319 Span(receiver1, 0, 1) 1320 areSlicesEqual(t, truth, receiver1, "Improper linspace") 1321 if !Panics(func() { Span(nil, 1, 5) }) { 1322 t.Errorf("Span accepts nil argument") 1323 } 1324 if !Panics(func() { Span(make([]float64, 1), 1, 5) }) { 1325 t.Errorf("Span accepts argument of len = 1") 1326 } 1327 1328 for _, test := range []struct { 1329 n int 1330 l, u float64 1331 want []float64 1332 }{ 1333 { 1334 n: 4, l: math.Inf(-1), u: math.Inf(1), 1335 want: []float64{math.Inf(-1), math.Inf(-1), math.Inf(1), math.Inf(1)}, 1336 }, 1337 { 1338 n: 4, l: math.Inf(1), u: math.Inf(-1), 1339 want: []float64{math.Inf(1), math.Inf(1), math.Inf(-1), math.Inf(-1)}, 1340 }, 1341 { 1342 n: 5, l: math.Inf(-1), u: math.Inf(1), 1343 want: []float64{math.Inf(-1), math.Inf(-1), 0, math.Inf(1), math.Inf(1)}, 1344 }, 1345 { 1346 n: 5, l: math.Inf(1), u: math.Inf(-1), 1347 want: []float64{math.Inf(1), math.Inf(1), 0, math.Inf(-1), math.Inf(-1)}, 1348 }, 1349 { 1350 n: 5, l: math.Inf(1), u: math.Inf(1), 1351 want: []float64{math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1)}, 1352 }, 1353 { 1354 n: 5, l: math.Inf(-1), u: math.Inf(-1), 1355 want: []float64{math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1)}, 1356 }, 1357 { 1358 n: 5, l: math.Inf(-1), u: math.NaN(), 1359 want: []float64{math.Inf(-1), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1360 }, 1361 { 1362 n: 5, l: math.Inf(1), u: math.NaN(), 1363 want: []float64{math.Inf(1), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1364 }, 1365 { 1366 n: 5, l: math.NaN(), u: math.Inf(-1), 1367 want: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.Inf(-1)}, 1368 }, 1369 { 1370 n: 5, l: math.NaN(), u: math.Inf(1), 1371 want: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.Inf(1)}, 1372 }, 1373 { 1374 n: 5, l: 42, u: math.Inf(-1), 1375 want: []float64{42, math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1)}, 1376 }, 1377 { 1378 n: 5, l: 42, u: math.Inf(1), 1379 want: []float64{42, math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1)}, 1380 }, 1381 { 1382 n: 5, l: 42, u: math.NaN(), 1383 want: []float64{42, math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1384 }, 1385 { 1386 n: 5, l: math.Inf(-1), u: 42, 1387 want: []float64{math.Inf(-1), math.Inf(-1), math.Inf(-1), math.Inf(-1), 42}, 1388 }, 1389 { 1390 n: 5, l: math.Inf(1), u: 42, 1391 want: []float64{math.Inf(1), math.Inf(1), math.Inf(1), math.Inf(1), 42}, 1392 }, 1393 { 1394 n: 5, l: math.NaN(), u: 42, 1395 want: []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), 42}, 1396 }, 1397 } { 1398 got := Span(make([]float64, test.n), test.l, test.u) 1399 areSlicesSame(t, test.want, got, 1400 fmt.Sprintf("Unexpected slice of length %d for %f to %f", test.n, test.l, test.u)) 1401 } 1402 } 1403 1404 func TestSub(t *testing.T) { 1405 t.Parallel() 1406 s := []float64{3, 4, 1, 7, 5} 1407 v := []float64{1, 2, 3, 4, 5} 1408 truth := []float64{2, 2, -2, 3, 0} 1409 Sub(s, v) 1410 areSlicesEqual(t, truth, s, "Bad subtract") 1411 // Test that it panics 1412 if !Panics(func() { Sub(make([]float64, 2), make([]float64, 3)) }) { 1413 t.Errorf("Did not panic with length mismatch") 1414 } 1415 } 1416 1417 func TestSubTo(t *testing.T) { 1418 t.Parallel() 1419 s := []float64{3, 4, 1, 7, 5} 1420 v := []float64{1, 2, 3, 4, 5} 1421 truth := []float64{2, 2, -2, 3, 0} 1422 dst1 := make([]float64, len(s)) 1423 dst2 := SubTo(dst1, s, v) 1424 areSlicesEqual(t, truth, dst1, "Bad subtract from mutator") 1425 areSlicesEqual(t, truth, dst2, "Bad subtract from returned slice") 1426 // Test that all mismatch combinations panic 1427 if !Panics(func() { SubTo(make([]float64, 2), make([]float64, 3), make([]float64, 3)) }) { 1428 t.Errorf("Did not panic with dst different length") 1429 } 1430 if !Panics(func() { SubTo(make([]float64, 3), make([]float64, 2), make([]float64, 3)) }) { 1431 t.Errorf("Did not panic with subtractor different length") 1432 } 1433 if !Panics(func() { SubTo(make([]float64, 3), make([]float64, 3), make([]float64, 2)) }) { 1434 t.Errorf("Did not panic with subtractee different length") 1435 } 1436 } 1437 1438 func TestSum(t *testing.T) { 1439 t.Parallel() 1440 s := []float64{} 1441 val := Sum(s) 1442 if val != 0 { 1443 t.Errorf("Val not returned as default when slice length is zero") 1444 } 1445 s = []float64{3, 4, 1, 7, 5} 1446 val = Sum(s) 1447 if val != 20 { 1448 t.Errorf("Wrong sum returned") 1449 } 1450 } 1451 1452 func TestWithin(t *testing.T) { 1453 t.Parallel() 1454 for i, test := range []struct { 1455 s []float64 1456 v float64 1457 idx int 1458 panics bool 1459 }{ 1460 { 1461 s: []float64{1, 2, 5, 9}, 1462 v: 1, 1463 idx: 0, 1464 }, 1465 { 1466 s: []float64{1, 2, 5, 9}, 1467 v: 9, 1468 idx: -1, 1469 }, 1470 { 1471 s: []float64{1, 2, 5, 9}, 1472 v: 1.5, 1473 idx: 0, 1474 }, 1475 { 1476 s: []float64{1, 2, 5, 9}, 1477 v: 2, 1478 idx: 1, 1479 }, 1480 { 1481 s: []float64{1, 2, 5, 9}, 1482 v: 2.5, 1483 idx: 1, 1484 }, 1485 { 1486 s: []float64{1, 2, 5, 9}, 1487 v: -3, 1488 idx: -1, 1489 }, 1490 { 1491 s: []float64{1, 2, 5, 9}, 1492 v: 15, 1493 idx: -1, 1494 }, 1495 { 1496 s: []float64{1, 2, 5, 9}, 1497 v: math.NaN(), 1498 idx: -1, 1499 }, 1500 { 1501 s: []float64{5, 2, 6}, 1502 panics: true, 1503 }, 1504 { 1505 panics: true, 1506 }, 1507 { 1508 s: []float64{1}, 1509 panics: true, 1510 }, 1511 } { 1512 var idx int 1513 panics := Panics(func() { idx = Within(test.s, test.v) }) 1514 if panics { 1515 if !test.panics { 1516 t.Errorf("Case %v: bad panic", i) 1517 } 1518 continue 1519 } 1520 if test.panics { 1521 if !panics { 1522 t.Errorf("Case %v: did not panic when it should", i) 1523 } 1524 continue 1525 } 1526 if idx != test.idx { 1527 t.Errorf("Case %v: Idx mismatch. Want: %v, got: %v", i, test.idx, idx) 1528 } 1529 } 1530 } 1531 1532 func TestSumCompensated(t *testing.T) { 1533 t.Parallel() 1534 k := 100000 1535 s1 := make([]float64, 2*k+1) 1536 for i := -k; i <= k; i++ { 1537 s1[i+k] = 0.2 * float64(i) 1538 } 1539 s2 := make([]float64, k+1) 1540 for i := 0; i < k; i++ { 1541 s2[i] = 10. / float64(k) 1542 } 1543 s2[k] = -10 1544 1545 for i, test := range []struct { 1546 s []float64 1547 want float64 1548 }{ 1549 { 1550 // Fails if we use simple Sum. 1551 s: s1, 1552 want: 0, 1553 }, 1554 { 1555 // Fails if we use simple Sum. 1556 s: s2, 1557 want: 0, 1558 }, 1559 { 1560 s: []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1561 want: 55, 1562 }, 1563 { 1564 s: []float64{1.2e20, 0.1, -2.4e20, -0.1, 1.2e20, 0.2, 0.2}, 1565 want: 0.4, 1566 }, 1567 { 1568 s: []float64{1, 1e100, 1, -1e100}, 1569 want: 2, 1570 }, 1571 } { 1572 got := SumCompensated(test.s) 1573 if math.Abs(got-test.want) > EqTolerance { 1574 t.Errorf("Wrong sum returned in test case %d. Want: %g, got: %g", i, test.want, got) 1575 } 1576 } 1577 } 1578 1579 func randomSlice(l int, src rand.Source) []float64 { 1580 rnd := rand.New(src) 1581 s := make([]float64, l) 1582 for i := range s { 1583 s[i] = rnd.Float64() 1584 } 1585 return s 1586 } 1587 1588 func benchmarkMin(b *testing.B, size int) { 1589 src := rand.NewSource(1) 1590 s := randomSlice(size, src) 1591 b.ResetTimer() 1592 for i := 0; i < b.N; i++ { 1593 Min(s) 1594 } 1595 } 1596 func BenchmarkMinSmall(b *testing.B) { benchmarkMin(b, Small) } 1597 func BenchmarkMinMed(b *testing.B) { benchmarkMin(b, Medium) } 1598 func BenchmarkMinLarge(b *testing.B) { benchmarkMin(b, Large) } 1599 func BenchmarkMinHuge(b *testing.B) { benchmarkMin(b, Huge) } 1600 1601 func benchmarkAdd(b *testing.B, size int) { 1602 src := rand.NewSource(1) 1603 s1 := randomSlice(size, src) 1604 s2 := randomSlice(size, src) 1605 b.ResetTimer() 1606 for i := 0; i < b.N; i++ { 1607 Add(s1, s2) 1608 } 1609 } 1610 func BenchmarkAddSmall(b *testing.B) { benchmarkAdd(b, Small) } 1611 func BenchmarkAddMed(b *testing.B) { benchmarkAdd(b, Medium) } 1612 func BenchmarkAddLarge(b *testing.B) { benchmarkAdd(b, Large) } 1613 func BenchmarkAddHuge(b *testing.B) { benchmarkAdd(b, Huge) } 1614 1615 func benchmarkAddTo(b *testing.B, size int) { 1616 src := rand.NewSource(1) 1617 s1 := randomSlice(size, src) 1618 s2 := randomSlice(size, src) 1619 dst := randomSlice(size, src) 1620 b.ResetTimer() 1621 for i := 0; i < b.N; i++ { 1622 AddTo(dst, s1, s2) 1623 } 1624 } 1625 func BenchmarkAddToSmall(b *testing.B) { benchmarkAddTo(b, Small) } 1626 func BenchmarkAddToMed(b *testing.B) { benchmarkAddTo(b, Medium) } 1627 func BenchmarkAddToLarge(b *testing.B) { benchmarkAddTo(b, Large) } 1628 func BenchmarkAddToHuge(b *testing.B) { benchmarkAddTo(b, Huge) } 1629 1630 func benchmarkCumProd(b *testing.B, size int) { 1631 src := rand.NewSource(1) 1632 s := randomSlice(size, src) 1633 dst := randomSlice(size, src) 1634 b.ResetTimer() 1635 for i := 0; i < b.N; i++ { 1636 CumProd(dst, s) 1637 } 1638 } 1639 func BenchmarkCumProdSmall(b *testing.B) { benchmarkCumProd(b, Small) } 1640 func BenchmarkCumProdMed(b *testing.B) { benchmarkCumProd(b, Medium) } 1641 func BenchmarkCumProdLarge(b *testing.B) { benchmarkCumProd(b, Large) } 1642 func BenchmarkCumProdHuge(b *testing.B) { benchmarkCumProd(b, Huge) } 1643 1644 func benchmarkCumSum(b *testing.B, size int) { 1645 src := rand.NewSource(1) 1646 s := randomSlice(size, src) 1647 dst := randomSlice(size, src) 1648 b.ResetTimer() 1649 for i := 0; i < b.N; i++ { 1650 CumSum(dst, s) 1651 } 1652 } 1653 func BenchmarkCumSumSmall(b *testing.B) { benchmarkCumSum(b, Small) } 1654 func BenchmarkCumSumMed(b *testing.B) { benchmarkCumSum(b, Medium) } 1655 func BenchmarkCumSumLarge(b *testing.B) { benchmarkCumSum(b, Large) } 1656 func BenchmarkCumSumHuge(b *testing.B) { benchmarkCumSum(b, Huge) } 1657 1658 func benchmarkDiv(b *testing.B, size int) { 1659 src := rand.NewSource(1) 1660 s := randomSlice(size, src) 1661 dst := randomSlice(size, src) 1662 b.ResetTimer() 1663 for i := 0; i < b.N; i++ { 1664 Div(dst, s) 1665 } 1666 } 1667 func BenchmarkDivSmall(b *testing.B) { benchmarkDiv(b, Small) } 1668 func BenchmarkDivMed(b *testing.B) { benchmarkDiv(b, Medium) } 1669 func BenchmarkDivLarge(b *testing.B) { benchmarkDiv(b, Large) } 1670 func BenchmarkDivHuge(b *testing.B) { benchmarkDiv(b, Huge) } 1671 1672 func benchmarkDivTo(b *testing.B, size int) { 1673 src := rand.NewSource(1) 1674 s1 := randomSlice(size, src) 1675 s2 := randomSlice(size, src) 1676 dst := randomSlice(size, src) 1677 b.ResetTimer() 1678 for i := 0; i < b.N; i++ { 1679 DivTo(dst, s1, s2) 1680 } 1681 } 1682 func BenchmarkDivToSmall(b *testing.B) { benchmarkDivTo(b, Small) } 1683 func BenchmarkDivToMed(b *testing.B) { benchmarkDivTo(b, Medium) } 1684 func BenchmarkDivToLarge(b *testing.B) { benchmarkDivTo(b, Large) } 1685 func BenchmarkDivToHuge(b *testing.B) { benchmarkDivTo(b, Huge) } 1686 1687 func benchmarkSub(b *testing.B, size int) { 1688 src := rand.NewSource(1) 1689 s1 := randomSlice(size, src) 1690 s2 := randomSlice(size, src) 1691 b.ResetTimer() 1692 for i := 0; i < b.N; i++ { 1693 Sub(s1, s2) 1694 } 1695 } 1696 func BenchmarkSubSmall(b *testing.B) { benchmarkSub(b, Small) } 1697 func BenchmarkSubMed(b *testing.B) { benchmarkSub(b, Medium) } 1698 func BenchmarkSubLarge(b *testing.B) { benchmarkSub(b, Large) } 1699 func BenchmarkSubHuge(b *testing.B) { benchmarkSub(b, Huge) } 1700 1701 func benchmarkSubTo(b *testing.B, size int) { 1702 src := rand.NewSource(1) 1703 s1 := randomSlice(size, src) 1704 s2 := randomSlice(size, src) 1705 dst := randomSlice(size, src) 1706 b.ResetTimer() 1707 for i := 0; i < b.N; i++ { 1708 SubTo(dst, s1, s2) 1709 } 1710 } 1711 func BenchmarkSubToSmall(b *testing.B) { benchmarkSubTo(b, Small) } 1712 func BenchmarkSubToMed(b *testing.B) { benchmarkSubTo(b, Medium) } 1713 func BenchmarkSubToLarge(b *testing.B) { benchmarkSubTo(b, Large) } 1714 func BenchmarkSubToHuge(b *testing.B) { benchmarkSubTo(b, Huge) } 1715 1716 func benchmarkLogSumExp(b *testing.B, size int) { 1717 src := rand.NewSource(1) 1718 s := randomSlice(size, src) 1719 b.ResetTimer() 1720 for i := 0; i < b.N; i++ { 1721 LogSumExp(s) 1722 } 1723 } 1724 func BenchmarkLogSumExpSmall(b *testing.B) { benchmarkLogSumExp(b, Small) } 1725 func BenchmarkLogSumExpMed(b *testing.B) { benchmarkLogSumExp(b, Medium) } 1726 func BenchmarkLogSumExpLarge(b *testing.B) { benchmarkLogSumExp(b, Large) } 1727 func BenchmarkLogSumExpHuge(b *testing.B) { benchmarkLogSumExp(b, Huge) } 1728 1729 func benchmarkDot(b *testing.B, size int) { 1730 src := rand.NewSource(1) 1731 s1 := randomSlice(size, src) 1732 s2 := randomSlice(size, src) 1733 b.ResetTimer() 1734 for i := 0; i < b.N; i++ { 1735 Dot(s1, s2) 1736 } 1737 } 1738 func BenchmarkDotSmall(b *testing.B) { benchmarkDot(b, Small) } 1739 func BenchmarkDotMed(b *testing.B) { benchmarkDot(b, Medium) } 1740 func BenchmarkDotLarge(b *testing.B) { benchmarkDot(b, Large) } 1741 func BenchmarkDotHuge(b *testing.B) { benchmarkDot(b, Huge) } 1742 1743 func benchmarkAddScaledTo(b *testing.B, size int) { 1744 src := rand.NewSource(1) 1745 dst := randomSlice(size, src) 1746 y := randomSlice(size, src) 1747 s := randomSlice(size, src) 1748 b.ResetTimer() 1749 for i := 0; i < b.N; i++ { 1750 AddScaledTo(dst, y, 2.3, s) 1751 } 1752 } 1753 func BenchmarkAddScaledToSmall(b *testing.B) { benchmarkAddScaledTo(b, Small) } 1754 func BenchmarkAddScaledToMedium(b *testing.B) { benchmarkAddScaledTo(b, Medium) } 1755 func BenchmarkAddScaledToLarge(b *testing.B) { benchmarkAddScaledTo(b, Large) } 1756 func BenchmarkAddScaledToHuge(b *testing.B) { benchmarkAddScaledTo(b, Huge) } 1757 1758 func benchmarkScale(b *testing.B, size int) { 1759 src := rand.NewSource(1) 1760 dst := randomSlice(size, src) 1761 b.ResetTimer() 1762 for i := 0; i < b.N; i += 2 { 1763 Scale(2.0, dst) 1764 Scale(0.5, dst) 1765 } 1766 } 1767 func BenchmarkScaleSmall(b *testing.B) { benchmarkScale(b, Small) } 1768 func BenchmarkScaleMedium(b *testing.B) { benchmarkScale(b, Medium) } 1769 func BenchmarkScaleLarge(b *testing.B) { benchmarkScale(b, Large) } 1770 func BenchmarkScaleHuge(b *testing.B) { benchmarkScale(b, Huge) } 1771 1772 func benchmarkNorm2(b *testing.B, size int) { 1773 src := rand.NewSource(1) 1774 s := randomSlice(size, src) 1775 b.ResetTimer() 1776 for i := 0; i < b.N; i++ { 1777 Norm(s, 2) 1778 } 1779 } 1780 func BenchmarkNorm2Small(b *testing.B) { benchmarkNorm2(b, Small) } 1781 func BenchmarkNorm2Medium(b *testing.B) { benchmarkNorm2(b, Medium) } 1782 func BenchmarkNorm2Large(b *testing.B) { benchmarkNorm2(b, Large) } 1783 func BenchmarkNorm2Huge(b *testing.B) { benchmarkNorm2(b, Huge) } 1784 1785 func benchmarkSumCompensated(b *testing.B, size int) { 1786 src := rand.NewSource(1) 1787 s := randomSlice(size, src) 1788 b.ResetTimer() 1789 for i := 0; i < b.N; i++ { 1790 SumCompensated(s) 1791 } 1792 } 1793 1794 func BenchmarkSumCompensatedSmall(b *testing.B) { benchmarkSumCompensated(b, Small) } 1795 func BenchmarkSumCompensatedMedium(b *testing.B) { benchmarkSumCompensated(b, Medium) } 1796 func BenchmarkSumCompensatedLarge(b *testing.B) { benchmarkSumCompensated(b, Large) } 1797 func BenchmarkSumCompensatedHuge(b *testing.B) { benchmarkSumCompensated(b, Huge) } 1798 1799 func benchmarkSum(b *testing.B, size int) { 1800 src := rand.NewSource(1) 1801 s := randomSlice(size, src) 1802 b.ResetTimer() 1803 for i := 0; i < b.N; i++ { 1804 Sum(s) 1805 } 1806 } 1807 1808 func BenchmarkSumSmall(b *testing.B) { benchmarkSum(b, Small) } 1809 func BenchmarkSumMedium(b *testing.B) { benchmarkSum(b, Medium) } 1810 func BenchmarkSumLarge(b *testing.B) { benchmarkSum(b, Large) } 1811 func BenchmarkSumHuge(b *testing.B) { benchmarkSum(b, Huge) }