OSDN Git Service

test (#52)
[bytom/vapor.git] / vendor / gonum.org / v1 / gonum / lapack / gonum / dlaln2.go
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^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 }