github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/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 "github.com/jingcheng-WU/gonum/blas" 15 "github.com/jingcheng-WU/gonum/blas/blas64" 16 "github.com/jingcheng-WU/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 != ErrShape.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, sameAnswerFloat, 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 } { 616 r, c := m.Dims() 617 618 want := Sum(m) 619 620 // got and fn sum the accessed elements in 621 // the Doer that is being operated on. 622 // fn also tests that the accessed elements 623 // are within the writable areas of the 624 // matrix to check that only valid elements 625 // are operated on. 626 var got float64 627 fn := func(i, j int, v float64) { 628 got += v 629 switch m := m.(type) { 630 case MutableTriangular: 631 m.SetTri(i, j, v) 632 case MutableBanded: 633 m.SetBand(i, j, v) 634 case MutableSymBanded: 635 m.SetSymBand(i, j, v) 636 default: 637 panic("bad test: need mutable type") 638 } 639 } 640 641 panicked, message := panics(func() { m.DoNonZero(fn) }) 642 if panicked { 643 t.Errorf("unexpected panic for Doer test %d: %q", i, message) 644 continue 645 } 646 if got != want { 647 t.Errorf("unexpected Doer sum: got:%f want:%f", got, want) 648 } 649 650 // Reset got for testing with DoRowNonZero. 651 got = 0 652 panicked, message = panics(func() { 653 for i := 0; i < r; i++ { 654 m.DoRowNonZero(i, fn) 655 } 656 }) 657 if panicked { 658 t.Errorf("unexpected panic for RowDoer test %d: %q", i, message) 659 continue 660 } 661 if got != want { 662 t.Errorf("unexpected RowDoer sum: got:%f want:%f", got, want) 663 } 664 665 // Reset got for testing with DoColNonZero. 666 got = 0 667 panicked, message = panics(func() { 668 for j := 0; j < c; j++ { 669 m.DoColNonZero(j, fn) 670 } 671 }) 672 if panicked { 673 t.Errorf("unexpected panic for ColDoer test %d: %q", i, message) 674 continue 675 } 676 if got != want { 677 t.Errorf("unexpected ColDoer sum: got:%f want:%f", got, want) 678 } 679 } 680 } 681 682 func TestMulVecToer(t *testing.T) { 683 t.Parallel() 684 const tol = 1e-14 685 686 rnd := rand.New(rand.NewSource(1)) 687 random := func(n int) []float64 { 688 d := make([]float64, n) 689 for i := range d { 690 d[i] = rnd.NormFloat64() 691 } 692 return d 693 } 694 695 type mulVecToer interface { 696 Matrix 697 MulVecTo(*VecDense, bool, Vector) 698 } 699 for _, a := range []mulVecToer{ 700 NewBandDense(1, 1, 0, 0, random(1)), 701 NewBandDense(3, 1, 0, 0, random(1)), 702 NewBandDense(3, 1, 1, 0, random(4)), 703 NewBandDense(1, 3, 0, 0, random(1)), 704 NewBandDense(1, 3, 0, 1, random(2)), 705 NewBandDense(7, 10, 0, 0, random(7)), 706 NewBandDense(7, 10, 2, 3, random(42)), 707 NewBandDense(10, 7, 0, 0, random(7)), 708 NewBandDense(10, 7, 2, 3, random(54)), 709 NewBandDense(10, 10, 0, 0, random(10)), 710 NewBandDense(10, 10, 2, 3, random(60)), 711 NewSymBandDense(1, 0, random(1)), 712 NewSymBandDense(3, 0, random(3)), 713 NewSymBandDense(3, 1, random(6)), 714 NewSymBandDense(10, 0, random(10)), 715 NewSymBandDense(10, 1, random(20)), 716 NewSymBandDense(10, 4, random(50)), 717 } { 718 // Dense copy of A used for computing the expected result. 719 var aDense Dense 720 aDense.CloneFrom(a) 721 722 r, c := a.Dims() 723 for _, trans := range []bool{false, true} { 724 m, n := r, c 725 if trans { 726 m, n = c, r 727 } 728 for _, dst := range []*VecDense{ 729 new(VecDense), 730 NewVecDense(m, random(m)), 731 } { 732 for xType := 0; xType <= 3; xType++ { 733 var x Vector 734 switch xType { 735 case 0: 736 x = NewVecDense(n, random(n)) 737 case 1: 738 if m != n { 739 continue 740 } 741 x = dst 742 case 2: 743 x = &rawVector{asBasicVector(NewVecDense(n, random(n)))} 744 case 3: 745 x = asBasicVector(NewVecDense(n, random(n))) 746 default: 747 panic("bad xType") 748 } 749 750 var want VecDense 751 if !trans { 752 want.MulVec(&aDense, x) 753 } else { 754 want.MulVec(aDense.T(), x) 755 } 756 757 a.MulVecTo(dst, trans, x) 758 759 var diff VecDense 760 diff.SubVec(dst, &want) 761 if resid := Norm(&diff, 1); resid > tol*float64(m) { 762 t.Errorf("r=%d,c=%d,trans=%t,xType=%d: unexpected result; resid=%v, want<=%v", 763 r, c, trans, xType, resid, tol*float64(m)) 764 } 765 } 766 } 767 } 768 } 769 }