github.com/gopherd/gonum@v0.0.4/lapack/gonum/dsytd2.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 (
     8  	"github.com/gopherd/gonum/blas"
     9  	"github.com/gopherd/gonum/blas/blas64"
    10  )
    11  
    12  // Dsytd2 reduces a symmetric n×n matrix A to symmetric tridiagonal form T by
    13  // an orthogonal similarity transformation
    14  //  Qᵀ * A * Q = T
    15  // On entry, the matrix is contained in the specified triangle of a. On exit,
    16  // if uplo == blas.Upper, the diagonal and first super-diagonal of a are
    17  // overwritten with the elements of T. The elements above the first super-diagonal
    18  // are overwritten with the elementary reflectors that are used with
    19  // the elements written to tau in order to construct Q. If uplo == blas.Lower,
    20  // the elements are written in the lower triangular region.
    21  //
    22  // d must have length at least n. e and tau must have length at least n-1. Dsytd2
    23  // will panic if these sizes are not met.
    24  //
    25  // Q is represented as a product of elementary reflectors.
    26  // If uplo == blas.Upper
    27  //  Q = H_{n-2} * ... * H_1 * H_0
    28  // and if uplo == blas.Lower
    29  //  Q = H_0 * H_1 * ... * H_{n-2}
    30  // where
    31  //  H_i = I - tau * v * vᵀ
    32  // where tau is stored in tau[i], and v is stored in a.
    33  //
    34  // If uplo == blas.Upper, v[0:i-1] is stored in A[0:i-1,i+1], v[i] = 1, and
    35  // v[i+1:] = 0. The elements of a are
    36  //  [ d   e  v2  v3  v4]
    37  //  [     d   e  v3  v4]
    38  //  [         d   e  v4]
    39  //  [             d   e]
    40  //  [                 d]
    41  // If uplo == blas.Lower, v[0:i+1] = 0, v[i+1] = 1, and v[i+2:] is stored in
    42  // A[i+2:n,i].
    43  // The elements of a are
    44  //  [ d                ]
    45  //  [ e   d            ]
    46  //  [v1   e   d        ]
    47  //  [v1  v2   e   d    ]
    48  //  [v1  v2  v3   e   d]
    49  //
    50  // Dsytd2 is an internal routine. It is exported for testing purposes.
    51  func (impl Implementation) Dsytd2(uplo blas.Uplo, n int, a []float64, lda int, d, e, tau []float64) {
    52  	switch {
    53  	case uplo != blas.Upper && uplo != blas.Lower:
    54  		panic(badUplo)
    55  	case n < 0:
    56  		panic(nLT0)
    57  	case lda < max(1, n):
    58  		panic(badLdA)
    59  	}
    60  
    61  	// Quick return if possible.
    62  	if n == 0 {
    63  		return
    64  	}
    65  
    66  	switch {
    67  	case len(a) < (n-1)*lda+n:
    68  		panic(shortA)
    69  	case len(d) < n:
    70  		panic(shortD)
    71  	case len(e) < n-1:
    72  		panic(shortE)
    73  	case len(tau) < n-1:
    74  		panic(shortTau)
    75  	}
    76  
    77  	bi := blas64.Implementation()
    78  
    79  	if uplo == blas.Upper {
    80  		// Reduce the upper triangle of A.
    81  		for i := n - 2; i >= 0; i-- {
    82  			// Generate elementary reflector H_i = I - tau * v * vᵀ to
    83  			// annihilate A[i:i-1, i+1].
    84  			var taui float64
    85  			a[i*lda+i+1], taui = impl.Dlarfg(i+1, a[i*lda+i+1], a[i+1:], lda)
    86  			e[i] = a[i*lda+i+1]
    87  			if taui != 0 {
    88  				// Apply H_i from both sides to A[0:i,0:i].
    89  				a[i*lda+i+1] = 1
    90  
    91  				// Compute x := tau * A * v storing x in tau[0:i].
    92  				bi.Dsymv(uplo, i+1, taui, a, lda, a[i+1:], lda, 0, tau, 1)
    93  
    94  				// Compute w := x - 1/2 * tau * (xᵀ * v) * v.
    95  				alpha := -0.5 * taui * bi.Ddot(i+1, tau, 1, a[i+1:], lda)
    96  				bi.Daxpy(i+1, alpha, a[i+1:], lda, tau, 1)
    97  
    98  				// Apply the transformation as a rank-2 update
    99  				// A = A - v * wᵀ - w * vᵀ.
   100  				bi.Dsyr2(uplo, i+1, -1, a[i+1:], lda, tau, 1, a, lda)
   101  				a[i*lda+i+1] = e[i]
   102  			}
   103  			d[i+1] = a[(i+1)*lda+i+1]
   104  			tau[i] = taui
   105  		}
   106  		d[0] = a[0]
   107  		return
   108  	}
   109  	// Reduce the lower triangle of A.
   110  	for i := 0; i < n-1; i++ {
   111  		// Generate elementary reflector H_i = I - tau * v * vᵀ to
   112  		// annihilate A[i+2:n, i].
   113  		var taui float64
   114  		a[(i+1)*lda+i], taui = impl.Dlarfg(n-i-1, a[(i+1)*lda+i], a[min(i+2, n-1)*lda+i:], lda)
   115  		e[i] = a[(i+1)*lda+i]
   116  		if taui != 0 {
   117  			// Apply H_i from both sides to A[i+1:n, i+1:n].
   118  			a[(i+1)*lda+i] = 1
   119  
   120  			// Compute x := tau * A * v, storing y in tau[i:n-1].
   121  			bi.Dsymv(uplo, n-i-1, taui, a[(i+1)*lda+i+1:], lda, a[(i+1)*lda+i:], lda, 0, tau[i:], 1)
   122  
   123  			// Compute w := x - 1/2 * tau * (xᵀ * v) * v.
   124  			alpha := -0.5 * taui * bi.Ddot(n-i-1, tau[i:], 1, a[(i+1)*lda+i:], lda)
   125  			bi.Daxpy(n-i-1, alpha, a[(i+1)*lda+i:], lda, tau[i:], 1)
   126  
   127  			// Apply the transformation as a rank-2 update
   128  			// A = A - v * wᵀ - w * vᵀ.
   129  			bi.Dsyr2(uplo, n-i-1, -1, a[(i+1)*lda+i:], lda, tau[i:], 1, a[(i+1)*lda+i+1:], lda)
   130  			a[(i+1)*lda+i] = e[i]
   131  		}
   132  		d[i] = a[i*lda+i]
   133  		tau[i] = taui
   134  	}
   135  	d[n-1] = a[(n-1)*lda+n-1]
   136  }