// updateCond updates the stored condition number of the matrix. Norm is the // norm of the original matrix. If norm is negative it will be estimated. func (lu *LU) updateCond(norm float64) { n := lu.lu.mat.Cols work := make([]float64, 4*n) iwork := make([]int, n) if norm < 0 { // This is an approximation. By the definition of a norm, ||AB|| <= ||A|| ||B||. // The condition number is ||A|| || A^-1||, so this will underestimate // the condition number somewhat. // The norm of the original factorized matrix cannot be stored because of // update possibilities, e.g. RankOne. u := lu.lu.asTriDense(n, blas.NonUnit, blas.Upper) l := lu.lu.asTriDense(n, blas.Unit, blas.Lower) unorm := lapack64.Lantr(matrix.CondNorm, u.mat, work) lnorm := lapack64.Lantr(matrix.CondNorm, l.mat, work) norm = unorm * lnorm } v := lapack64.Gecon(matrix.CondNorm, lu.lu.mat, norm, work, iwork) lu.cond = 1 / v }
// updateCond updates the condition number of the Cholesky decomposition. If // norm > 0, then that norm is used as the norm of the original matrix A, otherwise // the norm is estimated from the decompositon. func (c *Cholesky) updateCond(norm float64) { n := c.chol.mat.N work := make([]float64, 3*n) if norm < 0 { // This is an approximation. By the definition of a norm, ||AB|| <= ||A|| ||B||. // Here, A = U^T * U. // The condition number is ||A|| || A^-1||, so this will underestimate // the condition number somewhat. // The norm of the original factorized matrix cannot be stored because of // update possibilites. unorm := lapack64.Lantr(matrix.CondNorm, c.chol.mat, work) lnorm := lapack64.Lantr(matrix.CondNormTrans, c.chol.mat, work) norm = unorm * lnorm } sym := c.chol.asSymBlas() iwork := make([]int, n) v := lapack64.Pocon(sym, norm, work, iwork) c.cond = 1 / v }
// Norm returns the specified (induced) norm of the matrix a. See // https://en.wikipedia.org/wiki/Matrix_norm for the definition of an induced norm. // // Valid norms are: // 1 - The maximum absolute column sum // 2 - Frobenius norm, the square root of the sum of the squares of the elements. // Inf - The maximum absolute row sum. // Norm will panic with ErrNormOrder if an illegal norm order is specified. func Norm(a Matrix, norm float64) float64 { r, c := a.Dims() aMat, aTrans := untranspose(a) var work []float64 switch rma := aMat.(type) { case RawMatrixer: rm := rma.RawMatrix() n := normLapack(norm, aTrans) if n == lapack.MaxColumnSum { work = make([]float64, rm.Cols) } return lapack64.Lange(n, rm, work) case RawTriangular: rm := rma.RawTriangular() n := normLapack(norm, aTrans) if n == lapack.MaxRowSum || n == lapack.MaxColumnSum { work = make([]float64, rm.N) } return lapack64.Lantr(n, rm, work) case RawSymmetricer: rm := rma.RawSymmetric() n := normLapack(norm, aTrans) if n == lapack.MaxRowSum || n == lapack.MaxColumnSum { work = make([]float64, rm.N) } return lapack64.Lansy(n, rm, work) } switch norm { default: panic("unreachable") case 1: var max float64 for j := 0; j < c; j++ { var sum float64 for i := 0; i < r; i++ { sum += math.Abs(a.At(i, j)) } if sum > max { max = sum } } return max case 2: var sum float64 for i := 0; i < r; i++ { for j := 0; j < c; j++ { v := a.At(i, j) sum += v * v } } return math.Sqrt(sum) case math.Inf(1): var max float64 for i := 0; i < r; i++ { var sum float64 for j := 0; j < c; j++ { sum += math.Abs(a.At(i, j)) } if sum > max { max = sum } } return max } }
// Norm returns the specified (induced) norm of the matrix a. See // https://en.wikipedia.org/wiki/Matrix_norm for the definition of an induced norm. // // Valid norms are: // 1 - The maximum absolute column sum // 2 - Frobenius norm, the square root of the sum of the squares of the elements. // Inf - The maximum absolute row sum. // Norm will panic with ErrNormOrder if an illegal norm order is specified and // with matrix.ErrShape if the matrix has zero size. func Norm(a Matrix, norm float64) float64 { r, c := a.Dims() if r == 0 || c == 0 { panic(matrix.ErrShape) } aU, aTrans := untranspose(a) var work []float64 switch rma := aU.(type) { case RawMatrixer: rm := rma.RawMatrix() n := normLapack(norm, aTrans) if n == lapack.MaxColumnSum { work = make([]float64, rm.Cols) } return lapack64.Lange(n, rm, work) case RawTriangular: rm := rma.RawTriangular() n := normLapack(norm, aTrans) if n == lapack.MaxRowSum || n == lapack.MaxColumnSum { work = make([]float64, rm.N) } return lapack64.Lantr(n, rm, work) case RawSymmetricer: rm := rma.RawSymmetric() n := normLapack(norm, aTrans) if n == lapack.MaxRowSum || n == lapack.MaxColumnSum { work = make([]float64, rm.N) } return lapack64.Lansy(n, rm, work) case *Vector: rv := rma.RawVector() switch norm { default: panic("unreachable") case 1: if aTrans { imax := blas64.Iamax(rma.n, rv) return math.Abs(rma.At(imax, 0)) } return blas64.Asum(rma.n, rv) case 2: return blas64.Nrm2(rma.n, rv) case math.Inf(1): if aTrans { return blas64.Asum(rma.n, rv) } imax := blas64.Iamax(rma.n, rv) return math.Abs(rma.At(imax, 0)) } } switch norm { default: panic("unreachable") case 1: var max float64 for j := 0; j < c; j++ { var sum float64 for i := 0; i < r; i++ { sum += math.Abs(a.At(i, j)) } if sum > max { max = sum } } return max case 2: var sum float64 for i := 0; i < r; i++ { for j := 0; j < c; j++ { v := a.At(i, j) sum += v * v } } return math.Sqrt(sum) case math.Inf(1): var max float64 for i := 0; i < r; i++ { var sum float64 for j := 0; j < c; j++ { sum += math.Abs(a.At(i, j)) } if sum > max { max = sum } } return max } }