1 // Copyright ©2015 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.
13 "golang.org/x/exp/rand"
15 "gonum.org/v1/gonum/blas"
16 "gonum.org/v1/gonum/blas/blas64"
17 "gonum.org/v1/gonum/floats"
20 // legalSizeSameRectangular returns whether the two matrices have the same rectangular shape.
21 func legalSizeSameRectangular(ar, ac, br, bc int) bool {
31 // legalSizeSameSquare returns whether the two matrices have the same square shape.
32 func legalSizeSameSquare(ar, ac, br, bc int) bool {
45 // legalSizeSameHeight returns whether the two matrices have the same number of rows.
46 func legalSizeSameHeight(ar, _, br, _ int) bool {
50 // legalSizeSameWidth returns whether the two matrices have the same number of columns.
51 func legalSizeSameWidth(_, ac, _, bc int) bool {
55 // legalSizeSolve returns whether the two matrices can be used in a linear solve.
56 func legalSizeSolve(ar, ac, br, bc int) bool {
60 // legalSizeSameVec returns whether the two matrices are column vectors.
61 func legalSizeVector(_, ac, _, bc int) bool {
62 return ac == 1 && bc == 1
65 // legalSizeSameVec returns whether the two matrices are column vectors of the
67 func legalSizeSameVec(ar, ac, br, bc int) bool {
68 return ac == 1 && bc == 1 && ar == br
71 // isAnySize returns true for all matrix sizes.
72 func isAnySize(ar, ac int) bool {
76 // isAnySize2 returns true for all matrix sizes.
77 func isAnySize2(ar, ac, br, bc int) bool {
81 // isAnyColumnVector returns true for any column vector sizes.
82 func isAnyColumnVector(ar, ac int) bool {
86 // isSquare returns whether the input matrix is square.
87 func isSquare(r, c int) bool {
91 // sameAnswerFloat returns whether the two inputs are both NaN or are equal.
92 func sameAnswerFloat(a, b interface{}) bool {
93 if math.IsNaN(a.(float64)) {
94 return math.IsNaN(b.(float64))
96 return a.(float64) == b.(float64)
99 // sameAnswerFloatApproxTol returns a function that determines whether its two
100 // inputs are both NaN or within tol of each other.
101 func sameAnswerFloatApproxTol(tol float64) func(a, b interface{}) bool {
102 return func(a, b interface{}) bool {
103 if math.IsNaN(a.(float64)) {
104 return math.IsNaN(b.(float64))
106 return floats.EqualWithinAbsOrRel(a.(float64), b.(float64), tol, tol)
110 func sameAnswerF64SliceOfSlice(a, b interface{}) bool {
111 for i, v := range a.([][]float64) {
112 if same := floats.Same(v, b.([][]float64)[i]); !same {
119 // sameAnswerBool returns whether the two inputs have the same value.
120 func sameAnswerBool(a, b interface{}) bool {
121 return a.(bool) == b.(bool)
124 // isAnyType returns true for all Matrix types.
125 func isAnyType(Matrix) bool {
129 // legalTypesAll returns true for all Matrix types.
130 func legalTypesAll(a, b Matrix) bool {
134 // legalTypeSym returns whether a is a Symmetric.
135 func legalTypeSym(a Matrix) bool {
136 _, ok := a.(Symmetric)
140 // legalTypeTri returns whether a is a Triangular.
141 func legalTypeTri(a Matrix) bool {
142 _, ok := a.(Triangular)
146 // legalTypeTriLower returns whether a is a Triangular with kind == Lower.
147 func legalTypeTriLower(a Matrix) bool {
148 t, ok := a.(Triangular)
152 _, kind := t.Triangle()
156 // legalTypeTriUpper returns whether a is a Triangular with kind == Upper.
157 func legalTypeTriUpper(a Matrix) bool {
158 t, ok := a.(Triangular)
162 _, kind := t.Triangle()
166 // legalTypesSym returns whether both input arguments are Symmetric.
167 func legalTypesSym(a, b Matrix) bool {
168 if _, ok := a.(Symmetric); !ok {
171 if _, ok := b.(Symmetric); !ok {
177 // legalTypeVector returns whether v is a Vector.
178 func legalTypeVector(v Matrix) bool {
183 // legalTypeVec returns whether v is a *VecDense.
184 func legalTypeVecDense(v Matrix) bool {
185 _, ok := v.(*VecDense)
189 // legalTypesVectorVector returns whether both inputs are Vector
190 func legalTypesVectorVector(a, b Matrix) bool {
191 if _, ok := a.(Vector); !ok {
194 if _, ok := b.(Vector); !ok {
200 // legalTypesVecDenseVecDense returns whether both inputs are *VecDense.
201 func legalTypesVecDenseVecDense(a, b Matrix) bool {
202 if _, ok := a.(*VecDense); !ok {
205 if _, ok := b.(*VecDense); !ok {
211 // legalTypesMatrixVector returns whether the first input is an arbitrary Matrix
212 // and the second input is a Vector.
213 func legalTypesMatrixVector(a, b Matrix) bool {
218 // legalTypesMatrixVecDense returns whether the first input is an arbitrary Matrix
219 // and the second input is a *VecDense.
220 func legalTypesMatrixVecDense(a, b Matrix) bool {
221 _, ok := b.(*VecDense)
225 // legalDims returns whether {m,n} is a valid dimension of the given matrix type.
226 func legalDims(a Matrix, m, n int) bool {
227 switch t := a.(type) {
229 panic("legal dims type not coded")
231 return legalDims(t.Untranspose(), n, m)
232 case *Dense, *basicMatrix:
237 case *SymDense, *TriDense, *basicSymmetric, *basicTriangular:
238 if m < 0 || n < 0 || m != n {
242 case *VecDense, *basicVector:
250 // returnAs returns the matrix a with the type of t. Used for making a concrete
251 // type and changing to the basic form.
252 func returnAs(a, t Matrix) Matrix {
253 switch mat := a.(type) {
255 panic("unknown type for a")
263 return asBasicMatrix(mat)
271 case *basicSymmetric:
272 return asBasicSymmetric(mat)
280 case *basicTriangular:
281 return asBasicTriangular(mat)
286 // retranspose returns the matrix m inside an Untransposer of the type
288 func retranspose(a, m Matrix) Matrix {
291 return TransposeTri{m.(Triangular)}
295 panic("unknown transposer type")
297 panic("a is not an untransposer")
301 // makeRandOf returns a new randomly filled m×n matrix of the underlying matrix type.
302 func makeRandOf(a Matrix, m, n int) Matrix {
304 switch t := a.(type) {
306 panic("unknown type for make rand of")
308 rMatrix = retranspose(a, makeRandOf(t.Untranspose(), n, m))
309 case *Dense, *basicMatrix:
310 mat := NewDense(m, n, nil)
311 for i := 0; i < m; i++ {
312 for j := 0; j < n; j++ {
313 mat.Set(i, j, rand.NormFloat64())
316 rMatrix = returnAs(mat, t)
318 if m == 0 && n == 0 {
322 panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n))
332 Data: make([]float64, inc*(length-1)+1),
336 for i := 0; i < length; i++ {
337 mat.SetVec(i, rand.NormFloat64())
341 if m == 0 && n == 0 {
342 return &basicVector{}
345 panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n))
348 m: make([]float64, m),
350 for i := 0; i < m; i++ {
351 mat.m[i] = rand.NormFloat64()
354 case *SymDense, *basicSymmetric:
358 mat := NewSymDense(n, nil)
359 for i := 0; i < m; i++ {
360 for j := i; j < n; j++ {
361 mat.SetSym(i, j, rand.NormFloat64())
364 rMatrix = returnAs(mat, t)
365 case *TriDense, *basicTriangular:
370 // This is necessary because we are making
371 // a triangle from the zero value, which
372 // always returns upper as true.
374 switch t := t.(type) {
376 triKind = t.triKind()
377 case *basicTriangular:
378 triKind = (*TriDense)(t).triKind()
381 mat := NewTriDense(n, triKind, nil)
382 if triKind == Upper {
383 for i := 0; i < m; i++ {
384 for j := i; j < n; j++ {
385 mat.SetTri(i, j, rand.NormFloat64())
389 for i := 0; i < m; i++ {
390 for j := 0; j <= i; j++ {
391 mat.SetTri(i, j, rand.NormFloat64())
395 rMatrix = returnAs(mat, t)
397 if mr, mc := rMatrix.Dims(); mr != m || mc != n {
398 panic(fmt.Sprintf("makeRandOf for %T returns wrong size: %d×%d != %d×%d", a, m, n, mr, mc))
403 // makeCopyOf returns a copy of the matrix.
404 func makeCopyOf(a Matrix) Matrix {
405 switch t := a.(type) {
407 panic("unknown type in makeCopyOf")
409 return retranspose(a, makeCopyOf(t.Untranspose()))
410 case *Dense, *basicMatrix:
413 return returnAs(&m, t)
414 case *SymDense, *basicSymmetric:
415 n := t.(Symmetric).Symmetric()
416 m := NewSymDense(n, nil)
417 m.CopySym(t.(Symmetric))
418 return returnAs(m, t)
419 case *TriDense, *basicTriangular:
420 n, upper := t.(Triangular).Triangle()
421 m := NewTriDense(n, upper, nil)
423 for i := 0; i < n; i++ {
424 for j := i; j < n; j++ {
425 m.SetTri(i, j, t.At(i, j))
429 for i := 0; i < n; i++ {
430 for j := 0; j <= i; j++ {
431 m.SetTri(i, j, t.At(i, j))
435 return returnAs(m, t)
440 Data: make([]float64, t.mat.Inc*(t.n-1)+1),
444 copy(m.mat.Data, t.mat.Data)
448 m: make([]float64, t.Len()),
455 // sameType returns true if a and b have the same underlying type.
456 func sameType(a, b Matrix) bool {
457 return reflect.ValueOf(a).Type() == reflect.ValueOf(b).Type()
460 // maybeSame returns true if the two matrices could be represented by the same
462 func maybeSame(receiver, a Matrix) bool {
463 rr, rc := receiver.Dims()
464 u, trans := a.(Untransposer)
468 if !sameType(receiver, a) {
472 if rr != ar || rc != ac {
475 if _, ok := a.(Triangular); ok {
476 // They are both triangular types. The TriType needs to match
477 _, aKind := a.(Triangular).Triangle()
478 _, rKind := receiver.(Triangular).Triangle()
486 // equalApprox returns whether the elements of a and b are the same to within
487 // the tolerance. If ignoreNaN is true the test is relaxed such that NaN == NaN.
488 func equalApprox(a, b Matrix, tol float64, ignoreNaN bool) bool {
497 for i := 0; i < ar; i++ {
498 for j := 0; j < ac; j++ {
499 if !floats.EqualWithinAbsOrRel(a.At(i, j), b.At(i, j), tol, tol) {
500 if ignoreNaN && math.IsNaN(a.At(i, j)) && math.IsNaN(b.At(i, j)) {
510 // equal returns true if the matrices have equal entries.
511 func equal(a, b Matrix) bool {
520 for i := 0; i < ar; i++ {
521 for j := 0; j < ac; j++ {
522 if a.At(i, j) != b.At(i, j) {
530 // isDiagonal returns whether a is a diagonal matrix.
531 func isDiagonal(a Matrix) bool {
533 for i := 0; i < r; i++ {
534 for j := 0; j < c; j++ {
535 if a.At(i, j) != 0 && i != j {
543 // equalDiagonal returns whether a and b are equal on the diagonal.
544 func equalDiagonal(a, b Matrix) bool {
547 if min(ar, ac) != min(br, bc) {
550 for i := 0; i < min(ar, ac); i++ {
551 if a.At(i, i) != b.At(i, i) {
558 // underlyingData extracts the underlying data of the matrix a.
559 func underlyingData(a Matrix) []float64 {
560 switch t := a.(type) {
562 panic("matrix type not implemented for extracting underlying data")
564 return underlyingData(t.Untranspose())
576 // testMatrices is a list of matrix types to test.
577 // The TriDense types have actual sizes because the return from Triangular is
578 // only valid when n == 0.
579 var testMatrices = []Matrix{
582 NewTriDense(3, true, nil),
583 NewTriDense(3, false, nil),
586 &VecDense{mat: blas64.Vector{Inc: 10}},
589 &basicTriangular{cap: 3, mat: blas64.Triangular{N: 3, Stride: 3, Uplo: blas.Upper}},
590 &basicTriangular{cap: 3, mat: blas64.Triangular{N: 3, Stride: 3, Uplo: blas.Lower}},
593 Transpose{NewTriDense(3, true, nil)},
594 TransposeTri{NewTriDense(3, true, nil)},
595 Transpose{NewTriDense(3, false, nil)},
596 TransposeTri{NewTriDense(3, false, nil)},
597 Transpose{NewVecDense(0, nil)},
598 Transpose{&VecDense{mat: blas64.Vector{Inc: 10}}},
599 Transpose{&basicMatrix{}},
600 Transpose{&basicSymmetric{}},
601 Transpose{&basicTriangular{cap: 3, mat: blas64.Triangular{N: 3, Stride: 3, Uplo: blas.Upper}}},
602 Transpose{&basicTriangular{cap: 3, mat: blas64.Triangular{N: 3, Stride: 3, Uplo: blas.Lower}}},
605 var sizes = []struct {
617 func testOneInputFunc(t *testing.T,
618 // name is the name of the function being tested.
621 // f is the function being tested.
622 f func(a Matrix) interface{},
624 // denseComparison performs the same operation, but using Dense matrices for
626 denseComparison func(a *Dense) interface{},
628 // sameAnswer compares the result from two different evaluations of the function
629 // and returns true if they are the same. The specific function being tested
630 // determines the definition of "same". It may mean identical or it may mean
631 // approximately equal.
632 sameAnswer func(a, b interface{}) bool,
634 // legalType returns true if the type of the input is a legal type for the
635 // input of the function.
636 legalType func(a Matrix) bool,
638 // legalSize returns true if the size is valid for the function.
639 legalSize func(r, c int) bool,
641 for _, aMat := range testMatrices {
642 for _, test := range sizes {
643 // Skip the test if the argument would not be assignable to the
644 // method's corresponding input parameter or it is not possible
645 // to construct an argument of the requested size.
646 if !legalType(aMat) {
649 if !legalDims(aMat, test.ar, test.ac) {
652 a := makeRandOf(aMat, test.ar, test.ac)
654 // Compute the true answer if the sizes are legal.
655 dimsOK := legalSize(test.ar, test.ac)
660 want = denseComparison(&aDense)
662 aCopy := makeCopyOf(a)
663 // Test the method for a zero-value of the receiver.
664 aType, aTrans := untranspose(a)
665 errStr := fmt.Sprintf("%v(%T), size: %#v, atrans %t", name, aType, test, aTrans)
667 panicked, err := panics(func() { got = f(a) })
668 if !dimsOK && !panicked {
669 t.Errorf("Did not panic with illegal size: %s", errStr)
672 if dimsOK && panicked {
673 t.Errorf("Panicked with legal size: %s: %v", errStr, err)
676 if !equal(a, aCopy) {
677 t.Errorf("First input argument changed in call: %s", errStr)
682 if !sameAnswer(want, got) {
683 t.Errorf("Answer mismatch: %s", errStr)
689 var sizePairs = []struct {
781 func testTwoInputFunc(t *testing.T,
782 // name is the name of the function being tested.
785 // f is the function being tested.
786 f func(a, b Matrix) interface{},
788 // denseComparison performs the same operation, but using Dense matrices for
790 denseComparison func(a, b *Dense) interface{},
792 // sameAnswer compares the result from two different evaluations of the function
793 // and returns true if they are the same. The specific function being tested
794 // determines the definition of "same". It may mean identical or it may mean
795 // approximately equal.
796 sameAnswer func(a, b interface{}) bool,
798 // legalType returns true if the types of the inputs are legal for the
799 // input of the function.
800 legalType func(a, b Matrix) bool,
802 // legalSize returns true if the sizes are valid for the function.
803 legalSize func(ar, ac, br, bc int) bool,
805 for _, aMat := range testMatrices {
806 for _, bMat := range testMatrices {
807 // Loop over all of the size combinations (bigger, smaller, etc.).
808 for _, test := range sizePairs {
809 // Skip the test if the argument would not be assignable to the
810 // method's corresponding input parameter or it is not possible
811 // to construct an argument of the requested size.
812 if !legalType(aMat, bMat) {
815 if !legalDims(aMat, test.ar, test.ac) {
818 if !legalDims(bMat, test.br, test.bc) {
821 a := makeRandOf(aMat, test.ar, test.ac)
822 b := makeRandOf(bMat, test.br, test.bc)
824 // Compute the true answer if the sizes are legal.
825 dimsOK := legalSize(test.ar, test.ac, test.br, test.bc)
828 var aDense, bDense Dense
831 want = denseComparison(&aDense, &bDense)
833 aCopy := makeCopyOf(a)
834 bCopy := makeCopyOf(b)
835 // Test the method for a zero-value of the receiver.
836 aType, aTrans := untranspose(a)
837 bType, bTrans := untranspose(b)
838 errStr := fmt.Sprintf("%v(%T, %T), size: %#v, atrans %t, btrans %t", name, aType, bType, test, aTrans, bTrans)
840 panicked, err := panics(func() { got = f(a, b) })
841 if !dimsOK && !panicked {
842 t.Errorf("Did not panic with illegal size: %s", errStr)
845 if dimsOK && panicked {
846 t.Errorf("Panicked with legal size: %s: %v", errStr, err)
849 if !equal(a, aCopy) {
850 t.Errorf("First input argument changed in call: %s", errStr)
852 if !equal(b, bCopy) {
853 t.Errorf("First input argument changed in call: %s", errStr)
858 if !sameAnswer(want, got) {
859 t.Errorf("Answer mismatch: %s", errStr)
866 // testOneInput tests a method that has one matrix input argument
867 func testOneInput(t *testing.T,
868 // name is the name of the method being tested.
871 // receiver is a value of the receiver type.
874 // method is the generalized receiver.Method(a).
875 method func(receiver, a Matrix),
877 // denseComparison performs the same operation as method, but with dense
878 // matrices for comparison with the result.
879 denseComparison func(receiver, a *Dense),
881 // legalTypes returns whether the concrete types in Matrix are valid for
883 legalType func(a Matrix) bool,
885 // legalSize returns whether the matrix sizes are valid for the method.
886 legalSize func(ar, ac int) bool,
888 // tol is the tolerance for equality when comparing method results.
891 for _, aMat := range testMatrices {
892 for _, test := range sizes {
893 // Skip the test if the argument would not be assignable to the
894 // method's corresponding input parameter or it is not possible
895 // to construct an argument of the requested size.
896 if !legalType(aMat) {
899 if !legalDims(aMat, test.ar, test.ac) {
902 a := makeRandOf(aMat, test.ar, test.ac)
904 // Compute the true answer if the sizes are legal.
905 dimsOK := legalSize(test.ar, test.ac)
910 denseComparison(&want, &aDense)
912 aCopy := makeCopyOf(a)
914 // Test the method for a zero-value of the receiver.
915 aType, aTrans := untranspose(a)
916 errStr := fmt.Sprintf("%T.%s(%T), size: %#v, atrans %v", receiver, name, aType, test, aTrans)
917 zero := makeRandOf(receiver, 0, 0)
918 panicked, err := panics(func() { method(zero, a) })
919 if !dimsOK && !panicked {
920 t.Errorf("Did not panic with illegal size: %s", errStr)
923 if dimsOK && panicked {
924 t.Errorf("Panicked with legal size: %s: %v", errStr, err)
927 if !equal(a, aCopy) {
928 t.Errorf("First input argument changed in call: %s", errStr)
933 if !equalApprox(zero, &want, tol, false) {
934 t.Errorf("Answer mismatch with zero receiver: %s.\nGot:\n% v\nWant:\n% v\n", errStr, Formatted(zero), Formatted(&want))
938 // Test the method with a non-zero-value of the receiver.
939 // The receiver has been overwritten in place so use its size
940 // to construct a new random matrix.
941 rr, rc := zero.Dims()
942 neverZero := makeRandOf(receiver, rr, rc)
943 panicked, _ = panics(func() { method(neverZero, a) })
945 t.Errorf("Panicked with non-zero receiver: %s", errStr)
947 if !equalApprox(neverZero, &want, tol, false) {
948 t.Errorf("Answer mismatch non-zero receiver: %s", errStr)
951 // Test with an incorrectly sized matrix.
952 switch receiver.(type) {
954 panic("matrix type not coded for incorrect receiver size")
956 wrongSize := makeRandOf(receiver, rr+1, rc)
957 panicked, _ = panics(func() { method(wrongSize, a) })
959 t.Errorf("Did not panic with wrong number of rows: %s", errStr)
961 wrongSize = makeRandOf(receiver, rr, rc+1)
962 panicked, _ = panics(func() { method(wrongSize, a) })
964 t.Errorf("Did not panic with wrong number of columns: %s", errStr)
966 case *TriDense, *SymDense:
967 // Add to the square size.
968 wrongSize := makeRandOf(receiver, rr+1, rc+1)
969 panicked, _ = panics(func() { method(wrongSize, a) })
971 t.Errorf("Did not panic with wrong size: %s", errStr)
974 // Add to the column length.
975 wrongSize := makeRandOf(receiver, rr+1, rc)
976 panicked, _ = panics(func() { method(wrongSize, a) })
978 t.Errorf("Did not panic with wrong number of rows: %s", errStr)
982 // The receiver and the input may share a matrix pointer
983 // if the type and size of the receiver and one of the
984 // arguments match. Test the method works properly
985 // when this is the case.
986 aMaybeSame := maybeSame(neverZero, a)
988 aSame := makeCopyOf(a)
990 u, ok := aSame.(Untransposer)
992 receiver = u.Untranspose()
994 preData := underlyingData(receiver)
995 panicked, err = panics(func() { method(receiver, aSame) })
997 t.Errorf("Panics when a maybeSame: %s: %v", errStr, err)
999 if !equalApprox(receiver, &want, tol, false) {
1000 t.Errorf("Wrong answer when a maybeSame: %s", errStr)
1002 postData := underlyingData(receiver)
1003 if !floats.Equal(preData, postData) {
1004 t.Errorf("Original data slice not modified when a maybeSame: %s", errStr)
1012 // testTwoInput tests a method that has two input arguments.
1013 func testTwoInput(t *testing.T,
1014 // name is the name of the method being tested.
1017 // receiver is a value of the receiver type.
1020 // method is the generalized receiver.Method(a, b).
1021 method func(receiver, a, b Matrix),
1023 // denseComparison performs the same operation as method, but with dense
1024 // matrices for comparison with the result.
1025 denseComparison func(receiver, a, b *Dense),
1027 // legalTypes returns whether the concrete types in Matrix are valid for
1029 legalTypes func(a, b Matrix) bool,
1031 // legalSize returns whether the matrix sizes are valid for the method.
1032 legalSize func(ar, ac, br, bc int) bool,
1034 // tol is the tolerance for equality when comparing method results.
1037 for _, aMat := range testMatrices {
1038 for _, bMat := range testMatrices {
1039 // Loop over all of the size combinations (bigger, smaller, etc.).
1040 for _, test := range sizePairs {
1041 // Skip the test if any argument would not be assignable to the
1042 // method's corresponding input parameter or it is not possible
1043 // to construct an argument of the requested size.
1044 if !legalTypes(aMat, bMat) {
1047 if !legalDims(aMat, test.ar, test.ac) {
1050 if !legalDims(bMat, test.br, test.bc) {
1053 a := makeRandOf(aMat, test.ar, test.ac)
1054 b := makeRandOf(bMat, test.br, test.bc)
1056 // Compute the true answer if the sizes are legal.
1057 dimsOK := legalSize(test.ar, test.ac, test.br, test.bc)
1060 var aDense, bDense Dense
1063 denseComparison(&want, &aDense, &bDense)
1065 aCopy := makeCopyOf(a)
1066 bCopy := makeCopyOf(b)
1068 // Test the method for a zero-value of the receiver.
1069 aType, aTrans := untranspose(a)
1070 bType, bTrans := untranspose(b)
1071 errStr := fmt.Sprintf("%T.%s(%T, %T), sizes: %#v, atrans %v, btrans %v", receiver, name, aType, bType, test, aTrans, bTrans)
1072 zero := makeRandOf(receiver, 0, 0)
1073 panicked, err := panics(func() { method(zero, a, b) })
1074 if !dimsOK && !panicked {
1075 t.Errorf("Did not panic with illegal size: %s", errStr)
1078 if dimsOK && panicked {
1079 t.Errorf("Panicked with legal size: %s: %v", errStr, err)
1082 if !equal(a, aCopy) {
1083 t.Errorf("First input argument changed in call: %s", errStr)
1085 if !equal(b, bCopy) {
1086 t.Errorf("Second input argument changed in call: %s", errStr)
1091 wasZero, zero := zero, nil // Nil-out zero so we detect illegal use.
1092 // NaN equality is allowed because of 0/0 in DivElem test.
1093 if !equalApprox(wasZero, &want, tol, true) {
1094 t.Errorf("Answer mismatch with zero receiver: %s", errStr)
1098 // Test the method with a non-zero-value of the receiver.
1099 // The receiver has been overwritten in place so use its size
1100 // to construct a new random matrix.
1101 rr, rc := wasZero.Dims()
1102 neverZero := makeRandOf(receiver, rr, rc)
1103 panicked, message := panics(func() { method(neverZero, a, b) })
1105 t.Errorf("Panicked with non-zero receiver: %s: %s", errStr, message)
1107 // NaN equality is allowed because of 0/0 in DivElem test.
1108 if !equalApprox(neverZero, &want, tol, true) {
1109 t.Errorf("Answer mismatch non-zero receiver: %s", errStr)
1112 // Test with an incorrectly sized matrix.
1113 switch receiver.(type) {
1115 panic("matrix type not coded for incorrect receiver size")
1117 wrongSize := makeRandOf(receiver, rr+1, rc)
1118 panicked, _ = panics(func() { method(wrongSize, a, b) })
1120 t.Errorf("Did not panic with wrong number of rows: %s", errStr)
1122 wrongSize = makeRandOf(receiver, rr, rc+1)
1123 panicked, _ = panics(func() { method(wrongSize, a, b) })
1125 t.Errorf("Did not panic with wrong number of columns: %s", errStr)
1127 case *TriDense, *SymDense:
1128 // Add to the square size.
1129 wrongSize := makeRandOf(receiver, rr+1, rc+1)
1130 panicked, _ = panics(func() { method(wrongSize, a, b) })
1132 t.Errorf("Did not panic with wrong size: %s", errStr)
1135 // Add to the column length.
1136 wrongSize := makeRandOf(receiver, rr+1, rc)
1137 panicked, _ = panics(func() { method(wrongSize, a, b) })
1139 t.Errorf("Did not panic with wrong number of rows: %s", errStr)
1143 // The receiver and an input may share a matrix pointer
1144 // if the type and size of the receiver and one of the
1145 // arguments match. Test the method works properly
1146 // when this is the case.
1147 aMaybeSame := maybeSame(neverZero, a)
1148 bMaybeSame := maybeSame(neverZero, b)
1150 aSame := makeCopyOf(a)
1152 u, ok := aSame.(Untransposer)
1154 receiver = u.Untranspose()
1156 preData := underlyingData(receiver)
1157 panicked, err = panics(func() { method(receiver, aSame, b) })
1159 t.Errorf("Panics when a maybeSame: %s: %v", errStr, err)
1161 if !equalApprox(receiver, &want, tol, false) {
1162 t.Errorf("Wrong answer when a maybeSame: %s", errStr)
1164 postData := underlyingData(receiver)
1165 if !floats.Equal(preData, postData) {
1166 t.Errorf("Original data slice not modified when a maybeSame: %s", errStr)
1171 bSame := makeCopyOf(b)
1173 u, ok := bSame.(Untransposer)
1175 receiver = u.Untranspose()
1177 preData := underlyingData(receiver)
1178 panicked, err = panics(func() { method(receiver, a, bSame) })
1180 t.Errorf("Panics when b maybeSame: %s: %v", errStr, err)
1182 if !equalApprox(receiver, &want, tol, false) {
1183 t.Errorf("Wrong answer when b maybeSame: %s", errStr)
1185 postData := underlyingData(receiver)
1186 if !floats.Equal(preData, postData) {
1187 t.Errorf("Original data slice not modified when b maybeSame: %s", errStr)
1191 if aMaybeSame && bMaybeSame {
1192 aSame := makeCopyOf(a)
1194 u, ok := aSame.(Untransposer)
1196 receiver = u.Untranspose()
1198 // Ensure that b is the correct transpose type if applicable.
1199 // The receiver is always a concrete type so use it.
1201 u, ok = b.(Untransposer)
1203 bSame = retranspose(b, receiver)
1205 // Compute the real answer for this case. It is different
1206 // from the initial answer since now a and b have the
1208 zero = makeRandOf(wasZero, 0, 0)
1209 method(zero, aSame, bSame)
1210 wasZero, zero = zero, nil // Nil-out zero so we detect illegal use.
1211 preData := underlyingData(receiver)
1212 panicked, err = panics(func() { method(receiver, aSame, bSame) })
1214 t.Errorf("Panics when both maybeSame: %s: %v", errStr, err)
1216 if !equalApprox(receiver, wasZero, tol, false) {
1217 t.Errorf("Wrong answer when both maybeSame: %s", errStr)
1219 postData := underlyingData(receiver)
1220 if !floats.Equal(preData, postData) {
1221 t.Errorf("Original data slice not modified when both maybeSame: %s", errStr)