gonum.org/v1/gonum@v0.14.0/lapack/gonum/dgecon.go (about)

     1  // Copyright ©2015 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  	"gonum.org/v1/gonum/blas"
    11  	"gonum.org/v1/gonum/blas/blas64"
    12  	"gonum.org/v1/gonum/lapack"
    13  )
    14  
    15  // Dgecon estimates the reciprocal of the condition number of the n×n matrix A
    16  // given the LU decomposition of the matrix. The condition number computed may
    17  // be based on the 1-norm or the ∞-norm.
    18  //
    19  // The slice a contains the result of the LU decomposition of A as computed by Dgetrf.
    20  //
    21  // anorm is the corresponding 1-norm or ∞-norm of the original matrix A. anorm
    22  // must be non-negative.
    23  //
    24  // work must have length at least 4*n and iwork must have length at least n,
    25  // otherwise Dgecon will panic.
    26  func (impl Implementation) Dgecon(norm lapack.MatrixNorm, n int, a []float64, lda int, anorm float64, work []float64, iwork []int) float64 {
    27  	switch {
    28  	case norm != lapack.MaxColumnSum && norm != lapack.MaxRowSum:
    29  		panic(badNorm)
    30  	case n < 0:
    31  		panic(nLT0)
    32  	case lda < max(1, n):
    33  		panic(badLdA)
    34  	case anorm < 0:
    35  		panic(negANorm)
    36  	}
    37  
    38  	// Quick return if possible.
    39  	if n == 0 {
    40  		return 1
    41  	}
    42  
    43  	switch {
    44  	case len(a) < (n-1)*lda+n:
    45  		panic(shortA)
    46  	case len(work) < 4*n:
    47  		panic(shortWork)
    48  	case len(iwork) < n:
    49  		panic(shortIWork)
    50  	}
    51  
    52  	// Quick return if possible.
    53  	if anorm == 0 {
    54  		return 0
    55  	}
    56  	if math.IsNaN(anorm) {
    57  		// The reference implementation treats the NaN anorm as invalid and
    58  		// returns an error code. Our error handling is to panic which seems too
    59  		// harsh for a runtime condition, so we just propagate the NaN instead.
    60  		return anorm
    61  	}
    62  
    63  	bi := blas64.Implementation()
    64  	var rcond, ainvnm float64
    65  	var kase int
    66  	var normin bool
    67  	isave := new([3]int)
    68  	onenrm := norm == lapack.MaxColumnSum
    69  	smlnum := dlamchS
    70  	kase1 := 2
    71  	if onenrm {
    72  		kase1 = 1
    73  	}
    74  	for {
    75  		ainvnm, kase = impl.Dlacn2(n, work[n:], work, iwork, ainvnm, kase, isave)
    76  		if kase == 0 {
    77  			if ainvnm != 0 {
    78  				rcond = (1 / ainvnm) / anorm
    79  			}
    80  			return rcond
    81  		}
    82  		var sl, su float64
    83  		if kase == kase1 {
    84  			sl = impl.Dlatrs(blas.Lower, blas.NoTrans, blas.Unit, normin, n, a, lda, work, work[2*n:])
    85  			su = impl.Dlatrs(blas.Upper, blas.NoTrans, blas.NonUnit, normin, n, a, lda, work, work[3*n:])
    86  		} else {
    87  			su = impl.Dlatrs(blas.Upper, blas.Trans, blas.NonUnit, normin, n, a, lda, work, work[3*n:])
    88  			sl = impl.Dlatrs(blas.Lower, blas.Trans, blas.Unit, normin, n, a, lda, work, work[2*n:])
    89  		}
    90  		scale := sl * su
    91  		normin = true
    92  		if scale != 1 {
    93  			ix := bi.Idamax(n, work, 1)
    94  			if scale == 0 || scale < math.Abs(work[ix])*smlnum {
    95  				return rcond
    96  			}
    97  			impl.Drscl(n, scale, work, 1)
    98  		}
    99  	}
   100  }