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 }