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