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