// Inverse computes the inverse of the 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 (m *Dense) Inverse(a Matrix) error { // TODO(btracey): Special case for RawTriangular, etc. r, c := a.Dims() if r != c { panic(ErrSquare) } m.reuseAs(a.Dims()) aMat, aTrans := untranspose(a) if m != aMat { m.Copy(a) } else if aTrans { tmp := getWorkspace(r, c, false) tmp.Copy(a) m.Copy(tmp) putWorkspace(tmp) } ipiv := make([]int, r) lapack64.Getrf(m.mat, ipiv) work := make([]float64, 1, 4*r) // must be at least 4*r for cond. lapack64.Getri(m.mat, ipiv, work, -1) if int(work[0]) > 4*r { work = make([]float64, int(work[0])) } else { work = work[:4*r] } lapack64.Getri(m.mat, ipiv, work, len(work)) norm := lapack64.Lange(condNorm, m.mat, work) cond := lapack64.Gecon(condNorm, m.mat, norm, work, ipiv) // reuse ipiv if cond > condTol { return Condition(cond) } return nil }
// Inverse computes the inverse of the 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 (m *Dense) Inverse(a Matrix) error { // TODO(btracey): Special case for RawTriangular, etc. r, c := a.Dims() if r != c { panic(matrix.ErrSquare) } m.reuseAs(a.Dims()) aU, aTrans := untranspose(a) switch rm := aU.(type) { case RawMatrixer: if m != aU || aTrans { if m == aU || m.checkOverlap(rm.RawMatrix()) { tmp := getWorkspace(r, c, false) tmp.Copy(a) m.Copy(tmp) putWorkspace(tmp) break } m.Copy(a) } default: if m != aU { m.Copy(a) } else if aTrans { // m and a share data so Copy cannot be used directly. tmp := getWorkspace(r, c, false) tmp.Copy(a) m.Copy(tmp) putWorkspace(tmp) } } ipiv := make([]int, r) lapack64.Getrf(m.mat, ipiv) work := make([]float64, 1, 4*r) // must be at least 4*r for cond. lapack64.Getri(m.mat, ipiv, work, -1) if int(work[0]) > 4*r { work = make([]float64, int(work[0])) } else { work = work[:4*r] } lapack64.Getri(m.mat, ipiv, work, len(work)) norm := lapack64.Lange(matrix.CondNorm, m.mat, work) cond := lapack64.Gecon(matrix.CondNorm, m.mat, norm, work, ipiv) // reuse ipiv if cond > matrix.ConditionTolerance { return matrix.Condition(cond) } return nil }