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