gonum.org/v1/gonum@v0.14.0/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  	"golang.org/x/exp/rand"
    14  
    15  	"gonum.org/v1/gonum/blas"
    16  	"gonum.org/v1/gonum/blas/blas64"
    17  	"gonum.org/v1/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  //
   921  //lint:ignore U1000 This is useful for debugging.
   922  func printRowise(a []float64, m, n, lda int, beyond bool) {
   923  	for i := 0; i < m; i++ {
   924  		end := n
   925  		if beyond {
   926  			end = lda
   927  		}
   928  		fmt.Println(a[i*lda : i*lda+end])
   929  	}
   930  }
   931  
   932  func copyGeneral(dst, src blas64.General) {
   933  	r := min(dst.Rows, src.Rows)
   934  	c := min(dst.Cols, src.Cols)
   935  	for i := 0; i < r; i++ {
   936  		copy(dst.Data[i*dst.Stride:i*dst.Stride+c], src.Data[i*src.Stride:i*src.Stride+c])
   937  	}
   938  }
   939  
   940  // cloneGeneral allocates and returns an exact copy of the given general matrix.
   941  func cloneGeneral(a blas64.General) blas64.General {
   942  	c := a
   943  	c.Data = make([]float64, len(a.Data))
   944  	copy(c.Data, a.Data)
   945  	return c
   946  }
   947  
   948  // equalGeneral returns whether the general matrices a and b are equal.
   949  func equalGeneral(a, b blas64.General) bool {
   950  	if a.Rows != b.Rows || a.Cols != b.Cols {
   951  		panic("bad input")
   952  	}
   953  	for i := 0; i < a.Rows; i++ {
   954  		for j := 0; j < a.Cols; j++ {
   955  			if a.Data[i*a.Stride+j] != b.Data[i*b.Stride+j] {
   956  				return false
   957  			}
   958  		}
   959  	}
   960  	return true
   961  }
   962  
   963  // equalApproxGeneral returns whether the general matrices a and b are
   964  // approximately equal within given tolerance.
   965  func equalApproxGeneral(a, b blas64.General, tol float64) bool {
   966  	if a.Rows != b.Rows || a.Cols != b.Cols {
   967  		panic("bad input")
   968  	}
   969  	for i := 0; i < a.Rows; i++ {
   970  		for j := 0; j < a.Cols; j++ {
   971  			diff := a.Data[i*a.Stride+j] - b.Data[i*b.Stride+j]
   972  			if math.IsNaN(diff) || math.Abs(diff) > tol {
   973  				return false
   974  			}
   975  		}
   976  	}
   977  	return true
   978  }
   979  
   980  func intsEqual(a, b []int) bool {
   981  	if len(a) != len(b) {
   982  		return false
   983  	}
   984  	for i, ai := range a {
   985  		if b[i] != ai {
   986  			return false
   987  		}
   988  	}
   989  	return true
   990  }
   991  
   992  // randSymBand returns an n×n random symmetric positive definite band matrix
   993  // with kd diagonals.
   994  func randSymBand(uplo blas.Uplo, n, kd, ldab int, rnd *rand.Rand) []float64 {
   995  	// Allocate a triangular band matrix U or L and fill it with random numbers.
   996  	var ab []float64
   997  	if n > 0 {
   998  		ab = make([]float64, (n-1)*ldab+kd+1)
   999  	}
  1000  	for i := range ab {
  1001  		ab[i] = rnd.NormFloat64()
  1002  	}
  1003  	// Make sure that the matrix U or L has a sufficiently positive diagonal.
  1004  	switch uplo {
  1005  	case blas.Upper:
  1006  		for i := 0; i < n; i++ {
  1007  			ab[i*ldab] = float64(n) + rnd.Float64()
  1008  		}
  1009  	case blas.Lower:
  1010  		for i := 0; i < n; i++ {
  1011  			ab[i*ldab+kd] = float64(n) + rnd.Float64()
  1012  		}
  1013  	}
  1014  	// Compute Uᵀ*U or L*Lᵀ. The resulting (symmetric) matrix A will be
  1015  	// positive definite and well-conditioned.
  1016  	dsbmm(uplo, n, kd, ab, ldab)
  1017  	return ab
  1018  }
  1019  
  1020  // distSymBand returns the max-norm distance between the symmetric band matrices
  1021  // A and B.
  1022  func distSymBand(uplo blas.Uplo, n, kd int, a []float64, lda int, b []float64, ldb int) float64 {
  1023  	var dist float64
  1024  	switch uplo {
  1025  	case blas.Upper:
  1026  		for i := 0; i < n; i++ {
  1027  			for j := 0; j < min(kd+1, n-i); j++ {
  1028  				dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j]))
  1029  			}
  1030  		}
  1031  	case blas.Lower:
  1032  		for i := 0; i < n; i++ {
  1033  			for j := max(0, kd-i); j < kd+1; j++ {
  1034  				dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j]))
  1035  			}
  1036  		}
  1037  	}
  1038  	return dist
  1039  }
  1040  
  1041  // eye returns an identity matrix of given order and stride.
  1042  func eye(n, stride int) blas64.General {
  1043  	ans := nanGeneral(n, n, stride)
  1044  	for i := 0; i < n; i++ {
  1045  		for j := 0; j < n; j++ {
  1046  			ans.Data[i*ans.Stride+j] = 0
  1047  		}
  1048  		ans.Data[i*ans.Stride+i] = 1
  1049  	}
  1050  	return ans
  1051  }
  1052  
  1053  // zeros returns an m×n matrix with given stride filled with zeros.
  1054  func zeros(m, n, stride int) blas64.General {
  1055  	a := nanGeneral(m, n, stride)
  1056  	for i := 0; i < m; i++ {
  1057  		for j := 0; j < n; j++ {
  1058  			a.Data[i*a.Stride+j] = 0
  1059  		}
  1060  	}
  1061  	return a
  1062  }
  1063  
  1064  // extract2x2Block returns the elements of T at [0,0], [0,1], [1,0], and [1,1].
  1065  func extract2x2Block(t []float64, ldt int) (a, b, c, d float64) {
  1066  	return t[0], t[1], t[ldt], t[ldt+1]
  1067  }
  1068  
  1069  // isSchurCanonical returns whether the 2×2 matrix [a b; c d] is in Schur
  1070  // canonical form.
  1071  func isSchurCanonical(a, b, c, d float64) bool {
  1072  	return c == 0 || (b != 0 && a == d && math.Signbit(b) != math.Signbit(c))
  1073  }
  1074  
  1075  // isSchurCanonicalGeneral returns whether T is block upper triangular with 1×1
  1076  // and 2×2 diagonal blocks, each 2×2 block in Schur canonical form. The function
  1077  // checks only along the diagonal and the first subdiagonal, otherwise the lower
  1078  // triangle is not accessed.
  1079  func isSchurCanonicalGeneral(t blas64.General) bool {
  1080  	n := t.Cols
  1081  	if t.Rows != n {
  1082  		panic("invalid matrix")
  1083  	}
  1084  	for j := 0; j < n-1; {
  1085  		if t.Data[(j+1)*t.Stride+j] == 0 {
  1086  			// 1×1 block.
  1087  			for i := j + 1; i < n; i++ {
  1088  				if t.Data[i*t.Stride+j] != 0 {
  1089  					return false
  1090  				}
  1091  			}
  1092  			j++
  1093  			continue
  1094  		}
  1095  		// 2×2 block.
  1096  		a, b, c, d := extract2x2Block(t.Data[j*t.Stride+j:], t.Stride)
  1097  		if !isSchurCanonical(a, b, c, d) {
  1098  			return false
  1099  		}
  1100  		for i := j + 2; i < n; i++ {
  1101  			if t.Data[i*t.Stride+j] != 0 {
  1102  				return false
  1103  			}
  1104  		}
  1105  		for i := j + 2; i < n; i++ {
  1106  			if t.Data[i*t.Stride+j+1] != 0 {
  1107  				return false
  1108  			}
  1109  		}
  1110  		j += 2
  1111  	}
  1112  	return true
  1113  }
  1114  
  1115  // schurBlockEigenvalues returns the two eigenvalues of the 2×2 matrix [a b; c d]
  1116  // that must be in Schur canonical form.
  1117  //
  1118  //lint:ignore U1000 This is useful for debugging.
  1119  func schurBlockEigenvalues(a, b, c, d float64) (ev1, ev2 complex128) {
  1120  	if !isSchurCanonical(a, b, c, d) {
  1121  		panic("block not in Schur canonical form")
  1122  	}
  1123  	if c == 0 {
  1124  		return complex(a, 0), complex(d, 0)
  1125  	}
  1126  	im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c))
  1127  	return complex(a, im), complex(a, -im)
  1128  }
  1129  
  1130  // schurBlockSize returns the size of the diagonal block at i-th row in the
  1131  // upper quasi-triangular matrix t in Schur canonical form, and whether i points
  1132  // to the first row of the block. For zero-sized matrices the function returns 0
  1133  // and true.
  1134  func schurBlockSize(t blas64.General, i int) (size int, first bool) {
  1135  	if t.Rows != t.Cols {
  1136  		panic("matrix not square")
  1137  	}
  1138  	if t.Rows == 0 {
  1139  		return 0, true
  1140  	}
  1141  	if i < 0 || t.Rows <= i {
  1142  		panic("index out of range")
  1143  	}
  1144  
  1145  	first = true
  1146  	if i > 0 && t.Data[i*t.Stride+i-1] != 0 {
  1147  		// There is a non-zero element to the left, therefore i must
  1148  		// point to the second row in a 2×2 diagonal block.
  1149  		first = false
  1150  		i--
  1151  	}
  1152  	size = 1
  1153  	if i+1 < t.Rows && t.Data[(i+1)*t.Stride+i] != 0 {
  1154  		// There is a non-zero element below, this must be a 2×2
  1155  		// diagonal block.
  1156  		size = 2
  1157  	}
  1158  	return size, first
  1159  }
  1160  
  1161  // containsComplex returns whether z is approximately equal to one of the complex
  1162  // numbers in v. If z is found, its index in v will be also returned.
  1163  func containsComplex(v []complex128, z complex128, tol float64) (found bool, index int) {
  1164  	for i := range v {
  1165  		if cmplx.Abs(v[i]-z) < tol {
  1166  			return true, i
  1167  		}
  1168  	}
  1169  	return false, -1
  1170  }
  1171  
  1172  // isAllNaN returns whether x contains only NaN values.
  1173  func isAllNaN(x []float64) bool {
  1174  	for _, v := range x {
  1175  		if !math.IsNaN(v) {
  1176  			return false
  1177  		}
  1178  	}
  1179  	return true
  1180  }
  1181  
  1182  // isUpperHessenberg returns whether h contains only zeros below the
  1183  // subdiagonal.
  1184  func isUpperHessenberg(h blas64.General) bool {
  1185  	if h.Rows != h.Cols {
  1186  		panic("matrix not square")
  1187  	}
  1188  	n := h.Rows
  1189  	for i := 0; i < n; i++ {
  1190  		for j := 0; j < n; j++ {
  1191  			if i > j+1 && h.Data[i*h.Stride+j] != 0 {
  1192  				return false
  1193  			}
  1194  		}
  1195  	}
  1196  	return true
  1197  }
  1198  
  1199  // isUpperTriangular returns whether a contains only zeros below the diagonal.
  1200  func isUpperTriangular(a blas64.General) bool {
  1201  	n := a.Rows
  1202  	for i := 1; i < n; i++ {
  1203  		for j := 0; j < i; j++ {
  1204  			if a.Data[i*a.Stride+j] != 0 {
  1205  				return false
  1206  			}
  1207  		}
  1208  	}
  1209  	return true
  1210  }
  1211  
  1212  // unbalancedSparseGeneral returns an m×n dense matrix with a random sparse
  1213  // structure consisting of nz nonzero elements. The matrix will be unbalanced by
  1214  // multiplying each element randomly by its row or column index.
  1215  func unbalancedSparseGeneral(m, n, stride int, nonzeros int, rnd *rand.Rand) blas64.General {
  1216  	a := zeros(m, n, stride)
  1217  	for k := 0; k < nonzeros; k++ {
  1218  		i := rnd.Intn(n)
  1219  		j := rnd.Intn(n)
  1220  		if rnd.Float64() < 0.5 {
  1221  			a.Data[i*stride+j] = float64(i+1) * rnd.NormFloat64()
  1222  		} else {
  1223  			a.Data[i*stride+j] = float64(j+1) * rnd.NormFloat64()
  1224  		}
  1225  	}
  1226  	return a
  1227  }
  1228  
  1229  // rootsOfUnity returns the n complex numbers whose n-th power is equal to 1.
  1230  func rootsOfUnity(n int) []complex128 {
  1231  	w := make([]complex128, n)
  1232  	for i := 0; i < n; i++ {
  1233  		angle := math.Pi * float64(2*i) / float64(n)
  1234  		w[i] = complex(math.Cos(angle), math.Sin(angle))
  1235  	}
  1236  	return w
  1237  }
  1238  
  1239  // constructGSVDresults returns the matrices [ 0 R ], D1 and D2 described
  1240  // in the documentation of Dtgsja and Dggsvd3, and the result matrix in
  1241  // the documentation for Dggsvp3.
  1242  func constructGSVDresults(n, p, m, k, l int, a, b blas64.General, alpha, beta []float64) (zeroR, d1, d2 blas64.General) {
  1243  	// [ 0 R ]
  1244  	zeroR = zeros(k+l, n, n)
  1245  	dst := zeroR
  1246  	dst.Rows = min(m, k+l)
  1247  	dst.Cols = k + l
  1248  	dst.Data = zeroR.Data[n-k-l:]
  1249  	src := a
  1250  	src.Rows = min(m, k+l)
  1251  	src.Cols = k + l
  1252  	src.Data = a.Data[n-k-l:]
  1253  	copyGeneral(dst, src)
  1254  	if m < k+l {
  1255  		// [ 0 R ]
  1256  		dst.Rows = k + l - m
  1257  		dst.Cols = k + l - m
  1258  		dst.Data = zeroR.Data[m*zeroR.Stride+n-(k+l-m):]
  1259  		src = b
  1260  		src.Rows = k + l - m
  1261  		src.Cols = k + l - m
  1262  		src.Data = b.Data[(m-k)*b.Stride+n+m-k-l:]
  1263  		copyGeneral(dst, src)
  1264  	}
  1265  
  1266  	// D1
  1267  	d1 = zeros(m, k+l, k+l)
  1268  	for i := 0; i < k; i++ {
  1269  		d1.Data[i*d1.Stride+i] = 1
  1270  	}
  1271  	for i := k; i < min(m, k+l); i++ {
  1272  		d1.Data[i*d1.Stride+i] = alpha[i]
  1273  	}
  1274  
  1275  	// D2
  1276  	d2 = zeros(p, k+l, k+l)
  1277  	for i := 0; i < min(l, m-k); i++ {
  1278  		d2.Data[i*d2.Stride+i+k] = beta[k+i]
  1279  	}
  1280  	for i := m - k; i < l; i++ {
  1281  		d2.Data[i*d2.Stride+i+k] = 1
  1282  	}
  1283  
  1284  	return zeroR, d1, d2
  1285  }
  1286  
  1287  func constructGSVPresults(n, p, m, k, l int, a, b blas64.General) (zeroA, zeroB blas64.General) {
  1288  	zeroA = zeros(m, n, n)
  1289  	dst := zeroA
  1290  	dst.Rows = min(m, k+l)
  1291  	dst.Cols = k + l
  1292  	dst.Data = zeroA.Data[n-k-l:]
  1293  	src := a
  1294  	dst.Rows = min(m, k+l)
  1295  	src.Cols = k + l
  1296  	src.Data = a.Data[n-k-l:]
  1297  	copyGeneral(dst, src)
  1298  
  1299  	zeroB = zeros(p, n, n)
  1300  	dst = zeroB
  1301  	dst.Rows = l
  1302  	dst.Cols = l
  1303  	dst.Data = zeroB.Data[n-l:]
  1304  	src = b
  1305  	dst.Rows = l
  1306  	src.Cols = l
  1307  	src.Data = b.Data[n-l:]
  1308  	copyGeneral(dst, src)
  1309  
  1310  	return zeroA, zeroB
  1311  }
  1312  
  1313  // distFromIdentity returns the L-infinity distance of an n×n matrix A from the
  1314  // identity. If A contains NaN elements, distFromIdentity will return +inf.
  1315  func distFromIdentity(n int, a []float64, lda int) float64 {
  1316  	var dist float64
  1317  	for i := 0; i < n; i++ {
  1318  		for j := 0; j < n; j++ {
  1319  			aij := a[i*lda+j]
  1320  			if math.IsNaN(aij) {
  1321  				return math.Inf(1)
  1322  			}
  1323  			if i == j {
  1324  				dist = math.Max(dist, math.Abs(aij-1))
  1325  			} else {
  1326  				dist = math.Max(dist, math.Abs(aij))
  1327  			}
  1328  		}
  1329  	}
  1330  	return dist
  1331  }
  1332  
  1333  func sameFloat64(a, b float64) bool {
  1334  	return a == b || math.IsNaN(a) && math.IsNaN(b)
  1335  }
  1336  
  1337  // sameLowerTri returns whether n×n matrices A and B are same under the diagonal.
  1338  func sameLowerTri(n int, a []float64, lda int, b []float64, ldb int) bool {
  1339  	for i := 1; i < n; i++ {
  1340  		for j := 0; j < i; j++ {
  1341  			aij := a[i*lda+j]
  1342  			bij := b[i*ldb+j]
  1343  			if !sameFloat64(aij, bij) {
  1344  				return false
  1345  			}
  1346  		}
  1347  	}
  1348  	return true
  1349  }
  1350  
  1351  // sameUpperTri returns whether n×n matrices A and B are same above the diagonal.
  1352  func sameUpperTri(n int, a []float64, lda int, b []float64, ldb int) bool {
  1353  	for i := 0; i < n-1; i++ {
  1354  		for j := i + 1; j < n; j++ {
  1355  			aij := a[i*lda+j]
  1356  			bij := b[i*ldb+j]
  1357  			if !sameFloat64(aij, bij) {
  1358  				return false
  1359  			}
  1360  		}
  1361  	}
  1362  	return true
  1363  }
  1364  
  1365  // svdJobString returns a string representation of job.
  1366  func svdJobString(job lapack.SVDJob) string {
  1367  	switch job {
  1368  	case lapack.SVDAll:
  1369  		return "All"
  1370  	case lapack.SVDStore:
  1371  		return "Store"
  1372  	case lapack.SVDOverwrite:
  1373  		return "Overwrite"
  1374  	case lapack.SVDNone:
  1375  		return "None"
  1376  	}
  1377  	return "unknown SVD job"
  1378  }
  1379  
  1380  // residualOrthogonal returns the residual
  1381  //
  1382  //	|I - Q * Qᵀ|  if m < n or (m == n and rowwise == true),
  1383  //	|I - Qᵀ * Q|  otherwise.
  1384  //
  1385  // It can be used to check that the matrix Q is orthogonal.
  1386  func residualOrthogonal(q blas64.General, rowwise bool) float64 {
  1387  	m, n := q.Rows, q.Cols
  1388  	if m == 0 || n == 0 {
  1389  		return 0
  1390  	}
  1391  	var transq blas.Transpose
  1392  	if m < n || (m == n && rowwise) {
  1393  		transq = blas.NoTrans
  1394  	} else {
  1395  		transq = blas.Trans
  1396  	}
  1397  	minmn := min(m, n)
  1398  
  1399  	// Set work = I.
  1400  	work := blas64.Symmetric{
  1401  		Uplo:   blas.Upper,
  1402  		N:      minmn,
  1403  		Data:   make([]float64, minmn*minmn),
  1404  		Stride: minmn,
  1405  	}
  1406  	for i := 0; i < minmn; i++ {
  1407  		work.Data[i*work.Stride+i] = 1
  1408  	}
  1409  
  1410  	// Compute
  1411  	//  work = work - Q * Qᵀ = I - Q * Qᵀ
  1412  	// or
  1413  	//  work = work - Qᵀ * Q = I - Qᵀ * Q
  1414  	blas64.Syrk(transq, -1, q, 1, work)
  1415  	return dlansy(lapack.MaxColumnSum, blas.Upper, work.N, work.Data, work.Stride)
  1416  }