OSDN Git Service

fix commands
[bytom/shuttle.git] / vendor / github.com / bytom / vendor / gonum.org / v1 / gonum / lapack / gonum / dlasq2.go
diff --git a/vendor/github.com/bytom/vendor/gonum.org/v1/gonum/lapack/gonum/dlasq2.go b/vendor/github.com/bytom/vendor/gonum.org/v1/gonum/lapack/gonum/dlasq2.go
new file mode 100644 (file)
index 0000000..009e506
--- /dev/null
@@ -0,0 +1,368 @@
+// 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 gonum
+
+import (
+       "math"
+
+       "gonum.org/v1/gonum/lapack"
+)
+
+// Dlasq2 computes all the eigenvalues of the symmetric positive
+// definite tridiagonal matrix associated with the qd array Z. Eigevalues
+// are computed to high relative accuracy avoiding denormalization, underflow
+// and overflow.
+//
+// To see the relation of Z to the tridiagonal matrix, let L be a
+// unit lower bidiagonal matrix with sub-diagonals Z(2,4,6,,..) and
+// let U be an upper bidiagonal matrix with 1's above and diagonal
+// Z(1,3,5,,..). The tridiagonal is L*U or, if you prefer, the
+// symmetric tridiagonal to which it is similar.
+//
+// info returns a status error. The return codes mean as follows:
+//  0: The algorithm completed successfully.
+//  1: A split was marked by a positive value in e.
+//  2: Current block of Z not diagonalized after 100*n iterations (in inner
+//     while loop). On exit Z holds a qd array with the same eigenvalues as
+//     the given Z.
+//  3: Termination criterion of outer while loop not met (program created more
+//     than N unreduced blocks).
+//
+// z must have length at least 4*n, and must not contain any negative elements.
+// Dlasq2 will panic otherwise.
+//
+// Dlasq2 is an internal routine. It is exported for testing purposes.
+func (impl Implementation) Dlasq2(n int, z []float64) (info int) {
+       // TODO(btracey): make info an error.
+       if len(z) < 4*n {
+               panic(badZ)
+       }
+       const cbias = 1.5
+
+       eps := dlamchP
+       safmin := dlamchS
+       tol := eps * 100
+       tol2 := tol * tol
+       if n < 0 {
+               panic(nLT0)
+       }
+       if n == 0 {
+               return info
+       }
+       if n == 1 {
+               if z[0] < 0 {
+                       panic(negZ)
+               }
+               return info
+       }
+       if n == 2 {
+               if z[1] < 0 || z[2] < 0 {
+                       panic("lapack: bad z value")
+               } else if z[2] > z[0] {
+                       z[0], z[2] = z[2], z[0]
+               }
+               z[4] = z[0] + z[1] + z[2]
+               if z[1] > z[2]*tol2 {
+                       t := 0.5 * (z[0] - z[2] + z[1])
+                       s := z[2] * (z[1] / t)
+                       if s <= t {
+                               s = z[2] * (z[1] / (t * (1 + math.Sqrt(1+s/t))))
+                       } else {
+                               s = z[2] * (z[1] / (t + math.Sqrt(t)*math.Sqrt(t+s)))
+                       }
+                       t = z[0] + s + z[1]
+                       z[2] *= z[0] / t
+                       z[0] = t
+               }
+               z[1] = z[2]
+               z[5] = z[1] + z[0]
+               return info
+       }
+       // Check for negative data and compute sums of q's and e's.
+       z[2*n-1] = 0
+       emin := z[1]
+       var d, e, qmax float64
+       var i1, n1 int
+       for k := 0; k < 2*(n-1); k += 2 {
+               if z[k] < 0 || z[k+1] < 0 {
+                       panic("lapack: bad z value")
+               }
+               d += z[k]
+               e += z[k+1]
+               qmax = math.Max(qmax, z[k])
+               emin = math.Min(emin, z[k+1])
+       }
+       if z[2*(n-1)] < 0 {
+               panic("lapack: bad z value")
+       }
+       d += z[2*(n-1)]
+       qmax = math.Max(qmax, z[2*(n-1)])
+       // Check for diagonality.
+       if e == 0 {
+               for k := 1; k < n; k++ {
+                       z[k] = z[2*k]
+               }
+               impl.Dlasrt(lapack.SortDecreasing, n, z)
+               z[2*(n-1)] = d
+               return info
+       }
+       trace := d + e
+       // Check for zero data.
+       if trace == 0 {
+               z[2*(n-1)] = 0
+               return info
+       }
+       // Rearrange data for locality: Z=(q1,qq1,e1,ee1,q2,qq2,e2,ee2,...).
+       for k := 2 * n; k >= 2; k -= 2 {
+               z[2*k-1] = 0
+               z[2*k-2] = z[k-1]
+               z[2*k-3] = 0
+               z[2*k-4] = z[k-2]
+       }
+       i0 := 0
+       n0 := n - 1
+
+       // Reverse the qd-array, if warranted.
+       // z[4*i0-3] --> z[4*(i0+1)-3-1] --> z[4*i0]
+       if cbias*z[4*i0] < z[4*n0] {
+               ipn4Out := 4 * (i0 + n0 + 2)
+               for i4loop := 4 * (i0 + 1); i4loop <= 2*(i0+n0+1); i4loop += 4 {
+                       i4 := i4loop - 1
+                       ipn4 := ipn4Out - 1
+                       z[i4-3], z[ipn4-i4-4] = z[ipn4-i4-4], z[i4-3]
+                       z[i4-1], z[ipn4-i4-6] = z[ipn4-i4-6], z[i4-1]
+               }
+       }
+
+       // Initial split checking via dqd and Li's test.
+       pp := 0
+       for k := 0; k < 2; k++ {
+               d = z[4*n0+pp]
+               for i4loop := 4*n0 + pp; i4loop >= 4*(i0+1)+pp; i4loop -= 4 {
+                       i4 := i4loop - 1
+                       if z[i4-1] <= tol2*d {
+                               z[i4-1] = math.Copysign(0, -1)
+                               d = z[i4-3]
+                       } else {
+                               d = z[i4-3] * (d / (d + z[i4-1]))
+                       }
+               }
+               // dqd maps Z to ZZ plus Li's test.
+               emin = z[4*(i0+1)+pp]
+               d = z[4*i0+pp]
+               for i4loop := 4*(i0+1) + pp; i4loop <= 4*n0+pp; i4loop += 4 {
+                       i4 := i4loop - 1
+                       z[i4-2*pp-2] = d + z[i4-1]
+                       if z[i4-1] <= tol2*d {
+                               z[i4-1] = math.Copysign(0, -1)
+                               z[i4-2*pp-2] = d
+                               z[i4-2*pp] = 0
+                               d = z[i4+1]
+                       } else if safmin*z[i4+1] < z[i4-2*pp-2] && safmin*z[i4-2*pp-2] < z[i4+1] {
+                               tmp := z[i4+1] / z[i4-2*pp-2]
+                               z[i4-2*pp] = z[i4-1] * tmp
+                               d *= tmp
+                       } else {
+                               z[i4-2*pp] = z[i4+1] * (z[i4-1] / z[i4-2*pp-2])
+                               d = z[i4+1] * (d / z[i4-2*pp-2])
+                       }
+                       emin = math.Min(emin, z[i4-2*pp])
+               }
+               z[4*(n0+1)-pp-3] = d
+
+               // Now find qmax.
+               qmax = z[4*(i0+1)-pp-3]
+               for i4loop := 4*(i0+1) - pp + 2; i4loop <= 4*(n0+1)+pp-2; i4loop += 4 {
+                       i4 := i4loop - 1
+                       qmax = math.Max(qmax, z[i4])
+               }
+               // Prepare for the next iteration on K.
+               pp = 1 - pp
+       }
+
+       // Initialise variables to pass to DLASQ3.
+       var ttype int
+       var dmin1, dmin2, dn, dn1, dn2, g, tau float64
+       var tempq float64
+       iter := 2
+       var nFail int
+       nDiv := 2 * (n0 - i0)
+       var i4 int
+outer:
+       for iwhila := 1; iwhila <= n+1; iwhila++ {
+               // Test for completion.
+               if n0 < 0 {
+                       // Move q's to the front.
+                       for k := 1; k < n; k++ {
+                               z[k] = z[4*k]
+                       }
+                       // Sort and compute sum of eigenvalues.
+                       impl.Dlasrt(lapack.SortDecreasing, n, z)
+                       e = 0
+                       for k := n - 1; k >= 0; k-- {
+                               e += z[k]
+                       }
+                       // Store trace, sum(eigenvalues) and information on performance.
+                       z[2*n] = trace
+                       z[2*n+1] = e
+                       z[2*n+2] = float64(iter)
+                       z[2*n+3] = float64(nDiv) / float64(n*n)
+                       z[2*n+4] = 100 * float64(nFail) / float64(iter)
+                       return info
+               }
+
+               // While array unfinished do
+               // e[n0] holds the value of sigma when submatrix in i0:n0
+               // splits from the rest of the array, but is negated.
+               var desig float64
+               var sigma float64
+               if n0 != n-1 {
+                       sigma = -z[4*(n0+1)-2]
+               }
+               if sigma < 0 {
+                       info = 1
+                       return info
+               }
+               // Find last unreduced submatrix's top index i0, find qmax and
+               // emin. Find Gershgorin-type bound if Q's much greater than E's.
+               var emax float64
+               if n0 > i0 {
+                       emin = math.Abs(z[4*(n0+1)-6])
+               } else {
+                       emin = 0
+               }
+               qmin := z[4*(n0+1)-4]
+               qmax = qmin
+               zSmall := false
+               for i4loop := 4 * (n0 + 1); i4loop >= 8; i4loop -= 4 {
+                       i4 = i4loop - 1
+                       if z[i4-5] <= 0 {
+                               zSmall = true
+                               break
+                       }
+                       if qmin >= 4*emax {
+                               qmin = math.Min(qmin, z[i4-3])
+                               emax = math.Max(emax, z[i4-5])
+                       }
+                       qmax = math.Max(qmax, z[i4-7]+z[i4-5])
+                       emin = math.Min(emin, z[i4-5])
+               }
+               if !zSmall {
+                       i4 = 3
+               }
+               i0 = (i4+1)/4 - 1
+               pp = 0
+               if n0-i0 > 1 {
+                       dee := z[4*i0]
+                       deemin := dee
+                       kmin := i0
+                       for i4loop := 4*(i0+1) + 1; i4loop <= 4*(n0+1)-3; i4loop += 4 {
+                               i4 := i4loop - 1
+                               dee = z[i4] * (dee / (dee + z[i4-2]))
+                               if dee <= deemin {
+                                       deemin = dee
+                                       kmin = (i4+4)/4 - 1
+                               }
+                       }
+                       if (kmin-i0)*2 < n0-kmin && deemin <= 0.5*z[4*n0] {
+                               ipn4Out := 4 * (i0 + n0 + 2)
+                               pp = 2
+                               for i4loop := 4 * (i0 + 1); i4loop <= 2*(i0+n0+1); i4loop += 4 {
+                                       i4 := i4loop - 1
+                                       ipn4 := ipn4Out - 1
+                                       z[i4-3], z[ipn4-i4-4] = z[ipn4-i4-4], z[i4-3]
+                                       z[i4-2], z[ipn4-i4-3] = z[ipn4-i4-3], z[i4-2]
+                                       z[i4-1], z[ipn4-i4-6] = z[ipn4-i4-6], z[i4-1]
+                                       z[i4], z[ipn4-i4-5] = z[ipn4-i4-5], z[i4]
+                               }
+                       }
+               }
+               // Put -(initial shift) into DMIN.
+               dmin := -math.Max(0, qmin-2*math.Sqrt(qmin)*math.Sqrt(emax))
+
+               // Now i0:n0 is unreduced.
+               // PP = 0 for ping, PP = 1 for pong.
+               // PP = 2 indicates that flipping was applied to the Z array and
+               //              and that the tests for deflation upon entry in Dlasq3
+               //              should not be performed.
+               nbig := 100 * (n0 - i0 + 1)
+               for iwhilb := 0; iwhilb < nbig; iwhilb++ {
+                       if i0 > n0 {
+                               continue outer
+                       }
+
+                       // While submatrix unfinished take a good dqds step.
+                       i0, n0, pp, dmin, sigma, desig, qmax, nFail, iter, nDiv, ttype, dmin1, dmin2, dn, dn1, dn2, g, tau =
+                               impl.Dlasq3(i0, n0, z, pp, dmin, sigma, desig, qmax, nFail, iter, nDiv, ttype, dmin1, dmin2, dn, dn1, dn2, g, tau)
+
+                       pp = 1 - pp
+                       // When emin is very small check for splits.
+                       if pp == 0 && n0-i0 >= 3 {
+                               if z[4*(n0+1)-1] <= tol2*qmax || z[4*(n0+1)-2] <= tol2*sigma {
+                                       splt := i0 - 1
+                                       qmax = z[4*i0]
+                                       emin = z[4*(i0+1)-2]
+                                       oldemn := z[4*(i0+1)-1]
+                                       for i4loop := 4 * (i0 + 1); i4loop <= 4*(n0-2); i4loop += 4 {
+                                               i4 := i4loop - 1
+                                               if z[i4] <= tol2*z[i4-3] || z[i4-1] <= tol2*sigma {
+                                                       z[i4-1] = -sigma
+                                                       splt = i4 / 4
+                                                       qmax = 0
+                                                       emin = z[i4+3]
+                                                       oldemn = z[i4+4]
+                                               } else {
+                                                       qmax = math.Max(qmax, z[i4+1])
+                                                       emin = math.Min(emin, z[i4-1])
+                                                       oldemn = math.Min(oldemn, z[i4])
+                                               }
+                                       }
+                                       z[4*(n0+1)-2] = emin
+                                       z[4*(n0+1)-1] = oldemn
+                                       i0 = splt + 1
+                               }
+                       }
+               }
+               // Maximum number of iterations exceeded, restore the shift
+               // sigma and place the new d's and e's in a qd array.
+               // This might need to be done for several blocks.
+               info = 2
+               i1 = i0
+               n1 = n0
+               for {
+                       tempq = z[4*i0]
+                       z[4*i0] += sigma
+                       for k := i0 + 1; k <= n0; k++ {
+                               tempe := z[4*(k+1)-6]
+                               z[4*(k+1)-6] *= tempq / z[4*(k+1)-8]
+                               tempq = z[4*k]
+                               z[4*k] += sigma + tempe - z[4*(k+1)-6]
+                       }
+                       // Prepare to do this on the previous block if there is one.
+                       if i1 <= 0 {
+                               break
+                       }
+                       n1 = i1 - 1
+                       for i1 >= 1 && z[4*(i1+1)-6] >= 0 {
+                               i1 -= 1
+                       }
+                       sigma = -z[4*(n1+1)-2]
+               }
+               for k := 0; k < n; k++ {
+                       z[2*k] = z[4*k]
+                       // Only the block 1..N0 is unfinished.  The rest of the e's
+                       // must be essentially zero, although sometimes other data
+                       // has been stored in them.
+                       if k < n0 {
+                               z[2*(k+1)-1] = z[4*(k+1)-1]
+                       } else {
+                               z[2*(k+1)] = 0
+                       }
+               }
+               return info
+       }
+       info = 3
+       return info
+}