github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/dlags2.go (about)

     1  // Copyright ©2017 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  // Dlags2 computes 2-by-2 orthogonal matrices U, V and Q with the
    10  // triangles of A and B specified by upper.
    11  //
    12  // If upper is true
    13  //
    14  //  U^T*A*Q = U^T*[ a1 a2 ]*Q = [ x  0 ]
    15  //                [ 0  a3 ]     [ x  x ]
    16  // and
    17  //  V^T*B*Q = V^T*[ b1 b2 ]*Q = [ x  0 ]
    18  //                [ 0  b3 ]     [ x  x ]
    19  //
    20  // otherwise
    21  //
    22  //  U^T*A*Q = U^T*[ a1 0  ]*Q = [ x  x ]
    23  //                [ a2 a3 ]     [ 0  x ]
    24  // and
    25  //  V^T*B*Q = V^T*[ b1 0  ]*Q = [ x  x ]
    26  //                [ b2 b3 ]     [ 0  x ].
    27  //
    28  // The rows of the transformed A and B are parallel, where
    29  //
    30  //  U = [  csu  snu ], V = [  csv snv ], Q = [  csq   snq ]
    31  //      [ -snu  csu ]      [ -snv csv ]      [ -snq   csq ]
    32  //
    33  // Dlags2 is an internal routine. It is exported for testing purposes.
    34  func (impl Implementation) Dlags2(upper bool, a1, a2, a3, b1, b2, b3 float64) (csu, snu, csv, snv, csq, snq float64) {
    35  	if upper {
    36  		// Input matrices A and B are upper triangular matrices.
    37  		//
    38  		// Form matrix C = A*adj(B) = [ a b ]
    39  		//                            [ 0 d ]
    40  		a := a1 * b3
    41  		d := a3 * b1
    42  		b := a2*b1 - a1*b2
    43  
    44  		// The SVD of real 2-by-2 triangular C.
    45  		//
    46  		//  [ csl -snl ]*[ a b ]*[  csr  snr ] = [ r 0 ]
    47  		//  [ snl  csl ] [ 0 d ] [ -snr  csr ]   [ 0 t ]
    48  		_, _, snr, csr, snl, csl := impl.Dlasv2(a, b, d)
    49  
    50  		if math.Abs(csl) >= math.Abs(snl) || math.Abs(csr) >= math.Abs(snr) {
    51  			// Compute the [0, 0] and [0, 1] elements of U^T*A and V^T*B,
    52  			// and [0, 1] element of |U|^T*|A| and |V|^T*|B|.
    53  
    54  			ua11r := csl * a1
    55  			ua12 := csl*a2 + snl*a3
    56  
    57  			vb11r := csr * b1
    58  			vb12 := csr*b2 + snr*b3
    59  
    60  			aua12 := math.Abs(csl)*math.Abs(a2) + math.Abs(snl)*math.Abs(a3)
    61  			avb12 := math.Abs(csr)*math.Abs(b2) + math.Abs(snr)*math.Abs(b3)
    62  
    63  			// Zero [0, 1] elements of U^T*A and V^T*B.
    64  			if math.Abs(ua11r)+math.Abs(ua12) != 0 {
    65  				if aua12/(math.Abs(ua11r)+math.Abs(ua12)) <= avb12/(math.Abs(vb11r)+math.Abs(vb12)) {
    66  					csq, snq, _ = impl.Dlartg(-ua11r, ua12)
    67  				} else {
    68  					csq, snq, _ = impl.Dlartg(-vb11r, vb12)
    69  				}
    70  			} else {
    71  				csq, snq, _ = impl.Dlartg(-vb11r, vb12)
    72  			}
    73  
    74  			csu = csl
    75  			snu = -snl
    76  			csv = csr
    77  			snv = -snr
    78  		} else {
    79  			// Compute the [1, 0] and [1, 1] elements of U^T*A and V^T*B,
    80  			// and [1, 1] element of |U|^T*|A| and |V|^T*|B|.
    81  
    82  			ua21 := -snl * a1
    83  			ua22 := -snl*a2 + csl*a3
    84  
    85  			vb21 := -snr * b1
    86  			vb22 := -snr*b2 + csr*b3
    87  
    88  			aua22 := math.Abs(snl)*math.Abs(a2) + math.Abs(csl)*math.Abs(a3)
    89  			avb22 := math.Abs(snr)*math.Abs(b2) + math.Abs(csr)*math.Abs(b3)
    90  
    91  			// Zero [1, 1] elements of U^T*A and V^T*B, and then swap.
    92  			if math.Abs(ua21)+math.Abs(ua22) != 0 {
    93  				if aua22/(math.Abs(ua21)+math.Abs(ua22)) <= avb22/(math.Abs(vb21)+math.Abs(vb22)) {
    94  					csq, snq, _ = impl.Dlartg(-ua21, ua22)
    95  				} else {
    96  					csq, snq, _ = impl.Dlartg(-vb21, vb22)
    97  				}
    98  			} else {
    99  				csq, snq, _ = impl.Dlartg(-vb21, vb22)
   100  			}
   101  
   102  			csu = snl
   103  			snu = csl
   104  			csv = snr
   105  			snv = csr
   106  		}
   107  	} else {
   108  		// Input matrices A and B are lower triangular matrices
   109  		//
   110  		// Form matrix C = A*adj(B) = [ a 0 ]
   111  		//                            [ c d ]
   112  		a := a1 * b3
   113  		d := a3 * b1
   114  		c := a2*b3 - a3*b2
   115  
   116  		// The SVD of real 2-by-2 triangular C
   117  		//
   118  		// [ csl -snl ]*[ a 0 ]*[  csr  snr ] = [ r 0 ]
   119  		// [ snl  csl ] [ c d ] [ -snr  csr ]   [ 0 t ]
   120  		_, _, snr, csr, snl, csl := impl.Dlasv2(a, c, d)
   121  
   122  		if math.Abs(csr) >= math.Abs(snr) || math.Abs(csl) >= math.Abs(snl) {
   123  			// Compute the [1, 0] and [1, 1] elements of U^T*A and V^T*B,
   124  			// and [1, 0] element of |U|^T*|A| and |V|^T*|B|.
   125  
   126  			ua21 := -snr*a1 + csr*a2
   127  			ua22r := csr * a3
   128  
   129  			vb21 := -snl*b1 + csl*b2
   130  			vb22r := csl * b3
   131  
   132  			aua21 := math.Abs(snr)*math.Abs(a1) + math.Abs(csr)*math.Abs(a2)
   133  			avb21 := math.Abs(snl)*math.Abs(b1) + math.Abs(csl)*math.Abs(b2)
   134  
   135  			// Zero [1, 0] elements of U^T*A and V^T*B.
   136  			if (math.Abs(ua21) + math.Abs(ua22r)) != 0 {
   137  				if aua21/(math.Abs(ua21)+math.Abs(ua22r)) <= avb21/(math.Abs(vb21)+math.Abs(vb22r)) {
   138  					csq, snq, _ = impl.Dlartg(ua22r, ua21)
   139  				} else {
   140  					csq, snq, _ = impl.Dlartg(vb22r, vb21)
   141  				}
   142  			} else {
   143  				csq, snq, _ = impl.Dlartg(vb22r, vb21)
   144  			}
   145  
   146  			csu = csr
   147  			snu = -snr
   148  			csv = csl
   149  			snv = -snl
   150  		} else {
   151  			// Compute the [0, 0] and [0, 1] elements of U^T *A and V^T *B,
   152  			// and [0, 0] element of |U|^T*|A| and |V|^T*|B|.
   153  
   154  			ua11 := csr*a1 + snr*a2
   155  			ua12 := snr * a3
   156  
   157  			vb11 := csl*b1 + snl*b2
   158  			vb12 := snl * b3
   159  
   160  			aua11 := math.Abs(csr)*math.Abs(a1) + math.Abs(snr)*math.Abs(a2)
   161  			avb11 := math.Abs(csl)*math.Abs(b1) + math.Abs(snl)*math.Abs(b2)
   162  
   163  			// Zero [0, 0] elements of U^T*A and V^T*B, and then swap.
   164  			if (math.Abs(ua11) + math.Abs(ua12)) != 0 {
   165  				if aua11/(math.Abs(ua11)+math.Abs(ua12)) <= avb11/(math.Abs(vb11)+math.Abs(vb12)) {
   166  					csq, snq, _ = impl.Dlartg(ua12, ua11)
   167  				} else {
   168  					csq, snq, _ = impl.Dlartg(vb12, vb11)
   169  				}
   170  			} else {
   171  				csq, snq, _ = impl.Dlartg(vb12, vb11)
   172  			}
   173  
   174  			csu = snr
   175  			snu = csr
   176  			csv = snl
   177  			snv = csl
   178  		}
   179  	}
   180  
   181  	return csu, snu, csv, snv, csq, snq
   182  }