Symbolics.jl
Symbolics.jl copied to clipboard
Rogue `true` in inverse of a matrix
julia> @variables a, b, c, d
(a, b, c, d)
julia> A = [a b; c d]
2×2 Matrix{Num}:
a b
c d
julia> inv(A)
2×2 Matrix{Num}:
(a^-1)*(true + (b*c*(a^-1)*((d - (b*c*(a^-1)))^-1))) … -b*(a^-1)*((d - (b*c*(a^-1)))^-1)
-c*(a^-1)*((d - (b*c*(a^-1)))^-1) (d - (b*c*(a^-1)))^-1
Note the true
in A[1, 1].
┆Issue is synchronized with this Trello card by Unito
It does equal to d/det(A)
so at least it's not wrong :-). We might want to special case small inverses.
Maybe it should be returned in the form(1 / det(A)) * adj(A)
with the det
factored out?
In Julia v1.7 this has a nasty side effect:
julia> inv(A)
ERROR: MethodError: no method matching checknonsingular(::Int64, ::Val{true})
Closest candidates are:
checknonsingular(::Any) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.7/LinearAlgebra/src/factorization.jl:21
checknonsingular(::Any, ::LinearAlgebra.RowMaximum) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.7/LinearAlgebra/src/factorization.jl:19
checknonsingular(::Any, ::LinearAlgebra.NoPivot) at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.7/LinearAlgebra/src/factorization.jl:20
Stacktrace:
[1] sym_lu(A::Matrix{Num}; check::Bool)
@ Symbolics ~/.julia/packages/Symbolics/1TCCw/src/linear_algebra.jl:49
[2] #lu#25
@ ~/.julia/packages/Symbolics/1TCCw/src/num.jl:174 [inlined]
[3] lu
@ ~/.julia/packages/Symbolics/1TCCw/src/num.jl:174 [inlined]
[4] inv(A::Matrix{Num})
@ LinearAlgebra /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.7/LinearAlgebra/src/dense.jl:874
[5] top-level scope
@ REPL[7]:1
(Julia v1.7.0-beta3.0, SymbolicUtils v0.13.4, Symbolics v3.2.0)
Yeah that's not good. @YingboMa you got this one?
That's not related to this issue. Could you open another issue?
Is it not? As far as I can see, the problem comes from checknonsingular
being called on the true
that appears in the expression of the inverse, which maybe shouldn't be there in the first place?
That true is not related to this at all.
Ok, then I'll open another issue (#357).
I just had this issue, and in my case I have an upper triangular 2x2-matrix A
for which inv seems to compute ldiv!(A, Matrix{Num}(I, (2, 2)))
. The type of I
is UniformScaling{Bool}
and I get the result I expect by using 1.0*I
instead of I
to replace the UniformScaling{Bool}
by a UniformScaling{Float64}
.
The code in triangular.jl from the LinearAlgebra stdlib calls (in this case)
Matrix{Num}(I, (2, 2))
which becomes a matrix containing true
due to Num(true)
evaluating to a value true
.
I suggest that Num(true)
should return one(Num)
which is a "1" of some form instead of a symbolic expression with the content true
.
Is there a reason to want to treat symbolic boolean expressions at all, such as piecewise defined functions?
I expect that the standard library calls Matrix{Num}(I, (2, 2))
with the expectation that it return a value with ones along the diagonal, and I would therefore expect Num(true)
should return a value that represents the value 1 more clearly than true
does.
This seems to give me the behaviour I want, in the case I am looking at now:
import Symbolics: Num
Num(b :: Bool) = ifelse(b, one(Num), zero(Num))
Does this get some improvement? Currently result of inverse matrix is basically unreadable.
Does this get some improvement? Currently result of inverse matrix is basically unreadable.
Unfortunately no. See this related issue https://github.com/JuliaSymbolics/Symbolics.jl/issues/693.