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