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