github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/dlasq1.go (about) 1 // Copyright ©2015 The gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package native 6 7 import ( 8 "math" 9 10 "github.com/gonum/blas/blas64" 11 "github.com/gonum/lapack" 12 ) 13 14 // Dlasq1 computes the singular values of an n×n bidiagonal matrix with diagonal 15 // d and off-diagonal e. On exit, d contains the singular values in decreasing 16 // order, and e is overwritten. d must have length at least n, e must have 17 // length at least n-1, and the input work must have length at least 4*n. Dlasq1 18 // will panic if these conditions are not met. 19 // 20 // Dlasq1 is an internal routine. It is exported for testing purposes. 21 func (impl Implementation) Dlasq1(n int, d, e, work []float64) (info int) { 22 // TODO(btracey): replace info with an error. 23 if n < 0 { 24 panic(nLT0) 25 } 26 if len(work) < 4*n { 27 panic(badWork) 28 } 29 if len(d) < n { 30 panic("lapack: length of d less than n") 31 } 32 if len(e) < n-1 { 33 panic("lapack: length of e less than n-1") 34 } 35 if n == 0 { 36 return info 37 } 38 if n == 1 { 39 d[0] = math.Abs(d[0]) 40 return info 41 } 42 if n == 2 { 43 d[1], d[0] = impl.Dlas2(d[0], e[0], d[1]) 44 return info 45 } 46 // Estimate the largest singular value. 47 var sigmx float64 48 for i := 0; i < n-1; i++ { 49 d[i] = math.Abs(d[i]) 50 sigmx = math.Max(sigmx, math.Abs(e[i])) 51 } 52 d[n-1] = math.Abs(d[n-1]) 53 // Early return if sigmx is zero (matrix is already diagonal). 54 if sigmx == 0 { 55 impl.Dlasrt(lapack.SortDecreasing, n, d) 56 return info 57 } 58 59 for i := 0; i < n; i++ { 60 sigmx = math.Max(sigmx, d[i]) 61 } 62 63 // Copy D and E into WORK (in the Z format) and scale (squaring the 64 // input data makes scaling by a power of the radix pointless). 65 66 eps := dlamchP 67 safmin := dlamchS 68 scale := math.Sqrt(eps / safmin) 69 bi := blas64.Implementation() 70 bi.Dcopy(n, d, 1, work, 2) 71 bi.Dcopy(n-1, e, 1, work[1:], 2) 72 impl.Dlascl(lapack.General, 0, 0, sigmx, scale, 2*n-1, 1, work, 1) 73 74 // Compute the q's and e's. 75 for i := 0; i < 2*n-1; i++ { 76 work[i] *= work[i] 77 } 78 work[2*n-1] = 0 79 80 info = impl.Dlasq2(n, work) 81 if info == 0 { 82 for i := 0; i < n; i++ { 83 d[i] = math.Sqrt(work[i]) 84 } 85 impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, d, 1) 86 } else if info == 2 { 87 // Maximum number of iterations exceeded. Move data from work 88 // into D and E so the calling subroutine can try to finish. 89 for i := 0; i < n; i++ { 90 d[i] = math.Sqrt(work[2*i]) 91 e[i] = math.Sqrt(work[2*i+1]) 92 } 93 impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, d, 1) 94 impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, e, 1) 95 } 96 return info 97 }