Who "Symbolics.jl" is for?

Just a generic question on who is the target user for the Symbolics.jl package.
I had a quick look on it, looking to find some alternative to the python-based SymPy (and the SymPy.jl wrapper), but I have now doubts if the two packages are for the same kind of users.

I am a low-math, lazy guy, and all I want is find simple way to avoid pen and paper for computing tedious derivatives, integral (no, by parts no!), solving a few system of equations and so on.
SymPy and the SymPy tutorial are fantastic for these kind of things. I can even say I can arrive to understand them :slight_smile:

But then, looking at Symbolic.jl package I am pretty lost… it is full of topics that for me are “advanced” or look “of detail”… ok, I can arrive to understand a bit about IR and ASL because I frequent the Julia community by a while now, but my colleagues would be completely lost.
Sym, istree, “expression”, Num… what are these ?? (don’t answer, I got it after a while…) By comparison the SymPy tutorial is much more gently, it starts by showing how to achieve basic stuff and, for example, the “tree” concept is given only at the very end of the tutorial.
So, my question is if indeed the objective of the package is to provide a sympy-alternative in native Julia or the focus is a bit different/ do more advanced stuff…
I would point that I am not “complaining” about the documentation, I am only trying to understand who is the target group of this package.
For example the API is also more elaborated than SymPy.
For a derivative:
SymPy:

using SymPy
@vars q
utility   = 100q - 2q^2
marg_util = diff(utility,q)

Symbolics.jl:

using Symbolics
@variables q
utility   = 100q - 2q^2
marg_util = expand_derivatives(Differential(q)(utility)) # doesn't feel very intuitive...

Perhaps to be more general and/or efficient… but for basic things it is overwhelming :-/

9 Likes

I think Symbolics.jl would benefit from a tutorial that is similar to the Sympy walk through. I also could not follow how to do some straightforward things. In the mean time, a pointer to some example code snippets from other projects might be helpful.

1 Like

You can just write

Symbolics.derivative(utility, q)

It’s a bit unfortunate that derivative is not exported by default.

Personally, I think Symbolic.jl and other Julia packages for symbolic calculations are very useful when you want to embed symbolic calculations into high-performance Julia code. If you just need a glorified calculator to get some math done, probably there are better choices elsewhere.

2 Likes

I think a lot of the answer is that Symbolics was partially designed for use by code rather than users. The library came out of internal usage of the DifferentialEquations ecosystem, and it still has some of that heritage in its API.

5 Likes

The real answer is that it’s still young and needs work both in APIs and docs.

11 Likes

Yeah, this block of code shows up halfway through the very first tutorial, and I’ll go out on a limb and say that there’s not a single new user who’s gained a better understanding of Symbolics.jl by seeing it:

(var"##MTIIPVar#317", var"##MTKArg#315")->begin
        @inbounds begin
                @sync begin
                        let (x, y) = (var"##MTKArg#315"[1], var"##MTKArg#315"[2])
                            begin
                                Threads.@spawn begin
                                        (var"##MTIIPVar#317").nzval[1] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 1), (getproperty(Base, :^))(y, 7))
                                        (var"##MTIIPVar#317").nzval[2] = (getproperty(Base, :^))(x, 1)
                                        (var"##MTIIPVar#317").nzval[3] = (getproperty(Base, :^))(y, 1)
                                        (var"##MTIIPVar#317").nzval[4] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 2), (getproperty(Base, :^))(y, 6))
                                        (var"##MTIIPVar#317").nzval[5] = (getproperty(Base, :^))(x, 2)
                                        (var"##MTIIPVar#317").nzval[6] = (getproperty(Base, :^))(y, 2)
                                    end
                            end
                            begin
                                Threads.@spawn begin
                                        (var"##MTIIPVar#317").nzval[7] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 3), (getproperty(Base, :^))(y, 5))
                                        (var"##MTIIPVar#317").nzval[8] = (getproperty(Base, :^))(x, 3)
                                        (var"##MTIIPVar#317").nzval[9] = (getproperty(Base, :^))(y, 3)
                                        (var"##MTIIPVar#317").nzval[10] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 4), (getproperty(Base, :^))(y, 4))
                                        (var"##MTIIPVar#317").nzval[11] = (getproperty(Base, :^))(x, 4)
                                        (var"##MTIIPVar#317").nzval[12] = (getproperty(Base, :^))(y, 4)
                                    end
                            end
                            begin
                                Threads.@spawn begin
                                        (var"##MTIIPVar#317").nzval[13] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 5), (getproperty(Base, :^))(y, 3))
                                        (var"##MTIIPVar#317").nzval[14] = (getproperty(Base, :^))(x, 5)
                                        (var"##MTIIPVar#317").nzval[15] = (getproperty(Base, :^))(y, 5)
                                        (var"##MTIIPVar#317").nzval[16] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 6), (getproperty(Base, :^))(y, 2))
                                        (var"##MTIIPVar#317").nzval[17] = (getproperty(Base, :^))(x, 6)
                                        (var"##MTIIPVar#317").nzval[18] = (getproperty(Base, :^))(y, 6)
                                    end
                            end
                            begin
                                Threads.@spawn begin
                                        (var"##MTIIPVar#317").nzval[19] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 7), (getproperty(Base, :^))(y, 1))
                                        (var"##MTIIPVar#317").nzval[20] = (getproperty(Base, :^))(x, 7)
                                        (var"##MTIIPVar#317").nzval[21] = (getproperty(Base, :^))(y, 7)
                                        (var"##MTIIPVar#317").nzval[22] = (getproperty(Base, :*))((getproperty(Base, :^))(x, 8), (getproperty(Base, :^))(y, 0))
                                    end
                            end
                        end
                    end
            end
        nothing
    end

I just created a PR to move this example to the end of the tutorial (it’s currently before the examples for substitution and differentiation).

8 Likes