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 }