github.com/gopherd/gonum@v0.0.4/lapack/testlapack/general.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  package testlapack
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"math/cmplx"
    11  	"testing"
    12  
    13  	"math/rand"
    14  
    15  	"github.com/gopherd/gonum/blas"
    16  	"github.com/gopherd/gonum/blas/blas64"
    17  	"github.com/gopherd/gonum/lapack"
    18  )
    19  
    20  const (
    21  	// dlamchE is the machine epsilon. For IEEE this is 2^{-53}.
    22  	dlamchE = 0x1p-53
    23  	dlamchB = 2
    24  	dlamchP = dlamchB * dlamchE
    25  	// dlamchS is the smallest normal number. For IEEE this is 2^{-1022}.
    26  	dlamchS = 0x1p-1022
    27  
    28  	safmin = dlamchS
    29  	safmax = 1 / safmin
    30  	ulp    = dlamchP
    31  	smlnum = safmin / ulp
    32  	bignum = safmax * ulp
    33  )
    34  
    35  func max(a, b int) int {
    36  	if a > b {
    37  		return a
    38  	}
    39  	return b
    40  }
    41  
    42  func min(a, b int) int {
    43  	if a < b {
    44  		return a
    45  	}
    46  	return b
    47  }
    48  
    49  // worklen describes how much workspace a test should use.
    50  type worklen int
    51  
    52  const (
    53  	minimumWork worklen = iota
    54  	mediumWork
    55  	optimumWork
    56  )
    57  
    58  func (wl worklen) String() string {
    59  	switch wl {
    60  	case minimumWork:
    61  		return "minimum"
    62  	case mediumWork:
    63  		return "medium"
    64  	case optimumWork:
    65  		return "optimum"
    66  	}
    67  	return ""
    68  }
    69  
    70  func normToString(norm lapack.MatrixNorm) string {
    71  	switch norm {
    72  	case lapack.MaxAbs:
    73  		return "MaxAbs"
    74  	case lapack.MaxRowSum:
    75  		return "MaxRowSum"
    76  	case lapack.MaxColumnSum:
    77  		return "MaxColSum"
    78  	case lapack.Frobenius:
    79  		return "Frobenius"
    80  	default:
    81  		panic("invalid norm")
    82  	}
    83  }
    84  
    85  func uploToString(uplo blas.Uplo) string {
    86  	switch uplo {
    87  	case blas.Lower:
    88  		return "Lower"
    89  	case blas.Upper:
    90  		return "Upper"
    91  	default:
    92  		panic("invalid uplo")
    93  	}
    94  }
    95  
    96  func diagToString(diag blas.Diag) string {
    97  	switch diag {
    98  	case blas.NonUnit:
    99  		return "NonUnit"
   100  	case blas.Unit:
   101  		return "Unit"
   102  	default:
   103  		panic("invalid diag")
   104  	}
   105  }
   106  
   107  func sideToString(side blas.Side) string {
   108  	switch side {
   109  	case blas.Left:
   110  		return "Left"
   111  	case blas.Right:
   112  		return "Right"
   113  	default:
   114  		panic("invalid side")
   115  	}
   116  }
   117  
   118  func transToString(trans blas.Transpose) string {
   119  	switch trans {
   120  	case blas.NoTrans:
   121  		return "NoTrans"
   122  	case blas.Trans:
   123  		return "Trans"
   124  	case blas.ConjTrans:
   125  		return "ConjTrans"
   126  	default:
   127  		panic("invalid trans")
   128  	}
   129  }
   130  
   131  // nanSlice allocates a new slice of length n filled with NaN.
   132  func nanSlice(n int) []float64 {
   133  	s := make([]float64, n)
   134  	for i := range s {
   135  		s[i] = math.NaN()
   136  	}
   137  	return s
   138  }
   139  
   140  // randomSlice allocates a new slice of length n filled with random values.
   141  func randomSlice(n int, rnd *rand.Rand) []float64 {
   142  	s := make([]float64, n)
   143  	for i := range s {
   144  		s[i] = rnd.NormFloat64()
   145  	}
   146  	return s
   147  }
   148  
   149  // nanGeneral allocates a new r×c general matrix filled with NaN values.
   150  func nanGeneral(r, c, stride int) blas64.General {
   151  	if r < 0 || c < 0 {
   152  		panic("bad matrix size")
   153  	}
   154  	if r == 0 || c == 0 {
   155  		return blas64.General{Stride: max(1, stride)}
   156  	}
   157  	if stride < c {
   158  		panic("bad stride")
   159  	}
   160  	return blas64.General{
   161  		Rows:   r,
   162  		Cols:   c,
   163  		Stride: stride,
   164  		Data:   nanSlice((r-1)*stride + c),
   165  	}
   166  }
   167  
   168  // randomGeneral allocates a new r×c general matrix filled with random
   169  // numbers. Out-of-range elements are filled with NaN values.
   170  func randomGeneral(r, c, stride int, rnd *rand.Rand) blas64.General {
   171  	ans := nanGeneral(r, c, stride)
   172  	for i := 0; i < r; i++ {
   173  		for j := 0; j < c; j++ {
   174  			ans.Data[i*ans.Stride+j] = rnd.NormFloat64()
   175  		}
   176  	}
   177  	return ans
   178  }
   179  
   180  // randomHessenberg allocates a new n×n Hessenberg matrix filled with zeros
   181  // under the first subdiagonal and with random numbers elsewhere. Out-of-range
   182  // elements are filled with NaN values.
   183  func randomHessenberg(n, stride int, rnd *rand.Rand) blas64.General {
   184  	ans := nanGeneral(n, n, stride)
   185  	for i := 0; i < n; i++ {
   186  		for j := 0; j < i-1; j++ {
   187  			ans.Data[i*ans.Stride+j] = 0
   188  		}
   189  		for j := max(0, i-1); j < n; j++ {
   190  			ans.Data[i*ans.Stride+j] = rnd.NormFloat64()
   191  		}
   192  	}
   193  	return ans
   194  }
   195  
   196  // randomSchurCanonical returns a random, general matrix in Schur canonical
   197  // form, that is, block upper triangular with 1×1 and 2×2 diagonal blocks where
   198  // each 2×2 diagonal block has its diagonal elements equal and its off-diagonal
   199  // elements of opposite sign. bad controls whether the returned matrix will have
   200  // zero or tiny eigenvalues.
   201  func randomSchurCanonical(n, stride int, bad bool, rnd *rand.Rand) (t blas64.General, wr, wi []float64) {
   202  	t = randomGeneral(n, n, stride, rnd)
   203  	// Zero out the lower triangle including the diagonal which will be set later.
   204  	for i := 0; i < t.Rows; i++ {
   205  		for j := 0; j <= i; j++ {
   206  			t.Data[i*t.Stride+j] = 0
   207  		}
   208  	}
   209  	// Randomly create 2×2 diagonal blocks.
   210  	for i := 0; i < t.Rows; {
   211  		a := rnd.NormFloat64()
   212  		if bad && rnd.Float64() < 0.5 {
   213  			if rnd.Float64() < 0.5 {
   214  				// A quarter of real parts of eigenvalues will be tiny.
   215  				a = dlamchS
   216  			} else {
   217  				// A quarter of them will be zero.
   218  				a = 0
   219  			}
   220  		}
   221  
   222  		// A half of eigenvalues will be real.
   223  		if rnd.Float64() < 0.5 || i == t.Rows-1 {
   224  			// Store 1×1 block at the diagonal of T.
   225  			t.Data[i*t.Stride+i] = a
   226  			wr = append(wr, a)
   227  			wi = append(wi, 0)
   228  			i++
   229  			continue
   230  		}
   231  
   232  		// Diagonal elements are equal.
   233  		d := a
   234  		// Element under the diagonal is "normal".
   235  		c := rnd.NormFloat64()
   236  		// Element above the diagonal cannot be zero.
   237  		var b float64
   238  		if bad && rnd.Float64() < 0.5 {
   239  			b = dlamchS
   240  		} else {
   241  			b = rnd.NormFloat64()
   242  		}
   243  		// Make sure off-diagonal elements are of opposite sign.
   244  		if math.Signbit(b) == math.Signbit(c) {
   245  			c *= -1
   246  		}
   247  
   248  		// Store 2×2 block at the diagonal of T.
   249  		t.Data[i*t.Stride+i], t.Data[i*t.Stride+i+1] = a, b
   250  		t.Data[(i+1)*t.Stride+i], t.Data[(i+1)*t.Stride+i+1] = c, d
   251  
   252  		wr = append(wr, a, a)
   253  		im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c))
   254  		wi = append(wi, im, -im)
   255  		i += 2
   256  	}
   257  	return t, wr, wi
   258  }
   259  
   260  // blockedUpperTriGeneral returns a normal random, general matrix in the form
   261  //
   262  //            c-k-l  k    l
   263  //  A =    k [  0   A12  A13 ] if r-k-l >= 0;
   264  //         l [  0    0   A23 ]
   265  //     r-k-l [  0    0    0  ]
   266  //
   267  //          c-k-l  k    l
   268  //  A =  k [  0   A12  A13 ] if r-k-l < 0;
   269  //     r-k [  0    0   A23 ]
   270  //
   271  // where the k×k matrix A12 and l×l matrix is non-singular
   272  // upper triangular. A23 is l×l upper triangular if r-k-l >= 0,
   273  // otherwise A23 is (r-k)×l upper trapezoidal.
   274  func blockedUpperTriGeneral(r, c, k, l, stride int, kblock bool, rnd *rand.Rand) blas64.General {
   275  	t := l
   276  	if kblock {
   277  		t += k
   278  	}
   279  	ans := zeros(r, c, stride)
   280  	for i := 0; i < min(r, t); i++ {
   281  		var v float64
   282  		for v == 0 {
   283  			v = rnd.NormFloat64()
   284  		}
   285  		ans.Data[i*ans.Stride+i+(c-t)] = v
   286  	}
   287  	for i := 0; i < min(r, t); i++ {
   288  		for j := i + (c - t) + 1; j < c; j++ {
   289  			ans.Data[i*ans.Stride+j] = rnd.NormFloat64()
   290  		}
   291  	}
   292  	return ans
   293  }
   294  
   295  // nanTriangular allocates a new r×c triangular matrix filled with NaN values.
   296  func nanTriangular(uplo blas.Uplo, n, stride int) blas64.Triangular {
   297  	if n < 0 {
   298  		panic("bad matrix size")
   299  	}
   300  	if n == 0 {
   301  		return blas64.Triangular{
   302  			Stride: max(1, stride),
   303  			Uplo:   uplo,
   304  			Diag:   blas.NonUnit,
   305  		}
   306  	}
   307  	if stride < n {
   308  		panic("bad stride")
   309  	}
   310  	return blas64.Triangular{
   311  		N:      n,
   312  		Stride: stride,
   313  		Data:   nanSlice((n-1)*stride + n),
   314  		Uplo:   uplo,
   315  		Diag:   blas.NonUnit,
   316  	}
   317  }
   318  
   319  // generalOutsideAllNaN returns whether all out-of-range elements have NaN
   320  // values.
   321  func generalOutsideAllNaN(a blas64.General) bool {
   322  	// Check after last column.
   323  	for i := 0; i < a.Rows-1; i++ {
   324  		for _, v := range a.Data[i*a.Stride+a.Cols : i*a.Stride+a.Stride] {
   325  			if !math.IsNaN(v) {
   326  				return false
   327  			}
   328  		}
   329  	}
   330  	// Check after last element.
   331  	last := (a.Rows-1)*a.Stride + a.Cols
   332  	if a.Rows == 0 || a.Cols == 0 {
   333  		last = 0
   334  	}
   335  	for _, v := range a.Data[last:] {
   336  		if !math.IsNaN(v) {
   337  			return false
   338  		}
   339  	}
   340  	return true
   341  }
   342  
   343  // triangularOutsideAllNaN returns whether all out-of-triangle elements have NaN
   344  // values.
   345  func triangularOutsideAllNaN(a blas64.Triangular) bool {
   346  	if a.Uplo == blas.Upper {
   347  		// Check below diagonal.
   348  		for i := 0; i < a.N; i++ {
   349  			for _, v := range a.Data[i*a.Stride : i*a.Stride+i] {
   350  				if !math.IsNaN(v) {
   351  					return false
   352  				}
   353  			}
   354  		}
   355  		// Check after last column.
   356  		for i := 0; i < a.N-1; i++ {
   357  			for _, v := range a.Data[i*a.Stride+a.N : i*a.Stride+a.Stride] {
   358  				if !math.IsNaN(v) {
   359  					return false
   360  				}
   361  			}
   362  		}
   363  	} else {
   364  		// Check above diagonal.
   365  		for i := 0; i < a.N-1; i++ {
   366  			for _, v := range a.Data[i*a.Stride+i+1 : i*a.Stride+a.Stride] {
   367  				if !math.IsNaN(v) {
   368  					return false
   369  				}
   370  			}
   371  		}
   372  	}
   373  	// Check after last element.
   374  	for _, v := range a.Data[max(0, a.N-1)*a.Stride+a.N:] {
   375  		if !math.IsNaN(v) {
   376  			return false
   377  		}
   378  	}
   379  	return true
   380  }
   381  
   382  // transposeGeneral returns a new general matrix that is the transpose of the
   383  // input. Nothing is done with data outside the {rows, cols} limit of the general.
   384  func transposeGeneral(a blas64.General) blas64.General {
   385  	ans := blas64.General{
   386  		Rows:   a.Cols,
   387  		Cols:   a.Rows,
   388  		Stride: a.Rows,
   389  		Data:   make([]float64, a.Cols*a.Rows),
   390  	}
   391  	for i := 0; i < a.Rows; i++ {
   392  		for j := 0; j < a.Cols; j++ {
   393  			ans.Data[j*ans.Stride+i] = a.Data[i*a.Stride+j]
   394  		}
   395  	}
   396  	return ans
   397  }
   398  
   399  // columnNorms returns the column norms of a.
   400  func columnNorms(m, n int, a []float64, lda int) []float64 {
   401  	bi := blas64.Implementation()
   402  	norms := make([]float64, n)
   403  	for j := 0; j < n; j++ {
   404  		norms[j] = bi.Dnrm2(m, a[j:], lda)
   405  	}
   406  	return norms
   407  }
   408  
   409  // extractVMat collects the single reflectors from a into a matrix.
   410  func extractVMat(m, n int, a []float64, lda int, direct lapack.Direct, store lapack.StoreV) blas64.General {
   411  	k := min(m, n)
   412  	switch {
   413  	default:
   414  		panic("not implemented")
   415  	case direct == lapack.Forward && store == lapack.ColumnWise:
   416  		v := blas64.General{
   417  			Rows:   m,
   418  			Cols:   k,
   419  			Stride: k,
   420  			Data:   make([]float64, m*k),
   421  		}
   422  		for i := 0; i < k; i++ {
   423  			for j := 0; j < i; j++ {
   424  				v.Data[j*v.Stride+i] = 0
   425  			}
   426  			v.Data[i*v.Stride+i] = 1
   427  			for j := i + 1; j < m; j++ {
   428  				v.Data[j*v.Stride+i] = a[j*lda+i]
   429  			}
   430  		}
   431  		return v
   432  	case direct == lapack.Forward && store == lapack.RowWise:
   433  		v := blas64.General{
   434  			Rows:   k,
   435  			Cols:   n,
   436  			Stride: n,
   437  			Data:   make([]float64, k*n),
   438  		}
   439  		for i := 0; i < k; i++ {
   440  			for j := 0; j < i; j++ {
   441  				v.Data[i*v.Stride+j] = 0
   442  			}
   443  			v.Data[i*v.Stride+i] = 1
   444  			for j := i + 1; j < n; j++ {
   445  				v.Data[i*v.Stride+j] = a[i*lda+j]
   446  			}
   447  		}
   448  		return v
   449  	}
   450  }
   451  
   452  // constructBidiagonal constructs a bidiagonal matrix with the given diagonal
   453  // and off-diagonal elements.
   454  func constructBidiagonal(uplo blas.Uplo, n int, d, e []float64) blas64.General {
   455  	bMat := blas64.General{
   456  		Rows:   n,
   457  		Cols:   n,
   458  		Stride: n,
   459  		Data:   make([]float64, n*n),
   460  	}
   461  
   462  	for i := 0; i < n-1; i++ {
   463  		bMat.Data[i*bMat.Stride+i] = d[i]
   464  		if uplo == blas.Upper {
   465  			bMat.Data[i*bMat.Stride+i+1] = e[i]
   466  		} else {
   467  			bMat.Data[(i+1)*bMat.Stride+i] = e[i]
   468  		}
   469  	}
   470  	bMat.Data[(n-1)*bMat.Stride+n-1] = d[n-1]
   471  	return bMat
   472  }
   473  
   474  // constructVMat transforms the v matrix based on the storage.
   475  func constructVMat(vMat blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General {
   476  	m := vMat.Rows
   477  	k := vMat.Cols
   478  	switch {
   479  	default:
   480  		panic("not implemented")
   481  	case store == lapack.ColumnWise && direct == lapack.Forward:
   482  		ldv := k
   483  		v := make([]float64, m*k)
   484  		for i := 0; i < m; i++ {
   485  			for j := 0; j < k; j++ {
   486  				if j > i {
   487  					v[i*ldv+j] = 0
   488  				} else if j == i {
   489  					v[i*ldv+i] = 1
   490  				} else {
   491  					v[i*ldv+j] = vMat.Data[i*vMat.Stride+j]
   492  				}
   493  			}
   494  		}
   495  		return blas64.General{
   496  			Rows:   m,
   497  			Cols:   k,
   498  			Stride: k,
   499  			Data:   v,
   500  		}
   501  	case store == lapack.RowWise && direct == lapack.Forward:
   502  		ldv := m
   503  		v := make([]float64, m*k)
   504  		for i := 0; i < m; i++ {
   505  			for j := 0; j < k; j++ {
   506  				if j > i {
   507  					v[j*ldv+i] = 0
   508  				} else if j == i {
   509  					v[j*ldv+i] = 1
   510  				} else {
   511  					v[j*ldv+i] = vMat.Data[i*vMat.Stride+j]
   512  				}
   513  			}
   514  		}
   515  		return blas64.General{
   516  			Rows:   k,
   517  			Cols:   m,
   518  			Stride: m,
   519  			Data:   v,
   520  		}
   521  	case store == lapack.ColumnWise && direct == lapack.Backward:
   522  		rowsv := m
   523  		ldv := k
   524  		v := make([]float64, m*k)
   525  		for i := 0; i < m; i++ {
   526  			for j := 0; j < k; j++ {
   527  				vrow := rowsv - i - 1
   528  				vcol := k - j - 1
   529  				if j > i {
   530  					v[vrow*ldv+vcol] = 0
   531  				} else if j == i {
   532  					v[vrow*ldv+vcol] = 1
   533  				} else {
   534  					v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j]
   535  				}
   536  			}
   537  		}
   538  		return blas64.General{
   539  			Rows:   rowsv,
   540  			Cols:   ldv,
   541  			Stride: ldv,
   542  			Data:   v,
   543  		}
   544  	case store == lapack.RowWise && direct == lapack.Backward:
   545  		rowsv := k
   546  		ldv := m
   547  		v := make([]float64, m*k)
   548  		for i := 0; i < m; i++ {
   549  			for j := 0; j < k; j++ {
   550  				vcol := ldv - i - 1
   551  				vrow := k - j - 1
   552  				if j > i {
   553  					v[vrow*ldv+vcol] = 0
   554  				} else if j == i {
   555  					v[vrow*ldv+vcol] = 1
   556  				} else {
   557  					v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j]
   558  				}
   559  			}
   560  		}
   561  		return blas64.General{
   562  			Rows:   rowsv,
   563  			Cols:   ldv,
   564  			Stride: ldv,
   565  			Data:   v,
   566  		}
   567  	}
   568  }
   569  
   570  func constructH(tau []float64, v blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General {
   571  	m := v.Rows
   572  	k := v.Cols
   573  	if store == lapack.RowWise {
   574  		m, k = k, m
   575  	}
   576  	h := blas64.General{
   577  		Rows:   m,
   578  		Cols:   m,
   579  		Stride: m,
   580  		Data:   make([]float64, m*m),
   581  	}
   582  	for i := 0; i < m; i++ {
   583  		h.Data[i*m+i] = 1
   584  	}
   585  	for i := 0; i < k; i++ {
   586  		vecData := make([]float64, m)
   587  		if store == lapack.ColumnWise {
   588  			for j := 0; j < m; j++ {
   589  				vecData[j] = v.Data[j*v.Cols+i]
   590  			}
   591  		} else {
   592  			for j := 0; j < m; j++ {
   593  				vecData[j] = v.Data[i*v.Cols+j]
   594  			}
   595  		}
   596  		vec := blas64.Vector{
   597  			Inc:  1,
   598  			Data: vecData,
   599  		}
   600  
   601  		hi := blas64.General{
   602  			Rows:   m,
   603  			Cols:   m,
   604  			Stride: m,
   605  			Data:   make([]float64, m*m),
   606  		}
   607  		for i := 0; i < m; i++ {
   608  			hi.Data[i*m+i] = 1
   609  		}
   610  		// hi = I - tau * v * vᵀ
   611  		blas64.Ger(-tau[i], vec, vec, hi)
   612  
   613  		hcopy := blas64.General{
   614  			Rows:   m,
   615  			Cols:   m,
   616  			Stride: m,
   617  			Data:   make([]float64, m*m),
   618  		}
   619  		copy(hcopy.Data, h.Data)
   620  		if direct == lapack.Forward {
   621  			// H = H * H_I in forward mode
   622  			blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hcopy, hi, 0, h)
   623  		} else {
   624  			// H = H_I * H in backward mode
   625  			blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hi, hcopy, 0, h)
   626  		}
   627  	}
   628  	return h
   629  }
   630  
   631  // constructQ constructs the Q matrix from the result of dgeqrf and dgeqr2.
   632  func constructQ(kind string, m, n int, a []float64, lda int, tau []float64) blas64.General {
   633  	k := min(m, n)
   634  	return constructQK(kind, m, n, k, a, lda, tau)
   635  }
   636  
   637  // constructQK constructs the Q matrix from the result of dgeqrf and dgeqr2 using
   638  // the first k reflectors.
   639  func constructQK(kind string, m, n, k int, a []float64, lda int, tau []float64) blas64.General {
   640  	var sz int
   641  	switch kind {
   642  	case "QR":
   643  		sz = m
   644  	case "LQ", "RQ":
   645  		sz = n
   646  	}
   647  
   648  	q := blas64.General{
   649  		Rows:   sz,
   650  		Cols:   sz,
   651  		Stride: max(1, sz),
   652  		Data:   make([]float64, sz*sz),
   653  	}
   654  	for i := 0; i < sz; i++ {
   655  		q.Data[i*sz+i] = 1
   656  	}
   657  	qCopy := blas64.General{
   658  		Rows:   q.Rows,
   659  		Cols:   q.Cols,
   660  		Stride: q.Stride,
   661  		Data:   make([]float64, len(q.Data)),
   662  	}
   663  	for i := 0; i < k; i++ {
   664  		h := blas64.General{
   665  			Rows:   sz,
   666  			Cols:   sz,
   667  			Stride: max(1, sz),
   668  			Data:   make([]float64, sz*sz),
   669  		}
   670  		for j := 0; j < sz; j++ {
   671  			h.Data[j*sz+j] = 1
   672  		}
   673  		vVec := blas64.Vector{
   674  			Inc:  1,
   675  			Data: make([]float64, sz),
   676  		}
   677  		switch kind {
   678  		case "QR":
   679  			vVec.Data[i] = 1
   680  			for j := i + 1; j < sz; j++ {
   681  				vVec.Data[j] = a[lda*j+i]
   682  			}
   683  		case "LQ":
   684  			vVec.Data[i] = 1
   685  			for j := i + 1; j < sz; j++ {
   686  				vVec.Data[j] = a[i*lda+j]
   687  			}
   688  		case "RQ":
   689  			for j := 0; j < n-k+i; j++ {
   690  				vVec.Data[j] = a[(m-k+i)*lda+j]
   691  			}
   692  			vVec.Data[n-k+i] = 1
   693  		}
   694  		blas64.Ger(-tau[i], vVec, vVec, h)
   695  		copy(qCopy.Data, q.Data)
   696  		// Multiply q by the new h.
   697  		switch kind {
   698  		case "QR", "RQ":
   699  			blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q)
   700  		case "LQ":
   701  			blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, qCopy, 0, q)
   702  		}
   703  	}
   704  	return q
   705  }
   706  
   707  // checkBidiagonal checks the bidiagonal decomposition from dlabrd and dgebd2.
   708  // The input to this function is the answer returned from the routines, stored
   709  // in a, d, e, tauP, and tauQ. The data of original A matrix (before
   710  // decomposition) is input in aCopy.
   711  //
   712  // checkBidiagonal constructs the V and U matrices, and from them constructs Q
   713  // and P. Using these constructions, it checks that Qᵀ * A * P and checks that
   714  // the result is bidiagonal.
   715  func checkBidiagonal(t *testing.T, m, n, nb int, a []float64, lda int, d, e, tauP, tauQ, aCopy []float64) {
   716  	// Check the answer.
   717  	// Construct V and U.
   718  	qMat := constructQPBidiagonal(lapack.ApplyQ, m, n, nb, a, lda, tauQ)
   719  	pMat := constructQPBidiagonal(lapack.ApplyP, m, n, nb, a, lda, tauP)
   720  
   721  	// Compute Qᵀ * A * P.
   722  	aMat := blas64.General{
   723  		Rows:   m,
   724  		Cols:   n,
   725  		Stride: lda,
   726  		Data:   make([]float64, len(aCopy)),
   727  	}
   728  	copy(aMat.Data, aCopy)
   729  
   730  	tmp1 := blas64.General{
   731  		Rows:   m,
   732  		Cols:   n,
   733  		Stride: n,
   734  		Data:   make([]float64, m*n),
   735  	}
   736  	blas64.Gemm(blas.Trans, blas.NoTrans, 1, qMat, aMat, 0, tmp1)
   737  	tmp2 := blas64.General{
   738  		Rows:   m,
   739  		Cols:   n,
   740  		Stride: n,
   741  		Data:   make([]float64, m*n),
   742  	}
   743  	blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp1, pMat, 0, tmp2)
   744  
   745  	// Check that the first nb rows and cols of tm2 are upper bidiagonal
   746  	// if m >= n, and lower bidiagonal otherwise.
   747  	correctDiag := true
   748  	matchD := true
   749  	matchE := true
   750  	for i := 0; i < m; i++ {
   751  		for j := 0; j < n; j++ {
   752  			if i >= nb && j >= nb {
   753  				continue
   754  			}
   755  			v := tmp2.Data[i*tmp2.Stride+j]
   756  			if i == j {
   757  				if math.Abs(d[i]-v) > 1e-12 {
   758  					matchD = false
   759  				}
   760  				continue
   761  			}
   762  			if m >= n && i == j-1 {
   763  				if math.Abs(e[j-1]-v) > 1e-12 {
   764  					matchE = false
   765  				}
   766  				continue
   767  			}
   768  			if m < n && i-1 == j {
   769  				if math.Abs(e[i-1]-v) > 1e-12 {
   770  					matchE = false
   771  				}
   772  				continue
   773  			}
   774  			if math.Abs(v) > 1e-12 {
   775  				correctDiag = false
   776  			}
   777  		}
   778  	}
   779  	if !correctDiag {
   780  		t.Errorf("Updated A not bi-diagonal")
   781  	}
   782  	if !matchD {
   783  		fmt.Println("d = ", d)
   784  		t.Errorf("D Mismatch")
   785  	}
   786  	if !matchE {
   787  		t.Errorf("E mismatch")
   788  	}
   789  }
   790  
   791  // constructQPBidiagonal constructs Q or P from the Bidiagonal decomposition
   792  // computed by dlabrd and bgebd2.
   793  func constructQPBidiagonal(vect lapack.ApplyOrtho, m, n, nb int, a []float64, lda int, tau []float64) blas64.General {
   794  	sz := n
   795  	if vect == lapack.ApplyQ {
   796  		sz = m
   797  	}
   798  
   799  	var ldv int
   800  	var v blas64.General
   801  	if vect == lapack.ApplyQ {
   802  		ldv = nb
   803  		v = blas64.General{
   804  			Rows:   m,
   805  			Cols:   nb,
   806  			Stride: ldv,
   807  			Data:   make([]float64, m*ldv),
   808  		}
   809  	} else {
   810  		ldv = n
   811  		v = blas64.General{
   812  			Rows:   nb,
   813  			Cols:   n,
   814  			Stride: ldv,
   815  			Data:   make([]float64, m*ldv),
   816  		}
   817  	}
   818  
   819  	if vect == lapack.ApplyQ {
   820  		if m >= n {
   821  			for i := 0; i < m; i++ {
   822  				for j := 0; j <= min(nb-1, i); j++ {
   823  					if i == j {
   824  						v.Data[i*ldv+j] = 1
   825  						continue
   826  					}
   827  					v.Data[i*ldv+j] = a[i*lda+j]
   828  				}
   829  			}
   830  		} else {
   831  			for i := 1; i < m; i++ {
   832  				for j := 0; j <= min(nb-1, i-1); j++ {
   833  					if i-1 == j {
   834  						v.Data[i*ldv+j] = 1
   835  						continue
   836  					}
   837  					v.Data[i*ldv+j] = a[i*lda+j]
   838  				}
   839  			}
   840  		}
   841  	} else {
   842  		if m < n {
   843  			for i := 0; i < nb; i++ {
   844  				for j := i; j < n; j++ {
   845  					if i == j {
   846  						v.Data[i*ldv+j] = 1
   847  						continue
   848  					}
   849  					v.Data[i*ldv+j] = a[i*lda+j]
   850  				}
   851  			}
   852  		} else {
   853  			for i := 0; i < nb; i++ {
   854  				for j := i + 1; j < n; j++ {
   855  					if j-1 == i {
   856  						v.Data[i*ldv+j] = 1
   857  						continue
   858  					}
   859  					v.Data[i*ldv+j] = a[i*lda+j]
   860  				}
   861  			}
   862  		}
   863  	}
   864  
   865  	// The variable name is a computation of Q, but the algorithm is mostly the
   866  	// same for computing P (just with different data).
   867  	qMat := blas64.General{
   868  		Rows:   sz,
   869  		Cols:   sz,
   870  		Stride: sz,
   871  		Data:   make([]float64, sz*sz),
   872  	}
   873  	hMat := blas64.General{
   874  		Rows:   sz,
   875  		Cols:   sz,
   876  		Stride: sz,
   877  		Data:   make([]float64, sz*sz),
   878  	}
   879  	// set Q to I
   880  	for i := 0; i < sz; i++ {
   881  		qMat.Data[i*qMat.Stride+i] = 1
   882  	}
   883  	for i := 0; i < nb; i++ {
   884  		qCopy := blas64.General{Rows: qMat.Rows, Cols: qMat.Cols, Stride: qMat.Stride, Data: make([]float64, len(qMat.Data))}
   885  		copy(qCopy.Data, qMat.Data)
   886  
   887  		// Set g and h to I
   888  		for i := 0; i < sz; i++ {
   889  			for j := 0; j < sz; j++ {
   890  				if i == j {
   891  					hMat.Data[i*sz+j] = 1
   892  				} else {
   893  					hMat.Data[i*sz+j] = 0
   894  				}
   895  			}
   896  		}
   897  		var vi blas64.Vector
   898  		// H -= tauQ[i] * v[i] * v[i]^t
   899  		if vect == lapack.ApplyQ {
   900  			vi = blas64.Vector{
   901  				Inc:  v.Stride,
   902  				Data: v.Data[i:],
   903  			}
   904  		} else {
   905  			vi = blas64.Vector{
   906  				Inc:  1,
   907  				Data: v.Data[i*v.Stride:],
   908  			}
   909  		}
   910  		blas64.Ger(-tau[i], vi, vi, hMat)
   911  		// Q = Q * G[1]
   912  		blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, hMat, 0, qMat)
   913  	}
   914  	return qMat
   915  }
   916  
   917  // printRowise prints the matrix with one row per line. This is useful for debugging.
   918  // If beyond is true, it prints beyond the final column to lda. If false, only
   919  // the columns are printed.
   920  //nolint:deadcode,unused
   921  func printRowise(a []float64, m, n, lda int, beyond bool) {
   922  	for i := 0; i < m; i++ {
   923  		end := n
   924  		if beyond {
   925  			end = lda
   926  		}
   927  		fmt.Println(a[i*lda : i*lda+end])
   928  	}
   929  }
   930  
   931  func copyGeneral(dst, src blas64.General) {
   932  	r := min(dst.Rows, src.Rows)
   933  	c := min(dst.Cols, src.Cols)
   934  	for i := 0; i < r; i++ {
   935  		copy(dst.Data[i*dst.Stride:i*dst.Stride+c], src.Data[i*src.Stride:i*src.Stride+c])
   936  	}
   937  }
   938  
   939  // cloneGeneral allocates and returns an exact copy of the given general matrix.
   940  func cloneGeneral(a blas64.General) blas64.General {
   941  	c := a
   942  	c.Data = make([]float64, len(a.Data))
   943  	copy(c.Data, a.Data)
   944  	return c
   945  }
   946  
   947  // equalGeneral returns whether the general matrices a and b are equal.
   948  func equalGeneral(a, b blas64.General) bool {
   949  	if a.Rows != b.Rows || a.Cols != b.Cols {
   950  		panic("bad input")
   951  	}
   952  	for i := 0; i < a.Rows; i++ {
   953  		for j := 0; j < a.Cols; j++ {
   954  			if a.Data[i*a.Stride+j] != b.Data[i*b.Stride+j] {
   955  				return false
   956  			}
   957  		}
   958  	}
   959  	return true
   960  }
   961  
   962  // equalApproxGeneral returns whether the general matrices a and b are
   963  // approximately equal within given tolerance.
   964  func equalApproxGeneral(a, b blas64.General, tol float64) bool {
   965  	if a.Rows != b.Rows || a.Cols != b.Cols {
   966  		panic("bad input")
   967  	}
   968  	for i := 0; i < a.Rows; i++ {
   969  		for j := 0; j < a.Cols; j++ {
   970  			diff := a.Data[i*a.Stride+j] - b.Data[i*b.Stride+j]
   971  			if math.IsNaN(diff) || math.Abs(diff) > tol {
   972  				return false
   973  			}
   974  		}
   975  	}
   976  	return true
   977  }
   978  
   979  func intsEqual(a, b []int) bool {
   980  	if len(a) != len(b) {
   981  		return false
   982  	}
   983  	for i, ai := range a {
   984  		if b[i] != ai {
   985  			return false
   986  		}
   987  	}
   988  	return true
   989  }
   990  
   991  // randSymBand returns an n×n random symmetric positive definite band matrix
   992  // with kd diagonals.
   993  func randSymBand(uplo blas.Uplo, n, kd, ldab int, rnd *rand.Rand) []float64 {
   994  	// Allocate a triangular band matrix U or L and fill it with random numbers.
   995  	var ab []float64
   996  	if n > 0 {
   997  		ab = make([]float64, (n-1)*ldab+kd+1)
   998  	}
   999  	for i := range ab {
  1000  		ab[i] = rnd.NormFloat64()
  1001  	}
  1002  	// Make sure that the matrix U or L has a sufficiently positive diagonal.
  1003  	switch uplo {
  1004  	case blas.Upper:
  1005  		for i := 0; i < n; i++ {
  1006  			ab[i*ldab] = float64(n) + rnd.Float64()
  1007  		}
  1008  	case blas.Lower:
  1009  		for i := 0; i < n; i++ {
  1010  			ab[i*ldab+kd] = float64(n) + rnd.Float64()
  1011  		}
  1012  	}
  1013  	// Compute Uᵀ*U or L*Lᵀ. The resulting (symmetric) matrix A will be
  1014  	// positive definite and well-conditioned.
  1015  	dsbmm(uplo, n, kd, ab, ldab)
  1016  	return ab
  1017  }
  1018  
  1019  // distSymBand returns the max-norm distance between the symmetric band matrices
  1020  // A and B.
  1021  func distSymBand(uplo blas.Uplo, n, kd int, a []float64, lda int, b []float64, ldb int) float64 {
  1022  	var dist float64
  1023  	switch uplo {
  1024  	case blas.Upper:
  1025  		for i := 0; i < n; i++ {
  1026  			for j := 0; j < min(kd+1, n-i); j++ {
  1027  				dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j]))
  1028  			}
  1029  		}
  1030  	case blas.Lower:
  1031  		for i := 0; i < n; i++ {
  1032  			for j := max(0, kd-i); j < kd+1; j++ {
  1033  				dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j]))
  1034  			}
  1035  		}
  1036  	}
  1037  	return dist
  1038  }
  1039  
  1040  // eye returns an identity matrix of given order and stride.
  1041  func eye(n, stride int) blas64.General {
  1042  	ans := nanGeneral(n, n, stride)
  1043  	for i := 0; i < n; i++ {
  1044  		for j := 0; j < n; j++ {
  1045  			ans.Data[i*ans.Stride+j] = 0
  1046  		}
  1047  		ans.Data[i*ans.Stride+i] = 1
  1048  	}
  1049  	return ans
  1050  }
  1051  
  1052  // zeros returns an m×n matrix with given stride filled with zeros.
  1053  func zeros(m, n, stride int) blas64.General {
  1054  	a := nanGeneral(m, n, stride)
  1055  	for i := 0; i < m; i++ {
  1056  		for j := 0; j < n; j++ {
  1057  			a.Data[i*a.Stride+j] = 0
  1058  		}
  1059  	}
  1060  	return a
  1061  }
  1062  
  1063  // extract2x2Block returns the elements of T at [0,0], [0,1], [1,0], and [1,1].
  1064  func extract2x2Block(t []float64, ldt int) (a, b, c, d float64) {
  1065  	return t[0], t[1], t[ldt], t[ldt+1]
  1066  }
  1067  
  1068  // isSchurCanonical returns whether the 2×2 matrix [a b; c d] is in Schur
  1069  // canonical form.
  1070  func isSchurCanonical(a, b, c, d float64) bool {
  1071  	return c == 0 || (b != 0 && a == d && math.Signbit(b) != math.Signbit(c))
  1072  }
  1073  
  1074  // isSchurCanonicalGeneral returns whether T is block upper triangular with 1×1
  1075  // and 2×2 diagonal blocks, each 2×2 block in Schur canonical form. The function
  1076  // checks only along the diagonal and the first subdiagonal, otherwise the lower
  1077  // triangle is not accessed.
  1078  func isSchurCanonicalGeneral(t blas64.General) bool {
  1079  	n := t.Cols
  1080  	if t.Rows != n {
  1081  		panic("invalid matrix")
  1082  	}
  1083  	for j := 0; j < n-1; {
  1084  		if t.Data[(j+1)*t.Stride+j] == 0 {
  1085  			// 1×1 block.
  1086  			for i := j + 1; i < n; i++ {
  1087  				if t.Data[i*t.Stride+j] != 0 {
  1088  					return false
  1089  				}
  1090  			}
  1091  			j++
  1092  			continue
  1093  		}
  1094  		// 2×2 block.
  1095  		a, b, c, d := extract2x2Block(t.Data[j*t.Stride+j:], t.Stride)
  1096  		if !isSchurCanonical(a, b, c, d) {
  1097  			return false
  1098  		}
  1099  		for i := j + 2; i < n; i++ {
  1100  			if t.Data[i*t.Stride+j] != 0 {
  1101  				return false
  1102  			}
  1103  		}
  1104  		for i := j + 2; i < n; i++ {
  1105  			if t.Data[i*t.Stride+j+1] != 0 {
  1106  				return false
  1107  			}
  1108  		}
  1109  		j += 2
  1110  	}
  1111  	return true
  1112  }
  1113  
  1114  // schurBlockEigenvalues returns the two eigenvalues of the 2×2 matrix [a b; c d]
  1115  // that must be in Schur canonical form.
  1116  func schurBlockEigenvalues(a, b, c, d float64) (ev1, ev2 complex128) {
  1117  	if !isSchurCanonical(a, b, c, d) {
  1118  		panic("block not in Schur canonical form")
  1119  	}
  1120  	if c == 0 {
  1121  		return complex(a, 0), complex(d, 0)
  1122  	}
  1123  	im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c))
  1124  	return complex(a, im), complex(a, -im)
  1125  }
  1126  
  1127  // schurBlockSize returns the size of the diagonal block at i-th row in the
  1128  // upper quasi-triangular matrix t in Schur canonical form, and whether i points
  1129  // to the first row of the block. For zero-sized matrices the function returns 0
  1130  // and true.
  1131  func schurBlockSize(t blas64.General, i int) (size int, first bool) {
  1132  	if t.Rows != t.Cols {
  1133  		panic("matrix not square")
  1134  	}
  1135  	if t.Rows == 0 {
  1136  		return 0, true
  1137  	}
  1138  	if i < 0 || t.Rows <= i {
  1139  		panic("index out of range")
  1140  	}
  1141  
  1142  	first = true
  1143  	if i > 0 && t.Data[i*t.Stride+i-1] != 0 {
  1144  		// There is a non-zero element to the left, therefore i must
  1145  		// point to the second row in a 2×2 diagonal block.
  1146  		first = false
  1147  		i--
  1148  	}
  1149  	size = 1
  1150  	if i+1 < t.Rows && t.Data[(i+1)*t.Stride+i] != 0 {
  1151  		// There is a non-zero element below, this must be a 2×2
  1152  		// diagonal block.
  1153  		size = 2
  1154  	}
  1155  	return size, first
  1156  }
  1157  
  1158  // containsComplex returns whether z is approximately equal to one of the complex
  1159  // numbers in v. If z is found, its index in v will be also returned.
  1160  func containsComplex(v []complex128, z complex128, tol float64) (found bool, index int) {
  1161  	for i := range v {
  1162  		if cmplx.Abs(v[i]-z) < tol {
  1163  			return true, i
  1164  		}
  1165  	}
  1166  	return false, -1
  1167  }
  1168  
  1169  // isAllNaN returns whether x contains only NaN values.
  1170  func isAllNaN(x []float64) bool {
  1171  	for _, v := range x {
  1172  		if !math.IsNaN(v) {
  1173  			return false
  1174  		}
  1175  	}
  1176  	return true
  1177  }
  1178  
  1179  // isUpperHessenberg returns whether h contains only zeros below the
  1180  // subdiagonal.
  1181  func isUpperHessenberg(h blas64.General) bool {
  1182  	if h.Rows != h.Cols {
  1183  		panic("matrix not square")
  1184  	}
  1185  	n := h.Rows
  1186  	for i := 0; i < n; i++ {
  1187  		for j := 0; j < n; j++ {
  1188  			if i > j+1 && h.Data[i*h.Stride+j] != 0 {
  1189  				return false
  1190  			}
  1191  		}
  1192  	}
  1193  	return true
  1194  }
  1195  
  1196  // isUpperTriangular returns whether a contains only zeros below the diagonal.
  1197  func isUpperTriangular(a blas64.General) bool {
  1198  	n := a.Rows
  1199  	for i := 1; i < n; i++ {
  1200  		for j := 0; j < i; j++ {
  1201  			if a.Data[i*a.Stride+j] != 0 {
  1202  				return false
  1203  			}
  1204  		}
  1205  	}
  1206  	return true
  1207  }
  1208  
  1209  // unbalancedSparseGeneral returns an m×n dense matrix with a random sparse
  1210  // structure consisting of nz nonzero elements. The matrix will be unbalanced by
  1211  // multiplying each element randomly by its row or column index.
  1212  func unbalancedSparseGeneral(m, n, stride int, nonzeros int, rnd *rand.Rand) blas64.General {
  1213  	a := zeros(m, n, stride)
  1214  	for k := 0; k < nonzeros; k++ {
  1215  		i := rnd.Intn(n)
  1216  		j := rnd.Intn(n)
  1217  		if rnd.Float64() < 0.5 {
  1218  			a.Data[i*stride+j] = float64(i+1) * rnd.NormFloat64()
  1219  		} else {
  1220  			a.Data[i*stride+j] = float64(j+1) * rnd.NormFloat64()
  1221  		}
  1222  	}
  1223  	return a
  1224  }
  1225  
  1226  // rootsOfUnity returns the n complex numbers whose n-th power is equal to 1.
  1227  func rootsOfUnity(n int) []complex128 {
  1228  	w := make([]complex128, n)
  1229  	for i := 0; i < n; i++ {
  1230  		angle := math.Pi * float64(2*i) / float64(n)
  1231  		w[i] = complex(math.Cos(angle), math.Sin(angle))
  1232  	}
  1233  	return w
  1234  }
  1235  
  1236  // constructGSVDresults returns the matrices [ 0 R ], D1 and D2 described
  1237  // in the documentation of Dtgsja and Dggsvd3, and the result matrix in
  1238  // the documentation for Dggsvp3.
  1239  func constructGSVDresults(n, p, m, k, l int, a, b blas64.General, alpha, beta []float64) (zeroR, d1, d2 blas64.General) {
  1240  	// [ 0 R ]
  1241  	zeroR = zeros(k+l, n, n)
  1242  	dst := zeroR
  1243  	dst.Rows = min(m, k+l)
  1244  	dst.Cols = k + l
  1245  	dst.Data = zeroR.Data[n-k-l:]
  1246  	src := a
  1247  	src.Rows = min(m, k+l)
  1248  	src.Cols = k + l
  1249  	src.Data = a.Data[n-k-l:]
  1250  	copyGeneral(dst, src)
  1251  	if m < k+l {
  1252  		// [ 0 R ]
  1253  		dst.Rows = k + l - m
  1254  		dst.Cols = k + l - m
  1255  		dst.Data = zeroR.Data[m*zeroR.Stride+n-(k+l-m):]
  1256  		src = b
  1257  		src.Rows = k + l - m
  1258  		src.Cols = k + l - m
  1259  		src.Data = b.Data[(m-k)*b.Stride+n+m-k-l:]
  1260  		copyGeneral(dst, src)
  1261  	}
  1262  
  1263  	// D1
  1264  	d1 = zeros(m, k+l, k+l)
  1265  	for i := 0; i < k; i++ {
  1266  		d1.Data[i*d1.Stride+i] = 1
  1267  	}
  1268  	for i := k; i < min(m, k+l); i++ {
  1269  		d1.Data[i*d1.Stride+i] = alpha[i]
  1270  	}
  1271  
  1272  	// D2
  1273  	d2 = zeros(p, k+l, k+l)
  1274  	for i := 0; i < min(l, m-k); i++ {
  1275  		d2.Data[i*d2.Stride+i+k] = beta[k+i]
  1276  	}
  1277  	for i := m - k; i < l; i++ {
  1278  		d2.Data[i*d2.Stride+i+k] = 1
  1279  	}
  1280  
  1281  	return zeroR, d1, d2
  1282  }
  1283  
  1284  func constructGSVPresults(n, p, m, k, l int, a, b blas64.General) (zeroA, zeroB blas64.General) {
  1285  	zeroA = zeros(m, n, n)
  1286  	dst := zeroA
  1287  	dst.Rows = min(m, k+l)
  1288  	dst.Cols = k + l
  1289  	dst.Data = zeroA.Data[n-k-l:]
  1290  	src := a
  1291  	dst.Rows = min(m, k+l)
  1292  	src.Cols = k + l
  1293  	src.Data = a.Data[n-k-l:]
  1294  	copyGeneral(dst, src)
  1295  
  1296  	zeroB = zeros(p, n, n)
  1297  	dst = zeroB
  1298  	dst.Rows = l
  1299  	dst.Cols = l
  1300  	dst.Data = zeroB.Data[n-l:]
  1301  	src = b
  1302  	dst.Rows = l
  1303  	src.Cols = l
  1304  	src.Data = b.Data[n-l:]
  1305  	copyGeneral(dst, src)
  1306  
  1307  	return zeroA, zeroB
  1308  }
  1309  
  1310  // distFromIdentity returns the L-infinity distance of an n×n matrix A from the
  1311  // identity. If A contains NaN elements, distFromIdentity will return +inf.
  1312  func distFromIdentity(n int, a []float64, lda int) float64 {
  1313  	var dist float64
  1314  	for i := 0; i < n; i++ {
  1315  		for j := 0; j < n; j++ {
  1316  			aij := a[i*lda+j]
  1317  			if math.IsNaN(aij) {
  1318  				return math.Inf(1)
  1319  			}
  1320  			if i == j {
  1321  				dist = math.Max(dist, math.Abs(aij-1))
  1322  			} else {
  1323  				dist = math.Max(dist, math.Abs(aij))
  1324  			}
  1325  		}
  1326  	}
  1327  	return dist
  1328  }
  1329  
  1330  func sameFloat64(a, b float64) bool {
  1331  	return a == b || math.IsNaN(a) && math.IsNaN(b)
  1332  }
  1333  
  1334  // sameLowerTri returns whether n×n matrices A and B are same under the diagonal.
  1335  func sameLowerTri(n int, a []float64, lda int, b []float64, ldb int) bool {
  1336  	for i := 1; i < n; i++ {
  1337  		for j := 0; j < i; j++ {
  1338  			aij := a[i*lda+j]
  1339  			bij := b[i*ldb+j]
  1340  			if !sameFloat64(aij, bij) {
  1341  				return false
  1342  			}
  1343  		}
  1344  	}
  1345  	return true
  1346  }
  1347  
  1348  // sameUpperTri returns whether n×n matrices A and B are same above the diagonal.
  1349  func sameUpperTri(n int, a []float64, lda int, b []float64, ldb int) bool {
  1350  	for i := 0; i < n-1; i++ {
  1351  		for j := i + 1; j < n; j++ {
  1352  			aij := a[i*lda+j]
  1353  			bij := b[i*ldb+j]
  1354  			if !sameFloat64(aij, bij) {
  1355  				return false
  1356  			}
  1357  		}
  1358  	}
  1359  	return true
  1360  }
  1361  
  1362  // svdJobString returns a string representation of job.
  1363  func svdJobString(job lapack.SVDJob) string {
  1364  	switch job {
  1365  	case lapack.SVDAll:
  1366  		return "All"
  1367  	case lapack.SVDStore:
  1368  		return "Store"
  1369  	case lapack.SVDOverwrite:
  1370  		return "Overwrite"
  1371  	case lapack.SVDNone:
  1372  		return "None"
  1373  	}
  1374  	return "unknown SVD job"
  1375  }
  1376  
  1377  // residualOrthogonal returns the residual
  1378  //  |I - Q * Qᵀ|  if m < n or (m == n and rowwise == true),
  1379  //  |I - Qᵀ * Q|  otherwise.
  1380  // It can be used to check that the matrix Q is orthogonal.
  1381  func residualOrthogonal(q blas64.General, rowwise bool) float64 {
  1382  	m, n := q.Rows, q.Cols
  1383  	if m == 0 || n == 0 {
  1384  		return 0
  1385  	}
  1386  	var transq blas.Transpose
  1387  	if m < n || (m == n && rowwise) {
  1388  		transq = blas.NoTrans
  1389  	} else {
  1390  		transq = blas.Trans
  1391  	}
  1392  	minmn := min(m, n)
  1393  
  1394  	// Set work = I.
  1395  	work := blas64.Symmetric{
  1396  		Uplo:   blas.Upper,
  1397  		N:      minmn,
  1398  		Data:   make([]float64, minmn*minmn),
  1399  		Stride: minmn,
  1400  	}
  1401  	for i := 0; i < minmn; i++ {
  1402  		work.Data[i*work.Stride+i] = 1
  1403  	}
  1404  
  1405  	// Compute
  1406  	//  work = work - Q * Qᵀ = I - Q * Qᵀ
  1407  	// or
  1408  	//  work = work - Qᵀ * Q = I - Qᵀ * Q
  1409  	blas64.Syrk(transq, -1, q, 1, work)
  1410  	return dlansy(lapack.MaxColumnSum, blas.Upper, work.N, work.Data, work.Stride)
  1411  }