// 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 } }
// 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 }
// 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 }
// 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 } }