Example #1
0
func (lq *LQ) updateCond() {
	// A = LQ, where Q is orthonormal. Orthonormal multiplications do not change
	// the condition number. Thus, ||A|| = ||L|| ||Q|| = ||Q||.
	m := lq.lq.mat.Rows
	work := make([]float64, 3*m)
	iwork := make([]int, m)
	l := lq.lq.asTriDense(m, blas.NonUnit, blas.Lower)
	v := lapack64.Trcon(matrix.CondNorm, l.mat, work, iwork)
	lq.cond = 1 / v
}
Example #2
0
func (qr *QR) updateCond() {
	// A = QR, where Q is orthonormal. Orthonormal multiplications do not change
	// the condition number. Thus, ||A|| = ||Q|| ||R|| = ||R||.
	n := qr.qr.mat.Cols
	work := make([]float64, 3*n)
	iwork := make([]int, n)
	r := qr.qr.asTriDense(n, blas.NonUnit, blas.Upper)
	v := lapack64.Trcon(matrix.CondNorm, r.mat, work, iwork)
	qr.cond = 1 / v
}
Example #3
0
// InverseTri computes the inverse of the triangular matrix a, storing the result
// into the receiver. If a is ill-conditioned, a Condition error will be returned.
// Note that matrix inversion is numerically unstable, and should generally be
// avoided where possible, for example by using the Solve routines.
func (t *TriDense) InverseTri(a Triangular) error {
	if rt, ok := a.(RawTriangular); ok {
		t.checkOverlap(rt.RawTriangular())
	}
	n, _ := a.Triangle()
	t.reuseAs(a.Triangle())
	t.Copy(a)
	work := make([]float64, 3*n)
	iwork := make([]int, n)
	cond := lapack64.Trcon(matrix.CondNorm, t.mat, work, iwork)
	if math.IsInf(cond, 1) {
		return matrix.Condition(cond)
	}
	ok := lapack64.Trtri(t.mat)
	if !ok {
		return matrix.Condition(math.Inf(1))
	}
	if cond > matrix.ConditionTolerance {
		return matrix.Condition(cond)
	}
	return nil
}
Example #4
0
// Cond returns the condition number of the given matrix under the given norm.
// The condition number must be based on the 1-norm, 2-norm or ∞-norm.
// Cond will panic with matrix.ErrShape if the matrix has zero size.
//
// BUG(btracey): The computation of the 1-norm and ∞-norm for non-square matrices
// is innacurate, although is typically the right order of magnitude. See
// https://github.com/xianyi/OpenBLAS/issues/636. While the value returned will
// change with the resolution of this bug, the result from Cond will match the
// condition number used internally.
func Cond(a Matrix, norm float64) float64 {
	m, n := a.Dims()
	if m == 0 || n == 0 {
		panic(matrix.ErrShape)
	}
	var lnorm lapack.MatrixNorm
	switch norm {
	default:
		panic("mat64: bad norm value")
	case 1:
		lnorm = lapack.MaxColumnSum
	case 2:
		var svd SVD
		ok := svd.Factorize(a, matrix.SVDNone)
		if !ok {
			return math.Inf(1)
		}
		return svd.Cond()
	case math.Inf(1):
		lnorm = lapack.MaxRowSum
	}
	if m == n {
		// Use the LU decomposition to compute the condition number.
		tmp := getWorkspace(m, n, false)
		tmp.Copy(a)
		work := make([]float64, 4*n)
		aNorm := lapack64.Lange(lnorm, tmp.mat, work)
		pivot := make([]int, m)
		lapack64.Getrf(tmp.mat, pivot)
		iwork := make([]int, n)
		v := lapack64.Gecon(lnorm, tmp.mat, aNorm, work, iwork)
		putWorkspace(tmp)
		return 1 / v
	}
	if m > n {
		// Use the QR factorization to compute the condition number.
		tmp := getWorkspace(m, n, false)
		tmp.Copy(a)
		work := make([]float64, 3*n)
		tau := make([]float64, min(m, n))
		lapack64.Geqrf(tmp.mat, tau, work, -1)
		if int(work[0]) > len(work) {
			work = make([]float64, int(work[0]))
		}
		lapack64.Geqrf(tmp.mat, tau, work, len(work))

		iwork := make([]int, n)
		r := tmp.asTriDense(n, blas.NonUnit, blas.Upper)
		v := lapack64.Trcon(lnorm, r.mat, work, iwork)
		putWorkspace(tmp)
		return 1 / v
	}
	// Use the LQ factorization to compute the condition number.
	tmp := getWorkspace(m, n, false)
	tmp.Copy(a)
	work := make([]float64, 3*m)
	tau := make([]float64, min(m, n))
	lapack64.Gelqf(tmp.mat, tau, work, -1)
	if int(work[0]) > len(work) {
		work = make([]float64, int(work[0]))
	}
	lapack64.Gelqf(tmp.mat, tau, work, len(work))

	iwork := make([]int, m)
	l := tmp.asTriDense(m, blas.NonUnit, blas.Lower)
	v := lapack64.Trcon(lnorm, l.mat, work, iwork)
	putWorkspace(tmp)
	return 1 / v
}
Example #5
0
// Cond returns the condition number of the given matrix under the given norm.
// The condition number must be based on the 1-norm, 2-norm or ∞-norm.
// Cond will panic with matrix.ErrShape if the matrix has zero size.
//
// BUG(btracey): The computation of the 1-norm and ∞-norm for non-square matrices
// is innacurate, although is typically the right order of magnitude. See
// https://github.com/xianyi/OpenBLAS/issues/636. While the value returned will
// change with the resolution of this bug, the result from Cond will match the
// condition number used internally.
func Cond(a Matrix, norm float64) float64 {
	m, n := a.Dims()
	if m == 0 || n == 0 {
		panic(matrix.ErrShape)
	}
	var lnorm lapack.MatrixNorm
	switch norm {
	default:
		panic("mat64: bad norm value")
	case 1:
		lnorm = lapack.MaxColumnSum
	case 2:
		// Use SVD to compute the condition number.
		// TODO(btracey): Replace this with temporary workspace when SVD is fixed.
		tmp := NewDense(m, n, nil)
		tmp.Copy(a)
		svd := SVD(tmp, math.Pow(2, -52.0), math.Pow(2, -966.0), false, false)
		return svd.Cond()
	case math.Inf(1):
		lnorm = lapack.MaxRowSum
	}
	if m == n {
		// Use the LU decomposition to compute the condition number.
		tmp := getWorkspace(m, n, false)
		tmp.Copy(a)
		work := make([]float64, 4*n)
		aNorm := lapack64.Lange(lnorm, tmp.mat, work)
		pivot := make([]int, m)
		lapack64.Getrf(tmp.mat, pivot)
		iwork := make([]int, n)
		v := lapack64.Gecon(lnorm, tmp.mat, aNorm, work, iwork)
		putWorkspace(tmp)
		return 1 / v
	}
	if m > n {
		// Use the QR factorization to compute the condition number.
		tmp := getWorkspace(m, n, false)
		tmp.Copy(a)
		work := make([]float64, 3*n)
		tau := make([]float64, min(m, n))
		lapack64.Geqrf(tmp.mat, tau, work, -1)
		if int(work[0]) > len(work) {
			work = make([]float64, int(work[0]))
		}
		lapack64.Geqrf(tmp.mat, tau, work, len(work))

		iwork := make([]int, n)
		r := tmp.asTriDense(n, blas.NonUnit, blas.Upper)
		v := lapack64.Trcon(lnorm, r.mat, work, iwork)
		putWorkspace(tmp)
		return 1 / v
	}
	// Use the LQ factorization to compute the condition number.
	tmp := getWorkspace(m, n, false)
	tmp.Copy(a)
	work := make([]float64, 3*m)
	tau := make([]float64, min(m, n))
	lapack64.Gelqf(tmp.mat, tau, work, -1)
	if int(work[0]) > len(work) {
		work = make([]float64, int(work[0]))
	}
	lapack64.Gelqf(tmp.mat, tau, work, len(work))

	iwork := make([]int, m)
	l := tmp.asTriDense(m, blas.NonUnit, blas.Lower)
	v := lapack64.Trcon(lnorm, l.mat, work, iwork)
	putWorkspace(tmp)
	return 1 / v
}
Example #6
0
// Solve solves a minimum-norm solution to a system of linear equations defined
// by the matrices a and b. If a is singular or near-singular a Condition error
// is returned. Please see the documentation for Condition for more information.
//
// The minimization problem solved depends on the input parameters.
//  1. If m >= n and trans == false, find X such that ||a*X - b||_2 is minimized.
//  2. If m < n and trans == false, find the minimum norm solution of a * X = b.
//  3. If m >= n and trans == true, find the minimum norm solution of a^T * X = b.
//  4. If m < n and trans == true, find X such that ||a*X - b||_2 is minimized.
// The solution matrix, X, is stored in place into the receiver.
func (m *Dense) Solve(a, b Matrix) error {
	ar, ac := a.Dims()
	br, bc := b.Dims()
	if ar != br {
		panic(ErrShape)
	}
	m.reuseAs(ac, bc)

	// TODO(btracey): Add special cases for SymDense, etc.
	aMat, aTrans := untranspose(a)
	bMat, bTrans := untranspose(b)
	switch rma := aMat.(type) {
	case RawTriangular:
		side := blas.Left
		tA := blas.NoTrans
		if aTrans {
			tA = blas.Trans
		}
		if m != bMat {
			m.Copy(b)
		} else if bTrans {
			// m and b share data so Copy cannot be used directly.
			tmp := getWorkspace(br, bc, false)
			tmp.Copy(b)
			m.Copy(tmp)
			putWorkspace(tmp)
		}

		rm := rma.RawTriangular()
		blas64.Trsm(side, tA, 1, rm, m.mat)
		work := make([]float64, 3*rm.N)
		iwork := make([]int, rm.N)
		cond := lapack64.Trcon(condNorm, rm, work, iwork)
		if cond > condTol {
			return Condition(cond)
		}
		return nil
	}

	switch {
	case ar == ac:
		if a == b {
			// x = I.
			if ar == 1 {
				m.mat.Data[0] = 1
				return nil
			}
			for i := 0; i < ar; i++ {
				v := m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+ac]
				zero(v)
				v[i] = 1
			}
			return nil
		}
		var lu LU
		lu.Factorize(a)
		return m.SolveLU(&lu, false, b)
	case ar > ac:
		var qr QR
		qr.Factorize(a)
		return m.SolveQR(&qr, false, b)
	default:
		var lq LQ
		lq.Factorize(a)
		return m.SolveLQ(&lq, false, b)
	}
}