github.com/gopherd/gonum@v0.0.4/lapack/gonum/dlaln2.go (about) 1 // Copyright ©2016 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 // Dlaln2 solves a linear equation or a system of 2 linear equations of the form 10 // (ca A - w D) X = scale B if trans == false, 11 // (ca Aᵀ - w D) X = scale B if trans == true, 12 // where A is a na×na real matrix, ca is a real scalar, D is a na×na diagonal 13 // real matrix, w is a scalar, real if nw == 1, complex if nw == 2, and X and B 14 // are na×1 matrices, real if w is real, complex if w is complex. 15 // 16 // If w is complex, X and B are represented as na×2 matrices, the first column 17 // of each being the real part and the second being the imaginary part. 18 // 19 // na and nw must be 1 or 2, otherwise Dlaln2 will panic. 20 // 21 // d1 and d2 are the diagonal elements of D. d2 is not used if na == 1. 22 // 23 // wr and wi represent the real and imaginary part, respectively, of the scalar 24 // w. wi is not used if nw == 1. 25 // 26 // smin is the desired lower bound on the singular values of A. This should be 27 // a safe distance away from underflow or overflow, say, between 28 // (underflow/machine precision) and (overflow*machine precision). 29 // 30 // If both singular values of (ca A - w D) are less than smin, smin*identity 31 // will be used instead of (ca A - w D). If only one singular value is less than 32 // smin, one element of (ca A - w D) will be perturbed enough to make the 33 // smallest singular value roughly smin. If both singular values are at least 34 // smin, (ca A - w D) will not be perturbed. In any case, the perturbation will 35 // be at most some small multiple of max(smin, ulp*norm(ca A - w D)). The 36 // singular values are computed by infinity-norm approximations, and thus will 37 // only be correct to a factor of 2 or so. 38 // 39 // All input quantities are assumed to be smaller than overflow by a reasonable 40 // factor. 41 // 42 // scale is a scaling factor less than or equal to 1 which is chosen so that X 43 // can be computed without overflow. X is further scaled if necessary to assure 44 // that norm(ca A - w D)*norm(X) is less than overflow. 45 // 46 // xnorm contains the infinity-norm of X when X is regarded as a na×nw real 47 // matrix. 48 // 49 // ok will be false if (ca A - w D) had to be perturbed to make its smallest 50 // singular value greater than smin, otherwise ok will be true. 51 // 52 // Dlaln2 is an internal routine. It is exported for testing purposes. 53 func (impl Implementation) Dlaln2(trans bool, na, nw int, smin, ca float64, a []float64, lda int, d1, d2 float64, b []float64, ldb int, wr, wi float64, x []float64, ldx int) (scale, xnorm float64, ok bool) { 54 // TODO(vladimir-ch): Consider splitting this function into two, one 55 // handling the real case (nw == 1) and the other handling the complex 56 // case (nw == 2). Given that Go has complex types, their signatures 57 // would be simpler and more natural, and the implementation not as 58 // convoluted. 59 60 switch { 61 case na != 1 && na != 2: 62 panic(badNa) 63 case nw != 1 && nw != 2: 64 panic(badNw) 65 case lda < na: 66 panic(badLdA) 67 case len(a) < (na-1)*lda+na: 68 panic(shortA) 69 case ldb < nw: 70 panic(badLdB) 71 case len(b) < (na-1)*ldb+nw: 72 panic(shortB) 73 case ldx < nw: 74 panic(badLdX) 75 case len(x) < (na-1)*ldx+nw: 76 panic(shortX) 77 } 78 79 smlnum := 2 * dlamchS 80 bignum := 1 / smlnum 81 smini := math.Max(smin, smlnum) 82 83 ok = true 84 scale = 1 85 86 if na == 1 { 87 // 1×1 (i.e., scalar) system C X = B. 88 89 if nw == 1 { 90 // Real 1×1 system. 91 92 // C = ca A - w D. 93 csr := ca*a[0] - wr*d1 94 cnorm := math.Abs(csr) 95 96 // If |C| < smini, use C = smini. 97 if cnorm < smini { 98 csr = smini 99 cnorm = smini 100 ok = false 101 } 102 103 // Check scaling for X = B / C. 104 bnorm := math.Abs(b[0]) 105 if cnorm < 1 && bnorm > math.Max(1, bignum*cnorm) { 106 scale = 1 / bnorm 107 } 108 109 // Compute X. 110 x[0] = b[0] * scale / csr 111 xnorm = math.Abs(x[0]) 112 113 return scale, xnorm, ok 114 } 115 116 // Complex 1×1 system (w is complex). 117 118 // C = ca A - w D. 119 csr := ca*a[0] - wr*d1 120 csi := -wi * d1 121 cnorm := math.Abs(csr) + math.Abs(csi) 122 123 // If |C| < smini, use C = smini. 124 if cnorm < smini { 125 csr = smini 126 csi = 0 127 cnorm = smini 128 ok = false 129 } 130 131 // Check scaling for X = B / C. 132 bnorm := math.Abs(b[0]) + math.Abs(b[1]) 133 if cnorm < 1 && bnorm > math.Max(1, bignum*cnorm) { 134 scale = 1 / bnorm 135 } 136 137 // Compute X. 138 cx := complex(scale*b[0], scale*b[1]) / complex(csr, csi) 139 x[0], x[1] = real(cx), imag(cx) 140 xnorm = math.Abs(x[0]) + math.Abs(x[1]) 141 142 return scale, xnorm, ok 143 } 144 145 // 2×2 system. 146 147 // Compute the real part of 148 // C = ca A - w D 149 // or 150 // C = ca Aᵀ - w D. 151 crv := [4]float64{ 152 ca*a[0] - wr*d1, 153 ca * a[1], 154 ca * a[lda], 155 ca*a[lda+1] - wr*d2, 156 } 157 if trans { 158 crv[1] = ca * a[lda] 159 crv[2] = ca * a[1] 160 } 161 162 pivot := [4][4]int{ 163 {0, 1, 2, 3}, 164 {1, 0, 3, 2}, 165 {2, 3, 0, 1}, 166 {3, 2, 1, 0}, 167 } 168 169 if nw == 1 { 170 // Real 2×2 system (w is real). 171 172 // Find the largest element in C. 173 var cmax float64 174 var icmax int 175 for j, v := range crv { 176 v = math.Abs(v) 177 if v > cmax { 178 cmax = v 179 icmax = j 180 } 181 } 182 183 // If norm(C) < smini, use smini*identity. 184 if cmax < smini { 185 bnorm := math.Max(math.Abs(b[0]), math.Abs(b[ldb])) 186 if smini < 1 && bnorm > math.Max(1, bignum*smini) { 187 scale = 1 / bnorm 188 } 189 temp := scale / smini 190 x[0] = temp * b[0] 191 x[ldx] = temp * b[ldb] 192 xnorm = temp * bnorm 193 ok = false 194 195 return scale, xnorm, ok 196 } 197 198 // Gaussian elimination with complete pivoting. 199 // Form upper triangular matrix 200 // [ur11 ur12] 201 // [ 0 ur22] 202 ur11 := crv[icmax] 203 ur12 := crv[pivot[icmax][1]] 204 cr21 := crv[pivot[icmax][2]] 205 cr22 := crv[pivot[icmax][3]] 206 ur11r := 1 / ur11 207 lr21 := ur11r * cr21 208 ur22 := cr22 - ur12*lr21 209 210 // If smaller pivot < smini, use smini. 211 if math.Abs(ur22) < smini { 212 ur22 = smini 213 ok = false 214 } 215 216 var br1, br2 float64 217 if icmax > 1 { 218 // If the pivot lies in the second row, swap the rows. 219 br1 = b[ldb] 220 br2 = b[0] 221 } else { 222 br1 = b[0] 223 br2 = b[ldb] 224 } 225 br2 -= lr21 * br1 // Apply the Gaussian elimination step to the right-hand side. 226 227 bbnd := math.Max(math.Abs(ur22*ur11r*br1), math.Abs(br2)) 228 if bbnd > 1 && math.Abs(ur22) < 1 && bbnd >= bignum*math.Abs(ur22) { 229 scale = 1 / bbnd 230 } 231 232 // Solve the linear system ur*xr=br. 233 xr2 := br2 * scale / ur22 234 xr1 := scale*br1*ur11r - ur11r*ur12*xr2 235 if icmax&0x1 != 0 { 236 // If the pivot lies in the second column, swap the components of the solution. 237 x[0] = xr2 238 x[ldx] = xr1 239 } else { 240 x[0] = xr1 241 x[ldx] = xr2 242 } 243 xnorm = math.Max(math.Abs(xr1), math.Abs(xr2)) 244 245 // Further scaling if norm(A)*norm(X) > overflow. 246 if xnorm > 1 && cmax > 1 && xnorm > bignum/cmax { 247 temp := cmax / bignum 248 x[0] *= temp 249 x[ldx] *= temp 250 xnorm *= temp 251 scale *= temp 252 } 253 254 return scale, xnorm, ok 255 } 256 257 // Complex 2×2 system (w is complex). 258 259 // Find the largest element in C. 260 civ := [4]float64{ 261 -wi * d1, 262 0, 263 0, 264 -wi * d2, 265 } 266 var cmax float64 267 var icmax int 268 for j, v := range crv { 269 v := math.Abs(v) 270 if v+math.Abs(civ[j]) > cmax { 271 cmax = v + math.Abs(civ[j]) 272 icmax = j 273 } 274 } 275 276 // If norm(C) < smini, use smini*identity. 277 if cmax < smini { 278 br1 := math.Abs(b[0]) + math.Abs(b[1]) 279 br2 := math.Abs(b[ldb]) + math.Abs(b[ldb+1]) 280 bnorm := math.Max(br1, br2) 281 if smini < 1 && bnorm > 1 && bnorm > bignum*smini { 282 scale = 1 / bnorm 283 } 284 temp := scale / smini 285 x[0] = temp * b[0] 286 x[1] = temp * b[1] 287 x[ldb] = temp * b[ldb] 288 x[ldb+1] = temp * b[ldb+1] 289 xnorm = temp * bnorm 290 ok = false 291 292 return scale, xnorm, ok 293 } 294 295 // Gaussian elimination with complete pivoting. 296 ur11 := crv[icmax] 297 ui11 := civ[icmax] 298 ur12 := crv[pivot[icmax][1]] 299 ui12 := civ[pivot[icmax][1]] 300 cr21 := crv[pivot[icmax][2]] 301 ci21 := civ[pivot[icmax][2]] 302 cr22 := crv[pivot[icmax][3]] 303 ci22 := civ[pivot[icmax][3]] 304 var ( 305 ur11r, ui11r float64 306 lr21, li21 float64 307 ur12s, ui12s float64 308 ur22, ui22 float64 309 ) 310 if icmax == 0 || icmax == 3 { 311 // Off-diagonals of pivoted C are real. 312 if math.Abs(ur11) > math.Abs(ui11) { 313 temp := ui11 / ur11 314 ur11r = 1 / (ur11 * (1 + temp*temp)) 315 ui11r = -temp * ur11r 316 } else { 317 temp := ur11 / ui11 318 ui11r = -1 / (ui11 * (1 + temp*temp)) 319 ur11r = -temp * ui11r 320 } 321 lr21 = cr21 * ur11r 322 li21 = cr21 * ui11r 323 ur12s = ur12 * ur11r 324 ui12s = ur12 * ui11r 325 ur22 = cr22 - ur12*lr21 326 ui22 = ci22 - ur12*li21 327 } else { 328 // Diagonals of pivoted C are real. 329 ur11r = 1 / ur11 330 // ui11r is already 0. 331 lr21 = cr21 * ur11r 332 li21 = ci21 * ur11r 333 ur12s = ur12 * ur11r 334 ui12s = ui12 * ur11r 335 ur22 = cr22 - ur12*lr21 + ui12*li21 336 ui22 = -ur12*li21 - ui12*lr21 337 } 338 u22abs := math.Abs(ur22) + math.Abs(ui22) 339 340 // If smaller pivot < smini, use smini. 341 if u22abs < smini { 342 ur22 = smini 343 ui22 = 0 344 ok = false 345 } 346 347 var br1, bi1 float64 348 var br2, bi2 float64 349 if icmax > 1 { 350 // If the pivot lies in the second row, swap the rows. 351 br1 = b[ldb] 352 bi1 = b[ldb+1] 353 br2 = b[0] 354 bi2 = b[1] 355 } else { 356 br1 = b[0] 357 bi1 = b[1] 358 br2 = b[ldb] 359 bi2 = b[ldb+1] 360 } 361 br2 += -lr21*br1 + li21*bi1 362 bi2 += -li21*br1 - lr21*bi1 363 364 bbnd1 := u22abs * (math.Abs(ur11r) + math.Abs(ui11r)) * (math.Abs(br1) + math.Abs(bi1)) 365 bbnd2 := math.Abs(br2) + math.Abs(bi2) 366 bbnd := math.Max(bbnd1, bbnd2) 367 if bbnd > 1 && u22abs < 1 && bbnd >= bignum*u22abs { 368 scale = 1 / bbnd 369 br1 *= scale 370 bi1 *= scale 371 br2 *= scale 372 bi2 *= scale 373 } 374 375 cx2 := complex(br2, bi2) / complex(ur22, ui22) 376 xr2, xi2 := real(cx2), imag(cx2) 377 xr1 := ur11r*br1 - ui11r*bi1 - ur12s*xr2 + ui12s*xi2 378 xi1 := ui11r*br1 + ur11r*bi1 - ui12s*xr2 - ur12s*xi2 379 if icmax&0x1 != 0 { 380 // If the pivot lies in the second column, swap the components of the solution. 381 x[0] = xr2 382 x[1] = xi2 383 x[ldx] = xr1 384 x[ldx+1] = xi1 385 } else { 386 x[0] = xr1 387 x[1] = xi1 388 x[ldx] = xr2 389 x[ldx+1] = xi2 390 } 391 xnorm = math.Max(math.Abs(xr1)+math.Abs(xi1), math.Abs(xr2)+math.Abs(xi2)) 392 393 // Further scaling if norm(A)*norm(X) > overflow. 394 if xnorm > 1 && cmax > 1 && xnorm > bignum/cmax { 395 temp := cmax / bignum 396 x[0] *= temp 397 x[1] *= temp 398 x[ldx] *= temp 399 x[ldx+1] *= temp 400 xnorm *= temp 401 scale *= temp 402 } 403 404 return scale, xnorm, ok 405 }