Example #1
0
// Solve returns a matrix x that satisfies ax = b.
// It returns a nil matrix and ErrSingular if a is singular.
func Solve(a, b Matrix) (x *Dense, err error) {
	m, n := a.Dims()
	br, _ := b.Dims()
	if m != br {
		panic("rowMismatch")
	}
	switch {
	case m == n:
		var lu LU
		lu.Factorize(a)
		if lu.Det() == 0 {
			return nil, ErrSingular
		}
		x := DenseCopyOf(b)
		lapack64.Getrs(blas.NoTrans, lu.lu.mat, x.mat, lu.pivot)
		return x, nil
	default:
		_, bc := b.Dims()
		mn := max(m, n)
		// TODO(btracey): Employ special cases to avoid the copy where possible.
		aCopy := DenseCopyOf(a)
		x := NewDense(mn, bc, nil)

		x.Copy(b)
		work := make([]float64, 1)
		lapack64.Gels(blas.NoTrans, aCopy.mat, x.mat, work, -1)
		work = make([]float64, int(work[0]))
		ok := lapack64.Gels(blas.NoTrans, aCopy.mat, x.mat, work, len(work))
		if !ok {
			return nil, ErrSingular
		}
		return x.View(0, 0, n, bc).(*Dense), nil
	}
}
Example #2
0
// SolveLUVec solves a system of linear equations using the LU decomposition of a matrix.
// It computes
//  A * x = b if trans == false
//  A^T * x = b if trans == true
// In both cases, A is represeneted in LU factorized form, and the matrix x is
// stored into the receiver.
//
// If A is singular or near-singular a Condition error is returned. Please see
// the documentation for Condition for more information.
func (v *Vector) SolveLUVec(lu *LU, trans bool, b *Vector) error {
	_, n := lu.lu.Dims()
	bn := b.Len()
	if bn != n {
		panic(matrix.ErrShape)
	}
	// TODO(btracey): Should test the condition number instead of testing that
	// the determinant is exactly zero.
	if lu.Det() == 0 {
		return matrix.Condition(math.Inf(1))
	}

	v.reuseAs(n)
	var restore func()
	if v == b {
		v, restore = v.isolatedWorkspace(b)
		defer restore()
	}
	v.CopyVec(b)
	vMat := blas64.General{
		Rows:   n,
		Cols:   1,
		Stride: v.mat.Inc,
		Data:   v.mat.Data,
	}
	t := blas.NoTrans
	if trans {
		t = blas.Trans
	}
	lapack64.Getrs(t, lu.lu.mat, vMat, lu.pivot)
	if lu.cond > matrix.ConditionTolerance {
		return matrix.Condition(lu.cond)
	}
	return nil
}
Example #3
0
// SolveLU solves a system of linear equations using the LU decomposition of a matrix.
// It computes
//  A * x = b if trans == false
//  A^T * x = b if trans == true
// In both cases, A is represented in LU factorized form, and the matrix x is
// stored into the receiver.
//
// If A is singular or near-singular a Condition error is returned. Please see
// the documentation for Condition for more information.
func (m *Dense) SolveLU(lu *LU, trans bool, b Matrix) error {
	_, n := lu.lu.Dims()
	br, bc := b.Dims()
	if br != n {
		panic(matrix.ErrShape)
	}
	// TODO(btracey): Should test the condition number instead of testing that
	// the determinant is exactly zero.
	if lu.Det() == 0 {
		return matrix.Condition(math.Inf(1))
	}

	m.reuseAs(n, bc)
	bU, _ := untranspose(b)
	var restore func()
	if m == bU {
		m, restore = m.isolatedWorkspace(bU)
		defer restore()
	} else if rm, ok := bU.(RawMatrixer); ok {
		m.checkOverlap(rm.RawMatrix())
	}

	m.Copy(b)
	t := blas.NoTrans
	if trans {
		t = blas.Trans
	}
	lapack64.Getrs(t, lu.lu.mat, m.mat, lu.pivot)
	if lu.cond > matrix.ConditionTolerance {
		return matrix.Condition(lu.cond)
	}
	return nil
}
Example #4
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 a test for the condition number of A.
	// TODO(btracey): Add special cases for TriDense, SymDense, etc.
	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
		}
		// Solve using an LU decomposition.
		var lu LU
		lu.Factorize(a)
		if lu.Det() == 0 {
			return Condition(math.Inf(1))
		}
		bMat, bTrans := untranspose(b)
		if m == bMat && bTrans {
			var restore func()
			m, restore = m.isolatedWorkspace(bMat)
			defer restore()
		}
		if m != bMat {
			m.Copy(b)
		}
		lapack64.Getrs(blas.NoTrans, lu.lu.mat, m.mat, lu.pivot)
		return nil
	default:
		// Solve using QR/LQ.

		// Copy a since the corresponding LAPACK argument is modified during
		// the call.
		var aCopy Dense
		aCopy.Clone(a)

		x := getWorkspace(max(ar, ac), bc, false)
		defer putWorkspace(x)
		x.Copy(b)

		work := make([]float64, 1)
		lapack64.Gels(blas.NoTrans, aCopy.mat, x.mat, work, -1)
		work = make([]float64, int(work[0]))
		ok := lapack64.Gels(blas.NoTrans, aCopy.mat, x.mat, work, len(work))
		if !ok {
			return Condition(math.Inf(1))
		}
		m.Copy(x)
		return nil
	}
}