github.com/gopherd/gonum@v0.0.4/lapack/gonum/dlangt.go (about)

     1  // Copyright ©2020 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  	"math"
     9  
    10  	"github.com/gopherd/gonum/lapack"
    11  )
    12  
    13  // Dlangt returns the value of the given norm of an n×n tridiagonal matrix
    14  // represented by the three diagonals.
    15  //
    16  // d must have length at least n and dl and du must have length at least n-1.
    17  func (impl Implementation) Dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64 {
    18  	switch {
    19  	case norm != lapack.MaxAbs && norm != lapack.MaxRowSum && norm != lapack.MaxColumnSum && norm != lapack.Frobenius:
    20  		panic(badNorm)
    21  	case n < 0:
    22  		panic(nLT0)
    23  	}
    24  
    25  	if n == 0 {
    26  		return 0
    27  	}
    28  
    29  	switch {
    30  	case len(dl) < n-1:
    31  		panic(shortDL)
    32  	case len(d) < n:
    33  		panic(shortD)
    34  	case len(du) < n-1:
    35  		panic(shortDU)
    36  	}
    37  
    38  	dl = dl[:n-1]
    39  	d = d[:n]
    40  	du = du[:n-1]
    41  
    42  	var anorm float64
    43  	switch norm {
    44  	case lapack.MaxAbs:
    45  		for _, diag := range [][]float64{dl, d, du} {
    46  			for _, di := range diag {
    47  				if math.IsNaN(di) {
    48  					return di
    49  				}
    50  				di = math.Abs(di)
    51  				if di > anorm {
    52  					anorm = di
    53  				}
    54  			}
    55  		}
    56  	case lapack.MaxColumnSum:
    57  		if n == 1 {
    58  			return math.Abs(d[0])
    59  		}
    60  		anorm = math.Abs(d[0]) + math.Abs(dl[0])
    61  		if math.IsNaN(anorm) {
    62  			return anorm
    63  		}
    64  		tmp := math.Abs(du[n-2]) + math.Abs(d[n-1])
    65  		if math.IsNaN(tmp) {
    66  			return tmp
    67  		}
    68  		if tmp > anorm {
    69  			anorm = tmp
    70  		}
    71  		for i := 1; i < n-1; i++ {
    72  			tmp = math.Abs(du[i-1]) + math.Abs(d[i]) + math.Abs(dl[i])
    73  			if math.IsNaN(tmp) {
    74  				return tmp
    75  			}
    76  			if tmp > anorm {
    77  				anorm = tmp
    78  			}
    79  		}
    80  	case lapack.MaxRowSum:
    81  		if n == 1 {
    82  			return math.Abs(d[0])
    83  		}
    84  		anorm = math.Abs(d[0]) + math.Abs(du[0])
    85  		if math.IsNaN(anorm) {
    86  			return anorm
    87  		}
    88  		tmp := math.Abs(dl[n-2]) + math.Abs(d[n-1])
    89  		if math.IsNaN(tmp) {
    90  			return tmp
    91  		}
    92  		if tmp > anorm {
    93  			anorm = tmp
    94  		}
    95  		for i := 1; i < n-1; i++ {
    96  			tmp = math.Abs(dl[i-1]) + math.Abs(d[i]) + math.Abs(du[i])
    97  			if math.IsNaN(tmp) {
    98  				return tmp
    99  			}
   100  			if tmp > anorm {
   101  				anorm = tmp
   102  			}
   103  		}
   104  	case lapack.Frobenius:
   105  		scale := 0.0
   106  		ssq := 1.0
   107  		scale, ssq = impl.Dlassq(n, d, 1, scale, ssq)
   108  		if n > 1 {
   109  			scale, ssq = impl.Dlassq(n-1, dl, 1, scale, ssq)
   110  			scale, ssq = impl.Dlassq(n-1, du, 1, scale, ssq)
   111  		}
   112  		anorm = scale * math.Sqrt(ssq)
   113  	}
   114  	return anorm
   115  }