github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/dlasq4.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 "math"
     8  
     9  // Dlasq4 computes an approximation to the smallest eigenvalue using values of d
    10  // from the previous transform.
    11  // i0, n0, and n0in are zero-indexed.
    12  //
    13  // Dlasq4 is an internal routine. It is exported for testing purposes.
    14  func (impl Implementation) Dlasq4(i0, n0 int, z []float64, pp int, n0in int, dmin, dmin1, dmin2, dn, dn1, dn2, tau float64, ttype int, g float64) (tauOut float64, ttypeOut int, gOut float64) {
    15  	const (
    16  		cnst1 = 0.563
    17  		cnst2 = 1.01
    18  		cnst3 = 1.05
    19  
    20  		cnstthird = 0.333 // TODO(btracey): Fix?
    21  	)
    22  	// A negative dmin forces the shift to take that absolute value
    23  	// ttype records the type of shift.
    24  	if dmin <= 0 {
    25  		tau = -dmin
    26  		ttype = -1
    27  		return tau, ttype, g
    28  	}
    29  	nn := 4*(n0+1) + pp - 1 // -1 for zero indexing
    30  	s := math.NaN()         // Poison s so that failure to take a path below is obvious
    31  	if n0in == n0 {
    32  		// No eigenvalues deflated.
    33  		if dmin == dn || dmin == dn1 {
    34  			b1 := math.Sqrt(z[nn-3]) * math.Sqrt(z[nn-5])
    35  			b2 := math.Sqrt(z[nn-7]) * math.Sqrt(z[nn-9])
    36  			a2 := z[nn-7] + z[nn-5]
    37  			if dmin == dn && dmin1 == dn1 {
    38  				gap2 := dmin2 - a2 - dmin2/4
    39  				var gap1 float64
    40  				if gap2 > 0 && gap2 > b2 {
    41  					gap1 = a2 - dn - (b2/gap2)*b2
    42  				} else {
    43  					gap1 = a2 - dn - (b1 + b2)
    44  				}
    45  				if gap1 > 0 && gap1 > b1 {
    46  					s = math.Max(dn-(b1/gap1)*b1, 0.5*dmin)
    47  					ttype = -2
    48  				} else {
    49  					s = 0
    50  					if dn > b1 {
    51  						s = dn - b1
    52  					}
    53  					if a2 > b1+b2 {
    54  						s = math.Min(s, a2-(b1+b2))
    55  					}
    56  					s = math.Max(s, cnstthird*dmin)
    57  					ttype = -3
    58  				}
    59  			} else {
    60  				ttype = -4
    61  				s = dmin / 4
    62  				var gam float64
    63  				var np int
    64  				if dmin == dn {
    65  					gam = dn
    66  					a2 = 0
    67  					if z[nn-5] > z[nn-7] {
    68  						return tau, ttype, g
    69  					}
    70  					b2 = z[nn-5] / z[nn-7]
    71  					np = nn - 9
    72  				} else {
    73  					np = nn - 2*pp
    74  					b2 = z[np-2]
    75  					gam = dn1
    76  					if z[np-4] > z[np-2] {
    77  						return tau, ttype, g
    78  					}
    79  					a2 = z[np-4] / z[np-2]
    80  					if z[nn-9] > z[nn-11] {
    81  						return tau, ttype, g
    82  					}
    83  					b2 = z[nn-9] / z[nn-11]
    84  					np = nn - 13
    85  				}
    86  				// Approximate contribution to norm squared from i < nn-1.
    87  				a2 += b2
    88  				for i4loop := np + 1; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 {
    89  					i4 := i4loop - 1
    90  					if b2 == 0 {
    91  						break
    92  					}
    93  					b1 = b2
    94  					if z[i4] > z[i4-2] {
    95  						return tau, ttype, g
    96  					}
    97  					b2 *= z[i4] / z[i4-2]
    98  					a2 += b2
    99  					if 100*math.Max(b2, b1) < a2 || cnst1 < a2 {
   100  						break
   101  					}
   102  				}
   103  				a2 *= cnst3
   104  				// Rayleigh quotient residual bound.
   105  				if a2 < cnst1 {
   106  					s = gam * (1 - math.Sqrt(a2)) / (1 + a2)
   107  				}
   108  			}
   109  		} else if dmin == dn2 {
   110  			ttype = -5
   111  			s = dmin / 4
   112  			// Compute contribution to norm squared from i > nn-2.
   113  			np := nn - 2*pp
   114  			b1 := z[np-2]
   115  			b2 := z[np-6]
   116  			gam := dn2
   117  			if z[np-8] > b2 || z[np-4] > b1 {
   118  				return tau, ttype, g
   119  			}
   120  			a2 := (z[np-8] / b2) * (1 + z[np-4]/b1)
   121  			// Approximate contribution to norm squared from i < nn-2.
   122  			if n0-i0 > 2 {
   123  				b2 = z[nn-13] / z[nn-15]
   124  				a2 += b2
   125  				for i4loop := (nn + 1) - 17; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 {
   126  					i4 := i4loop - 1
   127  					if b2 == 0 {
   128  						break
   129  					}
   130  					b1 = b2
   131  					if z[i4] > z[i4-2] {
   132  						return tau, ttype, g
   133  					}
   134  					b2 *= z[i4] / z[i4-2]
   135  					a2 += b2
   136  					if 100*math.Max(b2, b1) < a2 || cnst1 < a2 {
   137  						break
   138  					}
   139  				}
   140  				a2 *= cnst3
   141  			}
   142  			if a2 < cnst1 {
   143  				s = gam * (1 - math.Sqrt(a2)) / (1 + a2)
   144  			}
   145  		} else {
   146  			// Case 6, no information to guide us.
   147  			if ttype == -6 {
   148  				g += cnstthird * (1 - g)
   149  			} else if ttype == -18 {
   150  				g = cnstthird / 4
   151  			} else {
   152  				g = 1.0 / 4
   153  			}
   154  			s = g * dmin
   155  			ttype = -6
   156  		}
   157  	} else if n0in == (n0 + 1) {
   158  		// One eigenvalue just deflated. Use DMIN1, DN1 for DMIN and DN.
   159  		if dmin1 == dn1 && dmin2 == dn2 {
   160  			ttype = -7
   161  			s = cnstthird * dmin1
   162  			if z[nn-5] > z[nn-7] {
   163  				return tau, ttype, g
   164  			}
   165  			b1 := z[nn-5] / z[nn-7]
   166  			b2 := b1
   167  			if b2 != 0 {
   168  				for i4loop := 4*(n0+1) - 9 + pp; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 {
   169  					i4 := i4loop - 1
   170  					a2 := b1
   171  					if z[i4] > z[i4-2] {
   172  						return tau, ttype, g
   173  					}
   174  					b1 *= z[i4] / z[i4-2]
   175  					b2 += b1
   176  					if 100*math.Max(b1, a2) < b2 {
   177  						break
   178  					}
   179  				}
   180  			}
   181  			b2 = math.Sqrt(cnst3 * b2)
   182  			a2 := dmin1 / (1 + b2*b2)
   183  			gap2 := 0.5*dmin2 - a2
   184  			if gap2 > 0 && gap2 > b2*a2 {
   185  				s = math.Max(s, a2*(1-cnst2*a2*(b2/gap2)*b2))
   186  			} else {
   187  				s = math.Max(s, a2*(1-cnst2*b2))
   188  				ttype = -8
   189  			}
   190  		} else {
   191  			s = dmin1 / 4
   192  			if dmin1 == dn1 {
   193  				s = 0.5 * dmin1
   194  			}
   195  			ttype = -9
   196  		}
   197  	} else if n0in == (n0 + 2) {
   198  		// Two eigenvalues deflated. Use DMIN2, DN2 for DMIN and DN.
   199  		if dmin2 == dn2 && 2*z[nn-5] < z[nn-7] {
   200  			ttype = -10
   201  			s = cnstthird * dmin2
   202  			if z[nn-5] > z[nn-7] {
   203  				return tau, ttype, g
   204  			}
   205  			b1 := z[nn-5] / z[nn-7]
   206  			b2 := b1
   207  			if b2 != 0 {
   208  				for i4loop := 4*(n0+1) - 9 + pp; i4loop >= 4*(i0+1)-1+pp; i4loop -= 4 {
   209  					i4 := i4loop - 1
   210  					if z[i4] > z[i4-2] {
   211  						return tau, ttype, g
   212  					}
   213  					b1 *= z[i4] / z[i4-2]
   214  					b2 += b1
   215  					if 100*b1 < b2 {
   216  						break
   217  					}
   218  				}
   219  			}
   220  			b2 = math.Sqrt(cnst3 * b2)
   221  			a2 := dmin2 / (1 + b2*b2)
   222  			gap2 := z[nn-7] + z[nn-9] - math.Sqrt(z[nn-11])*math.Sqrt(z[nn-9]) - a2
   223  			if gap2 > 0 && gap2 > b2*a2 {
   224  				s = math.Max(s, a2*(1-cnst2*a2*(b2/gap2)*b2))
   225  			} else {
   226  				s = math.Max(s, a2*(1-cnst2*b2))
   227  			}
   228  		} else {
   229  			s = dmin2 / 4
   230  			ttype = -11
   231  		}
   232  	} else if n0in > n0+2 {
   233  		// Case 12, more than two eigenvalues deflated. No information.
   234  		s = 0
   235  		ttype = -12
   236  	}
   237  	tau = s
   238  	return tau, ttype, g
   239  }