github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/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 native 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^T - 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 if na != 1 && na != 2 { 61 panic("lapack: invalid value of na") 62 } 63 if nw != 1 && nw != 2 { 64 panic("lapack: invalid value of nw") 65 } 66 checkMatrix(na, na, a, lda) 67 checkMatrix(na, nw, b, ldb) 68 checkMatrix(na, nw, x, ldx) 69 70 smlnum := 2 * dlamchS 71 bignum := 1 / smlnum 72 smini := math.Max(smin, smlnum) 73 74 ok = true 75 scale = 1 76 77 if na == 1 { 78 // 1×1 (i.e., scalar) system C X = B. 79 80 if nw == 1 { 81 // Real 1×1 system. 82 83 // C = ca A - w D. 84 csr := ca*a[0] - wr*d1 85 cnorm := math.Abs(csr) 86 87 // If |C| < smini, use C = smini. 88 if cnorm < smini { 89 csr = smini 90 cnorm = smini 91 ok = false 92 } 93 94 // Check scaling for X = B / C. 95 bnorm := math.Abs(b[0]) 96 if cnorm < 1 && bnorm > math.Max(1, bignum*cnorm) { 97 scale = 1 / bnorm 98 } 99 100 // Compute X. 101 x[0] = b[0] * scale / csr 102 xnorm = math.Abs(x[0]) 103 104 return scale, xnorm, ok 105 } 106 107 // Complex 1×1 system (w is complex). 108 109 // C = ca A - w D. 110 csr := ca*a[0] - wr*d1 111 csi := -wi * d1 112 cnorm := math.Abs(csr) + math.Abs(csi) 113 114 // If |C| < smini, use C = smini. 115 if cnorm < smini { 116 csr = smini 117 csi = 0 118 cnorm = smini 119 ok = false 120 } 121 122 // Check scaling for X = B / C. 123 bnorm := math.Abs(b[0]) + math.Abs(b[1]) 124 if cnorm < 1 && bnorm > math.Max(1, bignum*cnorm) { 125 scale = 1 / bnorm 126 } 127 128 // Compute X. 129 cx := complex(scale*b[0], scale*b[1]) / complex(csr, csi) 130 x[0], x[1] = real(cx), imag(cx) 131 xnorm = math.Abs(x[0]) + math.Abs(x[1]) 132 133 return scale, xnorm, ok 134 } 135 136 // 2×2 system. 137 138 // Compute the real part of 139 // C = ca A - w D 140 // or 141 // C = ca A^T - w D. 142 crv := [4]float64{ 143 ca*a[0] - wr*d1, 144 ca * a[1], 145 ca * a[lda], 146 ca*a[lda+1] - wr*d2, 147 } 148 if trans { 149 crv[1] = ca * a[lda] 150 crv[2] = ca * a[1] 151 } 152 153 pivot := [4][4]int{ 154 {0, 1, 2, 3}, 155 {1, 0, 3, 2}, 156 {2, 3, 0, 1}, 157 {3, 2, 1, 0}, 158 } 159 160 if nw == 1 { 161 // Real 2×2 system (w is real). 162 163 // Find the largest element in C. 164 var cmax float64 165 var icmax int 166 for j, v := range crv { 167 v = math.Abs(v) 168 if v > cmax { 169 cmax = v 170 icmax = j 171 } 172 } 173 174 // If norm(C) < smini, use smini*identity. 175 if cmax < smini { 176 bnorm := math.Max(math.Abs(b[0]), math.Abs(b[ldb])) 177 if smini < 1 && bnorm > math.Max(1, bignum*smini) { 178 scale = 1 / bnorm 179 } 180 temp := scale / smini 181 x[0] = temp * b[0] 182 x[ldx] = temp * b[ldb] 183 xnorm = temp * bnorm 184 ok = false 185 186 return scale, xnorm, ok 187 } 188 189 // Gaussian elimination with complete pivoting. 190 // Form upper triangular matrix 191 // [ur11 ur12] 192 // [ 0 ur22] 193 ur11 := crv[icmax] 194 ur12 := crv[pivot[icmax][1]] 195 cr21 := crv[pivot[icmax][2]] 196 cr22 := crv[pivot[icmax][3]] 197 ur11r := 1 / ur11 198 lr21 := ur11r * cr21 199 ur22 := cr22 - ur12*lr21 200 201 // If smaller pivot < smini, use smini. 202 if math.Abs(ur22) < smini { 203 ur22 = smini 204 ok = false 205 } 206 207 var br1, br2 float64 208 if icmax > 1 { 209 // If the pivot lies in the second row, swap the rows. 210 br1 = b[ldb] 211 br2 = b[0] 212 } else { 213 br1 = b[0] 214 br2 = b[ldb] 215 } 216 br2 -= lr21 * br1 // Apply the Gaussian elimination step to the right-hand side. 217 218 bbnd := math.Max(math.Abs(ur22*ur11r*br1), math.Abs(br2)) 219 if bbnd > 1 && math.Abs(ur22) < 1 && bbnd >= bignum*math.Abs(ur22) { 220 scale = 1 / bbnd 221 } 222 223 // Solve the linear system ur*xr=br. 224 xr2 := br2 * scale / ur22 225 xr1 := scale*br1*ur11r - ur11r*ur12*xr2 226 if icmax&0x1 != 0 { 227 // If the pivot lies in the second column, swap the components of the solution. 228 x[0] = xr2 229 x[ldx] = xr1 230 } else { 231 x[0] = xr1 232 x[ldx] = xr2 233 } 234 xnorm = math.Max(math.Abs(xr1), math.Abs(xr2)) 235 236 // Further scaling if norm(A)*norm(X) > overflow. 237 if xnorm > 1 && cmax > 1 && xnorm > bignum/cmax { 238 temp := cmax / bignum 239 x[0] *= temp 240 x[ldx] *= temp 241 xnorm *= temp 242 scale *= temp 243 } 244 245 return scale, xnorm, ok 246 } 247 248 // Complex 2×2 system (w is complex). 249 250 // Find the largest element in C. 251 civ := [4]float64{ 252 -wi * d1, 253 0, 254 0, 255 -wi * d2, 256 } 257 var cmax float64 258 var icmax int 259 for j, v := range crv { 260 v := math.Abs(v) 261 if v+math.Abs(civ[j]) > cmax { 262 cmax = v + math.Abs(civ[j]) 263 icmax = j 264 } 265 } 266 267 // If norm(C) < smini, use smini*identity. 268 if cmax < smini { 269 br1 := math.Abs(b[0]) + math.Abs(b[1]) 270 br2 := math.Abs(b[ldb]) + math.Abs(b[ldb+1]) 271 bnorm := math.Max(br1, br2) 272 if smini < 1 && bnorm > 1 && bnorm > bignum*smini { 273 scale = 1 / bnorm 274 } 275 temp := scale / smini 276 x[0] = temp * b[0] 277 x[1] = temp * b[1] 278 x[ldb] = temp * b[ldb] 279 x[ldb+1] = temp * b[ldb+1] 280 xnorm = temp * bnorm 281 ok = false 282 283 return scale, xnorm, ok 284 } 285 286 // Gaussian elimination with complete pivoting. 287 ur11 := crv[icmax] 288 ui11 := civ[icmax] 289 ur12 := crv[pivot[icmax][1]] 290 ui12 := civ[pivot[icmax][1]] 291 cr21 := crv[pivot[icmax][2]] 292 ci21 := civ[pivot[icmax][2]] 293 cr22 := crv[pivot[icmax][3]] 294 ci22 := civ[pivot[icmax][3]] 295 var ( 296 ur11r, ui11r float64 297 lr21, li21 float64 298 ur12s, ui12s float64 299 ur22, ui22 float64 300 ) 301 if icmax == 0 || icmax == 3 { 302 // Off-diagonals of pivoted C are real. 303 if math.Abs(ur11) > math.Abs(ui11) { 304 temp := ui11 / ur11 305 ur11r = 1 / (ur11 * (1 + temp*temp)) 306 ui11r = -temp * ur11r 307 } else { 308 temp := ur11 / ui11 309 ui11r = -1 / (ui11 * (1 + temp*temp)) 310 ur11r = -temp * ui11r 311 } 312 lr21 = cr21 * ur11r 313 li21 = cr21 * ui11r 314 ur12s = ur12 * ur11r 315 ui12s = ur12 * ui11r 316 ur22 = cr22 - ur12*lr21 317 ui22 = ci22 - ur12*li21 318 } else { 319 // Diagonals of pivoted C are real. 320 ur11r = 1 / ur11 321 // ui11r is already 0. 322 lr21 = cr21 * ur11r 323 li21 = ci21 * ur11r 324 ur12s = ur12 * ur11r 325 ui12s = ui12 * ur11r 326 ur22 = cr22 - ur12*lr21 + ui12*li21 327 ui22 = -ur12*li21 - ui12*lr21 328 } 329 u22abs := math.Abs(ur22) + math.Abs(ui22) 330 331 // If smaller pivot < smini, use smini. 332 if u22abs < smini { 333 ur22 = smini 334 ui22 = 0 335 ok = false 336 } 337 338 var br1, bi1 float64 339 var br2, bi2 float64 340 if icmax > 1 { 341 // If the pivot lies in the second row, swap the rows. 342 br1 = b[ldb] 343 bi1 = b[ldb+1] 344 br2 = b[0] 345 bi2 = b[1] 346 } else { 347 br1 = b[0] 348 bi1 = b[1] 349 br2 = b[ldb] 350 bi2 = b[ldb+1] 351 } 352 br2 += -lr21*br1 + li21*bi1 353 bi2 += -li21*br1 - lr21*bi1 354 355 bbnd1 := u22abs * (math.Abs(ur11r) + math.Abs(ui11r)) * (math.Abs(br1) + math.Abs(bi1)) 356 bbnd2 := math.Abs(br2) + math.Abs(bi2) 357 bbnd := math.Max(bbnd1, bbnd2) 358 if bbnd > 1 && u22abs < 1 && bbnd >= bignum*u22abs { 359 scale = 1 / bbnd 360 br1 *= scale 361 bi1 *= scale 362 br2 *= scale 363 bi2 *= scale 364 } 365 366 cx2 := complex(br2, bi2) / complex(ur22, ui22) 367 xr2, xi2 := real(cx2), imag(cx2) 368 xr1 := ur11r*br1 - ui11r*bi1 - ur12s*xr2 + ui12s*xi2 369 xi1 := ui11r*br1 + ur11r*bi1 - ui12s*xr2 - ur12s*xi2 370 if icmax&0x1 != 0 { 371 // If the pivot lies in the second column, swap the components of the solution. 372 x[0] = xr2 373 x[1] = xi2 374 x[ldx] = xr1 375 x[ldx+1] = xi1 376 } else { 377 x[0] = xr1 378 x[1] = xi1 379 x[ldx] = xr2 380 x[ldx+1] = xi2 381 } 382 xnorm = math.Max(math.Abs(xr1)+math.Abs(xi1), math.Abs(xr2)+math.Abs(xi2)) 383 384 // Further scaling if norm(A)*norm(X) > overflow. 385 if xnorm > 1 && cmax > 1 && xnorm > bignum/cmax { 386 temp := cmax / bignum 387 x[0] *= temp 388 x[1] *= temp 389 x[ldx] *= temp 390 x[ldx+1] *= temp 391 xnorm *= temp 392 scale *= temp 393 } 394 395 return scale, xnorm, ok 396 }