OSDN Git Service

fix commands
[bytom/shuttle.git] / vendor / github.com / bytom / vendor / gonum.org / v1 / gonum / lapack / testlapack / general.go
diff --git a/vendor/github.com/bytom/vendor/gonum.org/v1/gonum/lapack/testlapack/general.go b/vendor/github.com/bytom/vendor/gonum.org/v1/gonum/lapack/testlapack/general.go
new file mode 100644 (file)
index 0000000..15b2feb
--- /dev/null
@@ -0,0 +1,1517 @@
+// Copyright ©2015 The Gonum Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testlapack
+
+import (
+       "fmt"
+       "math"
+       "math/cmplx"
+       "testing"
+
+       "golang.org/x/exp/rand"
+
+       "gonum.org/v1/gonum/blas"
+       "gonum.org/v1/gonum/blas/blas64"
+       "gonum.org/v1/gonum/floats"
+       "gonum.org/v1/gonum/lapack"
+)
+
+const (
+       // dlamchE is the machine epsilon. For IEEE this is 2^{-53}.
+       dlamchE = 1.0 / (1 << 53)
+       dlamchB = 2
+       dlamchP = dlamchB * dlamchE
+       // dlamchS is the smallest normal number. For IEEE this is 2^{-1022}.
+       dlamchS = 1.0 / (1 << 256) / (1 << 256) / (1 << 256) / (1 << 254)
+)
+
+func max(a, b int) int {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func min(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+// worklen describes how much workspace a test should use.
+type worklen int
+
+const (
+       minimumWork worklen = iota
+       mediumWork
+       optimumWork
+)
+
+// nanSlice allocates a new slice of length n filled with NaN.
+func nanSlice(n int) []float64 {
+       s := make([]float64, n)
+       for i := range s {
+               s[i] = math.NaN()
+       }
+       return s
+}
+
+// randomSlice allocates a new slice of length n filled with random values.
+func randomSlice(n int, rnd *rand.Rand) []float64 {
+       s := make([]float64, n)
+       for i := range s {
+               s[i] = rnd.NormFloat64()
+       }
+       return s
+}
+
+// nanGeneral allocates a new r×c general matrix filled with NaN values.
+func nanGeneral(r, c, stride int) blas64.General {
+       if r < 0 || c < 0 {
+               panic("bad matrix size")
+       }
+       if r == 0 || c == 0 {
+               return blas64.General{Stride: max(1, stride)}
+       }
+       if stride < c {
+               panic("bad stride")
+       }
+       return blas64.General{
+               Rows:   r,
+               Cols:   c,
+               Stride: stride,
+               Data:   nanSlice((r-1)*stride + c),
+       }
+}
+
+// randomGeneral allocates a new r×c general matrix filled with random
+// numbers. Out-of-range elements are filled with NaN values.
+func randomGeneral(r, c, stride int, rnd *rand.Rand) blas64.General {
+       ans := nanGeneral(r, c, stride)
+       for i := 0; i < r; i++ {
+               for j := 0; j < c; j++ {
+                       ans.Data[i*ans.Stride+j] = rnd.NormFloat64()
+               }
+       }
+       return ans
+}
+
+// randomHessenberg allocates a new n×n Hessenberg matrix filled with zeros
+// under the first subdiagonal and with random numbers elsewhere. Out-of-range
+// elements are filled with NaN values.
+func randomHessenberg(n, stride int, rnd *rand.Rand) blas64.General {
+       ans := nanGeneral(n, n, stride)
+       for i := 0; i < n; i++ {
+               for j := 0; j < i-1; j++ {
+                       ans.Data[i*ans.Stride+j] = 0
+               }
+               for j := max(0, i-1); j < n; j++ {
+                       ans.Data[i*ans.Stride+j] = rnd.NormFloat64()
+               }
+       }
+       return ans
+}
+
+// randomSchurCanonical returns a random, general matrix in Schur canonical
+// form, that is, block upper triangular with 1×1 and 2×2 diagonal blocks where
+// each 2×2 diagonal block has its diagonal elements equal and its off-diagonal
+// elements of opposite sign.
+func randomSchurCanonical(n, stride int, rnd *rand.Rand) blas64.General {
+       t := randomGeneral(n, n, stride, rnd)
+       // Zero out the lower triangle.
+       for i := 0; i < t.Rows; i++ {
+               for j := 0; j < i; j++ {
+                       t.Data[i*t.Stride+j] = 0
+               }
+       }
+       // Randomly create 2×2 diagonal blocks.
+       for i := 0; i < t.Rows; {
+               if i == t.Rows-1 || rnd.Float64() < 0.5 {
+                       // 1×1 block.
+                       i++
+                       continue
+               }
+               // 2×2 block.
+               // Diagonal elements equal.
+               t.Data[(i+1)*t.Stride+i+1] = t.Data[i*t.Stride+i]
+               // Off-diagonal elements of opposite sign.
+               c := rnd.NormFloat64()
+               if math.Signbit(c) == math.Signbit(t.Data[i*t.Stride+i+1]) {
+                       c *= -1
+               }
+               t.Data[(i+1)*t.Stride+i] = c
+               i += 2
+       }
+       return t
+}
+
+// blockedUpperTriGeneral returns a normal random, general matrix in the form
+//
+//            c-k-l  k    l
+//  A =    k [  0   A12  A13 ] if r-k-l >= 0;
+//         l [  0    0   A23 ]
+//     r-k-l [  0    0    0  ]
+//
+//          c-k-l  k    l
+//  A =  k [  0   A12  A13 ] if r-k-l < 0;
+//     r-k [  0    0   A23 ]
+//
+// where the k×k matrix A12 and l×l matrix is non-singular
+// upper triangular. A23 is l×l upper triangular if r-k-l >= 0,
+// otherwise A23 is (r-k)×l upper trapezoidal.
+func blockedUpperTriGeneral(r, c, k, l, stride int, kblock bool, rnd *rand.Rand) blas64.General {
+       t := l
+       if kblock {
+               t += k
+       }
+       ans := zeros(r, c, stride)
+       for i := 0; i < min(r, t); i++ {
+               var v float64
+               for v == 0 {
+                       v = rnd.NormFloat64()
+               }
+               ans.Data[i*ans.Stride+i+(c-t)] = v
+       }
+       for i := 0; i < min(r, t); i++ {
+               for j := i + (c - t) + 1; j < c; j++ {
+                       ans.Data[i*ans.Stride+j] = rnd.NormFloat64()
+               }
+       }
+       return ans
+}
+
+// nanTriangular allocates a new r×c triangular matrix filled with NaN values.
+func nanTriangular(uplo blas.Uplo, n, stride int) blas64.Triangular {
+       if n < 0 {
+               panic("bad matrix size")
+       }
+       if n == 0 {
+               return blas64.Triangular{
+                       Stride: max(1, stride),
+                       Uplo:   uplo,
+                       Diag:   blas.NonUnit,
+               }
+       }
+       if stride < n {
+               panic("bad stride")
+       }
+       return blas64.Triangular{
+               N:      n,
+               Stride: stride,
+               Data:   nanSlice((n-1)*stride + n),
+               Uplo:   uplo,
+               Diag:   blas.NonUnit,
+       }
+}
+
+// generalOutsideAllNaN returns whether all out-of-range elements have NaN
+// values.
+func generalOutsideAllNaN(a blas64.General) bool {
+       // Check after last column.
+       for i := 0; i < a.Rows-1; i++ {
+               for _, v := range a.Data[i*a.Stride+a.Cols : i*a.Stride+a.Stride] {
+                       if !math.IsNaN(v) {
+                               return false
+                       }
+               }
+       }
+       // Check after last element.
+       last := (a.Rows-1)*a.Stride + a.Cols
+       if a.Rows == 0 || a.Cols == 0 {
+               last = 0
+       }
+       for _, v := range a.Data[last:] {
+               if !math.IsNaN(v) {
+                       return false
+               }
+       }
+       return true
+}
+
+// triangularOutsideAllNaN returns whether all out-of-triangle elements have NaN
+// values.
+func triangularOutsideAllNaN(a blas64.Triangular) bool {
+       if a.Uplo == blas.Upper {
+               // Check below diagonal.
+               for i := 0; i < a.N; i++ {
+                       for _, v := range a.Data[i*a.Stride : i*a.Stride+i] {
+                               if !math.IsNaN(v) {
+                                       return false
+                               }
+                       }
+               }
+               // Check after last column.
+               for i := 0; i < a.N-1; i++ {
+                       for _, v := range a.Data[i*a.Stride+a.N : i*a.Stride+a.Stride] {
+                               if !math.IsNaN(v) {
+                                       return false
+                               }
+                       }
+               }
+       } else {
+               // Check above diagonal.
+               for i := 0; i < a.N-1; i++ {
+                       for _, v := range a.Data[i*a.Stride+i+1 : i*a.Stride+a.Stride] {
+                               if !math.IsNaN(v) {
+                                       return false
+                               }
+                       }
+               }
+       }
+       // Check after last element.
+       for _, v := range a.Data[max(0, a.N-1)*a.Stride+a.N:] {
+               if !math.IsNaN(v) {
+                       return false
+               }
+       }
+       return true
+}
+
+// transposeGeneral returns a new general matrix that is the transpose of the
+// input. Nothing is done with data outside the {rows, cols} limit of the general.
+func transposeGeneral(a blas64.General) blas64.General {
+       ans := blas64.General{
+               Rows:   a.Cols,
+               Cols:   a.Rows,
+               Stride: a.Rows,
+               Data:   make([]float64, a.Cols*a.Rows),
+       }
+       for i := 0; i < a.Rows; i++ {
+               for j := 0; j < a.Cols; j++ {
+                       ans.Data[j*ans.Stride+i] = a.Data[i*a.Stride+j]
+               }
+       }
+       return ans
+}
+
+// columnNorms returns the column norms of a.
+func columnNorms(m, n int, a []float64, lda int) []float64 {
+       bi := blas64.Implementation()
+       norms := make([]float64, n)
+       for j := 0; j < n; j++ {
+               norms[j] = bi.Dnrm2(m, a[j:], lda)
+       }
+       return norms
+}
+
+// extractVMat collects the single reflectors from a into a matrix.
+func extractVMat(m, n int, a []float64, lda int, direct lapack.Direct, store lapack.StoreV) blas64.General {
+       k := min(m, n)
+       switch {
+       default:
+               panic("not implemented")
+       case direct == lapack.Forward && store == lapack.ColumnWise:
+               v := blas64.General{
+                       Rows:   m,
+                       Cols:   k,
+                       Stride: k,
+                       Data:   make([]float64, m*k),
+               }
+               for i := 0; i < k; i++ {
+                       for j := 0; j < i; j++ {
+                               v.Data[j*v.Stride+i] = 0
+                       }
+                       v.Data[i*v.Stride+i] = 1
+                       for j := i + 1; j < m; j++ {
+                               v.Data[j*v.Stride+i] = a[j*lda+i]
+                       }
+               }
+               return v
+       case direct == lapack.Forward && store == lapack.RowWise:
+               v := blas64.General{
+                       Rows:   k,
+                       Cols:   n,
+                       Stride: n,
+                       Data:   make([]float64, k*n),
+               }
+               for i := 0; i < k; i++ {
+                       for j := 0; j < i; j++ {
+                               v.Data[i*v.Stride+j] = 0
+                       }
+                       v.Data[i*v.Stride+i] = 1
+                       for j := i + 1; j < n; j++ {
+                               v.Data[i*v.Stride+j] = a[i*lda+j]
+                       }
+               }
+               return v
+       }
+}
+
+// constructBidiagonal constructs a bidiagonal matrix with the given diagonal
+// and off-diagonal elements.
+func constructBidiagonal(uplo blas.Uplo, n int, d, e []float64) blas64.General {
+       bMat := blas64.General{
+               Rows:   n,
+               Cols:   n,
+               Stride: n,
+               Data:   make([]float64, n*n),
+       }
+
+       for i := 0; i < n-1; i++ {
+               bMat.Data[i*bMat.Stride+i] = d[i]
+               if uplo == blas.Upper {
+                       bMat.Data[i*bMat.Stride+i+1] = e[i]
+               } else {
+                       bMat.Data[(i+1)*bMat.Stride+i] = e[i]
+               }
+       }
+       bMat.Data[(n-1)*bMat.Stride+n-1] = d[n-1]
+       return bMat
+}
+
+// constructVMat transforms the v matrix based on the storage.
+func constructVMat(vMat blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General {
+       m := vMat.Rows
+       k := vMat.Cols
+       switch {
+       default:
+               panic("not implemented")
+       case store == lapack.ColumnWise && direct == lapack.Forward:
+               ldv := k
+               v := make([]float64, m*k)
+               for i := 0; i < m; i++ {
+                       for j := 0; j < k; j++ {
+                               if j > i {
+                                       v[i*ldv+j] = 0
+                               } else if j == i {
+                                       v[i*ldv+i] = 1
+                               } else {
+                                       v[i*ldv+j] = vMat.Data[i*vMat.Stride+j]
+                               }
+                       }
+               }
+               return blas64.General{
+                       Rows:   m,
+                       Cols:   k,
+                       Stride: k,
+                       Data:   v,
+               }
+       case store == lapack.RowWise && direct == lapack.Forward:
+               ldv := m
+               v := make([]float64, m*k)
+               for i := 0; i < m; i++ {
+                       for j := 0; j < k; j++ {
+                               if j > i {
+                                       v[j*ldv+i] = 0
+                               } else if j == i {
+                                       v[j*ldv+i] = 1
+                               } else {
+                                       v[j*ldv+i] = vMat.Data[i*vMat.Stride+j]
+                               }
+                       }
+               }
+               return blas64.General{
+                       Rows:   k,
+                       Cols:   m,
+                       Stride: m,
+                       Data:   v,
+               }
+       case store == lapack.ColumnWise && direct == lapack.Backward:
+               rowsv := m
+               ldv := k
+               v := make([]float64, m*k)
+               for i := 0; i < m; i++ {
+                       for j := 0; j < k; j++ {
+                               vrow := rowsv - i - 1
+                               vcol := k - j - 1
+                               if j > i {
+                                       v[vrow*ldv+vcol] = 0
+                               } else if j == i {
+                                       v[vrow*ldv+vcol] = 1
+                               } else {
+                                       v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j]
+                               }
+                       }
+               }
+               return blas64.General{
+                       Rows:   rowsv,
+                       Cols:   ldv,
+                       Stride: ldv,
+                       Data:   v,
+               }
+       case store == lapack.RowWise && direct == lapack.Backward:
+               rowsv := k
+               ldv := m
+               v := make([]float64, m*k)
+               for i := 0; i < m; i++ {
+                       for j := 0; j < k; j++ {
+                               vcol := ldv - i - 1
+                               vrow := k - j - 1
+                               if j > i {
+                                       v[vrow*ldv+vcol] = 0
+                               } else if j == i {
+                                       v[vrow*ldv+vcol] = 1
+                               } else {
+                                       v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j]
+                               }
+                       }
+               }
+               return blas64.General{
+                       Rows:   rowsv,
+                       Cols:   ldv,
+                       Stride: ldv,
+                       Data:   v,
+               }
+       }
+}
+
+func constructH(tau []float64, v blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General {
+       m := v.Rows
+       k := v.Cols
+       if store == lapack.RowWise {
+               m, k = k, m
+       }
+       h := blas64.General{
+               Rows:   m,
+               Cols:   m,
+               Stride: m,
+               Data:   make([]float64, m*m),
+       }
+       for i := 0; i < m; i++ {
+               h.Data[i*m+i] = 1
+       }
+       for i := 0; i < k; i++ {
+               vecData := make([]float64, m)
+               if store == lapack.ColumnWise {
+                       for j := 0; j < m; j++ {
+                               vecData[j] = v.Data[j*v.Cols+i]
+                       }
+               } else {
+                       for j := 0; j < m; j++ {
+                               vecData[j] = v.Data[i*v.Cols+j]
+                       }
+               }
+               vec := blas64.Vector{
+                       Inc:  1,
+                       Data: vecData,
+               }
+
+               hi := blas64.General{
+                       Rows:   m,
+                       Cols:   m,
+                       Stride: m,
+                       Data:   make([]float64, m*m),
+               }
+               for i := 0; i < m; i++ {
+                       hi.Data[i*m+i] = 1
+               }
+               // hi = I - tau * v * v^T
+               blas64.Ger(-tau[i], vec, vec, hi)
+
+               hcopy := blas64.General{
+                       Rows:   m,
+                       Cols:   m,
+                       Stride: m,
+                       Data:   make([]float64, m*m),
+               }
+               copy(hcopy.Data, h.Data)
+               if direct == lapack.Forward {
+                       // H = H * H_I in forward mode
+                       blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hcopy, hi, 0, h)
+               } else {
+                       // H = H_I * H in backward mode
+                       blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hi, hcopy, 0, h)
+               }
+       }
+       return h
+}
+
+// constructQ constructs the Q matrix from the result of dgeqrf and dgeqr2.
+func constructQ(kind string, m, n int, a []float64, lda int, tau []float64) blas64.General {
+       k := min(m, n)
+       return constructQK(kind, m, n, k, a, lda, tau)
+}
+
+// constructQK constructs the Q matrix from the result of dgeqrf and dgeqr2 using
+// the first k reflectors.
+func constructQK(kind string, m, n, k int, a []float64, lda int, tau []float64) blas64.General {
+       var sz int
+       switch kind {
+       case "QR":
+               sz = m
+       case "LQ", "RQ":
+               sz = n
+       }
+
+       q := blas64.General{
+               Rows:   sz,
+               Cols:   sz,
+               Stride: sz,
+               Data:   make([]float64, sz*sz),
+       }
+       for i := 0; i < sz; i++ {
+               q.Data[i*sz+i] = 1
+       }
+       qCopy := blas64.General{
+               Rows:   q.Rows,
+               Cols:   q.Cols,
+               Stride: q.Stride,
+               Data:   make([]float64, len(q.Data)),
+       }
+       for i := 0; i < k; i++ {
+               h := blas64.General{
+                       Rows:   sz,
+                       Cols:   sz,
+                       Stride: sz,
+                       Data:   make([]float64, sz*sz),
+               }
+               for j := 0; j < sz; j++ {
+                       h.Data[j*sz+j] = 1
+               }
+               vVec := blas64.Vector{
+                       Inc:  1,
+                       Data: make([]float64, sz),
+               }
+               switch kind {
+               case "QR":
+                       vVec.Data[i] = 1
+                       for j := i + 1; j < sz; j++ {
+                               vVec.Data[j] = a[lda*j+i]
+                       }
+               case "LQ":
+                       vVec.Data[i] = 1
+                       for j := i + 1; j < sz; j++ {
+                               vVec.Data[j] = a[i*lda+j]
+                       }
+               case "RQ":
+                       for j := 0; j < n-k+i; j++ {
+                               vVec.Data[j] = a[(m-k+i)*lda+j]
+                       }
+                       vVec.Data[n-k+i] = 1
+               }
+               blas64.Ger(-tau[i], vVec, vVec, h)
+               copy(qCopy.Data, q.Data)
+               // Multiply q by the new h.
+               switch kind {
+               case "QR", "RQ":
+                       blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q)
+               case "LQ":
+                       blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, qCopy, 0, q)
+               }
+       }
+       return q
+}
+
+// checkBidiagonal checks the bidiagonal decomposition from dlabrd and dgebd2.
+// The input to this function is the answer returned from the routines, stored
+// in a, d, e, tauP, and tauQ. The data of original A matrix (before
+// decomposition) is input in aCopy.
+//
+// checkBidiagonal constructs the V and U matrices, and from them constructs Q
+// and P. Using these constructions, it checks that Q^T * A * P and checks that
+// the result is bidiagonal.
+func checkBidiagonal(t *testing.T, m, n, nb int, a []float64, lda int, d, e, tauP, tauQ, aCopy []float64) {
+       // Check the answer.
+       // Construct V and U.
+       qMat := constructQPBidiagonal(lapack.ApplyQ, m, n, nb, a, lda, tauQ)
+       pMat := constructQPBidiagonal(lapack.ApplyP, m, n, nb, a, lda, tauP)
+
+       // Compute Q^T * A * P.
+       aMat := blas64.General{
+               Rows:   m,
+               Cols:   n,
+               Stride: lda,
+               Data:   make([]float64, len(aCopy)),
+       }
+       copy(aMat.Data, aCopy)
+
+       tmp1 := blas64.General{
+               Rows:   m,
+               Cols:   n,
+               Stride: n,
+               Data:   make([]float64, m*n),
+       }
+       blas64.Gemm(blas.Trans, blas.NoTrans, 1, qMat, aMat, 0, tmp1)
+       tmp2 := blas64.General{
+               Rows:   m,
+               Cols:   n,
+               Stride: n,
+               Data:   make([]float64, m*n),
+       }
+       blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp1, pMat, 0, tmp2)
+
+       // Check that the first nb rows and cols of tm2 are upper bidiagonal
+       // if m >= n, and lower bidiagonal otherwise.
+       correctDiag := true
+       matchD := true
+       matchE := true
+       for i := 0; i < m; i++ {
+               for j := 0; j < n; j++ {
+                       if i >= nb && j >= nb {
+                               continue
+                       }
+                       v := tmp2.Data[i*tmp2.Stride+j]
+                       if i == j {
+                               if math.Abs(d[i]-v) > 1e-12 {
+                                       matchD = false
+                               }
+                               continue
+                       }
+                       if m >= n && i == j-1 {
+                               if math.Abs(e[j-1]-v) > 1e-12 {
+                                       matchE = false
+                               }
+                               continue
+                       }
+                       if m < n && i-1 == j {
+                               if math.Abs(e[i-1]-v) > 1e-12 {
+                                       matchE = false
+                               }
+                               continue
+                       }
+                       if math.Abs(v) > 1e-12 {
+                               correctDiag = false
+                       }
+               }
+       }
+       if !correctDiag {
+               t.Errorf("Updated A not bi-diagonal")
+       }
+       if !matchD {
+               fmt.Println("d = ", d)
+               t.Errorf("D Mismatch")
+       }
+       if !matchE {
+               t.Errorf("E mismatch")
+       }
+}
+
+// constructQPBidiagonal constructs Q or P from the Bidiagonal decomposition
+// computed by dlabrd and bgebd2.
+func constructQPBidiagonal(vect lapack.DecompUpdate, m, n, nb int, a []float64, lda int, tau []float64) blas64.General {
+       sz := n
+       if vect == lapack.ApplyQ {
+               sz = m
+       }
+
+       var ldv int
+       var v blas64.General
+       if vect == lapack.ApplyQ {
+               ldv = nb
+               v = blas64.General{
+                       Rows:   m,
+                       Cols:   nb,
+                       Stride: ldv,
+                       Data:   make([]float64, m*ldv),
+               }
+       } else {
+               ldv = n
+               v = blas64.General{
+                       Rows:   nb,
+                       Cols:   n,
+                       Stride: ldv,
+                       Data:   make([]float64, m*ldv),
+               }
+       }
+
+       if vect == lapack.ApplyQ {
+               if m >= n {
+                       for i := 0; i < m; i++ {
+                               for j := 0; j <= min(nb-1, i); j++ {
+                                       if i == j {
+                                               v.Data[i*ldv+j] = 1
+                                               continue
+                                       }
+                                       v.Data[i*ldv+j] = a[i*lda+j]
+                               }
+                       }
+               } else {
+                       for i := 1; i < m; i++ {
+                               for j := 0; j <= min(nb-1, i-1); j++ {
+                                       if i-1 == j {
+                                               v.Data[i*ldv+j] = 1
+                                               continue
+                                       }
+                                       v.Data[i*ldv+j] = a[i*lda+j]
+                               }
+                       }
+               }
+       } else {
+               if m < n {
+                       for i := 0; i < nb; i++ {
+                               for j := i; j < n; j++ {
+                                       if i == j {
+                                               v.Data[i*ldv+j] = 1
+                                               continue
+                                       }
+                                       v.Data[i*ldv+j] = a[i*lda+j]
+                               }
+                       }
+               } else {
+                       for i := 0; i < nb; i++ {
+                               for j := i + 1; j < n; j++ {
+                                       if j-1 == i {
+                                               v.Data[i*ldv+j] = 1
+                                               continue
+                                       }
+                                       v.Data[i*ldv+j] = a[i*lda+j]
+                               }
+                       }
+               }
+       }
+
+       // The variable name is a computation of Q, but the algorithm is mostly the
+       // same for computing P (just with different data).
+       qMat := blas64.General{
+               Rows:   sz,
+               Cols:   sz,
+               Stride: sz,
+               Data:   make([]float64, sz*sz),
+       }
+       hMat := blas64.General{
+               Rows:   sz,
+               Cols:   sz,
+               Stride: sz,
+               Data:   make([]float64, sz*sz),
+       }
+       // set Q to I
+       for i := 0; i < sz; i++ {
+               qMat.Data[i*qMat.Stride+i] = 1
+       }
+       for i := 0; i < nb; i++ {
+               qCopy := blas64.General{Rows: qMat.Rows, Cols: qMat.Cols, Stride: qMat.Stride, Data: make([]float64, len(qMat.Data))}
+               copy(qCopy.Data, qMat.Data)
+
+               // Set g and h to I
+               for i := 0; i < sz; i++ {
+                       for j := 0; j < sz; j++ {
+                               if i == j {
+                                       hMat.Data[i*sz+j] = 1
+                               } else {
+                                       hMat.Data[i*sz+j] = 0
+                               }
+                       }
+               }
+               var vi blas64.Vector
+               // H -= tauQ[i] * v[i] * v[i]^t
+               if vect == lapack.ApplyQ {
+                       vi = blas64.Vector{
+                               Inc:  v.Stride,
+                               Data: v.Data[i:],
+                       }
+               } else {
+                       vi = blas64.Vector{
+                               Inc:  1,
+                               Data: v.Data[i*v.Stride:],
+                       }
+               }
+               blas64.Ger(-tau[i], vi, vi, hMat)
+               // Q = Q * G[1]
+               blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, hMat, 0, qMat)
+       }
+       return qMat
+}
+
+// printRowise prints the matrix with one row per line. This is useful for debugging.
+// If beyond is true, it prints beyond the final column to lda. If false, only
+// the columns are printed.
+func printRowise(a []float64, m, n, lda int, beyond bool) {
+       for i := 0; i < m; i++ {
+               end := n
+               if beyond {
+                       end = lda
+               }
+               fmt.Println(a[i*lda : i*lda+end])
+       }
+}
+
+// isOrthonormal checks that a general matrix is orthonormal.
+func isOrthonormal(q blas64.General) bool {
+       n := q.Rows
+       for i := 0; i < n; i++ {
+               for j := i; j < n; j++ {
+                       dot := blas64.Dot(n,
+                               blas64.Vector{Inc: 1, Data: q.Data[i*q.Stride:]},
+                               blas64.Vector{Inc: 1, Data: q.Data[j*q.Stride:]},
+                       )
+                       if math.IsNaN(dot) {
+                               return false
+                       }
+                       if i == j {
+                               if math.Abs(dot-1) > 1e-10 {
+                                       return false
+                               }
+                       } else {
+                               if math.Abs(dot) > 1e-10 {
+                                       return false
+                               }
+                       }
+               }
+       }
+       return true
+}
+
+// copyMatrix copies an m×n matrix src of stride n into an m×n matrix dst of stride ld.
+func copyMatrix(m, n int, dst []float64, ld int, src []float64) {
+       for i := 0; i < m; i++ {
+               copy(dst[i*ld:i*ld+n], src[i*n:i*n+n])
+       }
+}
+
+func copyGeneral(dst, src blas64.General) {
+       r := min(dst.Rows, src.Rows)
+       c := min(dst.Cols, src.Cols)
+       for i := 0; i < r; i++ {
+               copy(dst.Data[i*dst.Stride:i*dst.Stride+c], src.Data[i*src.Stride:i*src.Stride+c])
+       }
+}
+
+// cloneGeneral allocates and returns an exact copy of the given general matrix.
+func cloneGeneral(a blas64.General) blas64.General {
+       c := a
+       c.Data = make([]float64, len(a.Data))
+       copy(c.Data, a.Data)
+       return c
+}
+
+// equalApprox returns whether the matrices A and B of order n are approximately
+// equal within given tolerance.
+func equalApprox(m, n int, a []float64, lda int, b []float64, tol float64) bool {
+       for i := 0; i < m; i++ {
+               for j := 0; j < n; j++ {
+                       diff := a[i*lda+j] - b[i*n+j]
+                       if math.IsNaN(diff) || math.Abs(diff) > tol {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// equalApproxGeneral returns whether the general matrices a and b are
+// approximately equal within given tolerance.
+func equalApproxGeneral(a, b blas64.General, tol float64) bool {
+       if a.Rows != b.Rows || a.Cols != b.Cols {
+               panic("bad input")
+       }
+       for i := 0; i < a.Rows; i++ {
+               for j := 0; j < a.Cols; j++ {
+                       diff := a.Data[i*a.Stride+j] - b.Data[i*b.Stride+j]
+                       if math.IsNaN(diff) || math.Abs(diff) > tol {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// equalApproxTriangular returns whether the triangular matrices A and B of
+// order n are approximately equal within given tolerance.
+func equalApproxTriangular(upper bool, n int, a []float64, lda int, b []float64, tol float64) bool {
+       if upper {
+               for i := 0; i < n; i++ {
+                       for j := i; j < n; j++ {
+                               diff := a[i*lda+j] - b[i*n+j]
+                               if math.IsNaN(diff) || math.Abs(diff) > tol {
+                                       return false
+                               }
+                       }
+               }
+               return true
+       }
+       for i := 0; i < n; i++ {
+               for j := 0; j <= i; j++ {
+                       diff := a[i*lda+j] - b[i*n+j]
+                       if math.IsNaN(diff) || math.Abs(diff) > tol {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+func equalApproxSymmetric(a, b blas64.Symmetric, tol float64) bool {
+       if a.Uplo != b.Uplo {
+               return false
+       }
+       if a.N != b.N {
+               return false
+       }
+       if a.Uplo == blas.Upper {
+               for i := 0; i < a.N; i++ {
+                       for j := i; j < a.N; j++ {
+                               if !floats.EqualWithinAbsOrRel(a.Data[i*a.Stride+j], b.Data[i*b.Stride+j], tol, tol) {
+                                       return false
+                               }
+                       }
+               }
+               return true
+       }
+       for i := 0; i < a.N; i++ {
+               for j := 0; j <= i; j++ {
+                       if !floats.EqualWithinAbsOrRel(a.Data[i*a.Stride+j], b.Data[i*b.Stride+j], tol, tol) {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// randSymBand creates a random symmetric banded matrix, and returns both the
+// random matrix and the equivalent Symmetric matrix for testing. rnder
+// specifies the random number
+func randSymBand(ul blas.Uplo, n, ldab, kb int, rnd *rand.Rand) (blas64.Symmetric, blas64.SymmetricBand) {
+       // A matrix is positive definite if and only if it has a Cholesky
+       // decomposition. Generate a random banded lower triangular matrix
+       // to construct the random symmetric matrix.
+       a := make([]float64, n*n)
+       for i := 0; i < n; i++ {
+               for j := max(0, i-kb); j <= i; j++ {
+                       a[i*n+j] = rnd.NormFloat64()
+               }
+               a[i*n+i] = math.Abs(a[i*n+i])
+               // Add an extra amound to the diagonal in order to improve the condition number.
+               a[i*n+i] += 1.5 * rnd.Float64()
+       }
+       agen := blas64.General{
+               Rows:   n,
+               Cols:   n,
+               Stride: n,
+               Data:   a,
+       }
+
+       // Construct the SymDense from a*a^T
+       c := make([]float64, n*n)
+       cgen := blas64.General{
+               Rows:   n,
+               Cols:   n,
+               Stride: n,
+               Data:   c,
+       }
+       blas64.Gemm(blas.NoTrans, blas.Trans, 1, agen, agen, 0, cgen)
+       sym := blas64.Symmetric{
+               N:      n,
+               Stride: n,
+               Data:   c,
+               Uplo:   ul,
+       }
+
+       b := symToSymBand(ul, c, n, n, kb, ldab)
+       band := blas64.SymmetricBand{
+               N:      n,
+               K:      kb,
+               Stride: ldab,
+               Data:   b,
+               Uplo:   ul,
+       }
+
+       return sym, band
+}
+
+// symToSymBand takes the data in a Symmetric matrix and returns a
+// SymmetricBanded matrix.
+func symToSymBand(ul blas.Uplo, a []float64, n, lda, kb, ldab int) []float64 {
+       if ul == blas.Upper {
+               band := make([]float64, (n-1)*ldab+kb+1)
+               for i := 0; i < n; i++ {
+                       for j := i; j < min(i+kb+1, n); j++ {
+                               band[i*ldab+j-i] = a[i*lda+j]
+                       }
+               }
+               return band
+       }
+       band := make([]float64, (n-1)*ldab+kb+1)
+       for i := 0; i < n; i++ {
+               for j := max(0, i-kb); j <= i; j++ {
+                       band[i*ldab+j-i+kb] = a[i*lda+j]
+               }
+       }
+       return band
+}
+
+// symBandToSym takes a banded symmetric matrix and returns the same data as
+// a Symmetric matrix.
+func symBandToSym(ul blas.Uplo, band []float64, n, kb, ldab int) blas64.Symmetric {
+       sym := make([]float64, n*n)
+       if ul == blas.Upper {
+               for i := 0; i < n; i++ {
+                       for j := 0; j < min(kb+1+i, n)-i; j++ {
+                               sym[i*n+i+j] = band[i*ldab+j]
+                       }
+               }
+       } else {
+               for i := 0; i < n; i++ {
+                       for j := kb - min(i, kb); j < kb+1; j++ {
+                               sym[i*n+i-kb+j] = band[i*ldab+j]
+                       }
+               }
+       }
+       return blas64.Symmetric{
+               N:      n,
+               Stride: n,
+               Data:   sym,
+               Uplo:   ul,
+       }
+}
+
+// eye returns an identity matrix of given order and stride.
+func eye(n, stride int) blas64.General {
+       ans := nanGeneral(n, n, stride)
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       ans.Data[i*ans.Stride+j] = 0
+               }
+               ans.Data[i*ans.Stride+i] = 1
+       }
+       return ans
+}
+
+// zeros returns an m×n matrix with given stride filled with zeros.
+func zeros(m, n, stride int) blas64.General {
+       a := nanGeneral(m, n, stride)
+       for i := 0; i < m; i++ {
+               for j := 0; j < n; j++ {
+                       a.Data[i*a.Stride+j] = 0
+               }
+       }
+       return a
+}
+
+// extract2x2Block returns the elements of T at [0,0], [0,1], [1,0], and [1,1].
+func extract2x2Block(t []float64, ldt int) (a, b, c, d float64) {
+       return t[0], t[1], t[ldt], t[ldt+1]
+}
+
+// isSchurCanonical returns whether the 2×2 matrix [a b; c d] is in Schur
+// canonical form.
+func isSchurCanonical(a, b, c, d float64) bool {
+       return c == 0 || (a == d && math.Signbit(b) != math.Signbit(c))
+}
+
+// isSchurCanonicalGeneral returns whether T is block upper triangular with 1×1
+// and 2×2 diagonal blocks, each 2×2 block in Schur canonical form. The function
+// checks only along the diagonal and the first subdiagonal, otherwise the lower
+// triangle is not accessed.
+func isSchurCanonicalGeneral(t blas64.General) bool {
+       if t.Rows != t.Cols {
+               panic("invalid matrix")
+       }
+       for i := 0; i < t.Rows-1; {
+               if t.Data[(i+1)*t.Stride+i] == 0 {
+                       // 1×1 block.
+                       i++
+                       continue
+               }
+               // 2×2 block.
+               a, b, c, d := extract2x2Block(t.Data[i*t.Stride+i:], t.Stride)
+               if !isSchurCanonical(a, b, c, d) {
+                       return false
+               }
+               i += 2
+       }
+       return true
+}
+
+// schurBlockEigenvalues returns the two eigenvalues of the 2×2 matrix [a b; c d]
+// that must be in Schur canonical form.
+func schurBlockEigenvalues(a, b, c, d float64) (ev1, ev2 complex128) {
+       if !isSchurCanonical(a, b, c, d) {
+               panic("block not in Schur canonical form")
+       }
+       if c == 0 {
+               return complex(a, 0), complex(d, 0)
+       }
+       im := math.Sqrt(-b * c)
+       return complex(a, im), complex(a, -im)
+}
+
+// schurBlockSize returns the size of the diagonal block at i-th row in the
+// upper quasi-triangular matrix t in Schur canonical form, and whether i points
+// to the first row of the block. For zero-sized matrices the function returns 0
+// and true.
+func schurBlockSize(t blas64.General, i int) (size int, first bool) {
+       if t.Rows != t.Cols {
+               panic("matrix not square")
+       }
+       if t.Rows == 0 {
+               return 0, true
+       }
+       if i < 0 || t.Rows <= i {
+               panic("index out of range")
+       }
+
+       first = true
+       if i > 0 && t.Data[i*t.Stride+i-1] != 0 {
+               // There is a non-zero element to the left, therefore i must
+               // point to the second row in a 2×2 diagonal block.
+               first = false
+               i--
+       }
+       size = 1
+       if i+1 < t.Rows && t.Data[(i+1)*t.Stride+i] != 0 {
+               // There is a non-zero element below, this must be a 2×2
+               // diagonal block.
+               size = 2
+       }
+       return size, first
+}
+
+// containsComplex returns whether z is approximately equal to one of the complex
+// numbers in v. If z is found, its index in v will be also returned.
+func containsComplex(v []complex128, z complex128, tol float64) (found bool, index int) {
+       for i := range v {
+               if cmplx.Abs(v[i]-z) < tol {
+                       return true, i
+               }
+       }
+       return false, -1
+}
+
+// isAllNaN returns whether x contains only NaN values.
+func isAllNaN(x []float64) bool {
+       for _, v := range x {
+               if !math.IsNaN(v) {
+                       return false
+               }
+       }
+       return true
+}
+
+// isUpperHessenberg returns whether h contains only zeros below the
+// subdiagonal.
+func isUpperHessenberg(h blas64.General) bool {
+       if h.Rows != h.Cols {
+               panic("matrix not square")
+       }
+       n := h.Rows
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       if i > j+1 && h.Data[i*h.Stride+j] != 0 {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// isUpperTriangular returns whether a contains only zeros below the diagonal.
+func isUpperTriangular(a blas64.General) bool {
+       n := a.Rows
+       for i := 1; i < n; i++ {
+               for j := 0; j < i; j++ {
+                       if a.Data[i*a.Stride+j] != 0 {
+                               return false
+                       }
+               }
+       }
+       return true
+}
+
+// unbalancedSparseGeneral returns an m×n dense matrix with a random sparse
+// structure consisting of nz nonzero elements. The matrix will be unbalanced by
+// multiplying each element randomly by its row or column index.
+func unbalancedSparseGeneral(m, n, stride int, nonzeros int, rnd *rand.Rand) blas64.General {
+       a := zeros(m, n, stride)
+       for k := 0; k < nonzeros; k++ {
+               i := rnd.Intn(n)
+               j := rnd.Intn(n)
+               if rnd.Float64() < 0.5 {
+                       a.Data[i*stride+j] = float64(i+1) * rnd.NormFloat64()
+               } else {
+                       a.Data[i*stride+j] = float64(j+1) * rnd.NormFloat64()
+               }
+       }
+       return a
+}
+
+// columnOf returns a copy of the j-th column of a.
+func columnOf(a blas64.General, j int) []float64 {
+       if j < 0 || a.Cols <= j {
+               panic("bad column index")
+       }
+       col := make([]float64, a.Rows)
+       for i := range col {
+               col[i] = a.Data[i*a.Stride+j]
+       }
+       return col
+}
+
+// isRightEigenvectorOf returns whether the vector xRe+i*xIm, where i is the
+// imaginary unit, is the right eigenvector of A corresponding to the eigenvalue
+// lambda.
+//
+// A right eigenvector corresponding to a complex eigenvalue λ is a complex
+// non-zero vector x such that
+//  A x = λ x.
+func isRightEigenvectorOf(a blas64.General, xRe, xIm []float64, lambda complex128, tol float64) bool {
+       if a.Rows != a.Cols {
+               panic("matrix not square")
+       }
+
+       if imag(lambda) != 0 && xIm == nil {
+               // Complex eigenvalue of a real matrix cannot have a real
+               // eigenvector.
+               return false
+       }
+
+       n := a.Rows
+
+       // Compute A real(x) and store the result into xReAns.
+       xReAns := make([]float64, n)
+       blas64.Gemv(blas.NoTrans, 1, a, blas64.Vector{1, xRe}, 0, blas64.Vector{1, xReAns})
+
+       if imag(lambda) == 0 && xIm == nil {
+               // Real eigenvalue and eigenvector.
+
+               // Compute λx and store the result into lambdax.
+               lambdax := make([]float64, n)
+               floats.AddScaled(lambdax, real(lambda), xRe)
+
+               // This is expressed as the inverse to catch the case
+               // xReAns_i = Inf and lambdax_i = Inf of the same sign.
+               return !(floats.Distance(xReAns, lambdax, math.Inf(1)) > tol)
+       }
+
+       // Complex eigenvector, and real or complex eigenvalue.
+
+       // Compute A imag(x) and store the result into xImAns.
+       xImAns := make([]float64, n)
+       blas64.Gemv(blas.NoTrans, 1, a, blas64.Vector{1, xIm}, 0, blas64.Vector{1, xImAns})
+
+       // Compute λx and store the result into lambdax.
+       lambdax := make([]complex128, n)
+       for i := range lambdax {
+               lambdax[i] = lambda * complex(xRe[i], xIm[i])
+       }
+
+       for i, v := range lambdax {
+               ax := complex(xReAns[i], xImAns[i])
+               if cmplx.Abs(v-ax) > tol {
+                       return false
+               }
+       }
+       return true
+}
+
+// isLeftEigenvectorOf returns whether the vector yRe+i*yIm, where i is the
+// imaginary unit, is the left eigenvector of A corresponding to the eigenvalue
+// lambda.
+//
+// A left eigenvector corresponding to a complex eigenvalue λ is a complex
+// non-zero vector y such that
+//  y^H A = λ y^H,
+// which is equivalent for real A to
+//  A^T y = conj(λ) y,
+func isLeftEigenvectorOf(a blas64.General, yRe, yIm []float64, lambda complex128, tol float64) bool {
+       if a.Rows != a.Cols {
+               panic("matrix not square")
+       }
+
+       if imag(lambda) != 0 && yIm == nil {
+               // Complex eigenvalue of a real matrix cannot have a real
+               // eigenvector.
+               return false
+       }
+
+       n := a.Rows
+
+       // Compute A^T real(y) and store the result into yReAns.
+       yReAns := make([]float64, n)
+       blas64.Gemv(blas.Trans, 1, a, blas64.Vector{1, yRe}, 0, blas64.Vector{1, yReAns})
+
+       if imag(lambda) == 0 && yIm == nil {
+               // Real eigenvalue and eigenvector.
+
+               // Compute λy and store the result into lambday.
+               lambday := make([]float64, n)
+               floats.AddScaled(lambday, real(lambda), yRe)
+
+               // This is expressed as the inverse to catch the case
+               // yReAns_i = Inf and lambday_i = Inf of the same sign.
+               return !(floats.Distance(yReAns, lambday, math.Inf(1)) > tol)
+       }
+
+       // Complex eigenvector, and real or complex eigenvalue.
+
+       // Compute A^T imag(y) and store the result into yImAns.
+       yImAns := make([]float64, n)
+       blas64.Gemv(blas.Trans, 1, a, blas64.Vector{1, yIm}, 0, blas64.Vector{1, yImAns})
+
+       // Compute conj(λ)y and store the result into lambday.
+       lambda = cmplx.Conj(lambda)
+       lambday := make([]complex128, n)
+       for i := range lambday {
+               lambday[i] = lambda * complex(yRe[i], yIm[i])
+       }
+
+       for i, v := range lambday {
+               ay := complex(yReAns[i], yImAns[i])
+               if cmplx.Abs(v-ay) > tol {
+                       return false
+               }
+       }
+       return true
+}
+
+// rootsOfUnity returns the n complex numbers whose n-th power is equal to 1.
+func rootsOfUnity(n int) []complex128 {
+       w := make([]complex128, n)
+       for i := 0; i < n; i++ {
+               angle := math.Pi * float64(2*i) / float64(n)
+               w[i] = complex(math.Cos(angle), math.Sin(angle))
+       }
+       return w
+}
+
+// randomOrthogonal returns an n×n random orthogonal matrix.
+func randomOrthogonal(n int, rnd *rand.Rand) blas64.General {
+       q := eye(n, n)
+       x := make([]float64, n)
+       v := make([]float64, n)
+       for j := 0; j < n-1; j++ {
+               // x represents the j-th column of a random matrix.
+               for i := 0; i < j; i++ {
+                       x[i] = 0
+               }
+               for i := j; i < n; i++ {
+                       x[i] = rnd.NormFloat64()
+               }
+               // Compute v that represents the elementary reflector that
+               // annihilates the subdiagonal elements of x.
+               reflector(v, x, j)
+               // Compute Q * H_j and store the result into Q.
+               applyReflector(q, q, v)
+       }
+       if !isOrthonormal(q) {
+               panic("Q not orthogonal")
+       }
+       return q
+}
+
+// reflector generates a Householder reflector v that zeros out subdiagonal
+// entries in the j-th column of a matrix.
+func reflector(v, col []float64, j int) {
+       n := len(col)
+       if len(v) != n {
+               panic("slice length mismatch")
+       }
+       if j < 0 || n <= j {
+               panic("invalid column index")
+       }
+
+       for i := range v {
+               v[i] = 0
+       }
+       if j == n-1 {
+               return
+       }
+       s := floats.Norm(col[j:], 2)
+       if s == 0 {
+               return
+       }
+       v[j] = col[j] + math.Copysign(s, col[j])
+       copy(v[j+1:], col[j+1:])
+       s = floats.Norm(v[j:], 2)
+       floats.Scale(1/s, v[j:])
+}
+
+// applyReflector computes Q*H where H is a Householder matrix represented by
+// the Householder reflector v.
+func applyReflector(qh blas64.General, q blas64.General, v []float64) {
+       n := len(v)
+       if qh.Rows != n || qh.Cols != n {
+               panic("bad size of qh")
+       }
+       if q.Rows != n || q.Cols != n {
+               panic("bad size of q")
+       }
+       qv := make([]float64, n)
+       blas64.Gemv(blas.NoTrans, 1, q, blas64.Vector{1, v}, 0, blas64.Vector{1, qv})
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       qh.Data[i*qh.Stride+j] = q.Data[i*q.Stride+j]
+               }
+       }
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       qh.Data[i*qh.Stride+j] -= 2 * qv[i] * v[j]
+               }
+       }
+       var norm2 float64
+       for _, vi := range v {
+               norm2 += vi * vi
+       }
+       norm2inv := 1 / norm2
+       for i := 0; i < n; i++ {
+               for j := 0; j < n; j++ {
+                       qh.Data[i*qh.Stride+j] *= norm2inv
+               }
+       }
+}
+
+// constructGSVDresults returns the matrices [ 0 R ], D1 and D2 described
+// in the documentation of Dtgsja and Dggsvd3, and the result matrix in
+// the documentation for Dggsvp3.
+func constructGSVDresults(n, p, m, k, l int, a, b blas64.General, alpha, beta []float64) (zeroR, d1, d2 blas64.General) {
+       // [ 0 R ]
+       zeroR = zeros(k+l, n, n)
+       dst := zeroR
+       dst.Rows = min(m, k+l)
+       dst.Cols = k + l
+       dst.Data = zeroR.Data[n-k-l:]
+       src := a
+       src.Rows = min(m, k+l)
+       src.Cols = k + l
+       src.Data = a.Data[n-k-l:]
+       copyGeneral(dst, src)
+       if m < k+l {
+               // [ 0 R ]
+               dst.Rows = k + l - m
+               dst.Cols = k + l - m
+               dst.Data = zeroR.Data[m*zeroR.Stride+n-(k+l-m):]
+               src = b
+               src.Rows = k + l - m
+               src.Cols = k + l - m
+               src.Data = b.Data[(m-k)*b.Stride+n+m-k-l:]
+               copyGeneral(dst, src)
+       }
+
+       // D1
+       d1 = zeros(m, k+l, k+l)
+       for i := 0; i < k; i++ {
+               d1.Data[i*d1.Stride+i] = 1
+       }
+       for i := k; i < min(m, k+l); i++ {
+               d1.Data[i*d1.Stride+i] = alpha[i]
+       }
+
+       // D2
+       d2 = zeros(p, k+l, k+l)
+       for i := 0; i < min(l, m-k); i++ {
+               d2.Data[i*d2.Stride+i+k] = beta[k+i]
+       }
+       for i := m - k; i < l; i++ {
+               d2.Data[i*d2.Stride+i+k] = 1
+       }
+
+       return zeroR, d1, d2
+}
+
+func constructGSVPresults(n, p, m, k, l int, a, b blas64.General) (zeroA, zeroB blas64.General) {
+       zeroA = zeros(m, n, n)
+       dst := zeroA
+       dst.Rows = min(m, k+l)
+       dst.Cols = k + l
+       dst.Data = zeroA.Data[n-k-l:]
+       src := a
+       dst.Rows = min(m, k+l)
+       src.Cols = k + l
+       src.Data = a.Data[n-k-l:]
+       copyGeneral(dst, src)
+
+       zeroB = zeros(p, n, n)
+       dst = zeroB
+       dst.Rows = l
+       dst.Cols = l
+       dst.Data = zeroB.Data[n-l:]
+       src = b
+       dst.Rows = l
+       src.Cols = l
+       src.Data = b.Data[n-l:]
+       copyGeneral(dst, src)
+
+       return zeroA, zeroB
+}