github.com/gopherd/gonum@v0.0.4/lapack/testlapack/matgen.go (about)

     1  // Copyright ©2017 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  	"math"
     9  
    10  	"math/rand"
    11  
    12  	"github.com/gopherd/gonum/blas"
    13  	"github.com/gopherd/gonum/blas/blas64"
    14  	"github.com/gopherd/gonum/floats"
    15  )
    16  
    17  // Dlatm1 computes the entries of dst as specified by mode, cond and rsign.
    18  //
    19  // mode describes how dst will be computed:
    20  //  |mode| == 1: dst[0] = 1 and dst[1:n] = 1/cond
    21  //  |mode| == 2: dst[:n-1] = 1/cond and dst[n-1] = 1
    22  //  |mode| == 3: dst[i] = cond^{-i/(n-1)}, i=0,...,n-1
    23  //  |mode| == 4: dst[i] = 1 - i*(1-1/cond)/(n-1)
    24  //  |mode| == 5: dst[i] = random number in the range (1/cond, 1) such that
    25  //                    their logarithms are uniformly distributed
    26  //  |mode| == 6: dst[i] = random number from the distribution given by dist
    27  // If mode is negative, the order of the elements of dst will be reversed.
    28  // For other values of mode Dlatm1 will panic.
    29  //
    30  // If rsign is true and mode is not ±6, each entry of dst will be multiplied by 1
    31  // or -1 with probability 0.5
    32  //
    33  // dist specifies the type of distribution to be used when mode == ±6:
    34  //  dist == 1: Uniform[0,1)
    35  //  dist == 2: Uniform[-1,1)
    36  //  dist == 3: Normal(0,1)
    37  // For other values of dist Dlatm1 will panic.
    38  //
    39  // rnd is used as a source of random numbers.
    40  func Dlatm1(dst []float64, mode int, cond float64, rsign bool, dist int, rnd *rand.Rand) {
    41  	amode := mode
    42  	if amode < 0 {
    43  		amode = -amode
    44  	}
    45  	if amode < 1 || 6 < amode {
    46  		panic("testlapack: invalid mode")
    47  	}
    48  	if cond < 1 {
    49  		panic("testlapack: cond < 1")
    50  	}
    51  	if amode == 6 && (dist < 1 || 3 < dist) {
    52  		panic("testlapack: invalid dist")
    53  	}
    54  
    55  	n := len(dst)
    56  	if n == 0 {
    57  		return
    58  	}
    59  
    60  	switch amode {
    61  	case 1:
    62  		dst[0] = 1
    63  		for i := 1; i < n; i++ {
    64  			dst[i] = 1 / cond
    65  		}
    66  	case 2:
    67  		for i := 0; i < n-1; i++ {
    68  			dst[i] = 1
    69  		}
    70  		dst[n-1] = 1 / cond
    71  	case 3:
    72  		dst[0] = 1
    73  		if n > 1 {
    74  			alpha := math.Pow(cond, -1/float64(n-1))
    75  			for i := 1; i < n; i++ {
    76  				dst[i] = math.Pow(alpha, float64(i))
    77  			}
    78  		}
    79  	case 4:
    80  		dst[0] = 1
    81  		if n > 1 {
    82  			condInv := 1 / cond
    83  			alpha := (1 - condInv) / float64(n-1)
    84  			for i := 1; i < n; i++ {
    85  				dst[i] = float64(n-i-1)*alpha + condInv
    86  			}
    87  		}
    88  	case 5:
    89  		alpha := math.Log(1 / cond)
    90  		for i := range dst {
    91  			dst[i] = math.Exp(alpha * rnd.Float64())
    92  		}
    93  	case 6:
    94  		switch dist {
    95  		case 1:
    96  			for i := range dst {
    97  				dst[i] = rnd.Float64()
    98  			}
    99  		case 2:
   100  			for i := range dst {
   101  				dst[i] = 2*rnd.Float64() - 1
   102  			}
   103  		case 3:
   104  			for i := range dst {
   105  				dst[i] = rnd.NormFloat64()
   106  			}
   107  		}
   108  	}
   109  
   110  	if rsign && amode != 6 {
   111  		for i, v := range dst {
   112  			if rnd.Float64() < 0.5 {
   113  				dst[i] = -v
   114  			}
   115  		}
   116  	}
   117  
   118  	if mode < 0 {
   119  		for i := 0; i < n/2; i++ {
   120  			dst[i], dst[n-i-1] = dst[n-i-1], dst[i]
   121  		}
   122  	}
   123  }
   124  
   125  // Dlagsy generates an n×n symmetric matrix A, by pre- and post- multiplying a
   126  // real diagonal matrix D with a random orthogonal matrix:
   127  //  A = U * D * Uᵀ.
   128  //
   129  // work must have length at least 2*n, otherwise Dlagsy will panic.
   130  //
   131  // The parameter k is unused but it must satisfy
   132  //  0 <= k <= n-1.
   133  func Dlagsy(n, k int, d []float64, a []float64, lda int, rnd *rand.Rand, work []float64) {
   134  	checkMatrix(n, n, a, lda)
   135  	if k < 0 || max(0, n-1) < k {
   136  		panic("testlapack: invalid value of k")
   137  	}
   138  	if len(d) != n {
   139  		panic("testlapack: bad length of d")
   140  	}
   141  	if len(work) < 2*n {
   142  		panic("testlapack: insufficient work length")
   143  	}
   144  
   145  	// Initialize lower triangle of A to diagonal matrix.
   146  	for i := 1; i < n; i++ {
   147  		for j := 0; j < i; j++ {
   148  			a[i*lda+j] = 0
   149  		}
   150  	}
   151  	for i := 0; i < n; i++ {
   152  		a[i*lda+i] = d[i]
   153  	}
   154  
   155  	bi := blas64.Implementation()
   156  
   157  	// Generate lower triangle of symmetric matrix.
   158  	for i := n - 2; i >= 0; i-- {
   159  		for j := 0; j < n-i; j++ {
   160  			work[j] = rnd.NormFloat64()
   161  		}
   162  		wn := bi.Dnrm2(n-i, work[:n-i], 1)
   163  		wa := math.Copysign(wn, work[0])
   164  		var tau float64
   165  		if wn != 0 {
   166  			wb := work[0] + wa
   167  			bi.Dscal(n-i-1, 1/wb, work[1:n-i], 1)
   168  			work[0] = 1
   169  			tau = wb / wa
   170  		}
   171  
   172  		// Apply random reflection to A[i:n,i:n] from the left and the
   173  		// right.
   174  		//
   175  		// Compute y := tau * A * u.
   176  		bi.Dsymv(blas.Lower, n-i, tau, a[i*lda+i:], lda, work[:n-i], 1, 0, work[n:2*n-i], 1)
   177  
   178  		// Compute v := y - 1/2 * tau * ( y, u ) * u.
   179  		alpha := -0.5 * tau * bi.Ddot(n-i, work[n:2*n-i], 1, work[:n-i], 1)
   180  		bi.Daxpy(n-i, alpha, work[:n-i], 1, work[n:2*n-i], 1)
   181  
   182  		// Apply the transformation as a rank-2 update to A[i:n,i:n].
   183  		bi.Dsyr2(blas.Lower, n-i, -1, work[:n-i], 1, work[n:2*n-i], 1, a[i*lda+i:], lda)
   184  	}
   185  
   186  	// Store full symmetric matrix.
   187  	for i := 1; i < n; i++ {
   188  		for j := 0; j < i; j++ {
   189  			a[j*lda+i] = a[i*lda+j]
   190  		}
   191  	}
   192  }
   193  
   194  // Dlagge generates a real general m×n matrix A, by pre- and post-multiplying
   195  // a real diagonal matrix D with random orthogonal matrices:
   196  //  A = U*D*V.
   197  //
   198  // d must have length min(m,n), and work must have length m+n, otherwise Dlagge
   199  // will panic.
   200  //
   201  // The parameters ku and kl are unused but they must satisfy
   202  //  0 <= kl <= m-1,
   203  //  0 <= ku <= n-1.
   204  func Dlagge(m, n, kl, ku int, d []float64, a []float64, lda int, rnd *rand.Rand, work []float64) {
   205  	checkMatrix(m, n, a, lda)
   206  	if kl < 0 || max(0, m-1) < kl {
   207  		panic("testlapack: invalid value of kl")
   208  	}
   209  	if ku < 0 || max(0, n-1) < ku {
   210  		panic("testlapack: invalid value of ku")
   211  	}
   212  	if len(d) != min(m, n) {
   213  		panic("testlapack: bad length of d")
   214  	}
   215  	if len(work) < m+n {
   216  		panic("testlapack: insufficient work length")
   217  	}
   218  
   219  	// Initialize A to diagonal matrix.
   220  	for i := 0; i < m; i++ {
   221  		for j := 0; j < n; j++ {
   222  			a[i*lda+j] = 0
   223  		}
   224  	}
   225  	for i := 0; i < min(m, n); i++ {
   226  		a[i*lda+i] = d[i]
   227  	}
   228  
   229  	// Quick exit if the user wants a diagonal matrix.
   230  	// if kl == 0 && ku == 0 {
   231  	// 	return
   232  	// }
   233  
   234  	bi := blas64.Implementation()
   235  
   236  	// Pre- and post-multiply A by random orthogonal matrices.
   237  	for i := min(m, n) - 1; i >= 0; i-- {
   238  		if i < m-1 {
   239  			for j := 0; j < m-i; j++ {
   240  				work[j] = rnd.NormFloat64()
   241  			}
   242  			wn := bi.Dnrm2(m-i, work[:m-i], 1)
   243  			wa := math.Copysign(wn, work[0])
   244  			var tau float64
   245  			if wn != 0 {
   246  				wb := work[0] + wa
   247  				bi.Dscal(m-i-1, 1/wb, work[1:m-i], 1)
   248  				work[0] = 1
   249  				tau = wb / wa
   250  			}
   251  
   252  			// Multiply A[i:m,i:n] by random reflection from the left.
   253  			bi.Dgemv(blas.Trans, m-i, n-i,
   254  				1, a[i*lda+i:], lda, work[:m-i], 1,
   255  				0, work[m:m+n-i], 1)
   256  			bi.Dger(m-i, n-i,
   257  				-tau, work[:m-i], 1, work[m:m+n-i], 1,
   258  				a[i*lda+i:], lda)
   259  		}
   260  		if i < n-1 {
   261  			for j := 0; j < n-i; j++ {
   262  				work[j] = rnd.NormFloat64()
   263  			}
   264  			wn := bi.Dnrm2(n-i, work[:n-i], 1)
   265  			wa := math.Copysign(wn, work[0])
   266  			var tau float64
   267  			if wn != 0 {
   268  				wb := work[0] + wa
   269  				bi.Dscal(n-i-1, 1/wb, work[1:n-i], 1)
   270  				work[0] = 1
   271  				tau = wb / wa
   272  			}
   273  
   274  			// Multiply A[i:m,i:n] by random reflection from the right.
   275  			bi.Dgemv(blas.NoTrans, m-i, n-i,
   276  				1, a[i*lda+i:], lda, work[:n-i], 1,
   277  				0, work[n:n+m-i], 1)
   278  			bi.Dger(m-i, n-i,
   279  				-tau, work[n:n+m-i], 1, work[:n-i], 1,
   280  				a[i*lda+i:], lda)
   281  		}
   282  	}
   283  
   284  	// TODO(vladimir-ch): Reduce number of subdiagonals to kl and number of
   285  	// superdiagonals to ku.
   286  }
   287  
   288  // dlarnv fills dst with random numbers from a uniform or normal distribution
   289  // specified by dist:
   290  //  dist=1: uniform(0,1),
   291  //  dist=2: uniform(-1,1),
   292  //  dist=3: normal(0,1).
   293  // For other values of dist dlarnv will panic.
   294  func dlarnv(dst []float64, dist int, rnd *rand.Rand) {
   295  	switch dist {
   296  	default:
   297  		panic("testlapack: invalid dist")
   298  	case 1:
   299  		for i := range dst {
   300  			dst[i] = rnd.Float64()
   301  		}
   302  	case 2:
   303  		for i := range dst {
   304  			dst[i] = 2*rnd.Float64() - 1
   305  		}
   306  	case 3:
   307  		for i := range dst {
   308  			dst[i] = rnd.NormFloat64()
   309  		}
   310  	}
   311  }
   312  
   313  // dlattr generates an n×n triangular test matrix A with its properties uniquely
   314  // determined by imat and uplo, and returns whether A has unit diagonal. If diag
   315  // is blas.Unit, the diagonal elements are set so that A[k,k]=k.
   316  //
   317  // trans specifies whether the matrix A or its transpose will be used.
   318  //
   319  // If imat is greater than 10, dlattr also generates the right hand side of the
   320  // linear system A*x=b, or Aᵀ*x=b. Valid values of imat are 7, and all between 11
   321  // and 19, inclusive.
   322  //
   323  // b mush have length n, and work must have length 3*n, and dlattr will panic
   324  // otherwise.
   325  func dlattr(imat int, uplo blas.Uplo, trans blas.Transpose, n int, a []float64, lda int, b, work []float64, rnd *rand.Rand) (diag blas.Diag) {
   326  	checkMatrix(n, n, a, lda)
   327  	if len(b) != n {
   328  		panic("testlapack: bad length of b")
   329  	}
   330  	if len(work) < 3*n {
   331  		panic("testlapack: insufficient length of work")
   332  	}
   333  	if uplo != blas.Upper && uplo != blas.Lower {
   334  		panic("testlapack: bad uplo")
   335  	}
   336  	if trans != blas.Trans && trans != blas.NoTrans {
   337  		panic("testlapack: bad trans")
   338  	}
   339  
   340  	if n == 0 {
   341  		return blas.NonUnit
   342  	}
   343  
   344  	const (
   345  		tiny = safmin
   346  		huge = (1 - ulp) / tiny
   347  	)
   348  
   349  	bi := blas64.Implementation()
   350  
   351  	switch imat {
   352  	default:
   353  		// TODO(vladimir-ch): Implement the remaining cases.
   354  		panic("testlapack: invalid or unimplemented imat")
   355  	case 7:
   356  		// Identity matrix. The diagonal is set to NaN.
   357  		diag = blas.Unit
   358  		switch uplo {
   359  		case blas.Upper:
   360  			for i := 0; i < n; i++ {
   361  				a[i*lda+i] = math.NaN()
   362  				for j := i + 1; j < n; j++ {
   363  					a[i*lda+j] = 0
   364  				}
   365  			}
   366  		case blas.Lower:
   367  			for i := 0; i < n; i++ {
   368  				for j := 0; j < i; j++ {
   369  					a[i*lda+j] = 0
   370  				}
   371  				a[i*lda+i] = math.NaN()
   372  			}
   373  		}
   374  	case 11:
   375  		// Generate a triangular matrix with elements between -1 and 1,
   376  		// give the diagonal norm 2 to make it well-conditioned, and
   377  		// make the right hand side large so that it requires scaling.
   378  		diag = blas.NonUnit
   379  		switch uplo {
   380  		case blas.Upper:
   381  			for i := 0; i < n-1; i++ {
   382  				dlarnv(a[i*lda+i:i*lda+n], 2, rnd)
   383  			}
   384  		case blas.Lower:
   385  			for i := 1; i < n; i++ {
   386  				dlarnv(a[i*lda:i*lda+i+1], 2, rnd)
   387  			}
   388  		}
   389  		for i := 0; i < n; i++ {
   390  			a[i*lda+i] = math.Copysign(2, a[i*lda+i])
   391  		}
   392  		// Set the right hand side so that the largest value is huge.
   393  		dlarnv(b, 2, rnd)
   394  		imax := bi.Idamax(n, b, 1)
   395  		bscal := huge / math.Max(1, b[imax])
   396  		bi.Dscal(n, bscal, b, 1)
   397  	case 12:
   398  		// Make the first diagonal element in the solve small to cause
   399  		// immediate overflow when dividing by T[j,j]. The off-diagonal
   400  		// elements are small (cnorm[j] < 1).
   401  		diag = blas.NonUnit
   402  		tscal := 1 / math.Max(1, float64(n-1))
   403  		switch uplo {
   404  		case blas.Upper:
   405  			for i := 0; i < n; i++ {
   406  				dlarnv(a[i*lda+i:i*lda+n], 2, rnd)
   407  				bi.Dscal(n-i-1, tscal, a[i*lda+i+1:], 1)
   408  				a[i*lda+i] = math.Copysign(1, a[i*lda+i])
   409  			}
   410  			a[(n-1)*lda+n-1] *= tiny
   411  		case blas.Lower:
   412  			for i := 0; i < n; i++ {
   413  				dlarnv(a[i*lda:i*lda+i+1], 2, rnd)
   414  				bi.Dscal(i, tscal, a[i*lda:], 1)
   415  				a[i*lda+i] = math.Copysign(1, a[i*lda+i])
   416  			}
   417  			a[0] *= tiny
   418  		}
   419  		dlarnv(b, 2, rnd)
   420  	case 13:
   421  		// Make the first diagonal element in the solve small to cause
   422  		// immediate overflow when dividing by T[j,j]. The off-diagonal
   423  		// elements are O(1) (cnorm[j] > 1).
   424  		diag = blas.NonUnit
   425  		switch uplo {
   426  		case blas.Upper:
   427  			for i := 0; i < n; i++ {
   428  				dlarnv(a[i*lda+i:i*lda+n], 2, rnd)
   429  				a[i*lda+i] = math.Copysign(1, a[i*lda+i])
   430  			}
   431  			a[(n-1)*lda+n-1] *= tiny
   432  		case blas.Lower:
   433  			for i := 0; i < n; i++ {
   434  				dlarnv(a[i*lda:i*lda+i+1], 2, rnd)
   435  				a[i*lda+i] = math.Copysign(1, a[i*lda+i])
   436  			}
   437  			a[0] *= tiny
   438  		}
   439  		dlarnv(b, 2, rnd)
   440  	case 14:
   441  		// T is diagonal with small numbers on the diagonal to
   442  		// make the growth factor underflow, but a small right hand side
   443  		// chosen so that the solution does not overflow.
   444  		diag = blas.NonUnit
   445  		switch uplo {
   446  		case blas.Upper:
   447  			for i := 0; i < n; i++ {
   448  				for j := i + 1; j < n; j++ {
   449  					a[i*lda+j] = 0
   450  				}
   451  				if (n-1-i)&0x2 == 0 {
   452  					a[i*lda+i] = tiny
   453  				} else {
   454  					a[i*lda+i] = 1
   455  				}
   456  			}
   457  		case blas.Lower:
   458  			for i := 0; i < n; i++ {
   459  				for j := 0; j < i; j++ {
   460  					a[i*lda+j] = 0
   461  				}
   462  				if i&0x2 == 0 {
   463  					a[i*lda+i] = tiny
   464  				} else {
   465  					a[i*lda+i] = 1
   466  				}
   467  			}
   468  		}
   469  		// Set the right hand side alternately zero and small.
   470  		switch uplo {
   471  		case blas.Upper:
   472  			b[0] = 0
   473  			for i := n - 1; i > 0; i -= 2 {
   474  				b[i] = 0
   475  				b[i-1] = tiny
   476  			}
   477  		case blas.Lower:
   478  			for i := 0; i < n-1; i += 2 {
   479  				b[i] = 0
   480  				b[i+1] = tiny
   481  			}
   482  			b[n-1] = 0
   483  		}
   484  	case 15:
   485  		// Make the diagonal elements small to cause gradual overflow
   486  		// when dividing by T[j,j]. To control the amount of scaling
   487  		// needed, the matrix is bidiagonal.
   488  		diag = blas.NonUnit
   489  		texp := 1 / math.Max(1, float64(n-1))
   490  		tscal := math.Pow(tiny, texp)
   491  		switch uplo {
   492  		case blas.Upper:
   493  			for i := 0; i < n; i++ {
   494  				a[i*lda+i] = tscal
   495  				if i < n-1 {
   496  					a[i*lda+i+1] = -1
   497  				}
   498  				for j := i + 2; j < n; j++ {
   499  					a[i*lda+j] = 0
   500  				}
   501  			}
   502  		case blas.Lower:
   503  			for i := 0; i < n; i++ {
   504  				for j := 0; j < i-1; j++ {
   505  					a[i*lda+j] = 0
   506  				}
   507  				if i > 0 {
   508  					a[i*lda+i-1] = -1
   509  				}
   510  				a[i*lda+i] = tscal
   511  			}
   512  		}
   513  		dlarnv(b, 2, rnd)
   514  	case 16:
   515  		// One zero diagonal element.
   516  		diag = blas.NonUnit
   517  		switch uplo {
   518  		case blas.Upper:
   519  			for i := 0; i < n; i++ {
   520  				dlarnv(a[i*lda+i:i*lda+n], 2, rnd)
   521  				a[i*lda+i] = math.Copysign(2, a[i*lda+i])
   522  			}
   523  		case blas.Lower:
   524  			for i := 0; i < n; i++ {
   525  				dlarnv(a[i*lda:i*lda+i+1], 2, rnd)
   526  				a[i*lda+i] = math.Copysign(2, a[i*lda+i])
   527  			}
   528  		}
   529  		iy := n / 2
   530  		a[iy*lda+iy] = 0
   531  		dlarnv(b, 2, rnd)
   532  		bi.Dscal(n, 2, b, 1)
   533  	case 17:
   534  		// Make the offdiagonal elements large to cause overflow when
   535  		// adding a column of T. In the non-transposed case, the matrix
   536  		// is constructed to cause overflow when adding a column in
   537  		// every other step.
   538  		diag = blas.NonUnit
   539  		tscal := (1 - ulp) / tiny
   540  		texp := 1.0
   541  		switch uplo {
   542  		case blas.Upper:
   543  			for i := 0; i < n; i++ {
   544  				for j := i; j < n; j++ {
   545  					a[i*lda+j] = 0
   546  				}
   547  			}
   548  			for j := n - 1; j >= 1; j -= 2 {
   549  				a[j] = -tscal / float64(n+1)
   550  				a[j*lda+j] = 1
   551  				b[j] = texp * (1 - ulp)
   552  				a[j-1] = -tscal / float64(n+1) / float64(n+2)
   553  				a[(j-1)*lda+j-1] = 1
   554  				b[j-1] = texp * float64(n*n+n-1)
   555  				texp *= 2
   556  			}
   557  			b[0] = float64(n+1) / float64(n+2) * tscal
   558  		case blas.Lower:
   559  			for i := 0; i < n; i++ {
   560  				for j := 0; j <= i; j++ {
   561  					a[i*lda+j] = 0
   562  				}
   563  			}
   564  			for j := 0; j < n-1; j += 2 {
   565  				a[(n-1)*lda+j] = -tscal / float64(n+1)
   566  				a[j*lda+j] = 1
   567  				b[j] = texp * (1 - ulp)
   568  				a[(n-1)*lda+j+1] = -tscal / float64(n+1) / float64(n+2)
   569  				a[(j+1)*lda+j+1] = 1
   570  				b[j+1] = texp * float64(n*n+n-1)
   571  				texp *= 2
   572  			}
   573  			b[n-1] = float64(n+1) / float64(n+2) * tscal
   574  		}
   575  	case 18:
   576  		// Generate a unit triangular matrix with elements between -1
   577  		// and 1, and make the right hand side large so that it requires
   578  		// scaling. The diagonal is set to NaN.
   579  		diag = blas.Unit
   580  		switch uplo {
   581  		case blas.Upper:
   582  			for i := 0; i < n; i++ {
   583  				a[i*lda+i] = math.NaN()
   584  				dlarnv(a[i*lda+i+1:i*lda+n], 2, rnd)
   585  			}
   586  		case blas.Lower:
   587  			for i := 0; i < n; i++ {
   588  				dlarnv(a[i*lda:i*lda+i], 2, rnd)
   589  				a[i*lda+i] = math.NaN()
   590  			}
   591  		}
   592  		// Set the right hand side so that the largest value is huge.
   593  		dlarnv(b, 2, rnd)
   594  		iy := bi.Idamax(n, b, 1)
   595  		bnorm := math.Abs(b[iy])
   596  		bscal := huge / math.Max(1, bnorm)
   597  		bi.Dscal(n, bscal, b, 1)
   598  	case 19:
   599  		// Generate a triangular matrix with elements between
   600  		// huge/(n-1) and huge so that at least one of the column
   601  		// norms will exceed huge.
   602  		// Dlatrs cannot handle this case for (typically) n>5.
   603  		diag = blas.NonUnit
   604  		tleft := huge / math.Max(1, float64(n-1))
   605  		tscal := huge * (float64(n-1) / math.Max(1, float64(n)))
   606  		switch uplo {
   607  		case blas.Upper:
   608  			for i := 0; i < n; i++ {
   609  				dlarnv(a[i*lda+i:i*lda+n], 2, rnd)
   610  				for j := i; j < n; j++ {
   611  					aij := a[i*lda+j]
   612  					a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij
   613  				}
   614  			}
   615  		case blas.Lower:
   616  			for i := 0; i < n; i++ {
   617  				dlarnv(a[i*lda:i*lda+i+1], 2, rnd)
   618  				for j := 0; j <= i; j++ {
   619  					aij := a[i*lda+j]
   620  					a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij
   621  				}
   622  			}
   623  		}
   624  		dlarnv(b, 2, rnd)
   625  		bi.Dscal(n, 2, b, 1)
   626  	}
   627  
   628  	// Flip the matrix if the transpose will be used.
   629  	if trans == blas.Trans {
   630  		switch uplo {
   631  		case blas.Upper:
   632  			for j := 0; j < n/2; j++ {
   633  				bi.Dswap(n-2*j-1, a[j*lda+j:], 1, a[(j+1)*lda+n-j-1:], -lda)
   634  			}
   635  		case blas.Lower:
   636  			for j := 0; j < n/2; j++ {
   637  				bi.Dswap(n-2*j-1, a[j*lda+j:], lda, a[(n-j-1)*lda+j+1:], -1)
   638  			}
   639  		}
   640  	}
   641  
   642  	return diag
   643  }
   644  
   645  func checkMatrix(m, n int, a []float64, lda int) {
   646  	if m < 0 {
   647  		panic("testlapack: m < 0")
   648  	}
   649  	if n < 0 {
   650  		panic("testlapack: n < 0")
   651  	}
   652  	if lda < max(1, n) {
   653  		panic("testlapack: lda < max(1, n)")
   654  	}
   655  	if len(a) < (m-1)*lda+n {
   656  		panic("testlapack: insufficient matrix slice length")
   657  	}
   658  }
   659  
   660  // randomOrthogonal returns an n×n random orthogonal matrix.
   661  func randomOrthogonal(n int, rnd *rand.Rand) blas64.General {
   662  	q := eye(n, n)
   663  	x := make([]float64, n)
   664  	v := make([]float64, n)
   665  	for j := 0; j < n-1; j++ {
   666  		// x represents the j-th column of a random matrix.
   667  		for i := 0; i < j; i++ {
   668  			x[i] = 0
   669  		}
   670  		for i := j; i < n; i++ {
   671  			x[i] = rnd.NormFloat64()
   672  		}
   673  		// Compute v that represents the elementary reflector that
   674  		// annihilates the subdiagonal elements of x.
   675  		reflector(v, x, j)
   676  		// Compute Q * H_j and store the result into Q.
   677  		applyReflector(q, q, v)
   678  	}
   679  	return q
   680  }
   681  
   682  // reflector generates a Householder reflector v that zeros out subdiagonal
   683  // entries in the j-th column of a matrix.
   684  func reflector(v, col []float64, j int) {
   685  	n := len(col)
   686  	if len(v) != n {
   687  		panic("slice length mismatch")
   688  	}
   689  	if j < 0 || n <= j {
   690  		panic("invalid column index")
   691  	}
   692  
   693  	for i := range v {
   694  		v[i] = 0
   695  	}
   696  	if j == n-1 {
   697  		return
   698  	}
   699  	s := floats.Norm(col[j:], 2)
   700  	if s == 0 {
   701  		return
   702  	}
   703  	v[j] = col[j] + math.Copysign(s, col[j])
   704  	copy(v[j+1:], col[j+1:])
   705  	s = floats.Norm(v[j:], 2)
   706  	floats.Scale(1/s, v[j:])
   707  }
   708  
   709  // applyReflector computes Q*H where H is a Householder matrix represented by
   710  // the Householder reflector v.
   711  func applyReflector(qh blas64.General, q blas64.General, v []float64) {
   712  	n := len(v)
   713  	if qh.Rows != n || qh.Cols != n {
   714  		panic("bad size of qh")
   715  	}
   716  	if q.Rows != n || q.Cols != n {
   717  		panic("bad size of q")
   718  	}
   719  	qv := make([]float64, n)
   720  	blas64.Gemv(blas.NoTrans, 1, q, blas64.Vector{Data: v, Inc: 1}, 0, blas64.Vector{Data: qv, Inc: 1})
   721  	for i := 0; i < n; i++ {
   722  		for j := 0; j < n; j++ {
   723  			qh.Data[i*qh.Stride+j] = q.Data[i*q.Stride+j]
   724  		}
   725  	}
   726  	for i := 0; i < n; i++ {
   727  		for j := 0; j < n; j++ {
   728  			qh.Data[i*qh.Stride+j] -= 2 * qv[i] * v[j]
   729  		}
   730  	}
   731  	var norm2 float64
   732  	for _, vi := range v {
   733  		norm2 += vi * vi
   734  	}
   735  	norm2inv := 1 / norm2
   736  	for i := 0; i < n; i++ {
   737  		for j := 0; j < n; j++ {
   738  			qh.Data[i*qh.Stride+j] *= norm2inv
   739  		}
   740  	}
   741  }
   742  
   743  func dlattb(kind int, uplo blas.Uplo, trans blas.Transpose, n, kd int, ab []float64, ldab int, rnd *rand.Rand) (diag blas.Diag, b []float64) {
   744  	switch {
   745  	case kind < 1 || 18 < kind:
   746  		panic("bad matrix kind")
   747  	case (6 <= kind && kind <= 9) || kind == 17:
   748  		diag = blas.Unit
   749  	default:
   750  		diag = blas.NonUnit
   751  	}
   752  
   753  	if n == 0 {
   754  		return
   755  	}
   756  
   757  	const (
   758  		tiny = safmin
   759  		huge = (1 - ulp) / tiny
   760  
   761  		small = 0.25 * (safmin / ulp)
   762  		large = 1 / small
   763  		badc2 = 0.1 / ulp
   764  	)
   765  	badc1 := math.Sqrt(badc2)
   766  
   767  	var cndnum float64
   768  	switch {
   769  	case kind == 2 || kind == 8:
   770  		cndnum = badc1
   771  	case kind == 3 || kind == 9:
   772  		cndnum = badc2
   773  	default:
   774  		cndnum = 2
   775  	}
   776  
   777  	uniformM11 := func() float64 {
   778  		return 2*rnd.Float64() - 1
   779  	}
   780  
   781  	// Allocate the right-hand side and fill it with random numbers.
   782  	// The pathological matrix types below overwrite it with their
   783  	// custom vector.
   784  	b = make([]float64, n)
   785  	for i := range b {
   786  		b[i] = uniformM11()
   787  	}
   788  
   789  	bi := blas64.Implementation()
   790  	switch kind {
   791  	default:
   792  		panic("test matrix type not implemented")
   793  
   794  	case 1, 2, 3, 4, 5:
   795  		// Non-unit triangular matrix
   796  		// TODO(vladimir-ch)
   797  		var kl, ku int
   798  		switch uplo {
   799  		case blas.Upper:
   800  			ku = kd
   801  			kl = 0
   802  			// IOFF = 1 + MAX( 0, KD-N+1 )
   803  			// PACKIT = 'Q'
   804  			// 'Q' => store the upper triangle in band storage scheme
   805  			//        (only if matrix symmetric or upper triangular)
   806  		case blas.Lower:
   807  			ku = 0
   808  			kl = kd
   809  			// IOFF = 1
   810  			// PACKIT = 'B'
   811  			// 'B' => store the lower triangle in band storage scheme
   812  			//        (only if matrix symmetric or lower triangular)
   813  		}
   814  		anorm := 1.0
   815  		switch kind {
   816  		case 4:
   817  			anorm = small
   818  		case 5:
   819  			anorm = large
   820  		}
   821  		_, _, _ = kl, ku, anorm
   822  		// // DIST = 'S' // UNIFORM(-1, 1)
   823  		// // MODE = 3   // MODE = 3 sets D(I)=CNDNUM**(-(I-1)/(N-1))
   824  		// // TYPE = 'N' // If TYPE='N', the generated matrix is nonsymmetric
   825  		// CALL DLATMS( N, N, DIST, ISEED, TYPE, B, MODE, CNDNUM, ANORM,
   826  		// $            KL, KU, PACKIT, AB( IOFF, 1 ), LDAB, WORK, INFO )
   827  		panic("test matrix type not implemented")
   828  
   829  	case 6:
   830  		// Matrix is the identity.
   831  		if uplo == blas.Upper {
   832  			for i := 0; i < n; i++ {
   833  				// Fill the diagonal with non-unit numbers.
   834  				ab[i*ldab] = float64(i + 2)
   835  				for j := 1; j < min(n-i, kd+1); j++ {
   836  					ab[i*ldab+j] = 0
   837  				}
   838  			}
   839  		} else {
   840  			for i := 0; i < n; i++ {
   841  				for j := max(0, kd-i); j < kd; j++ {
   842  					ab[i*ldab+j] = 0
   843  				}
   844  				// Fill the diagonal with non-unit numbers.
   845  				ab[i*ldab+kd] = float64(i + 2)
   846  			}
   847  		}
   848  
   849  	case 7, 8, 9:
   850  		// Non-trivial unit triangular matrix
   851  		//
   852  		// A unit triangular matrix T with condition cndnum is formed.
   853  		// In this version, T only has bandwidth 2, the rest of it is
   854  		// zero.
   855  
   856  		tnorm := math.Sqrt(cndnum)
   857  
   858  		// Initialize AB to zero.
   859  		if uplo == blas.Upper {
   860  			for i := 0; i < n; i++ {
   861  				// Fill the diagonal with non-unit numbers.
   862  				ab[i*ldab] = float64(i + 2)
   863  				for j := 1; j < min(n-i, kd+1); j++ {
   864  					ab[i*ldab+j] = 0
   865  				}
   866  			}
   867  		} else {
   868  			for i := 0; i < n; i++ {
   869  				for j := max(0, kd-i); j < kd; j++ {
   870  					ab[i*ldab+j] = 0
   871  				}
   872  				// Fill the diagonal with non-unit numbers.
   873  				ab[i*ldab+kd] = float64(i + 2)
   874  			}
   875  		}
   876  
   877  		switch kd {
   878  		case 0:
   879  			// Unit diagonal matrix, nothing else to do.
   880  		case 1:
   881  			// Special case: T is tridiagonal. Set every other
   882  			// off-diagonal so that the matrix has norm tnorm+1.
   883  			if n > 1 {
   884  				if uplo == blas.Upper {
   885  					ab[1] = math.Copysign(tnorm, uniformM11())
   886  					for i := 2; i < n-1; i += 2 {
   887  						ab[i*ldab+1] = tnorm * uniformM11()
   888  					}
   889  				} else {
   890  					ab[ldab] = math.Copysign(tnorm, uniformM11())
   891  					for i := 3; i < n; i += 2 {
   892  						ab[i*ldab] = tnorm * uniformM11()
   893  					}
   894  				}
   895  			}
   896  		default:
   897  			// Form a unit triangular matrix T with condition cndnum. T is given
   898  			// by
   899  			//      | 1   +   *                      |
   900  			//      |     1   +                      |
   901  			//  T = |         1   +   *              |
   902  			//      |             1   +              |
   903  			//      |                 1   +   *      |
   904  			//      |                     1   +      |
   905  			//      |                          . . . |
   906  			// Each element marked with a '*' is formed by taking the product of
   907  			// the adjacent elements marked with '+'. The '*'s can be chosen
   908  			// freely, and the '+'s are chosen so that the inverse of T will
   909  			// have elements of the same magnitude as T.
   910  			work1 := make([]float64, n)
   911  			work2 := make([]float64, n)
   912  			star1 := math.Copysign(tnorm, uniformM11())
   913  			sfac := math.Sqrt(tnorm)
   914  			plus1 := math.Copysign(sfac, uniformM11())
   915  			for i := 0; i < n; i += 2 {
   916  				work1[i] = plus1
   917  				work2[i] = star1
   918  				if i+1 == n {
   919  					continue
   920  				}
   921  				plus2 := star1 / plus1
   922  				work1[i+1] = plus2
   923  				plus1 = star1 / plus2
   924  				// Generate a new *-value with norm between sqrt(tnorm)
   925  				// and tnorm.
   926  				rexp := uniformM11()
   927  				if rexp < 0 {
   928  					star1 = -math.Pow(sfac, 1-rexp)
   929  				} else {
   930  					star1 = math.Pow(sfac, 1+rexp)
   931  				}
   932  			}
   933  			// Copy the diagonal to AB.
   934  			if uplo == blas.Upper {
   935  				bi.Dcopy(n-1, work1, 1, ab[1:], ldab)
   936  				if n > 2 {
   937  					bi.Dcopy(n-2, work2, 1, ab[2:], ldab)
   938  				}
   939  			} else {
   940  				bi.Dcopy(n-1, work1, 1, ab[ldab+kd-1:], ldab)
   941  				if n > 2 {
   942  					bi.Dcopy(n-2, work2, 1, ab[2*ldab+kd-2:], ldab)
   943  				}
   944  			}
   945  		}
   946  
   947  	// Pathological test cases 10-18: these triangular matrices are badly
   948  	// scaled or badly conditioned, so when used in solving a triangular
   949  	// system they may cause overflow in the solution vector.
   950  
   951  	case 10:
   952  		// Generate a triangular matrix with elements between -1 and 1.
   953  		// Give the diagonal norm 2 to make it well-conditioned.
   954  		// Make the right hand side large so that it requires scaling.
   955  		if uplo == blas.Upper {
   956  			for i := 0; i < n; i++ {
   957  				for j := 0; j < min(n-j, kd+1); j++ {
   958  					ab[i*ldab+j] = uniformM11()
   959  				}
   960  				ab[i*ldab] = math.Copysign(2, ab[i*ldab])
   961  			}
   962  		} else {
   963  			for i := 0; i < n; i++ {
   964  				for j := max(0, kd-i); j < kd+1; j++ {
   965  					ab[i*ldab+j] = uniformM11()
   966  				}
   967  				ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd])
   968  			}
   969  		}
   970  		// Set the right hand side so that the largest value is huge.
   971  		bnorm := math.Abs(b[bi.Idamax(n, b, 1)])
   972  		bscal := huge / math.Max(1, bnorm)
   973  		bi.Dscal(n, bscal, b, 1)
   974  
   975  	case 11:
   976  		// Make the first diagonal element in the solve small to cause
   977  		// immediate overflow when dividing by T[j,j].
   978  		// The offdiagonal elements are small (cnorm[j] < 1).
   979  		tscal := 1 / float64(kd+1)
   980  		if uplo == blas.Upper {
   981  			for i := 0; i < n; i++ {
   982  				jlen := min(n-i, kd+1)
   983  				arow := ab[i*ldab : i*ldab+jlen]
   984  				dlarnv(arow, 2, rnd)
   985  				if jlen > 1 {
   986  					bi.Dscal(jlen-1, tscal, arow[1:], 1)
   987  				}
   988  				ab[i*ldab] = math.Copysign(1, ab[i*ldab])
   989  			}
   990  			ab[(n-1)*ldab] *= tiny
   991  		} else {
   992  			for i := 0; i < n; i++ {
   993  				jlen := min(i+1, kd+1)
   994  				arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1]
   995  				dlarnv(arow, 2, rnd)
   996  				if jlen > 1 {
   997  					bi.Dscal(jlen-1, tscal, arow[:jlen-1], 1)
   998  				}
   999  				ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd])
  1000  			}
  1001  			ab[kd] *= tiny
  1002  		}
  1003  
  1004  	case 12:
  1005  		// Make the first diagonal element in the solve small to cause
  1006  		// immediate overflow when dividing by T[j,j].
  1007  		// The offdiagonal elements are O(1) (cnorm[j] > 1).
  1008  		if uplo == blas.Upper {
  1009  			for i := 0; i < n; i++ {
  1010  				jlen := min(n-i, kd+1)
  1011  				arow := ab[i*ldab : i*ldab+jlen]
  1012  				dlarnv(arow, 2, rnd)
  1013  				ab[i*ldab] = math.Copysign(1, ab[i*ldab])
  1014  			}
  1015  			ab[(n-1)*ldab] *= tiny
  1016  		} else {
  1017  			for i := 0; i < n; i++ {
  1018  				jlen := min(i+1, kd+1)
  1019  				arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1]
  1020  				dlarnv(arow, 2, rnd)
  1021  				ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd])
  1022  			}
  1023  			ab[kd] *= tiny
  1024  		}
  1025  
  1026  	case 13:
  1027  		// T is diagonal with small numbers on the diagonal to make the growth
  1028  		// factor underflow, but a small right hand side chosen so that the
  1029  		// solution does not overflow.
  1030  		if uplo == blas.Upper {
  1031  			icount := 1
  1032  			for i := n - 1; i >= 0; i-- {
  1033  				if icount <= 2 {
  1034  					ab[i*ldab] = tiny
  1035  				} else {
  1036  					ab[i*ldab] = 1
  1037  				}
  1038  				for j := 1; j < min(n-i, kd+1); j++ {
  1039  					ab[i*ldab+j] = 0
  1040  				}
  1041  				icount++
  1042  				if icount > 4 {
  1043  					icount = 1
  1044  				}
  1045  			}
  1046  		} else {
  1047  			icount := 1
  1048  			for i := 0; i < n; i++ {
  1049  				for j := max(0, kd-i); j < kd; j++ {
  1050  					ab[i*ldab+j] = 0
  1051  				}
  1052  				if icount <= 2 {
  1053  					ab[i*ldab+kd] = tiny
  1054  				} else {
  1055  					ab[i*ldab+kd] = 1
  1056  				}
  1057  				icount++
  1058  				if icount > 4 {
  1059  					icount = 1
  1060  				}
  1061  			}
  1062  		}
  1063  		// Set the right hand side alternately zero and small.
  1064  		if uplo == blas.Upper {
  1065  			b[0] = 0
  1066  			for i := n - 1; i > 1; i -= 2 {
  1067  				b[i] = 0
  1068  				b[i-1] = tiny
  1069  			}
  1070  		} else {
  1071  			b[n-1] = 0
  1072  			for i := 0; i < n-1; i += 2 {
  1073  				b[i] = 0
  1074  				b[i+1] = tiny
  1075  			}
  1076  		}
  1077  
  1078  	case 14:
  1079  		// Make the diagonal elements small to cause gradual overflow when
  1080  		// dividing by T[j,j]. To control the amount of scaling needed, the
  1081  		// matrix is bidiagonal.
  1082  		tscal := math.Pow(tiny, 1/float64(kd+1))
  1083  		if uplo == blas.Upper {
  1084  			for i := 0; i < n; i++ {
  1085  				ab[i*ldab] = tscal
  1086  				if i < n-1 && kd > 0 {
  1087  					ab[i*ldab+1] = -1
  1088  				}
  1089  				for j := 2; j < min(n-i, kd+1); j++ {
  1090  					ab[i*ldab+j] = 0
  1091  				}
  1092  			}
  1093  			b[n-1] = 1
  1094  		} else {
  1095  			for i := 0; i < n; i++ {
  1096  				for j := max(0, kd-i); j < kd-1; j++ {
  1097  					ab[i*ldab+j] = 0
  1098  				}
  1099  				if i > 0 && kd > 0 {
  1100  					ab[i*ldab+kd-1] = -1
  1101  				}
  1102  				ab[i*ldab+kd] = tscal
  1103  			}
  1104  			b[0] = 1
  1105  		}
  1106  
  1107  	case 15:
  1108  		// One zero diagonal element.
  1109  		iy := n / 2
  1110  		if uplo == blas.Upper {
  1111  			for i := 0; i < n; i++ {
  1112  				jlen := min(n-i, kd+1)
  1113  				dlarnv(ab[i*ldab:i*ldab+jlen], 2, rnd)
  1114  				if i != iy {
  1115  					ab[i*ldab] = math.Copysign(2, ab[i*ldab])
  1116  				} else {
  1117  					ab[i*ldab] = 0
  1118  				}
  1119  			}
  1120  		} else {
  1121  			for i := 0; i < n; i++ {
  1122  				jlen := min(i+1, kd+1)
  1123  				dlarnv(ab[i*ldab+kd+1-jlen:i*ldab+kd+1], 2, rnd)
  1124  				if i != iy {
  1125  					ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd])
  1126  				} else {
  1127  					ab[i*ldab+kd] = 0
  1128  				}
  1129  			}
  1130  		}
  1131  		bi.Dscal(n, 2, b, 1)
  1132  
  1133  		// case 16:
  1134  		// TODO(vladimir-ch)
  1135  		// Make the off-diagonal elements large to cause overflow when adding a
  1136  		// column of T. In the non-transposed case, the matrix is constructed to
  1137  		// cause overflow when adding a column in every other step.
  1138  
  1139  		// Initialize the matrix to zero.
  1140  		// if uplo == blas.Upper {
  1141  		// 	for i := 0; i < n; i++ {
  1142  		// 		for j := 0; j < min(n-i, kd+1); j++ {
  1143  		// 			ab[i*ldab+j] = 0
  1144  		// 		}
  1145  		// 	}
  1146  		// } else {
  1147  		// 	for i := 0; i < n; i++ {
  1148  		// 		for j := max(0, kd-i); j < kd+1; j++ {
  1149  		// 			ab[i*ldab+j] = 0
  1150  		// 		}
  1151  		// 	}
  1152  		// }
  1153  
  1154  		// const tscal = (1 - ulp) / (unfl / ulp)
  1155  		// texp := 1.0
  1156  		// if kd > 0 {
  1157  		// 	if uplo == blas.Upper {
  1158  		// 		for j := n - 1; j >= 0; j -= kd {
  1159  		// 		}
  1160  		// 	} else {
  1161  		// 		for j := 0; j < n; j += kd {
  1162  		// 		}
  1163  		// 	}
  1164  		// } else {
  1165  		// 	// Diagonal matrix.
  1166  		// 	for i := 0; i < n; i++ {
  1167  		// 		ab[i*ldab] = 1
  1168  		// 		b[i] = float64(i + 1)
  1169  		// 	}
  1170  		// }
  1171  
  1172  	case 17:
  1173  		// Generate a unit triangular matrix with elements between -1 and 1, and
  1174  		// make the right hand side large so that it requires scaling.
  1175  		if uplo == blas.Upper {
  1176  			for i := 0; i < n; i++ {
  1177  				ab[i*ldab] = float64(i + 2)
  1178  				jlen := min(n-i-1, kd)
  1179  				if jlen > 0 {
  1180  					dlarnv(ab[i*ldab+1:i*ldab+1+jlen], 2, rnd)
  1181  				}
  1182  			}
  1183  		} else {
  1184  			for i := 0; i < n; i++ {
  1185  				jlen := min(i, kd)
  1186  				if jlen > 0 {
  1187  					dlarnv(ab[i*ldab+kd-jlen:i*ldab+kd], 2, rnd)
  1188  				}
  1189  				ab[i*ldab+kd] = float64(i + 2)
  1190  			}
  1191  		}
  1192  		// Set the right hand side so that the largest value is huge.
  1193  		bnorm := math.Abs(b[bi.Idamax(n, b, 1)])
  1194  		bscal := huge / math.Max(1, bnorm)
  1195  		bi.Dscal(n, bscal, b, 1)
  1196  
  1197  	case 18:
  1198  		// Generate a triangular matrix with elements between huge/kd and
  1199  		// huge so that at least one of the column norms will exceed huge.
  1200  		tleft := huge / math.Max(1, float64(kd))
  1201  		// The reference LAPACK has
  1202  		//  tscal := huge * (float64(kd) / float64(kd+1))
  1203  		// but this causes overflow when computing cnorm in Dlatbs. Our choice
  1204  		// is more conservative but increases coverage in the same way as the
  1205  		// LAPACK version.
  1206  		tscal := huge / math.Max(1, float64(kd))
  1207  		if uplo == blas.Upper {
  1208  			for i := 0; i < n; i++ {
  1209  				for j := 0; j < min(n-i, kd+1); j++ {
  1210  					r := uniformM11()
  1211  					ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r
  1212  				}
  1213  			}
  1214  		} else {
  1215  			for i := 0; i < n; i++ {
  1216  				for j := max(0, kd-i); j < kd+1; j++ {
  1217  					r := uniformM11()
  1218  					ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r
  1219  				}
  1220  			}
  1221  		}
  1222  		bi.Dscal(n, 2, b, 1)
  1223  	}
  1224  
  1225  	// Flip the matrix if the transpose will be used.
  1226  	if trans != blas.NoTrans {
  1227  		if uplo == blas.Upper {
  1228  			for j := 0; j < n/2; j++ {
  1229  				jlen := min(n-2*j-1, kd+1)
  1230  				bi.Dswap(jlen, ab[j*ldab:], 1, ab[(n-j-jlen)*ldab+jlen-1:], min(-ldab+1, -1))
  1231  			}
  1232  		} else {
  1233  			for j := 0; j < n/2; j++ {
  1234  				jlen := min(n-2*j-1, kd+1)
  1235  				bi.Dswap(jlen, ab[j*ldab+kd:], max(ldab-1, 1), ab[(n-j-1)*ldab+kd+1-jlen:], -1)
  1236  			}
  1237  		}
  1238  	}
  1239  
  1240  	return diag, b
  1241  }