github.com/gopherd/gonum@v0.0.4/lapack/gonum/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 gonum 6 7 import ( 8 "math" 9 10 "github.com/gopherd/gonum/blas/blas64" 11 "github.com/gopherd/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 if n < 0 { 23 panic(nLT0) 24 } 25 26 if n == 0 { 27 return info 28 } 29 30 switch { 31 case len(d) < n: 32 panic(shortD) 33 case len(e) < n-1: 34 panic(shortE) 35 case len(work) < 4*n: 36 panic(shortWork) 37 } 38 39 if n == 1 { 40 d[0] = math.Abs(d[0]) 41 return info 42 } 43 44 if n == 2 { 45 d[1], d[0] = impl.Dlas2(d[0], e[0], d[1]) 46 return info 47 } 48 49 // Estimate the largest singular value. 50 var sigmx float64 51 for i := 0; i < n-1; i++ { 52 d[i] = math.Abs(d[i]) 53 sigmx = math.Max(sigmx, math.Abs(e[i])) 54 } 55 d[n-1] = math.Abs(d[n-1]) 56 // Early return if sigmx is zero (matrix is already diagonal). 57 if sigmx == 0 { 58 impl.Dlasrt(lapack.SortDecreasing, n, d) 59 return info 60 } 61 62 for i := 0; i < n; i++ { 63 sigmx = math.Max(sigmx, d[i]) 64 } 65 66 // Copy D and E into WORK (in the Z format) and scale (squaring the 67 // input data makes scaling by a power of the radix pointless). 68 69 eps := dlamchP 70 safmin := dlamchS 71 scale := math.Sqrt(eps / safmin) 72 bi := blas64.Implementation() 73 bi.Dcopy(n, d, 1, work, 2) 74 bi.Dcopy(n-1, e, 1, work[1:], 2) 75 impl.Dlascl(lapack.General, 0, 0, sigmx, scale, 2*n-1, 1, work, 1) 76 77 // Compute the q's and e's. 78 for i := 0; i < 2*n-1; i++ { 79 work[i] *= work[i] 80 } 81 work[2*n-1] = 0 82 83 info = impl.Dlasq2(n, work) 84 if info == 0 { 85 for i := 0; i < n; i++ { 86 d[i] = math.Sqrt(work[i]) 87 } 88 impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, d, 1) 89 } else if info == 2 { 90 // Maximum number of iterations exceeded. Move data from work 91 // into D and E so the calling subroutine can try to finish. 92 for i := 0; i < n; i++ { 93 d[i] = math.Sqrt(work[2*i]) 94 e[i] = math.Sqrt(work[2*i+1]) 95 } 96 impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, d, 1) 97 impl.Dlascl(lapack.General, 0, 0, scale, sigmx, n, 1, e, 1) 98 } 99 return info 100 }