github.com/gopherd/gonum@v0.0.4/mat/list_test.go (about)

     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.
     4  
     5  //nolint:deadcode,unused
     6  package mat
     7  
     8  import (
     9  	"fmt"
    10  	"math"
    11  	"reflect"
    12  	"testing"
    13  
    14  	"math/rand"
    15  
    16  	"github.com/gopherd/gonum/blas"
    17  	"github.com/gopherd/gonum/blas/blas64"
    18  	"github.com/gopherd/gonum/floats"
    19  	"github.com/gopherd/gonum/floats/scalar"
    20  )
    21  
    22  // legalSizeSameRectangular returns whether the two matrices have the same rectangular shape.
    23  func legalSizeSameRectangular(ar, ac, br, bc int) bool {
    24  	if ar != br {
    25  		return false
    26  	}
    27  	if ac != bc {
    28  		return false
    29  	}
    30  	return true
    31  }
    32  
    33  // legalSizeSameSquare returns whether the two matrices have the same square shape.
    34  func legalSizeSameSquare(ar, ac, br, bc int) bool {
    35  	if ar != br {
    36  		return false
    37  	}
    38  	if ac != bc {
    39  		return false
    40  	}
    41  	if ar != ac {
    42  		return false
    43  	}
    44  	return true
    45  }
    46  
    47  // legalSizeSameHeight returns whether the two matrices have the same number of rows.
    48  func legalSizeSameHeight(ar, _, br, _ int) bool {
    49  	return ar == br
    50  }
    51  
    52  // legalSizeSameWidth returns whether the two matrices have the same number of columns.
    53  func legalSizeSameWidth(_, ac, _, bc int) bool {
    54  	return ac == bc
    55  }
    56  
    57  // legalSizeSolve returns whether the two matrices can be used in a linear solve.
    58  func legalSizeSolve(ar, ac, br, bc int) bool {
    59  	return ar == br
    60  }
    61  
    62  // legalSizeSameVec returns whether the two matrices are column vectors.
    63  func legalSizeVector(_, ac, _, bc int) bool {
    64  	return ac == 1 && bc == 1
    65  }
    66  
    67  // legalSizeSameVec returns whether the two matrices are column vectors of the
    68  // same dimension.
    69  func legalSizeSameVec(ar, ac, br, bc int) bool {
    70  	return ac == 1 && bc == 1 && ar == br
    71  }
    72  
    73  // isAnySize returns true for all matrix sizes.
    74  func isAnySize(ar, ac int) bool {
    75  	return true
    76  }
    77  
    78  // isAnySize2 returns true for all matrix sizes.
    79  func isAnySize2(ar, ac, br, bc int) bool {
    80  	return true
    81  }
    82  
    83  // isAnyColumnVector returns true for any column vector sizes.
    84  func isAnyColumnVector(ar, ac int) bool {
    85  	return ac == 1
    86  }
    87  
    88  // isSquare returns whether the input matrix is square.
    89  func isSquare(r, c int) bool {
    90  	return r == c
    91  }
    92  
    93  // sameAnswerFloat returns whether the two inputs are both NaN or are equal.
    94  func sameAnswerFloat(a, b interface{}) bool {
    95  	if math.IsNaN(a.(float64)) {
    96  		return math.IsNaN(b.(float64))
    97  	}
    98  	return a.(float64) == b.(float64)
    99  }
   100  
   101  // sameAnswerFloatApproxTol returns a function that determines whether its two
   102  // inputs are both NaN or within tol of each other.
   103  func sameAnswerFloatApproxTol(tol float64) func(a, b interface{}) bool {
   104  	return func(a, b interface{}) bool {
   105  		if math.IsNaN(a.(float64)) {
   106  			return math.IsNaN(b.(float64))
   107  		}
   108  		return scalar.EqualWithinAbsOrRel(a.(float64), b.(float64), tol, tol)
   109  	}
   110  }
   111  
   112  func sameAnswerF64SliceOfSlice(a, b interface{}) bool {
   113  	for i, v := range a.([][]float64) {
   114  		if same := floats.Same(v, b.([][]float64)[i]); !same {
   115  			return false
   116  		}
   117  	}
   118  	return true
   119  }
   120  
   121  // sameAnswerBool returns whether the two inputs have the same value.
   122  func sameAnswerBool(a, b interface{}) bool {
   123  	return a.(bool) == b.(bool)
   124  }
   125  
   126  // isAnyType returns true for all Matrix types.
   127  func isAnyType(Matrix) bool {
   128  	return true
   129  }
   130  
   131  // legalTypesAll returns true for all Matrix types.
   132  func legalTypesAll(a, b Matrix) bool {
   133  	return true
   134  }
   135  
   136  // legalTypeSym returns whether a is a Symmetric.
   137  func legalTypeSym(a Matrix) bool {
   138  	_, ok := a.(Symmetric)
   139  	return ok
   140  }
   141  
   142  // legalTypeTri returns whether a is a Triangular.
   143  func legalTypeTri(a Matrix) bool {
   144  	_, ok := a.(Triangular)
   145  	return ok
   146  }
   147  
   148  // legalTypeTriLower returns whether a is a Triangular with kind == Lower.
   149  func legalTypeTriLower(a Matrix) bool {
   150  	t, ok := a.(Triangular)
   151  	if !ok {
   152  		return false
   153  	}
   154  	_, kind := t.Triangle()
   155  	return kind == Lower
   156  }
   157  
   158  // legalTypeTriUpper returns whether a is a Triangular with kind == Upper.
   159  func legalTypeTriUpper(a Matrix) bool {
   160  	t, ok := a.(Triangular)
   161  	if !ok {
   162  		return false
   163  	}
   164  	_, kind := t.Triangle()
   165  	return kind == Upper
   166  }
   167  
   168  // legalTypesSym returns whether both input arguments are Symmetric.
   169  func legalTypesSym(a, b Matrix) bool {
   170  	if _, ok := a.(Symmetric); !ok {
   171  		return false
   172  	}
   173  	if _, ok := b.(Symmetric); !ok {
   174  		return false
   175  	}
   176  	return true
   177  }
   178  
   179  // legalTypeVector returns whether v is a Vector.
   180  func legalTypeVector(v Matrix) bool {
   181  	_, ok := v.(Vector)
   182  	return ok
   183  }
   184  
   185  // legalTypeVec returns whether v is a *VecDense.
   186  func legalTypeVecDense(v Matrix) bool {
   187  	_, ok := v.(*VecDense)
   188  	return ok
   189  }
   190  
   191  // legalTypesVectorVector returns whether both inputs are Vector
   192  func legalTypesVectorVector(a, b Matrix) bool {
   193  	if _, ok := a.(Vector); !ok {
   194  		return false
   195  	}
   196  	if _, ok := b.(Vector); !ok {
   197  		return false
   198  	}
   199  	return true
   200  }
   201  
   202  // legalTypesVecDenseVecDense returns whether both inputs are *VecDense.
   203  func legalTypesVecDenseVecDense(a, b Matrix) bool {
   204  	if _, ok := a.(*VecDense); !ok {
   205  		return false
   206  	}
   207  	if _, ok := b.(*VecDense); !ok {
   208  		return false
   209  	}
   210  	return true
   211  }
   212  
   213  // legalTypesMatrixVector returns whether the first input is an arbitrary Matrix
   214  // and the second input is a Vector.
   215  func legalTypesMatrixVector(a, b Matrix) bool {
   216  	_, ok := b.(Vector)
   217  	return ok
   218  }
   219  
   220  // legalTypesMatrixVecDense returns whether the first input is an arbitrary Matrix
   221  // and the second input is a *VecDense.
   222  func legalTypesMatrixVecDense(a, b Matrix) bool {
   223  	_, ok := b.(*VecDense)
   224  	return ok
   225  }
   226  
   227  // legalDims returns whether {m,n} is a valid dimension of the given matrix type.
   228  func legalDims(a Matrix, m, n int) bool {
   229  	switch t := a.(type) {
   230  	default:
   231  		panic("legal dims type not coded")
   232  	case Untransposer:
   233  		return legalDims(t.Untranspose(), n, m)
   234  	case *Dense, *basicMatrix, *BandDense, *basicBanded:
   235  		if m < 0 || n < 0 {
   236  			return false
   237  		}
   238  		return true
   239  	case *SymDense, *TriDense, *basicSymmetric, *basicTriangular,
   240  		*SymBandDense, *basicSymBanded, *TriBandDense, *basicTriBanded,
   241  		*basicDiagonal, *DiagDense, *Tridiag:
   242  		if m < 0 || n < 0 || m != n {
   243  			return false
   244  		}
   245  		return true
   246  	case *VecDense, *basicVector:
   247  		if m < 0 || n < 0 {
   248  			return false
   249  		}
   250  		return n == 1
   251  	}
   252  }
   253  
   254  // returnAs returns the matrix a with the type of t. Used for making a concrete
   255  // type and changing to the basic form.
   256  func returnAs(a, t Matrix) Matrix {
   257  	switch mat := a.(type) {
   258  	default:
   259  		panic("unknown type for a")
   260  	case *Dense:
   261  		switch t.(type) {
   262  		default:
   263  			panic("bad type")
   264  		case *Dense:
   265  			return mat
   266  		case *basicMatrix:
   267  			return asBasicMatrix(mat)
   268  		}
   269  	case *SymDense:
   270  		switch t.(type) {
   271  		default:
   272  			panic("bad type")
   273  		case *SymDense:
   274  			return mat
   275  		case *basicSymmetric:
   276  			return asBasicSymmetric(mat)
   277  		}
   278  	case *TriDense:
   279  		switch t.(type) {
   280  		default:
   281  			panic("bad type")
   282  		case *TriDense:
   283  			return mat
   284  		case *basicTriangular:
   285  			return asBasicTriangular(mat)
   286  		}
   287  	case *BandDense:
   288  		switch t.(type) {
   289  		default:
   290  			panic("bad type")
   291  		case *BandDense:
   292  			return mat
   293  		case *basicBanded:
   294  			return asBasicBanded(mat)
   295  		}
   296  	case *SymBandDense:
   297  		switch t.(type) {
   298  		default:
   299  			panic("bad type")
   300  		case *SymBandDense:
   301  			return mat
   302  		case *basicSymBanded:
   303  			return asBasicSymBanded(mat)
   304  		}
   305  	case *TriBandDense:
   306  		switch t.(type) {
   307  		default:
   308  			panic("bad type")
   309  		case *TriBandDense:
   310  			return mat
   311  		case *basicTriBanded:
   312  			return asBasicTriBanded(mat)
   313  		}
   314  	case *DiagDense:
   315  		switch t.(type) {
   316  		default:
   317  			panic("bad type")
   318  		case *DiagDense:
   319  			return mat
   320  		case *basicDiagonal:
   321  			return asBasicDiagonal(mat)
   322  		}
   323  	case *Tridiag:
   324  		switch t.(type) {
   325  		default:
   326  			panic("bad type")
   327  		case *Tridiag:
   328  			return mat
   329  		}
   330  	}
   331  }
   332  
   333  // retranspose returns the matrix m inside an Untransposer of the type
   334  // of a.
   335  func retranspose(a, m Matrix) Matrix {
   336  	switch a.(type) {
   337  	case TransposeTriBand:
   338  		return TransposeTriBand{m.(TriBanded)}
   339  	case TransposeBand:
   340  		return TransposeBand{m.(Banded)}
   341  	case TransposeTri:
   342  		return TransposeTri{m.(Triangular)}
   343  	case Transpose:
   344  		return Transpose{m}
   345  	case Untransposer:
   346  		panic("unknown transposer type")
   347  	default:
   348  		panic("a is not an untransposer")
   349  	}
   350  }
   351  
   352  // makeRandOf returns a new randomly filled m×n matrix of the underlying matrix type.
   353  func makeRandOf(a Matrix, m, n int, src rand.Source) Matrix {
   354  	rnd := rand.New(src)
   355  	var rMatrix Matrix
   356  	switch t := a.(type) {
   357  	default:
   358  		panic("unknown type for make rand of")
   359  	case Untransposer:
   360  		rMatrix = retranspose(a, makeRandOf(t.Untranspose(), n, m, src))
   361  	case *Dense, *basicMatrix:
   362  		var mat = &Dense{}
   363  		if m != 0 && n != 0 {
   364  			mat = NewDense(m, n, nil)
   365  		}
   366  		for i := 0; i < m; i++ {
   367  			for j := 0; j < n; j++ {
   368  				mat.Set(i, j, rnd.NormFloat64())
   369  			}
   370  		}
   371  		rMatrix = returnAs(mat, t)
   372  	case *VecDense:
   373  		if m == 0 && n == 0 {
   374  			return &VecDense{}
   375  		}
   376  		if n != 1 {
   377  			panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n))
   378  		}
   379  		length := m
   380  		inc := 1
   381  		if t.mat.Inc != 0 {
   382  			inc = t.mat.Inc
   383  		}
   384  		mat := &VecDense{
   385  			mat: blas64.Vector{
   386  				N:    length,
   387  				Inc:  inc,
   388  				Data: make([]float64, inc*(length-1)+1),
   389  			},
   390  		}
   391  		for i := 0; i < length; i++ {
   392  			mat.SetVec(i, rnd.NormFloat64())
   393  		}
   394  		return mat
   395  	case *basicVector:
   396  		if n != 1 {
   397  			panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n))
   398  		}
   399  		if m == 0 {
   400  			return &basicVector{}
   401  		}
   402  		mat := NewVecDense(m, nil)
   403  		for i := 0; i < m; i++ {
   404  			mat.SetVec(i, rnd.NormFloat64())
   405  		}
   406  		return asBasicVector(mat)
   407  	case *SymDense, *basicSymmetric:
   408  		if m != n {
   409  			panic("bad size")
   410  		}
   411  		mat := &SymDense{}
   412  		if n != 0 {
   413  			mat = NewSymDense(n, nil)
   414  		}
   415  		for i := 0; i < m; i++ {
   416  			for j := i; j < n; j++ {
   417  				mat.SetSym(i, j, rnd.NormFloat64())
   418  			}
   419  		}
   420  		rMatrix = returnAs(mat, t)
   421  	case *TriDense, *basicTriangular:
   422  		if m != n {
   423  			panic("bad size")
   424  		}
   425  
   426  		// This is necessary because we are making
   427  		// a triangle from the zero value, which
   428  		// always returns upper as true.
   429  		var triKind TriKind
   430  		switch t := t.(type) {
   431  		case *TriDense:
   432  			triKind = t.triKind()
   433  		case *basicTriangular:
   434  			triKind = (*TriDense)(t).triKind()
   435  		}
   436  
   437  		if n == 0 {
   438  			uplo := blas.Upper
   439  			if triKind == Lower {
   440  				uplo = blas.Lower
   441  			}
   442  			return returnAs(&TriDense{mat: blas64.Triangular{Uplo: uplo}}, t)
   443  		}
   444  
   445  		mat := NewTriDense(n, triKind, nil)
   446  		if triKind == Upper {
   447  			for i := 0; i < m; i++ {
   448  				for j := i; j < n; j++ {
   449  					mat.SetTri(i, j, rnd.NormFloat64())
   450  				}
   451  			}
   452  		} else {
   453  			for i := 0; i < m; i++ {
   454  				for j := 0; j <= i; j++ {
   455  					mat.SetTri(i, j, rnd.NormFloat64())
   456  				}
   457  			}
   458  		}
   459  		rMatrix = returnAs(mat, t)
   460  	case *BandDense, *basicBanded:
   461  		var kl, ku int
   462  		switch t := t.(type) {
   463  		case *BandDense:
   464  			kl = t.mat.KL
   465  			ku = t.mat.KU
   466  		case *basicBanded:
   467  			ku = (*BandDense)(t).mat.KU
   468  			kl = (*BandDense)(t).mat.KL
   469  		}
   470  		ku = min(ku, n-1)
   471  		kl = min(kl, m-1)
   472  		data := make([]float64, min(m, n+kl)*(kl+ku+1))
   473  		for i := range data {
   474  			data[i] = rnd.NormFloat64()
   475  		}
   476  		mat := NewBandDense(m, n, kl, ku, data)
   477  		rMatrix = returnAs(mat, t)
   478  	case *SymBandDense, *basicSymBanded:
   479  		if m != n {
   480  			panic("bad size")
   481  		}
   482  		var k int
   483  		switch t := t.(type) {
   484  		case *SymBandDense:
   485  			k = t.mat.K
   486  		case *basicSymBanded:
   487  			k = (*SymBandDense)(t).mat.K
   488  		}
   489  		k = min(k, m-1) // Special case for small sizes.
   490  		data := make([]float64, m*(k+1))
   491  		for i := range data {
   492  			data[i] = rnd.NormFloat64()
   493  		}
   494  		mat := NewSymBandDense(n, k, data)
   495  		rMatrix = returnAs(mat, t)
   496  	case *TriBandDense, *basicTriBanded:
   497  		if m != n {
   498  			panic("bad size")
   499  		}
   500  		var k int
   501  		var triKind TriKind
   502  		switch t := t.(type) {
   503  		case *TriBandDense:
   504  			k = t.mat.K
   505  			triKind = t.triKind()
   506  		case *basicTriBanded:
   507  			k = (*TriBandDense)(t).mat.K
   508  			triKind = (*TriBandDense)(t).triKind()
   509  		}
   510  		k = min(k, m-1) // Special case for small sizes.
   511  		data := make([]float64, m*(k+1))
   512  		for i := range data {
   513  			data[i] = rnd.NormFloat64()
   514  		}
   515  		mat := NewTriBandDense(n, k, triKind, data)
   516  		rMatrix = returnAs(mat, t)
   517  	case *DiagDense, *basicDiagonal:
   518  		if m != n {
   519  			panic("bad size")
   520  		}
   521  		var inc int
   522  		switch t := t.(type) {
   523  		case *DiagDense:
   524  			inc = t.mat.Inc
   525  		case *basicDiagonal:
   526  			inc = (*DiagDense)(t).mat.Inc
   527  		}
   528  		if inc == 0 {
   529  			inc = 1
   530  		}
   531  		mat := &DiagDense{
   532  			mat: blas64.Vector{
   533  				N:    n,
   534  				Inc:  inc,
   535  				Data: make([]float64, inc*(n-1)+1),
   536  			},
   537  		}
   538  		for i := 0; i < n; i++ {
   539  			mat.SetDiag(i, rnd.Float64())
   540  		}
   541  		rMatrix = returnAs(mat, t)
   542  	case *Tridiag:
   543  		if m != n {
   544  			panic("bad size")
   545  		}
   546  		mat := NewTridiag(n, nil, nil, nil)
   547  		for i := 0; i < n; i++ {
   548  			for j := max(0, i-1); j <= min(i+1, n-1); j++ {
   549  				mat.SetBand(i, j, rnd.NormFloat64())
   550  			}
   551  		}
   552  		rMatrix = returnAs(mat, t)
   553  	}
   554  	if mr, mc := rMatrix.Dims(); mr != m || mc != n {
   555  		panic(fmt.Sprintf("makeRandOf for %T returns wrong size: %d×%d != %d×%d", a, m, n, mr, mc))
   556  	}
   557  	return rMatrix
   558  }
   559  
   560  // makeNaNOf returns a new m×n matrix of the underlying matrix type filled with NaN values.
   561  func makeNaNOf(a Matrix, m, n int) Matrix {
   562  	var rMatrix Matrix
   563  	switch t := a.(type) {
   564  	default:
   565  		panic("unknown type for makeNaNOf")
   566  	case Untransposer:
   567  		rMatrix = retranspose(a, makeNaNOf(t.Untranspose(), n, m))
   568  	case *Dense, *basicMatrix:
   569  		var mat = &Dense{}
   570  		if m != 0 && n != 0 {
   571  			mat = NewDense(m, n, nil)
   572  		}
   573  		for i := 0; i < m; i++ {
   574  			for j := 0; j < n; j++ {
   575  				mat.Set(i, j, math.NaN())
   576  			}
   577  		}
   578  		rMatrix = returnAs(mat, t)
   579  	case *VecDense:
   580  		if m == 0 && n == 0 {
   581  			return &VecDense{}
   582  		}
   583  		if n != 1 {
   584  			panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n))
   585  		}
   586  		length := m
   587  		inc := 1
   588  		if t.mat.Inc != 0 {
   589  			inc = t.mat.Inc
   590  		}
   591  		mat := &VecDense{
   592  			mat: blas64.Vector{
   593  				N:    length,
   594  				Inc:  inc,
   595  				Data: make([]float64, inc*(length-1)+1),
   596  			},
   597  		}
   598  		for i := 0; i < length; i++ {
   599  			mat.SetVec(i, math.NaN())
   600  		}
   601  		return mat
   602  	case *basicVector:
   603  		if n != 1 {
   604  			panic(fmt.Sprintf("bad vector size: m = %v, n = %v", m, n))
   605  		}
   606  		if m == 0 {
   607  			return &basicVector{}
   608  		}
   609  		mat := NewVecDense(m, nil)
   610  		for i := 0; i < m; i++ {
   611  			mat.SetVec(i, math.NaN())
   612  		}
   613  		return asBasicVector(mat)
   614  	case *SymDense, *basicSymmetric:
   615  		if m != n {
   616  			panic("bad size")
   617  		}
   618  		mat := &SymDense{}
   619  		if n != 0 {
   620  			mat = NewSymDense(n, nil)
   621  		}
   622  		for i := 0; i < m; i++ {
   623  			for j := i; j < n; j++ {
   624  				mat.SetSym(i, j, math.NaN())
   625  			}
   626  		}
   627  		rMatrix = returnAs(mat, t)
   628  	case *TriDense, *basicTriangular:
   629  		if m != n {
   630  			panic("bad size")
   631  		}
   632  
   633  		// This is necessary because we are making
   634  		// a triangle from the zero value, which
   635  		// always returns upper as true.
   636  		var triKind TriKind
   637  		switch t := t.(type) {
   638  		case *TriDense:
   639  			triKind = t.triKind()
   640  		case *basicTriangular:
   641  			triKind = (*TriDense)(t).triKind()
   642  		}
   643  
   644  		if n == 0 {
   645  			uplo := blas.Upper
   646  			if triKind == Lower {
   647  				uplo = blas.Lower
   648  			}
   649  			return returnAs(&TriDense{mat: blas64.Triangular{Uplo: uplo}}, t)
   650  		}
   651  
   652  		mat := NewTriDense(n, triKind, nil)
   653  		if triKind == Upper {
   654  			for i := 0; i < m; i++ {
   655  				for j := i; j < n; j++ {
   656  					mat.SetTri(i, j, math.NaN())
   657  				}
   658  			}
   659  		} else {
   660  			for i := 0; i < m; i++ {
   661  				for j := 0; j <= i; j++ {
   662  					mat.SetTri(i, j, math.NaN())
   663  				}
   664  			}
   665  		}
   666  		rMatrix = returnAs(mat, t)
   667  	case *BandDense, *basicBanded:
   668  		var kl, ku int
   669  		switch t := t.(type) {
   670  		case *BandDense:
   671  			kl = t.mat.KL
   672  			ku = t.mat.KU
   673  		case *basicBanded:
   674  			ku = (*BandDense)(t).mat.KU
   675  			kl = (*BandDense)(t).mat.KL
   676  		}
   677  		ku = min(ku, n-1)
   678  		kl = min(kl, m-1)
   679  		data := make([]float64, min(m, n+kl)*(kl+ku+1))
   680  		for i := range data {
   681  			data[i] = math.NaN()
   682  		}
   683  		mat := NewBandDense(m, n, kl, ku, data)
   684  		rMatrix = returnAs(mat, t)
   685  	case *SymBandDense, *basicSymBanded:
   686  		if m != n {
   687  			panic("bad size")
   688  		}
   689  		var k int
   690  		switch t := t.(type) {
   691  		case *SymBandDense:
   692  			k = t.mat.K
   693  		case *basicSymBanded:
   694  			k = (*SymBandDense)(t).mat.K
   695  		}
   696  		k = min(k, m-1) // Special case for small sizes.
   697  		data := make([]float64, m*(k+1))
   698  		for i := range data {
   699  			data[i] = math.NaN()
   700  		}
   701  		mat := NewSymBandDense(n, k, data)
   702  		rMatrix = returnAs(mat, t)
   703  	case *TriBandDense, *basicTriBanded:
   704  		if m != n {
   705  			panic("bad size")
   706  		}
   707  		var k int
   708  		var triKind TriKind
   709  		switch t := t.(type) {
   710  		case *TriBandDense:
   711  			k = t.mat.K
   712  			triKind = t.triKind()
   713  		case *basicTriBanded:
   714  			k = (*TriBandDense)(t).mat.K
   715  			triKind = (*TriBandDense)(t).triKind()
   716  		}
   717  		k = min(k, m-1) // Special case for small sizes.
   718  		data := make([]float64, m*(k+1))
   719  		for i := range data {
   720  			data[i] = math.NaN()
   721  		}
   722  		mat := NewTriBandDense(n, k, triKind, data)
   723  		rMatrix = returnAs(mat, t)
   724  	case *DiagDense, *basicDiagonal:
   725  		if m != n {
   726  			panic("bad size")
   727  		}
   728  		var inc int
   729  		switch t := t.(type) {
   730  		case *DiagDense:
   731  			inc = t.mat.Inc
   732  		case *basicDiagonal:
   733  			inc = (*DiagDense)(t).mat.Inc
   734  		}
   735  		if inc == 0 {
   736  			inc = 1
   737  		}
   738  		mat := &DiagDense{
   739  			mat: blas64.Vector{
   740  				N:    n,
   741  				Inc:  inc,
   742  				Data: make([]float64, inc*(n-1)+1),
   743  			},
   744  		}
   745  		for i := 0; i < n; i++ {
   746  			mat.SetDiag(i, math.NaN())
   747  		}
   748  		rMatrix = returnAs(mat, t)
   749  	}
   750  	if mr, mc := rMatrix.Dims(); mr != m || mc != n {
   751  		panic(fmt.Sprintf("makeNaNOf for %T returns wrong size: %d×%d != %d×%d", a, m, n, mr, mc))
   752  	}
   753  	return rMatrix
   754  }
   755  
   756  // makeCopyOf returns a copy of the matrix.
   757  func makeCopyOf(a Matrix) Matrix {
   758  	switch t := a.(type) {
   759  	default:
   760  		panic("unknown type in makeCopyOf")
   761  	case Untransposer:
   762  		return retranspose(a, makeCopyOf(t.Untranspose()))
   763  	case *Dense, *basicMatrix:
   764  		var m Dense
   765  		m.CloneFrom(a)
   766  		return returnAs(&m, t)
   767  	case *SymDense, *basicSymmetric:
   768  		n := t.(Symmetric).SymmetricDim()
   769  		m := NewSymDense(n, nil)
   770  		m.CopySym(t.(Symmetric))
   771  		return returnAs(m, t)
   772  	case *TriDense, *basicTriangular:
   773  		n, upper := t.(Triangular).Triangle()
   774  		m := NewTriDense(n, upper, nil)
   775  		if upper {
   776  			for i := 0; i < n; i++ {
   777  				for j := i; j < n; j++ {
   778  					m.SetTri(i, j, t.At(i, j))
   779  				}
   780  			}
   781  		} else {
   782  			for i := 0; i < n; i++ {
   783  				for j := 0; j <= i; j++ {
   784  					m.SetTri(i, j, t.At(i, j))
   785  				}
   786  			}
   787  		}
   788  		return returnAs(m, t)
   789  	case *BandDense, *basicBanded:
   790  		var band *BandDense
   791  		switch s := t.(type) {
   792  		case *BandDense:
   793  			band = s
   794  		case *basicBanded:
   795  			band = (*BandDense)(s)
   796  		}
   797  		m := &BandDense{
   798  			mat: blas64.Band{
   799  				Rows:   band.mat.Rows,
   800  				Cols:   band.mat.Cols,
   801  				KL:     band.mat.KL,
   802  				KU:     band.mat.KU,
   803  				Data:   make([]float64, len(band.mat.Data)),
   804  				Stride: band.mat.Stride,
   805  			},
   806  		}
   807  		copy(m.mat.Data, band.mat.Data)
   808  		return returnAs(m, t)
   809  	case *SymBandDense, *basicSymBanded:
   810  		var sym *SymBandDense
   811  		switch s := t.(type) {
   812  		case *SymBandDense:
   813  			sym = s
   814  		case *basicSymBanded:
   815  			sym = (*SymBandDense)(s)
   816  		}
   817  		m := &SymBandDense{
   818  			mat: blas64.SymmetricBand{
   819  				Uplo:   blas.Upper,
   820  				N:      sym.mat.N,
   821  				K:      sym.mat.K,
   822  				Data:   make([]float64, len(sym.mat.Data)),
   823  				Stride: sym.mat.Stride,
   824  			},
   825  		}
   826  		copy(m.mat.Data, sym.mat.Data)
   827  		return returnAs(m, t)
   828  	case *TriBandDense, *basicTriBanded:
   829  		var tri *TriBandDense
   830  		switch s := t.(type) {
   831  		case *TriBandDense:
   832  			tri = s
   833  		case *basicTriBanded:
   834  			tri = (*TriBandDense)(s)
   835  		}
   836  		m := &TriBandDense{
   837  			mat: blas64.TriangularBand{
   838  				Uplo:   tri.mat.Uplo,
   839  				Diag:   tri.mat.Diag,
   840  				N:      tri.mat.N,
   841  				K:      tri.mat.K,
   842  				Data:   make([]float64, len(tri.mat.Data)),
   843  				Stride: tri.mat.Stride,
   844  			},
   845  		}
   846  		copy(m.mat.Data, tri.mat.Data)
   847  		return returnAs(m, t)
   848  	case *VecDense:
   849  		var m VecDense
   850  		m.CloneFromVec(t)
   851  		return &m
   852  	case *basicVector:
   853  		var m VecDense
   854  		m.CloneFromVec(t)
   855  		return asBasicVector(&m)
   856  	case *DiagDense, *basicDiagonal:
   857  		var diag *DiagDense
   858  		switch s := t.(type) {
   859  		case *DiagDense:
   860  			diag = s
   861  		case *basicDiagonal:
   862  			diag = (*DiagDense)(s)
   863  		}
   864  		d := &DiagDense{
   865  			mat: blas64.Vector{N: diag.mat.N, Inc: diag.mat.Inc, Data: make([]float64, len(diag.mat.Data))},
   866  		}
   867  		copy(d.mat.Data, diag.mat.Data)
   868  		return returnAs(d, t)
   869  	case *Tridiag:
   870  		var m Tridiag
   871  		m.CloneFromTridiag(a.(*Tridiag))
   872  		return returnAs(&m, t)
   873  	}
   874  }
   875  
   876  // sameType returns true if a and b have the same underlying type.
   877  func sameType(a, b Matrix) bool {
   878  	return reflect.ValueOf(a).Type() == reflect.ValueOf(b).Type()
   879  }
   880  
   881  // maybeSame returns true if the two matrices could be represented by the same
   882  // pointer.
   883  func maybeSame(receiver, a Matrix) bool {
   884  	rr, rc := receiver.Dims()
   885  	u, trans := a.(Untransposer)
   886  	if trans {
   887  		a = u.Untranspose()
   888  	}
   889  	if !sameType(receiver, a) {
   890  		return false
   891  	}
   892  	ar, ac := a.Dims()
   893  	if rr != ar || rc != ac {
   894  		return false
   895  	}
   896  	if _, ok := a.(Triangular); ok {
   897  		// They are both triangular types. The TriType needs to match
   898  		_, aKind := a.(Triangular).Triangle()
   899  		_, rKind := receiver.(Triangular).Triangle()
   900  		if aKind != rKind {
   901  			return false
   902  		}
   903  	}
   904  	return true
   905  }
   906  
   907  // equalApprox returns whether the elements of a and b are the same to within
   908  // the tolerance. If ignoreNaN is true the test is relaxed such that NaN == NaN.
   909  func equalApprox(a, b Matrix, tol float64, ignoreNaN bool) bool {
   910  	ar, ac := a.Dims()
   911  	br, bc := b.Dims()
   912  	if ar != br {
   913  		return false
   914  	}
   915  	if ac != bc {
   916  		return false
   917  	}
   918  	for i := 0; i < ar; i++ {
   919  		for j := 0; j < ac; j++ {
   920  			if !scalar.EqualWithinAbsOrRel(a.At(i, j), b.At(i, j), tol, tol) {
   921  				if ignoreNaN && math.IsNaN(a.At(i, j)) && math.IsNaN(b.At(i, j)) {
   922  					continue
   923  				}
   924  				return false
   925  			}
   926  		}
   927  	}
   928  	return true
   929  }
   930  
   931  // equal returns true if the matrices have equal entries.
   932  func equal(a, b Matrix) bool {
   933  	ar, ac := a.Dims()
   934  	br, bc := b.Dims()
   935  	if ar != br {
   936  		return false
   937  	}
   938  	if ac != bc {
   939  		return false
   940  	}
   941  	for i := 0; i < ar; i++ {
   942  		for j := 0; j < ac; j++ {
   943  			if a.At(i, j) != b.At(i, j) {
   944  				return false
   945  			}
   946  		}
   947  	}
   948  	return true
   949  }
   950  
   951  // isDiagonal returns whether a is a diagonal matrix.
   952  func isDiagonal(a Matrix) bool {
   953  	r, c := a.Dims()
   954  	for i := 0; i < r; i++ {
   955  		for j := 0; j < c; j++ {
   956  			if a.At(i, j) != 0 && i != j {
   957  				return false
   958  			}
   959  		}
   960  	}
   961  	return true
   962  }
   963  
   964  // equalDiagonal returns whether a and b are equal on the diagonal.
   965  func equalDiagonal(a, b Matrix) bool {
   966  	ar, ac := a.Dims()
   967  	br, bc := a.Dims()
   968  	if min(ar, ac) != min(br, bc) {
   969  		return false
   970  	}
   971  	for i := 0; i < min(ar, ac); i++ {
   972  		if a.At(i, i) != b.At(i, i) {
   973  			return false
   974  		}
   975  	}
   976  	return true
   977  }
   978  
   979  // underlyingData extracts the underlying data of the matrix a.
   980  func underlyingData(a Matrix) []float64 {
   981  	switch t := a.(type) {
   982  	default:
   983  		panic("matrix type not implemented for extracting underlying data")
   984  	case Untransposer:
   985  		return underlyingData(t.Untranspose())
   986  	case *Dense:
   987  		return t.mat.Data
   988  	case *SymDense:
   989  		return t.mat.Data
   990  	case *TriDense:
   991  		return t.mat.Data
   992  	case *VecDense:
   993  		return t.mat.Data
   994  	}
   995  }
   996  
   997  // testMatrices is a list of matrix types to test.
   998  // This test relies on the fact that the implementations of Triangle do not
   999  // corrupt the value of Uplo when they are empty. This test will fail
  1000  // if that changes (and some mechanism will need to be used to force the
  1001  // correct TriKind to be read).
  1002  var testMatrices = []Matrix{
  1003  	&Dense{},
  1004  	&basicMatrix{},
  1005  	Transpose{&Dense{}},
  1006  
  1007  	&VecDense{mat: blas64.Vector{Inc: 1}},
  1008  	&VecDense{mat: blas64.Vector{Inc: 10}},
  1009  	&basicVector{},
  1010  	Transpose{&VecDense{mat: blas64.Vector{Inc: 1}}},
  1011  	Transpose{&VecDense{mat: blas64.Vector{Inc: 10}}},
  1012  	Transpose{&basicVector{}},
  1013  
  1014  	&BandDense{mat: blas64.Band{KL: 2, KU: 1}},
  1015  	&BandDense{mat: blas64.Band{KL: 1, KU: 2}},
  1016  	Transpose{&BandDense{mat: blas64.Band{KL: 2, KU: 1}}},
  1017  	Transpose{&BandDense{mat: blas64.Band{KL: 1, KU: 2}}},
  1018  	TransposeBand{&BandDense{mat: blas64.Band{KL: 2, KU: 1}}},
  1019  	TransposeBand{&BandDense{mat: blas64.Band{KL: 1, KU: 2}}},
  1020  
  1021  	&SymDense{},
  1022  	&basicSymmetric{},
  1023  	Transpose{&basicSymmetric{}},
  1024  
  1025  	&TriDense{mat: blas64.Triangular{Uplo: blas.Upper}},
  1026  	&TriDense{mat: blas64.Triangular{Uplo: blas.Lower}},
  1027  	&basicTriangular{mat: blas64.Triangular{Uplo: blas.Upper}},
  1028  	&basicTriangular{mat: blas64.Triangular{Uplo: blas.Lower}},
  1029  	Transpose{&TriDense{mat: blas64.Triangular{Uplo: blas.Upper}}},
  1030  	Transpose{&TriDense{mat: blas64.Triangular{Uplo: blas.Lower}}},
  1031  	TransposeTri{&TriDense{mat: blas64.Triangular{Uplo: blas.Upper}}},
  1032  	TransposeTri{&TriDense{mat: blas64.Triangular{Uplo: blas.Lower}}},
  1033  	Transpose{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Upper}}},
  1034  	Transpose{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Lower}}},
  1035  	TransposeTri{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Upper}}},
  1036  	TransposeTri{&basicTriangular{mat: blas64.Triangular{Uplo: blas.Lower}}},
  1037  
  1038  	&SymBandDense{},
  1039  	&basicSymBanded{},
  1040  	Transpose{&basicSymBanded{}},
  1041  
  1042  	&SymBandDense{mat: blas64.SymmetricBand{K: 2}},
  1043  	&basicSymBanded{mat: blas64.SymmetricBand{K: 2}},
  1044  	Transpose{&basicSymBanded{mat: blas64.SymmetricBand{K: 2}}},
  1045  	TransposeBand{&basicSymBanded{mat: blas64.SymmetricBand{K: 2}}},
  1046  
  1047  	&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}},
  1048  	&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}},
  1049  	&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}},
  1050  	&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}},
  1051  	Transpose{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1052  	Transpose{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1053  	Transpose{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1054  	Transpose{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1055  	TransposeTri{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1056  	TransposeTri{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1057  	TransposeTri{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1058  	TransposeTri{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1059  	TransposeBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1060  	TransposeBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1061  	TransposeBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1062  	TransposeBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1063  	TransposeTriBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1064  	TransposeTriBand{&TriBandDense{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1065  	TransposeTriBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Upper}}},
  1066  	TransposeTriBand{&basicTriBanded{mat: blas64.TriangularBand{K: 2, Uplo: blas.Lower}}},
  1067  
  1068  	&DiagDense{},
  1069  	&DiagDense{mat: blas64.Vector{Inc: 10}},
  1070  	Transpose{&DiagDense{}},
  1071  	Transpose{&DiagDense{mat: blas64.Vector{Inc: 10}}},
  1072  	TransposeTri{&DiagDense{}},
  1073  	TransposeTri{&DiagDense{mat: blas64.Vector{Inc: 10}}},
  1074  	TransposeBand{&DiagDense{}},
  1075  	TransposeBand{&DiagDense{mat: blas64.Vector{Inc: 10}}},
  1076  	TransposeTriBand{&DiagDense{}},
  1077  	TransposeTriBand{&DiagDense{mat: blas64.Vector{Inc: 10}}},
  1078  	&basicDiagonal{},
  1079  	Transpose{&basicDiagonal{}},
  1080  	TransposeTri{&basicDiagonal{}},
  1081  	TransposeBand{&basicDiagonal{}},
  1082  	TransposeTriBand{&basicDiagonal{}},
  1083  
  1084  	&Tridiag{},
  1085  	Transpose{&Tridiag{}},
  1086  	TransposeBand{&Tridiag{}},
  1087  }
  1088  
  1089  var sizes = []struct {
  1090  	ar, ac int
  1091  }{
  1092  	{1, 1},
  1093  	{1, 3},
  1094  	{3, 1},
  1095  
  1096  	{6, 6},
  1097  	{6, 11},
  1098  	{11, 6},
  1099  }
  1100  
  1101  func testOneInputFunc(t *testing.T,
  1102  	// name is the name of the function being tested.
  1103  	name string,
  1104  
  1105  	// f is the function being tested.
  1106  	f func(a Matrix) interface{},
  1107  
  1108  	// denseComparison performs the same operation, but using Dense matrices for
  1109  	// comparison.
  1110  	denseComparison func(a *Dense) interface{},
  1111  
  1112  	// sameAnswer compares the result from two different evaluations of the function
  1113  	// and returns true if they are the same. The specific function being tested
  1114  	// determines the definition of "same". It may mean identical or it may mean
  1115  	// approximately equal.
  1116  	sameAnswer func(a, b interface{}) bool,
  1117  
  1118  	// legalType returns true if the type of the input is a legal type for the
  1119  	// input of the function.
  1120  	legalType func(a Matrix) bool,
  1121  
  1122  	// legalSize returns true if the size is valid for the function.
  1123  	legalSize func(r, c int) bool,
  1124  ) {
  1125  	src := rand.NewSource(1)
  1126  	for _, aMat := range testMatrices {
  1127  		for _, test := range sizes {
  1128  			// Skip the test if the argument would not be assignable to the
  1129  			// method's corresponding input parameter or it is not possible
  1130  			// to construct an argument of the requested size.
  1131  			if !legalType(aMat) {
  1132  				continue
  1133  			}
  1134  			if !legalDims(aMat, test.ar, test.ac) {
  1135  				continue
  1136  			}
  1137  			a := makeRandOf(aMat, test.ar, test.ac, src)
  1138  
  1139  			// Compute the true answer if the sizes are legal.
  1140  			dimsOK := legalSize(test.ar, test.ac)
  1141  			var want interface{}
  1142  			if dimsOK {
  1143  				var aDense Dense
  1144  				aDense.CloneFrom(a)
  1145  				want = denseComparison(&aDense)
  1146  			}
  1147  			aCopy := makeCopyOf(a)
  1148  			// Test the method for a zero-value of the receiver.
  1149  			aType, aTrans := untranspose(a)
  1150  			errStr := fmt.Sprintf("%v(%T), size: %#v, atrans %t", name, aType, test, aTrans)
  1151  			var got interface{}
  1152  			panicked, err := panics(func() { got = f(a) })
  1153  			if !dimsOK && !panicked {
  1154  				t.Errorf("Did not panic with illegal size: %s", errStr)
  1155  				continue
  1156  			}
  1157  			if dimsOK && panicked {
  1158  				t.Errorf("Panicked with legal size: %s: %v", errStr, err)
  1159  				continue
  1160  			}
  1161  			if !equal(a, aCopy) {
  1162  				t.Errorf("First input argument changed in call: %s", errStr)
  1163  			}
  1164  			if !dimsOK {
  1165  				continue
  1166  			}
  1167  			if !sameAnswer(want, got) {
  1168  				t.Errorf("Answer mismatch: %s; got %v, want %v", errStr, got, want)
  1169  			}
  1170  		}
  1171  	}
  1172  }
  1173  
  1174  var sizePairs = []struct {
  1175  	ar, ac, br, bc int
  1176  }{
  1177  	{1, 1, 1, 1},
  1178  	{6, 6, 6, 6},
  1179  	{7, 7, 7, 7},
  1180  
  1181  	{1, 1, 1, 5},
  1182  	{1, 1, 5, 1},
  1183  	{1, 5, 1, 1},
  1184  	{5, 1, 1, 1},
  1185  
  1186  	{5, 5, 5, 1},
  1187  	{5, 5, 1, 5},
  1188  	{5, 1, 5, 5},
  1189  	{1, 5, 5, 5},
  1190  
  1191  	{6, 6, 6, 11},
  1192  	{6, 6, 11, 6},
  1193  	{6, 11, 6, 6},
  1194  	{11, 6, 6, 6},
  1195  	{11, 11, 11, 6},
  1196  	{11, 11, 6, 11},
  1197  	{11, 6, 11, 11},
  1198  	{6, 11, 11, 11},
  1199  
  1200  	{1, 1, 5, 5},
  1201  	{1, 5, 1, 5},
  1202  	{1, 5, 5, 1},
  1203  	{5, 1, 1, 5},
  1204  	{5, 1, 5, 1},
  1205  	{5, 5, 1, 1},
  1206  	{6, 6, 11, 11},
  1207  	{6, 11, 6, 11},
  1208  	{6, 11, 11, 6},
  1209  	{11, 6, 6, 11},
  1210  	{11, 6, 11, 6},
  1211  	{11, 11, 6, 6},
  1212  
  1213  	{1, 1, 17, 11},
  1214  	{1, 1, 11, 17},
  1215  	{1, 11, 1, 17},
  1216  	{1, 17, 1, 11},
  1217  	{1, 11, 17, 1},
  1218  	{1, 17, 11, 1},
  1219  	{11, 1, 1, 17},
  1220  	{17, 1, 1, 11},
  1221  	{11, 1, 17, 1},
  1222  	{17, 1, 11, 1},
  1223  	{11, 17, 1, 1},
  1224  	{17, 11, 1, 1},
  1225  
  1226  	{6, 6, 1, 11},
  1227  	{6, 6, 11, 1},
  1228  	{6, 11, 6, 1},
  1229  	{6, 1, 6, 11},
  1230  	{6, 11, 1, 6},
  1231  	{6, 1, 11, 6},
  1232  	{11, 6, 6, 1},
  1233  	{1, 6, 6, 11},
  1234  	{11, 6, 1, 6},
  1235  	{1, 6, 11, 6},
  1236  	{11, 1, 6, 6},
  1237  	{1, 11, 6, 6},
  1238  
  1239  	{6, 6, 17, 1},
  1240  	{6, 6, 1, 17},
  1241  	{6, 1, 6, 17},
  1242  	{6, 17, 6, 1},
  1243  	{6, 1, 17, 6},
  1244  	{6, 17, 1, 6},
  1245  	{1, 6, 6, 17},
  1246  	{17, 6, 6, 1},
  1247  	{1, 6, 17, 6},
  1248  	{17, 6, 1, 6},
  1249  	{1, 17, 6, 6},
  1250  	{17, 1, 6, 6},
  1251  
  1252  	{6, 6, 17, 11},
  1253  	{6, 6, 11, 17},
  1254  	{6, 11, 6, 17},
  1255  	{6, 17, 6, 11},
  1256  	{6, 11, 17, 6},
  1257  	{6, 17, 11, 6},
  1258  	{11, 6, 6, 17},
  1259  	{17, 6, 6, 11},
  1260  	{11, 6, 17, 6},
  1261  	{17, 6, 11, 6},
  1262  	{11, 17, 6, 6},
  1263  	{17, 11, 6, 6},
  1264  }
  1265  
  1266  func testTwoInputFunc(t *testing.T,
  1267  	// name is the name of the function being tested.
  1268  	name string,
  1269  
  1270  	// f is the function being tested.
  1271  	f func(a, b Matrix) interface{},
  1272  
  1273  	// denseComparison performs the same operation, but using Dense matrices for
  1274  	// comparison.
  1275  	denseComparison func(a, b *Dense) interface{},
  1276  
  1277  	// sameAnswer compares the result from two different evaluations of the function
  1278  	// and returns true if they are the same. The specific function being tested
  1279  	// determines the definition of "same". It may mean identical or it may mean
  1280  	// approximately equal.
  1281  	sameAnswer func(a, b interface{}) bool,
  1282  
  1283  	// legalType returns true if the types of the inputs are legal for the
  1284  	// input of the function.
  1285  	legalType func(a, b Matrix) bool,
  1286  
  1287  	// legalSize returns true if the sizes are valid for the function.
  1288  	legalSize func(ar, ac, br, bc int) bool,
  1289  ) {
  1290  	src := rand.NewSource(1)
  1291  	for _, aMat := range testMatrices {
  1292  		for _, bMat := range testMatrices {
  1293  			// Loop over all of the size combinations (bigger, smaller, etc.).
  1294  			for _, test := range sizePairs {
  1295  				// Skip the test if the argument would not be assignable to the
  1296  				// method's corresponding input parameter or it is not possible
  1297  				// to construct an argument of the requested size.
  1298  				if !legalType(aMat, bMat) {
  1299  					continue
  1300  				}
  1301  				if !legalDims(aMat, test.ar, test.ac) {
  1302  					continue
  1303  				}
  1304  				if !legalDims(bMat, test.br, test.bc) {
  1305  					continue
  1306  				}
  1307  				a := makeRandOf(aMat, test.ar, test.ac, src)
  1308  				b := makeRandOf(bMat, test.br, test.bc, src)
  1309  
  1310  				// Compute the true answer if the sizes are legal.
  1311  				dimsOK := legalSize(test.ar, test.ac, test.br, test.bc)
  1312  				var want interface{}
  1313  				if dimsOK {
  1314  					var aDense, bDense Dense
  1315  					aDense.CloneFrom(a)
  1316  					bDense.CloneFrom(b)
  1317  					want = denseComparison(&aDense, &bDense)
  1318  				}
  1319  				aCopy := makeCopyOf(a)
  1320  				bCopy := makeCopyOf(b)
  1321  				// Test the method for a zero-value of the receiver.
  1322  				aType, aTrans := untranspose(a)
  1323  				bType, bTrans := untranspose(b)
  1324  				errStr := fmt.Sprintf("%v(%T, %T), size: %#v, atrans %t, btrans %t", name, aType, bType, test, aTrans, bTrans)
  1325  				var got interface{}
  1326  				panicked, err := panics(func() { got = f(a, b) })
  1327  				if !dimsOK && !panicked {
  1328  					t.Errorf("Did not panic with illegal size: %s", errStr)
  1329  					continue
  1330  				}
  1331  				if dimsOK && panicked {
  1332  					t.Errorf("Panicked with legal size: %s: %v", errStr, err)
  1333  					continue
  1334  				}
  1335  				if !equal(a, aCopy) {
  1336  					t.Errorf("First input argument changed in call: %s", errStr)
  1337  				}
  1338  				if !equal(b, bCopy) {
  1339  					t.Errorf("First input argument changed in call: %s", errStr)
  1340  				}
  1341  				if !dimsOK {
  1342  					continue
  1343  				}
  1344  				if !sameAnswer(want, got) {
  1345  					t.Errorf("Answer mismatch: %s", errStr)
  1346  				}
  1347  			}
  1348  		}
  1349  	}
  1350  }
  1351  
  1352  // testOneInput tests a method that has one matrix input argument
  1353  func testOneInput(t *testing.T,
  1354  	// name is the name of the method being tested.
  1355  	name string,
  1356  
  1357  	// receiver is a value of the receiver type.
  1358  	receiver Matrix,
  1359  
  1360  	// method is the generalized receiver.Method(a).
  1361  	method func(receiver, a Matrix),
  1362  
  1363  	// denseComparison performs the same operation as method, but with dense
  1364  	// matrices for comparison with the result.
  1365  	denseComparison func(receiver, a *Dense),
  1366  
  1367  	// legalTypes returns whether the concrete types in Matrix are valid for
  1368  	// the method.
  1369  	legalType func(a Matrix) bool,
  1370  
  1371  	// legalSize returns whether the matrix sizes are valid for the method.
  1372  	legalSize func(ar, ac int) bool,
  1373  
  1374  	// tol is the tolerance for equality when comparing method results.
  1375  	tol float64,
  1376  ) {
  1377  	src := rand.NewSource(1)
  1378  	for _, aMat := range testMatrices {
  1379  		for _, test := range sizes {
  1380  			// Skip the test if the argument would not be assignable to the
  1381  			// method's corresponding input parameter or it is not possible
  1382  			// to construct an argument of the requested size.
  1383  			if !legalType(aMat) {
  1384  				continue
  1385  			}
  1386  			if !legalDims(aMat, test.ar, test.ac) {
  1387  				continue
  1388  			}
  1389  			a := makeRandOf(aMat, test.ar, test.ac, src)
  1390  
  1391  			// Compute the true answer if the sizes are legal.
  1392  			dimsOK := legalSize(test.ar, test.ac)
  1393  			var want Dense
  1394  			if dimsOK {
  1395  				var aDense Dense
  1396  				aDense.CloneFrom(a)
  1397  				denseComparison(&want, &aDense)
  1398  			}
  1399  			aCopy := makeCopyOf(a)
  1400  
  1401  			// Test the method for a zero-value of the receiver.
  1402  			aType, aTrans := untranspose(a)
  1403  			errStr := fmt.Sprintf("%T.%s(%T), size: %#v, atrans %v", receiver, name, aType, test, aTrans)
  1404  			empty := makeRandOf(receiver, 0, 0, src)
  1405  			panicked, err := panics(func() { method(empty, a) })
  1406  			if !dimsOK && !panicked {
  1407  				t.Errorf("Did not panic with illegal size: %s", errStr)
  1408  				continue
  1409  			}
  1410  			if dimsOK && panicked {
  1411  				t.Errorf("Panicked with legal size: %s: %v", errStr, err)
  1412  				continue
  1413  			}
  1414  			if !equal(a, aCopy) {
  1415  				t.Errorf("First input argument changed in call: %s", errStr)
  1416  			}
  1417  			if !dimsOK {
  1418  				continue
  1419  			}
  1420  			if !equalApprox(empty, &want, tol, false) {
  1421  				t.Errorf("Answer mismatch with empty receiver: %s.\nGot:\n% v\nWant:\n% v\n", errStr, Formatted(empty), Formatted(&want))
  1422  				continue
  1423  			}
  1424  
  1425  			// Test the method with a non-empty-value of the receiver.
  1426  			// The receiver has been overwritten in place so use its size
  1427  			// to construct a new random matrix.
  1428  			rr, rc := empty.Dims()
  1429  			neverEmpty := makeRandOf(receiver, rr, rc, src)
  1430  			panicked, message := panics(func() { method(neverEmpty, a) })
  1431  			if panicked {
  1432  				t.Errorf("Panicked with non-empty receiver: %s: %s", errStr, message)
  1433  			}
  1434  			if !equalApprox(neverEmpty, &want, tol, false) {
  1435  				t.Errorf("Answer mismatch non-empty receiver: %s", errStr)
  1436  			}
  1437  
  1438  			// Test the method with a NaN-filled-value of the receiver.
  1439  			// The receiver has been overwritten in place so use its size
  1440  			// to construct a new NaN matrix.
  1441  			nanMatrix := makeNaNOf(receiver, rr, rc)
  1442  			panicked, message = panics(func() { method(nanMatrix, a) })
  1443  			if panicked {
  1444  				t.Errorf("Panicked with NaN-filled receiver: %s: %s", errStr, message)
  1445  			}
  1446  			if !equalApprox(nanMatrix, &want, tol, false) {
  1447  				t.Errorf("Answer mismatch NaN-filled receiver: %s", errStr)
  1448  			}
  1449  
  1450  			// Test with an incorrectly sized matrix.
  1451  			switch receiver.(type) {
  1452  			default:
  1453  				panic("matrix type not coded for incorrect receiver size")
  1454  			case *Dense:
  1455  				wrongSize := makeRandOf(receiver, rr+1, rc, src)
  1456  				panicked, _ = panics(func() { method(wrongSize, a) })
  1457  				if !panicked {
  1458  					t.Errorf("Did not panic with wrong number of rows: %s", errStr)
  1459  				}
  1460  				wrongSize = makeRandOf(receiver, rr, rc+1, src)
  1461  				panicked, _ = panics(func() { method(wrongSize, a) })
  1462  				if !panicked {
  1463  					t.Errorf("Did not panic with wrong number of columns: %s", errStr)
  1464  				}
  1465  			case *TriDense, *SymDense:
  1466  				// Add to the square size.
  1467  				wrongSize := makeRandOf(receiver, rr+1, rc+1, src)
  1468  				panicked, _ = panics(func() { method(wrongSize, a) })
  1469  				if !panicked {
  1470  					t.Errorf("Did not panic with wrong size: %s", errStr)
  1471  				}
  1472  			case *VecDense:
  1473  				// Add to the column length.
  1474  				wrongSize := makeRandOf(receiver, rr+1, rc, src)
  1475  				panicked, _ = panics(func() { method(wrongSize, a) })
  1476  				if !panicked {
  1477  					t.Errorf("Did not panic with wrong number of rows: %s", errStr)
  1478  				}
  1479  			}
  1480  
  1481  			// The receiver and the input may share a matrix pointer
  1482  			// if the type and size of the receiver and one of the
  1483  			// arguments match. Test the method works properly
  1484  			// when this is the case.
  1485  			aMaybeSame := maybeSame(neverEmpty, a)
  1486  			if aMaybeSame {
  1487  				aSame := makeCopyOf(a)
  1488  				receiver = aSame
  1489  				u, ok := aSame.(Untransposer)
  1490  				if ok {
  1491  					receiver = u.Untranspose()
  1492  				}
  1493  				preData := underlyingData(receiver)
  1494  				panicked, err = panics(func() { method(receiver, aSame) })
  1495  				if panicked {
  1496  					t.Errorf("Panics when a maybeSame: %s: %v", errStr, err)
  1497  				} else {
  1498  					if !equalApprox(receiver, &want, tol, false) {
  1499  						t.Errorf("Wrong answer when a maybeSame: %s", errStr)
  1500  					}
  1501  					postData := underlyingData(receiver)
  1502  					if !floats.Equal(preData, postData) {
  1503  						t.Errorf("Original data slice not modified when a maybeSame: %s", errStr)
  1504  					}
  1505  				}
  1506  			}
  1507  		}
  1508  	}
  1509  }
  1510  
  1511  // testTwoInput tests a method that has two input arguments.
  1512  func testTwoInput(t *testing.T,
  1513  	// name is the name of the method being tested.
  1514  	name string,
  1515  
  1516  	// receiver is a value of the receiver type.
  1517  	receiver Matrix,
  1518  
  1519  	// method is the generalized receiver.Method(a, b).
  1520  	method func(receiver, a, b Matrix),
  1521  
  1522  	// denseComparison performs the same operation as method, but with dense
  1523  	// matrices for comparison with the result.
  1524  	denseComparison func(receiver, a, b *Dense),
  1525  
  1526  	// legalTypes returns whether the concrete types in Matrix are valid for
  1527  	// the method.
  1528  	legalTypes func(a, b Matrix) bool,
  1529  
  1530  	// legalSize returns whether the matrix sizes are valid for the method.
  1531  	legalSize func(ar, ac, br, bc int) bool,
  1532  
  1533  	// tol is the tolerance for equality when comparing method results.
  1534  	tol float64,
  1535  ) {
  1536  	src := rand.NewSource(1)
  1537  	for _, aMat := range testMatrices {
  1538  		for _, bMat := range testMatrices {
  1539  			// Loop over all of the size combinations (bigger, smaller, etc.).
  1540  			for _, test := range sizePairs {
  1541  				// Skip the test if any argument would not be assignable to the
  1542  				// method's corresponding input parameter or it is not possible
  1543  				// to construct an argument of the requested size.
  1544  				if !legalTypes(aMat, bMat) {
  1545  					continue
  1546  				}
  1547  				if !legalDims(aMat, test.ar, test.ac) {
  1548  					continue
  1549  				}
  1550  				if !legalDims(bMat, test.br, test.bc) {
  1551  					continue
  1552  				}
  1553  				a := makeRandOf(aMat, test.ar, test.ac, src)
  1554  				b := makeRandOf(bMat, test.br, test.bc, src)
  1555  
  1556  				// Compute the true answer if the sizes are legal.
  1557  				dimsOK := legalSize(test.ar, test.ac, test.br, test.bc)
  1558  				var want Dense
  1559  				if dimsOK {
  1560  					var aDense, bDense Dense
  1561  					aDense.CloneFrom(a)
  1562  					bDense.CloneFrom(b)
  1563  					denseComparison(&want, &aDense, &bDense)
  1564  				}
  1565  				aCopy := makeCopyOf(a)
  1566  				bCopy := makeCopyOf(b)
  1567  
  1568  				// Test the method for a empty-value of the receiver.
  1569  				aType, aTrans := untranspose(a)
  1570  				bType, bTrans := untranspose(b)
  1571  				errStr := fmt.Sprintf("%T.%s(%T, %T), sizes: %#v, atrans %v, btrans %v", receiver, name, aType, bType, test, aTrans, bTrans)
  1572  				empty := makeRandOf(receiver, 0, 0, src)
  1573  				panicked, err := panics(func() { method(empty, a, b) })
  1574  				if !dimsOK && !panicked {
  1575  					t.Errorf("Did not panic with illegal size: %s", errStr)
  1576  					continue
  1577  				}
  1578  				if dimsOK && panicked {
  1579  					t.Errorf("Panicked with legal size: %s: %v", errStr, err)
  1580  					continue
  1581  				}
  1582  				if !equal(a, aCopy) {
  1583  					t.Errorf("First input argument changed in call: %s", errStr)
  1584  				}
  1585  				if !equal(b, bCopy) {
  1586  					t.Errorf("Second input argument changed in call: %s", errStr)
  1587  				}
  1588  				if !dimsOK {
  1589  					continue
  1590  				}
  1591  				wasEmpty, empty := empty, nil // Nil-out empty so we detect illegal use.
  1592  				// NaN equality is allowed because of 0/0 in DivElem test.
  1593  				if !equalApprox(wasEmpty, &want, tol, true) {
  1594  					t.Errorf("Answer mismatch with empty receiver: %s", errStr)
  1595  					continue
  1596  				}
  1597  
  1598  				// Test the method with a non-empty-value of the receiver.
  1599  				// The receiver has been overwritten in place so use its size
  1600  				// to construct a new random matrix.
  1601  				rr, rc := wasEmpty.Dims()
  1602  				neverEmpty := makeRandOf(receiver, rr, rc, src)
  1603  				panicked, message := panics(func() { method(neverEmpty, a, b) })
  1604  				if panicked {
  1605  					t.Errorf("Panicked with non-empty receiver: %s: %s", errStr, message)
  1606  				}
  1607  				// NaN equality is allowed because of 0/0 in DivElem test.
  1608  				if !equalApprox(neverEmpty, &want, tol, true) {
  1609  					t.Errorf("Answer mismatch non-empty receiver: %s", errStr)
  1610  				}
  1611  
  1612  				// Test the method with a NaN-filled value of the receiver.
  1613  				// The receiver has been overwritten in place so use its size
  1614  				// to construct a new NaN matrix.
  1615  				nanMatrix := makeNaNOf(receiver, rr, rc)
  1616  				panicked, message = panics(func() { method(nanMatrix, a, b) })
  1617  				if panicked {
  1618  					t.Errorf("Panicked with NaN-filled receiver: %s: %s", errStr, message)
  1619  				}
  1620  				// NaN equality is allowed because of 0/0 in DivElem test.
  1621  				if !equalApprox(nanMatrix, &want, tol, true) {
  1622  					t.Errorf("Answer mismatch NaN-filled receiver: %s", errStr)
  1623  				}
  1624  
  1625  				// Test with an incorrectly sized matrix.
  1626  				switch receiver.(type) {
  1627  				default:
  1628  					panic("matrix type not coded for incorrect receiver size")
  1629  				case *Dense:
  1630  					wrongSize := makeRandOf(receiver, rr+1, rc, src)
  1631  					panicked, _ = panics(func() { method(wrongSize, a, b) })
  1632  					if !panicked {
  1633  						t.Errorf("Did not panic with wrong number of rows: %s", errStr)
  1634  					}
  1635  					wrongSize = makeRandOf(receiver, rr, rc+1, src)
  1636  					panicked, _ = panics(func() { method(wrongSize, a, b) })
  1637  					if !panicked {
  1638  						t.Errorf("Did not panic with wrong number of columns: %s", errStr)
  1639  					}
  1640  				case *TriDense, *SymDense:
  1641  					// Add to the square size.
  1642  					wrongSize := makeRandOf(receiver, rr+1, rc+1, src)
  1643  					panicked, _ = panics(func() { method(wrongSize, a, b) })
  1644  					if !panicked {
  1645  						t.Errorf("Did not panic with wrong size: %s", errStr)
  1646  					}
  1647  				case *VecDense:
  1648  					// Add to the column length.
  1649  					wrongSize := makeRandOf(receiver, rr+1, rc, src)
  1650  					panicked, _ = panics(func() { method(wrongSize, a, b) })
  1651  					if !panicked {
  1652  						t.Errorf("Did not panic with wrong number of rows: %s", errStr)
  1653  					}
  1654  				}
  1655  
  1656  				// The receiver and an input may share a matrix pointer
  1657  				// if the type and size of the receiver and one of the
  1658  				// arguments match. Test the method works properly
  1659  				// when this is the case.
  1660  				aMaybeSame := maybeSame(neverEmpty, a)
  1661  				bMaybeSame := maybeSame(neverEmpty, b)
  1662  				if aMaybeSame {
  1663  					aSame := makeCopyOf(a)
  1664  					receiver = aSame
  1665  					u, ok := aSame.(Untransposer)
  1666  					if ok {
  1667  						receiver = u.Untranspose()
  1668  					}
  1669  					preData := underlyingData(receiver)
  1670  					panicked, err = panics(func() { method(receiver, aSame, b) })
  1671  					if panicked {
  1672  						t.Errorf("Panics when a maybeSame: %s: %v", errStr, err)
  1673  					} else {
  1674  						if !equalApprox(receiver, &want, tol, false) {
  1675  							t.Errorf("Wrong answer when a maybeSame: %s", errStr)
  1676  						}
  1677  						postData := underlyingData(receiver)
  1678  						if !floats.Equal(preData, postData) {
  1679  							t.Errorf("Original data slice not modified when a maybeSame: %s", errStr)
  1680  						}
  1681  					}
  1682  				}
  1683  				if bMaybeSame {
  1684  					bSame := makeCopyOf(b)
  1685  					receiver = bSame
  1686  					u, ok := bSame.(Untransposer)
  1687  					if ok {
  1688  						receiver = u.Untranspose()
  1689  					}
  1690  					preData := underlyingData(receiver)
  1691  					panicked, err = panics(func() { method(receiver, a, bSame) })
  1692  					if panicked {
  1693  						t.Errorf("Panics when b maybeSame: %s: %v", errStr, err)
  1694  					} else {
  1695  						if !equalApprox(receiver, &want, tol, false) {
  1696  							t.Errorf("Wrong answer when b maybeSame: %s", errStr)
  1697  						}
  1698  						postData := underlyingData(receiver)
  1699  						if !floats.Equal(preData, postData) {
  1700  							t.Errorf("Original data slice not modified when b maybeSame: %s", errStr)
  1701  						}
  1702  					}
  1703  				}
  1704  				if aMaybeSame && bMaybeSame {
  1705  					aSame := makeCopyOf(a)
  1706  					receiver = aSame
  1707  					u, ok := aSame.(Untransposer)
  1708  					if ok {
  1709  						receiver = u.Untranspose()
  1710  					}
  1711  					// Ensure that b is the correct transpose type if applicable.
  1712  					// The receiver is always a concrete type so use it.
  1713  					bSame := receiver
  1714  					_, ok = b.(Untransposer)
  1715  					if ok {
  1716  						bSame = retranspose(b, receiver)
  1717  					}
  1718  					// Compute the real answer for this case. It is different
  1719  					// from the initial answer since now a and b have the
  1720  					// same data.
  1721  					empty = makeRandOf(wasEmpty, 0, 0, src)
  1722  					method(empty, aSame, bSame)
  1723  					wasEmpty, empty = empty, nil // Nil-out empty so we detect illegal use.
  1724  					preData := underlyingData(receiver)
  1725  					panicked, err = panics(func() { method(receiver, aSame, bSame) })
  1726  					if panicked {
  1727  						t.Errorf("Panics when both maybeSame: %s: %v", errStr, err)
  1728  					} else {
  1729  						if !equalApprox(receiver, wasEmpty, tol, false) {
  1730  							t.Errorf("Wrong answer when both maybeSame: %s", errStr)
  1731  						}
  1732  						postData := underlyingData(receiver)
  1733  						if !floats.Equal(preData, postData) {
  1734  							t.Errorf("Original data slice not modified when both maybeSame: %s", errStr)
  1735  						}
  1736  					}
  1737  				}
  1738  			}
  1739  		}
  1740  	}
  1741  }