gonum.org/v1/gonum@v0.14.0/mat/matrix_test.go (about) 1 // Copyright ©2013 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mat 6 7 import ( 8 "fmt" 9 "math" 10 "reflect" 11 "testing" 12 13 "golang.org/x/exp/rand" 14 "gonum.org/v1/gonum/blas" 15 "gonum.org/v1/gonum/blas/blas64" 16 "gonum.org/v1/gonum/floats/scalar" 17 ) 18 19 func panics(fn func()) (panicked bool, message string) { 20 defer func() { 21 r := recover() 22 panicked = r != nil 23 message = fmt.Sprint(r) 24 }() 25 fn() 26 return 27 } 28 29 func flatten(f [][]float64) (r, c int, d []float64) { 30 r = len(f) 31 if r == 0 { 32 panic("bad test: no row") 33 } 34 c = len(f[0]) 35 d = make([]float64, 0, r*c) 36 for _, row := range f { 37 if len(row) != c { 38 panic("bad test: ragged input") 39 } 40 d = append(d, row...) 41 } 42 return r, c, d 43 } 44 45 func unflatten(r, c int, d []float64) [][]float64 { 46 m := make([][]float64, r) 47 for i := 0; i < r; i++ { 48 m[i] = d[i*c : (i+1)*c] 49 } 50 return m 51 } 52 53 // eye returns a new identity matrix of size n×n. 54 func eye(n int) *Dense { 55 d := make([]float64, n*n) 56 for i := 0; i < n*n; i += n + 1 { 57 d[i] = 1 58 } 59 return NewDense(n, n, d) 60 } 61 62 func TestCol(t *testing.T) { 63 t.Parallel() 64 for id, af := range [][][]float64{ 65 { 66 {1, 2, 3}, 67 {4, 5, 6}, 68 {7, 8, 9}, 69 }, 70 { 71 {1, 2, 3}, 72 {4, 5, 6}, 73 {7, 8, 9}, 74 {10, 11, 12}, 75 }, 76 { 77 {1, 2, 3, 4}, 78 {5, 6, 7, 8}, 79 {9, 10, 11, 12}, 80 }, 81 } { 82 a := NewDense(flatten(af)) 83 col := make([]float64, a.mat.Rows) 84 for j := range af[0] { 85 for i := range col { 86 col[i] = float64(i*a.mat.Cols + j + 1) 87 } 88 89 if got := Col(nil, j, a); !reflect.DeepEqual(got, col) { 90 t.Errorf("test %d: unexpected values returned for dense col %d: got: %v want: %v", 91 id, j, got, col) 92 } 93 94 got := make([]float64, a.mat.Rows) 95 if Col(got, j, a); !reflect.DeepEqual(got, col) { 96 t.Errorf("test %d: unexpected values filled for dense col %d: got: %v want: %v", 97 id, j, got, col) 98 } 99 } 100 } 101 102 denseComparison := func(a *Dense) interface{} { 103 r, c := a.Dims() 104 ans := make([][]float64, c) 105 for j := range ans { 106 ans[j] = make([]float64, r) 107 for i := range ans[j] { 108 ans[j][i] = a.At(i, j) 109 } 110 } 111 return ans 112 } 113 114 f := func(a Matrix) interface{} { 115 _, c := a.Dims() 116 ans := make([][]float64, c) 117 for j := range ans { 118 ans[j] = Col(nil, j, a) 119 } 120 return ans 121 } 122 testOneInputFunc(t, "Col", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) 123 124 f = func(a Matrix) interface{} { 125 r, c := a.Dims() 126 ans := make([][]float64, c) 127 for j := range ans { 128 ans[j] = make([]float64, r) 129 Col(ans[j], j, a) 130 } 131 return ans 132 } 133 testOneInputFunc(t, "Col", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) 134 } 135 136 func TestRow(t *testing.T) { 137 t.Parallel() 138 for id, af := range [][][]float64{ 139 { 140 {1, 2, 3}, 141 {4, 5, 6}, 142 {7, 8, 9}, 143 }, 144 { 145 {1, 2, 3}, 146 {4, 5, 6}, 147 {7, 8, 9}, 148 {10, 11, 12}, 149 }, 150 { 151 {1, 2, 3, 4}, 152 {5, 6, 7, 8}, 153 {9, 10, 11, 12}, 154 }, 155 } { 156 a := NewDense(flatten(af)) 157 for i, row := range af { 158 if got := Row(nil, i, a); !reflect.DeepEqual(got, row) { 159 t.Errorf("test %d: unexpected values returned for dense row %d: got: %v want: %v", 160 id, i, got, row) 161 } 162 163 got := make([]float64, len(row)) 164 if Row(got, i, a); !reflect.DeepEqual(got, row) { 165 t.Errorf("test %d: unexpected values filled for dense row %d: got: %v want: %v", 166 id, i, got, row) 167 } 168 } 169 } 170 171 denseComparison := func(a *Dense) interface{} { 172 r, c := a.Dims() 173 ans := make([][]float64, r) 174 for i := range ans { 175 ans[i] = make([]float64, c) 176 for j := range ans[i] { 177 ans[i][j] = a.At(i, j) 178 } 179 } 180 return ans 181 } 182 183 f := func(a Matrix) interface{} { 184 r, _ := a.Dims() 185 ans := make([][]float64, r) 186 for i := range ans { 187 ans[i] = Row(nil, i, a) 188 } 189 return ans 190 } 191 testOneInputFunc(t, "Row", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) 192 193 f = func(a Matrix) interface{} { 194 r, c := a.Dims() 195 ans := make([][]float64, r) 196 for i := range ans { 197 ans[i] = make([]float64, c) 198 Row(ans[i], i, a) 199 } 200 return ans 201 } 202 testOneInputFunc(t, "Row", f, denseComparison, sameAnswerF64SliceOfSlice, isAnyType, isAnySize) 203 } 204 205 func TestCond(t *testing.T) { 206 t.Parallel() 207 for i, test := range []struct { 208 a *Dense 209 condOne float64 210 condTwo float64 211 condInf float64 212 }{ 213 { 214 a: NewDense(3, 3, []float64{ 215 8, 1, 6, 216 3, 5, 7, 217 4, 9, 2, 218 }), 219 condOne: 16.0 / 3.0, 220 condTwo: 4.330127018922192, 221 condInf: 16.0 / 3.0, 222 }, 223 { 224 a: NewDense(4, 4, []float64{ 225 2, 9, 3, 2, 226 10, 9, 9, 3, 227 1, 1, 5, 2, 228 8, 4, 10, 2, 229 }), 230 condOne: 1 / 0.024740155174938, 231 condTwo: 34.521576567075087, 232 condInf: 1 / 0.012034465570035, 233 }, 234 { 235 a: NewDense(3, 3, []float64{ 236 5, 6, 7, 237 8, -2, 1, 238 7, 7, 7}), 239 condOne: 30.769230769230749, 240 condTwo: 21.662689498448440, 241 condInf: 31.153846153846136, 242 }, 243 } { 244 orig := DenseCopyOf(test.a) 245 condOne := Cond(test.a, 1) 246 if !scalar.EqualWithinAbsOrRel(test.condOne, condOne, 1e-13, 1e-13) { 247 t.Errorf("Case %d: one norm mismatch. Want %v, got %v", i, test.condOne, condOne) 248 } 249 if !Equal(test.a, orig) { 250 t.Errorf("Case %d: unexpected mutation of input matrix for one norm. Want %v, got %v", i, orig, test.a) 251 } 252 condTwo := Cond(test.a, 2) 253 if !scalar.EqualWithinAbsOrRel(test.condTwo, condTwo, 1e-13, 1e-13) { 254 t.Errorf("Case %d: two norm mismatch. Want %v, got %v", i, test.condTwo, condTwo) 255 } 256 if !Equal(test.a, orig) { 257 t.Errorf("Case %d: unexpected mutation of input matrix for two norm. Want %v, got %v", i, orig, test.a) 258 } 259 condInf := Cond(test.a, math.Inf(1)) 260 if !scalar.EqualWithinAbsOrRel(test.condInf, condInf, 1e-13, 1e-13) { 261 t.Errorf("Case %d: inf norm mismatch. Want %v, got %v", i, test.condInf, condInf) 262 } 263 if !Equal(test.a, orig) { 264 t.Errorf("Case %d: unexpected mutation of input matrix for inf norm. Want %v, got %v", i, orig, test.a) 265 } 266 } 267 268 for _, test := range []struct { 269 name string 270 norm float64 271 }{ 272 { 273 name: "CondOne", 274 norm: 1, 275 }, 276 { 277 name: "CondTwo", 278 norm: 2, 279 }, 280 { 281 name: "CondInf", 282 norm: math.Inf(1), 283 }, 284 } { 285 f := func(a Matrix) interface{} { 286 return Cond(a, test.norm) 287 } 288 denseComparison := func(a *Dense) interface{} { 289 return Cond(a, test.norm) 290 } 291 testOneInputFunc(t, test.name, f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isAnySize) 292 } 293 } 294 295 func TestDet(t *testing.T) { 296 t.Parallel() 297 for c, test := range []struct { 298 a *Dense 299 ans float64 300 }{ 301 { 302 a: NewDense(2, 2, []float64{1, 0, 0, 1}), 303 ans: 1, 304 }, 305 { 306 a: NewDense(2, 2, []float64{1, 0, 0, -1}), 307 ans: -1, 308 }, 309 { 310 a: NewDense(3, 3, []float64{ 311 1, 2, 0, 312 0, 1, 2, 313 0, 2, 1, 314 }), 315 ans: -3, 316 }, 317 { 318 a: NewDense(3, 3, []float64{ 319 1, 2, 3, 320 5, 7, 9, 321 6, 9, 12, 322 }), 323 ans: 0, 324 }, 325 } { 326 a := DenseCopyOf(test.a) 327 det := Det(a) 328 if !Equal(a, test.a) { 329 t.Errorf("Input matrix changed during Det. Case %d.", c) 330 } 331 if !scalar.EqualWithinAbsOrRel(det, test.ans, 1e-14, 1e-14) { 332 t.Errorf("Det mismatch case %d. Got %v, want %v", c, det, test.ans) 333 } 334 } 335 // Perform the normal list test to ensure it works for all types. 336 f := func(a Matrix) interface{} { 337 return Det(a) 338 } 339 denseComparison := func(a *Dense) interface{} { 340 return Det(a) 341 } 342 testOneInputFunc(t, "Det", f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isSquare) 343 344 // Check that it gives approximately the same answer as Cholesky 345 // Ensure the input matrices are wider than tall so they are full rank 346 isWide := func(ar, ac int) bool { 347 return ar <= ac 348 } 349 f = func(a Matrix) interface{} { 350 ar, ac := a.Dims() 351 if !isWide(ar, ac) { 352 panic(ErrShape) 353 } 354 var tmp Dense 355 tmp.Mul(a, a.T()) 356 return Det(&tmp) 357 } 358 denseComparison = func(a *Dense) interface{} { 359 ar, ac := a.Dims() 360 if !isWide(ar, ac) { 361 panic(ErrShape) 362 } 363 var tmp SymDense 364 tmp.SymOuterK(1, a) 365 var chol Cholesky 366 ok := chol.Factorize(&tmp) 367 if !ok { 368 panic("bad chol test") 369 } 370 return chol.Det() 371 } 372 testOneInputFunc(t, "DetVsChol", f, denseComparison, sameAnswerFloatApproxTol(1e-10), isAnyType, isWide) 373 } 374 375 func TestDot(t *testing.T) { 376 t.Parallel() 377 f := func(a, b Matrix) interface{} { 378 return Dot(a.(Vector), b.(Vector)) 379 } 380 denseComparison := func(a, b *Dense) interface{} { 381 ra, ca := a.Dims() 382 rb, cb := b.Dims() 383 if ra != rb || ca != cb { 384 panic(ErrShape) 385 } 386 var sum float64 387 for i := 0; i < ra; i++ { 388 for j := 0; j < ca; j++ { 389 sum += a.At(i, j) * b.At(i, j) 390 } 391 } 392 return sum 393 } 394 testTwoInputFunc(t, "Dot", f, denseComparison, sameAnswerFloatApproxTol(1e-12), legalTypesVectorVector, legalSizeSameVec) 395 } 396 397 func TestEqual(t *testing.T) { 398 t.Parallel() 399 f := func(a, b Matrix) interface{} { 400 return Equal(a, b) 401 } 402 denseComparison := func(a, b *Dense) interface{} { 403 return Equal(a, b) 404 } 405 testTwoInputFunc(t, "Equal", f, denseComparison, sameAnswerBool, legalTypesAll, isAnySize2) 406 } 407 408 func TestMax(t *testing.T) { 409 t.Parallel() 410 // A direct test of Max with *Dense arguments is in TestNewDense. 411 f := func(a Matrix) interface{} { 412 return Max(a) 413 } 414 denseComparison := func(a *Dense) interface{} { 415 return Max(a) 416 } 417 testOneInputFunc(t, "Max", f, denseComparison, sameAnswerFloat, isAnyType, isAnySize) 418 } 419 420 func TestMin(t *testing.T) { 421 t.Parallel() 422 // A direct test of Min with *Dense arguments is in TestNewDense. 423 f := func(a Matrix) interface{} { 424 return Min(a) 425 } 426 denseComparison := func(a *Dense) interface{} { 427 return Min(a) 428 } 429 testOneInputFunc(t, "Min", f, denseComparison, sameAnswerFloat, isAnyType, isAnySize) 430 } 431 432 func TestNorm(t *testing.T) { 433 t.Parallel() 434 for i, test := range []struct { 435 a [][]float64 436 ord float64 437 norm float64 438 }{ 439 { 440 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, 441 ord: 1, 442 norm: 30, 443 }, 444 { 445 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, 446 ord: 2, 447 norm: 25.495097567963924, 448 }, 449 { 450 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, 451 ord: math.Inf(1), 452 norm: 33, 453 }, 454 { 455 a: [][]float64{{1, -2, -2}, {-4, 5, 6}}, 456 ord: 1, 457 norm: 8, 458 }, 459 { 460 a: [][]float64{{1, -2, -2}, {-4, 5, 6}}, 461 ord: math.Inf(1), 462 norm: 15, 463 }, 464 } { 465 a := NewDense(flatten(test.a)) 466 if math.Abs(Norm(a, test.ord)-test.norm) > 1e-14 { 467 t.Errorf("Mismatch test %d: %v norm = %f", i, test.a, test.norm) 468 } 469 } 470 471 for _, test := range []struct { 472 name string 473 norm float64 474 }{ 475 {"NormOne", 1}, 476 {"NormTwo", 2}, 477 {"NormInf", math.Inf(1)}, 478 } { 479 f := func(a Matrix) interface{} { 480 return Norm(a, test.norm) 481 } 482 denseComparison := func(a *Dense) interface{} { 483 return Norm(a, test.norm) 484 } 485 testOneInputFunc(t, test.name, f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isAnySize) 486 } 487 } 488 489 func TestNormZero(t *testing.T) { 490 t.Parallel() 491 for _, a := range []Matrix{ 492 &Dense{}, 493 &SymDense{}, 494 &SymDense{mat: blas64.Symmetric{Uplo: blas.Upper}}, 495 &TriDense{}, 496 &TriDense{mat: blas64.Triangular{Uplo: blas.Upper, Diag: blas.NonUnit}}, 497 &VecDense{}, 498 } { 499 for _, norm := range []float64{1, 2, math.Inf(1)} { 500 panicked, message := panics(func() { Norm(a, norm) }) 501 if !panicked { 502 t.Errorf("expected panic for Norm(&%T{}, %v)", a, norm) 503 } 504 if message != ErrZeroLength.Error() { 505 t.Errorf("unexpected panic string for Norm(&%T{}, %v): got:%s want:%s", 506 a, norm, message, ErrShape.Error()) 507 } 508 } 509 } 510 } 511 512 func TestSum(t *testing.T) { 513 t.Parallel() 514 f := func(a Matrix) interface{} { 515 return Sum(a) 516 } 517 denseComparison := func(a *Dense) interface{} { 518 return Sum(a) 519 } 520 testOneInputFunc(t, "Sum", f, denseComparison, sameAnswerFloatApproxTol(1e-12), isAnyType, isAnySize) 521 } 522 523 func TestTrace(t *testing.T) { 524 t.Parallel() 525 for _, test := range []struct { 526 a *Dense 527 trace float64 528 }{ 529 { 530 a: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), 531 trace: 15, 532 }, 533 } { 534 trace := Trace(test.a) 535 if trace != test.trace { 536 t.Errorf("Trace mismatch. Want %v, got %v", test.trace, trace) 537 } 538 } 539 f := func(a Matrix) interface{} { 540 return Trace(a) 541 } 542 denseComparison := func(a *Dense) interface{} { 543 return Trace(a) 544 } 545 testOneInputFunc(t, "Trace", f, denseComparison, sameAnswerFloatApproxTol(1e-15), isAnyType, isSquare) 546 } 547 548 func TestTracer(t *testing.T) { 549 t.Parallel() 550 for _, test := range []struct { 551 a Tracer 552 want float64 553 }{ 554 { 555 a: NewDense(3, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9}), 556 want: 15, 557 }, 558 { 559 a: NewSymDense(4, []float64{1, 2, 3, 4, 0, 5, 6, 7, 0, 0, 8, 9, 0, 0, 0, 10}), 560 want: 24, 561 }, 562 { 563 a: NewBandDense(6, 6, 1, 2, []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 19, 20, 0, 0}), 564 want: 65, 565 }, 566 { 567 a: NewDiagDense(6, []float64{1, 2, 3, 4, 5, 6}), 568 want: 21, 569 }, 570 { 571 a: NewSymBandDense(6, 2, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, 0, 0}), 572 want: 50, 573 }, 574 { 575 a: NewTriBandDense(6, 2, Upper, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15, 0, 0}), 576 want: 50, 577 }, 578 { 579 a: NewTriBandDense(6, 2, Lower, []float64{0, 0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}), 580 want: 46, 581 }, 582 } { 583 got := test.a.Trace() 584 if got != test.want { 585 t.Errorf("Trace mismatch. Want %v, got %v", test.want, got) 586 } 587 } 588 } 589 590 func TestDoer(t *testing.T) { 591 t.Parallel() 592 type MatrixDoer interface { 593 Matrix 594 NonZeroDoer 595 RowNonZeroDoer 596 ColNonZeroDoer 597 } 598 ones := func(n int) []float64 { 599 data := make([]float64, n) 600 for i := range data { 601 data[i] = 1 602 } 603 return data 604 } 605 for i, m := range []MatrixDoer{ 606 NewTriDense(3, Lower, ones(3*3)), 607 NewTriDense(3, Upper, ones(3*3)), 608 NewBandDense(6, 6, 1, 1, ones(3*6)), 609 NewBandDense(6, 10, 1, 1, ones(3*6)), 610 NewBandDense(10, 6, 1, 1, ones(7*3)), 611 NewSymBandDense(3, 0, ones(3)), 612 NewSymBandDense(3, 1, ones(3*(1+1))), 613 NewSymBandDense(6, 1, ones(6*(1+1))), 614 NewSymBandDense(6, 2, ones(6*(2+1))), 615 NewTriBandDense(3, 0, Upper, ones(3)), 616 NewTriBandDense(3, 1, Upper, ones(3*(1+1))), 617 NewTriBandDense(6, 1, Upper, ones(6*(1+1))), 618 NewTriBandDense(6, 2, Upper, ones(6*(2+1))), 619 NewTriBandDense(3, 0, Lower, ones(3)), 620 NewTriBandDense(3, 1, Lower, ones(3*(1+1))), 621 NewTriBandDense(6, 1, Lower, ones(6*(1+1))), 622 NewTriBandDense(6, 2, Lower, ones(6*(2+1))), 623 NewTridiag(1, nil, ones(1), nil), 624 NewTridiag(2, ones(1), ones(2), ones(1)), 625 NewTridiag(3, ones(2), ones(3), ones(2)), 626 NewTridiag(4, ones(3), ones(4), ones(3)), 627 NewTridiag(7, ones(6), ones(7), ones(6)), 628 NewTridiag(10, ones(9), ones(10), ones(9)), 629 } { 630 r, c := m.Dims() 631 632 want := Sum(m) 633 634 // got and fn sum the accessed elements in 635 // the Doer that is being operated on. 636 // fn also tests that the accessed elements 637 // are within the writable areas of the 638 // matrix to check that only valid elements 639 // are operated on. 640 var got float64 641 fn := func(i, j int, v float64) { 642 got += v 643 switch m := m.(type) { 644 case MutableTriangular: 645 m.SetTri(i, j, v) 646 case MutableBanded: 647 m.SetBand(i, j, v) 648 case MutableSymBanded: 649 m.SetSymBand(i, j, v) 650 case MutableTriBanded: 651 m.SetTriBand(i, j, v) 652 default: 653 panic("bad test: need mutable type") 654 } 655 } 656 657 panicked, message := panics(func() { m.DoNonZero(fn) }) 658 if panicked { 659 t.Errorf("unexpected panic for Doer test %d: %q", i, message) 660 continue 661 } 662 if got != want { 663 t.Errorf("unexpected Doer sum: got:%f want:%f", got, want) 664 } 665 666 // Reset got for testing with DoRowNonZero. 667 got = 0 668 panicked, message = panics(func() { 669 for i := 0; i < r; i++ { 670 m.DoRowNonZero(i, fn) 671 } 672 }) 673 if panicked { 674 t.Errorf("unexpected panic for RowDoer test %d: %q", i, message) 675 continue 676 } 677 if got != want { 678 t.Errorf("unexpected RowDoer sum: got:%f want:%f", got, want) 679 } 680 681 // Reset got for testing with DoColNonZero. 682 got = 0 683 panicked, message = panics(func() { 684 for j := 0; j < c; j++ { 685 m.DoColNonZero(j, fn) 686 } 687 }) 688 if panicked { 689 t.Errorf("unexpected panic for ColDoer test %d: %q", i, message) 690 continue 691 } 692 if got != want { 693 t.Errorf("unexpected ColDoer sum: got:%f want:%f", got, want) 694 } 695 } 696 } 697 698 func TestMulVecToer(t *testing.T) { 699 t.Parallel() 700 const tol = 1e-14 701 702 rnd := rand.New(rand.NewSource(1)) 703 random := func(n int) []float64 { 704 d := make([]float64, n) 705 for i := range d { 706 d[i] = rnd.NormFloat64() 707 } 708 return d 709 } 710 711 type mulVecToer interface { 712 Matrix 713 MulVecTo(*VecDense, bool, Vector) 714 } 715 for _, a := range []mulVecToer{ 716 NewBandDense(1, 1, 0, 0, random(1)), 717 NewBandDense(3, 1, 0, 0, random(1)), 718 NewBandDense(3, 1, 1, 0, random(4)), 719 NewBandDense(1, 3, 0, 0, random(1)), 720 NewBandDense(1, 3, 0, 1, random(2)), 721 NewBandDense(7, 10, 0, 0, random(7)), 722 NewBandDense(7, 10, 2, 3, random(42)), 723 NewBandDense(10, 7, 0, 0, random(7)), 724 NewBandDense(10, 7, 2, 3, random(54)), 725 NewBandDense(10, 10, 0, 0, random(10)), 726 NewBandDense(10, 10, 2, 3, random(60)), 727 NewSymBandDense(1, 0, random(1)), 728 NewSymBandDense(3, 0, random(3)), 729 NewSymBandDense(3, 1, random(6)), 730 NewSymBandDense(10, 0, random(10)), 731 NewSymBandDense(10, 1, random(20)), 732 NewSymBandDense(10, 4, random(50)), 733 NewTridiag(1, nil, random(1), nil), 734 NewTridiag(2, random(1), random(2), random(1)), 735 NewTridiag(3, random(2), random(3), random(2)), 736 NewTridiag(4, random(3), random(4), random(3)), 737 NewTridiag(7, random(6), random(7), random(6)), 738 NewTridiag(10, random(9), random(10), random(9)), 739 } { 740 // Dense copy of A used for computing the expected result. 741 var aDense Dense 742 aDense.CloneFrom(a) 743 744 r, c := a.Dims() 745 for _, trans := range []bool{false, true} { 746 m, n := r, c 747 if trans { 748 m, n = c, r 749 } 750 for _, dst := range []*VecDense{ 751 new(VecDense), 752 NewVecDense(m, random(m)), 753 } { 754 for xType := 0; xType <= 3; xType++ { 755 var x Vector 756 switch xType { 757 case 0: 758 x = NewVecDense(n, random(n)) 759 case 1: 760 if m != n { 761 continue 762 } 763 x = dst 764 case 2: 765 x = &rawVector{asBasicVector(NewVecDense(n, random(n)))} 766 case 3: 767 x = asBasicVector(NewVecDense(n, random(n))) 768 default: 769 panic("bad xType") 770 } 771 772 var want VecDense 773 if !trans { 774 want.MulVec(&aDense, x) 775 } else { 776 want.MulVec(aDense.T(), x) 777 } 778 779 a.MulVecTo(dst, trans, x) 780 781 var diff VecDense 782 diff.SubVec(dst, &want) 783 if resid := Norm(&diff, 1); resid > tol*float64(m) { 784 t.Errorf("r=%d,c=%d,trans=%t,xType=%d: unexpected result; resid=%v, want<=%v", 785 r, c, trans, xType, resid, tol*float64(m)) 786 } 787 } 788 } 789 } 790 } 791 }