mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 15:16:59 +08:00
183 lines
5.0 KiB
Go
183 lines
5.0 KiB
Go
// Copyright ©2017 The gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package native
|
|
|
|
import "math"
|
|
|
|
// Dlags2 computes 2-by-2 orthogonal matrices U, V and Q with the
|
|
// triangles of A and B specified by upper.
|
|
//
|
|
// If upper is true
|
|
//
|
|
// U^T*A*Q = U^T*[ a1 a2 ]*Q = [ x 0 ]
|
|
// [ 0 a3 ] [ x x ]
|
|
// and
|
|
// V^T*B*Q = V^T*[ b1 b2 ]*Q = [ x 0 ]
|
|
// [ 0 b3 ] [ x x ]
|
|
//
|
|
// otherwise
|
|
//
|
|
// U^T*A*Q = U^T*[ a1 0 ]*Q = [ x x ]
|
|
// [ a2 a3 ] [ 0 x ]
|
|
// and
|
|
// V^T*B*Q = V^T*[ b1 0 ]*Q = [ x x ]
|
|
// [ b2 b3 ] [ 0 x ].
|
|
//
|
|
// The rows of the transformed A and B are parallel, where
|
|
//
|
|
// U = [ csu snu ], V = [ csv snv ], Q = [ csq snq ]
|
|
// [ -snu csu ] [ -snv csv ] [ -snq csq ]
|
|
//
|
|
// Dlags2 is an internal routine. It is exported for testing purposes.
|
|
func (impl Implementation) Dlags2(upper bool, a1, a2, a3, b1, b2, b3 float64) (csu, snu, csv, snv, csq, snq float64) {
|
|
if upper {
|
|
// Input matrices A and B are upper triangular matrices.
|
|
//
|
|
// Form matrix C = A*adj(B) = [ a b ]
|
|
// [ 0 d ]
|
|
a := a1 * b3
|
|
d := a3 * b1
|
|
b := a2*b1 - a1*b2
|
|
|
|
// The SVD of real 2-by-2 triangular C.
|
|
//
|
|
// [ csl -snl ]*[ a b ]*[ csr snr ] = [ r 0 ]
|
|
// [ snl csl ] [ 0 d ] [ -snr csr ] [ 0 t ]
|
|
_, _, snr, csr, snl, csl := impl.Dlasv2(a, b, d)
|
|
|
|
if math.Abs(csl) >= math.Abs(snl) || math.Abs(csr) >= math.Abs(snr) {
|
|
// Compute the [0, 0] and [0, 1] elements of U^T*A and V^T*B,
|
|
// and [0, 1] element of |U|^T*|A| and |V|^T*|B|.
|
|
|
|
ua11r := csl * a1
|
|
ua12 := csl*a2 + snl*a3
|
|
|
|
vb11r := csr * b1
|
|
vb12 := csr*b2 + snr*b3
|
|
|
|
aua12 := math.Abs(csl)*math.Abs(a2) + math.Abs(snl)*math.Abs(a3)
|
|
avb12 := math.Abs(csr)*math.Abs(b2) + math.Abs(snr)*math.Abs(b3)
|
|
|
|
// Zero [0, 1] elements of U^T*A and V^T*B.
|
|
if math.Abs(ua11r)+math.Abs(ua12) != 0 {
|
|
if aua12/(math.Abs(ua11r)+math.Abs(ua12)) <= avb12/(math.Abs(vb11r)+math.Abs(vb12)) {
|
|
csq, snq, _ = impl.Dlartg(-ua11r, ua12)
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(-vb11r, vb12)
|
|
}
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(-vb11r, vb12)
|
|
}
|
|
|
|
csu = csl
|
|
snu = -snl
|
|
csv = csr
|
|
snv = -snr
|
|
} else {
|
|
// Compute the [1, 0] and [1, 1] elements of U^T*A and V^T*B,
|
|
// and [1, 1] element of |U|^T*|A| and |V|^T*|B|.
|
|
|
|
ua21 := -snl * a1
|
|
ua22 := -snl*a2 + csl*a3
|
|
|
|
vb21 := -snr * b1
|
|
vb22 := -snr*b2 + csr*b3
|
|
|
|
aua22 := math.Abs(snl)*math.Abs(a2) + math.Abs(csl)*math.Abs(a3)
|
|
avb22 := math.Abs(snr)*math.Abs(b2) + math.Abs(csr)*math.Abs(b3)
|
|
|
|
// Zero [1, 1] elements of U^T*A and V^T*B, and then swap.
|
|
if math.Abs(ua21)+math.Abs(ua22) != 0 {
|
|
if aua22/(math.Abs(ua21)+math.Abs(ua22)) <= avb22/(math.Abs(vb21)+math.Abs(vb22)) {
|
|
csq, snq, _ = impl.Dlartg(-ua21, ua22)
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(-vb21, vb22)
|
|
}
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(-vb21, vb22)
|
|
}
|
|
|
|
csu = snl
|
|
snu = csl
|
|
csv = snr
|
|
snv = csr
|
|
}
|
|
} else {
|
|
// Input matrices A and B are lower triangular matrices
|
|
//
|
|
// Form matrix C = A*adj(B) = [ a 0 ]
|
|
// [ c d ]
|
|
a := a1 * b3
|
|
d := a3 * b1
|
|
c := a2*b3 - a3*b2
|
|
|
|
// The SVD of real 2-by-2 triangular C
|
|
//
|
|
// [ csl -snl ]*[ a 0 ]*[ csr snr ] = [ r 0 ]
|
|
// [ snl csl ] [ c d ] [ -snr csr ] [ 0 t ]
|
|
_, _, snr, csr, snl, csl := impl.Dlasv2(a, c, d)
|
|
|
|
if math.Abs(csr) >= math.Abs(snr) || math.Abs(csl) >= math.Abs(snl) {
|
|
// Compute the [1, 0] and [1, 1] elements of U^T*A and V^T*B,
|
|
// and [1, 0] element of |U|^T*|A| and |V|^T*|B|.
|
|
|
|
ua21 := -snr*a1 + csr*a2
|
|
ua22r := csr * a3
|
|
|
|
vb21 := -snl*b1 + csl*b2
|
|
vb22r := csl * b3
|
|
|
|
aua21 := math.Abs(snr)*math.Abs(a1) + math.Abs(csr)*math.Abs(a2)
|
|
avb21 := math.Abs(snl)*math.Abs(b1) + math.Abs(csl)*math.Abs(b2)
|
|
|
|
// Zero [1, 0] elements of U^T*A and V^T*B.
|
|
if (math.Abs(ua21) + math.Abs(ua22r)) != 0 {
|
|
if aua21/(math.Abs(ua21)+math.Abs(ua22r)) <= avb21/(math.Abs(vb21)+math.Abs(vb22r)) {
|
|
csq, snq, _ = impl.Dlartg(ua22r, ua21)
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(vb22r, vb21)
|
|
}
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(vb22r, vb21)
|
|
}
|
|
|
|
csu = csr
|
|
snu = -snr
|
|
csv = csl
|
|
snv = -snl
|
|
} else {
|
|
// Compute the [0, 0] and [0, 1] elements of U^T *A and V^T *B,
|
|
// and [0, 0] element of |U|^T*|A| and |V|^T*|B|.
|
|
|
|
ua11 := csr*a1 + snr*a2
|
|
ua12 := snr * a3
|
|
|
|
vb11 := csl*b1 + snl*b2
|
|
vb12 := snl * b3
|
|
|
|
aua11 := math.Abs(csr)*math.Abs(a1) + math.Abs(snr)*math.Abs(a2)
|
|
avb11 := math.Abs(csl)*math.Abs(b1) + math.Abs(snl)*math.Abs(b2)
|
|
|
|
// Zero [0, 0] elements of U^T*A and V^T*B, and then swap.
|
|
if (math.Abs(ua11) + math.Abs(ua12)) != 0 {
|
|
if aua11/(math.Abs(ua11)+math.Abs(ua12)) <= avb11/(math.Abs(vb11)+math.Abs(vb12)) {
|
|
csq, snq, _ = impl.Dlartg(ua12, ua11)
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(vb12, vb11)
|
|
}
|
|
} else {
|
|
csq, snq, _ = impl.Dlartg(vb12, vb11)
|
|
}
|
|
|
|
csu = snr
|
|
snu = csr
|
|
csv = snl
|
|
snv = csl
|
|
}
|
|
}
|
|
|
|
return csu, snu, csv, snv, csq, snq
|
|
}
|