SymPyCore.sympy_plottingConstant

Plotting of symbolic objects.

The Plots package provide a uniform interface to many of Julia's plotting packages. SymPy plugs into Plots' "recipes."

The basic goal is that when Plots provides an interface for function objects, this package extends the interface to symbolic expressions.

In particular:

  • plot(ex::Sym, a, b; kwargs...) will plot a function evaluating ex over [a,b]

Example. Here we use the default backend for Plots to make a plot:

using Plots
@syms x
plot(x^2 - 2x, 0, 4)
  • plot(ex1, ex2, a, b; kwargs...) will plot the two expressions in a parametric plot over the interval [a,b].

Example:

@syms x
plot(sin(2x), cos(3x), 0, 4pi) ## also

For a few backends (those that support :path3d) a third symbolic expression may be added to have a 3d parametric plot rendered:

plot(sin(x), cos(x), x, 0, 4pi) # helix in 3d
  • plot(xs, ys, expression) will make a contour plot (for many backends).
@syms x y
plot(range(0,stop=5, length=50), range(0,stop=5, length=50), x*y)
  • To plot the surface z=ex(x,y) over a region we have Plots.surface. For example,
@syms x y
surface(-5:5, -5:5, 25 - x^2 - y^2)
  • To plot two or more functions at once, the style plot([ex1, ex2], a, b) does not work. Rather, use plot(ex1, a, b); plot!(ex2), as in:
@syms x
plot(sin(x), 0, 2pi)
plot!(cos(x))
source
SymPyCore.DifferentialType
Differential(x)

Use to find (partial) derivatives.

Example

@syms x y u()
Dx = Differential(x)
Dx(u(x,y))  # resolves to diff(u(x,y),x)
Dx(u)       # will evaluate diff(u(x), x)
(Dx^2)(u(x))  # two derivatives in x; not () to avoid 2u(x) eager evaluation
source
SymPyCore.DocType
SymPy.Doc(f::Symbol, [module=sympy])

Return docstring of f found within the specified module.

Examples

SymPy.Doc(:sin)
SymPy.Doc(:det, sympy.matrices)
## add module to query
SymPy.pyimport_conda("sympy.crypto.crypto", "sympy")
SymPy.Doc(:padded_key, sympy.crypto)
source
SymPyCore.IntrospectionType
 Introspection

Struct holding functions used to inspect an object

  • Introspection.func: Return pointer to Python function.
  • Introspection.operation: Return Julia generic function for given underlying function
  • Introspection.funcname: Returns name of function
  • Introspection.args: Returns arguments for expression or empty tuple
  • Introspection.arguments: Return arguments
  • Introspection.iscall: Check if object is an expression (with operation and arguments) or not
  • Introspection.class: Returns __class__ value
  • Introspection.classname: Returns __class__ value as a string
  • Introspection.similarterm: Create a similar term

Invariant:

As args returns symbolic objects, this becomes: every well-formed SymPy expression ex must either have length(args(ex)) == 0 or func(ex)(↓(args(ex))...) = ex.

Using the methods designed for SymbolicUtils usage, this becomes every expression one of !iscall(ex) or operation(ex)(args(ex)...) == ex should hold.

source
SymPyCore.SymType
Sym{T}

Main wrapper for symbolic Python objects.

This is useful for dispatching methods for generic functions. Sym is also used to make symbolic values, in particular numeric values can be made into symbolic values.

source
SymPyCore.SymFunctionType
SymFunction

A type and constructor to create symbolic functions. Such objects can be used for specifying differential equations. The macro @syms is also available for constructing SymFunctions (@syms f())

Examples:

julia> using SymPyPythonCall

julia> @syms t, v(); # recommended way to create a symbolic function

julia> u = SymFunction("u") # alternate
u

julia> diff(v(t), t) |> show
Derivative(v(t), t)

Extended help

For symbolic functions not wrapped in the SymFunction type, the sympy.Function constructor can be used, as can the symbols function to construct symbolic functions (F=sympy.Function("F", real=true); F = sympy.symbols("F", cls=sympy.Function, real=true)).

julia> @syms u(), v()::real, t
(u, v, t)

julia> sqrt(u(t)^2), sqrt(v(t)^2) # real values have different simplification rules
(sqrt(u(t)^2), Abs(v(t)))

Such functions are undefined functions in SymPy, and can be used symbolically, such as with taking derivatives:

julia> @syms x y u()
(x, y, u)

julia> diff(u(x), x) |> show
Derivative(u(x), x)

julia> diff(u(x, y), x) |> show
Derivative(u(x, y), x)

Here is one way to find the second derivative of an inverse function to f, utilizing the SymFunction class and the convenience Differential function:

julia> @syms f() f⁻¹() x;

julia> D = Differential(x) # ∂(f) is diff(f(x),x)
Differential(x)

julia> D² = D∘D
Differential(x) ∘ Differential(x)

julia> u1 = only(solve(D((f⁻¹∘f)(x))  ~ 1, D(f⁻¹)(f(x)))); show(u1)
1/Derivative(f(x), x)

julia> u2 = only(solve(D²((f⁻¹∘f)(x)) ~ 0, D²(f⁻¹)(f(x)))); show(u2)
-Derivative(f(x), (x, 2))*Derivative(f⁻¹(f(x)), f(x))/Derivative(f(x), x)^2

julia> u2(D(f⁻¹)(f(x)) => u1) |> show # f''/[f']^3
-Derivative(f(x), (x, 2))/Derivative(f(x), x)^3
source
SymPyCore.SymbolicCallableType
SymbolicCallable

Wrapper for python objects with a __call__ method. This is used by sympy.λ to call the underlying λ function without the user needing to manually convert Julia objects into Python objects and back.

Note

There are some times where this doesn't work well, and using sympy.o.λ along with and will work.

source
Base.:~Method
lhs ~ rhs

Specify an equation.

Alternative syntax to Eq(lhs, rhs) or lhs ⩵ rhs (\Equal[tab]). Notation borrowed from Symbolics.jl.

See rhs or lhs to extract the two sides.

Inequalities may be defined using other functions imported from CommonEq.

source
Base.matchMethod
match(pattern, expression, ...)

Match a pattern against an expression; returns a dictionary of matches.

If a match is unsuccessful, returns an empty dictionary. (SymPy returns "nothing")

The order of the arguments follows Julia's match function, not sympy.match, which can be used directly, otherwise.

source
Base.replaceMethod
replace(expression, pattern, value, ...)
replace(expression, pattern => value; kwargs...)

In the expression replace a matching pattern with the value. Returns the modified expression.

Extended help

From: SymPy Docs

Traverses an expression tree and performs replacement of matching subexpressions from the bottom to the top of the tree. The default approach is to do the replacement in a simultaneous fashion so changes made are targeted only once. If this is not desired or causes problems, simultaneous can be set to false. In addition, if an expression containing more than one Wild symbol is being used to match subexpressions and the exact flag is true, then the match will only succeed if non-zero values are received for each Wild that appears in the match pattern.

Differences from SymPy:

  • "types" are specified via calling func on the head of an expression: func(sin(x)) -> sin, or directly through sympy.sin

  • functions are only supported by calling into the glue package.

Examples (from the SymPy docs)

julia> using SymPyPythonCall


julia> @syms x, y, z
(x, y, z)

julia> f = log(sin(x)) + tan(sin(x^2)); show(f)
log(sin(x)) + tan(sin(x^2))

"type" -> "type"

Types are specified through func:

julia> func = Introspection.func
#399 (generic function with 1 method)

julia> replace(f, func(sin(x)), func(cos(x))) |> show # type -> type
log(cos(x)) + tan(cos(x^2))

The value sympy.sin does not work, as it is wrapped. Using ↓(sympy).sin will work:

julia> replace(f, ↓(sympy).sin, ↓(sympy).cos)
log(cos(x)) + tan(cos(x^2))

"pattern" -> "expression"

Using "Wild" variables allows a pattern to be replaced by an expression:

julia> a, b = Wild("a"), Wild("b")
(a_, b_)

julia> replace(f, sin(a), tan(2a)) |> show
log(tan(2*x)) + tan(tan(2*x^2))

julia> replace(f, sin(a), tan(a/2)) |> show
log(tan(x/2)) + tan(tan(x^2/2))

julia> f.replace(sin(a), a) |> show
log(x) + tan(x^2)

julia> (x*y).replace(a*x, a)
y

In the SymPy docs we have:

Matching is exact by default when more than one Wild symbol is used: matching fails unless the match gives non-zero values for all Wild symbols."

julia> replace(2x + y, a*x+b, b-a)  # y - 2
y - 2

julia> replace(2x + y, a*x+b, b-a, exact=false) |> show
y + 2/x

"type" -> "function"

To replace with a more complicated function, requires some assistance from Python, as an anonymous function must be defined within Python, not Julia. This is how it might be done:

julia> import PyCall

julia> ## Anonymous function a -> sin(2a)
       PyCall.py"""
       from sympy import sin, Mul
       def anonfn(*args):
           return sin(2*Mul(*args))
       """)


julia> replace(f, sympy.sin, PyCall.py"anonfn")
                   ⎛   ⎛   2⎞⎞
log(sin(2⋅x)) + tan⎝sin⎝2⋅x ⎠⎠

"pattern" -> "func"

The function is redefined, as a fixed argument is passed:

julia> PyCall.py"""
       from sympy import sin
       def anonfn(a):
           return sin(2*a)
       """

julia> replace(f, sin(a), PyCall.py"anonfn")
                   ⎛   ⎛   2⎞⎞
log(sin(2⋅x)) + tan⎝sin⎝2⋅x ⎠⎠

"func" -> "func"


julia> PyCall.py"""
       def fn1(expr):
           return expr.is_Number

       def fn2(expr):
           return expr**2
       """

julia> replace(2*sin(x^3), PyCall.py"fn1", PyCall.py"fn2")
     ⎛ 9⎞
4⋅sin⎝x ⎠
julia> PyCall.py"""
       def fn1(x):
           return x.is_Mul

       def fn2(x):
           return 2*x
       """

julia> replace(x*(x*y + 1), PyCall.py"fn1", PyCall.py"fn2")
2⋅x⋅(2⋅x⋅y + 1)
source
CommonSolve.solveFunction
solve

Use solve to solve algebraic equations.

Extended help

Examples:

julia> using SymPyPythonCall


julia> @syms x y a b c d
(x, y, a, b, c, d)

julia> solve(x^2 + 2x + 1, x) # [-1]
1-element Vector{Sym{PythonCall.Py}}:
 -1

julia> solve(x^2 + 2a*x + a^2, x) # [-a]
1-element Vector{Sym{PythonCall.Py}}:
 -a

julia> u = solve([a*x + b*y-3, c*x + b*y - 1], [x,y]); show(u[x])
2/(a - c)
Note

A very nice example using solve is a blog entry on Napoleon's theorem by Xing Shi Cai.

Systems

Use a tuple, not a vector, of equations when there is more than one.

source
SymPyCore.:↑Method

↑(::SymbolicObject)

Method to lift a python object into a symbolic counterpart.

source
SymPyCore.:↓Method

↓(::SymbolicObject) ↓ₖ([kwargs...])

The \downarrrow[tab] and \downarrow[tab]\_k[tab] operators push a symbolic object (or a container of symbolic objects) into a Python counterpart for passing to an underlying Python function.

source
SymPyCore.PermutationFunction
Permutation
PermutationGroup

Give access to the sympy.combinatorics.permutations module

Example

julia> using SymPyPythonCall

julia> p = Permutation([1,2,3,0])
(0 1 2 3)

julia> p^2
(0 2)(1 3)

julia> p^2 * p^2
()

Rubik's cube example from SymPy documentation

julia> F = Permutation([(2, 19, 21, 8),(3, 17, 20, 10),(4, 6, 7, 5)])
(2 19 21 8)(3 17 20 10)(4 6 7 5)

julia> R = Permutation([(1, 5, 21, 14),(3, 7, 23, 12),(8, 10, 11, 9)])
(1 5 21 14)(3 7 23 12)(8 10 11 9)

julia> D = Permutation([(6, 18, 14, 10),(7, 19, 15, 11),(20, 22, 23, 21)])
(6 18 14 10)(7 19 15 11)(20 22 23 21)

julia> G = PermutationGroup(F,R,D);

julia> G.order()
3674160
source
SymPyCore.PermutationGroupFunction
Permutation
PermutationGroup

Give access to the sympy.combinatorics.permutations module

Example

julia> using SymPyPythonCall

julia> p = Permutation([1,2,3,0])
(0 1 2 3)

julia> p^2
(0 2)(1 3)

julia> p^2 * p^2
()

Rubik's cube example from SymPy documentation

julia> F = Permutation([(2, 19, 21, 8),(3, 17, 20, 10),(4, 6, 7, 5)])
(2 19 21 8)(3 17 20 10)(4 6 7 5)

julia> R = Permutation([(1, 5, 21, 14),(3, 7, 23, 12),(8, 10, 11, 9)])
(1 5 21 14)(3 7 23 12)(8 10 11 9)

julia> D = Permutation([(6, 18, 14, 10),(7, 19, 15, 11),(20, 22, 23, 21)])
(6 18 14 10)(7 19 15 11)(20 22 23 21)

julia> G = PermutationGroup(F,R,D);

julia> G.order()
3674160
source
SymPyCore.doitMethod
doit

Evaluates objects that are not evaluated by default. Alias for object method.

Extended help

Examples:

julia> using SymPyPythonCall

julia> @syms x f()
(x, f)

julia> D = Differential(x)
Differential(x)

julia> df = D(f(x)); show(df)
Derivative(f(x), x)

julia> dfx = subs(df, (f(x), x^2));  show(dfx)
Derivative(x^2, x)

julia> doit(dfx)
2⋅x

Set deep=true to apply doit recursively to force evaluation of nested expressions:

julia> @syms g()
(g,)

julia> dgfx = g(dfx);  show(dgfx)
g(Derivative(x^2, x))

julia> doit(dgfx) |> show
g(Derivative(x^2, x))

julia> doit(dgfx, deep=true)
g(2⋅x)

There is also a curried form of doit:

julia> dfx |> doit
2⋅x

julia> dgfx |> doit(deep=true)
g(2⋅x)
source
SymPyCore.dsolveMethod
dsolve(eqn, var, args..,; ics=nothing, kwargs...)

Calls sympy.dsolve.

ics: The initial conditions are specified with a dictionary or nothing

Extended help

Example:

julia> using SymPyPythonCall

julia> @syms α, x, f(), g()
(α, x, f, g)

julia> ∂ = Differential(x)
Differential(x)

julia> eqn = ∂(f(x)) ~ α * x; show(eqn)
Eq(Derivative(f(x), x), x*α)
julia> dsolve(eqn) |> show
Eq(f(x), C1 + x^2*α/2)
julia> dsolve(eqn(α=>2); ics=Dict(f(0)=>1))
        2
f(x) = x  + 1

julia> eqn = ∂(∂(f(x))) ~ -f(x);

julia> dsolve(eqn)
f(x) = C₁⋅sin(x) + C₂⋅cos(x)

julia> dsolve(eqn; ics = Dict(f(0)=>1, ∂(f)(0) => -1))
f(x) = -sin(x) + cos(x)

julia> eqn = ∂(∂(f(x))) - f(x) - exp(x);

julia> dsolve(eqn, ics=Dict(f(0) => 1, f(1) => Sym(1//2))) |> show
Eq(f(x), (x/2 + (-exp(2) - 2 + E)/(-2 + 2*exp(2)))*exp(x) + (-E + 3*exp(2))*exp(-x)/(-2 + 2*exp(2)))
Systems

Use a tuple, not a vector, of equations when there is more than one.

julia> @syms x() y() t g
(x, y, t, g)

julia> ∂ = Differential(t)
Differential(t)

julia> eqns = (∂(x(t)) ~ y(t), ∂(y(t)) ~ x(t));

julia> dsolve(eqns)
2-element Vector{Sym{PythonCall.Py}}:
 Eq(x(t), -C1*exp(-t) + C2*exp(t))
  Eq(y(t), C1*exp(-t) + C2*exp(t))

julia> dsolve(eqns, ics = Dict(x(0) => 1, y(0) => 2))
2-element Vector{Sym{PythonCall.Py}}:
 Eq(x(t), 3*exp(t)/2 - exp(-t)/2)
 Eq(y(t), 3*exp(t)/2 + exp(-t)/2)

julia> eqns = (∂(∂(x(t))) ~ 0, ∂(∂(y(t))) ~ -g)
(Eq(Derivative(x(t), (t, 2)), 0), Eq(Derivative(y(t), (t, 2)), -g))

julia> dsolve(eqns)  # can't solve for initial conditions though! (NotAlgebraic)
2-element Vector{Sym{PythonCall.Py}}:
           x(t) = C₁ + C₂⋅t
 Eq(y(t), C3 + C4*t - g*t^2/2)

julia> @syms t x() y()
(t, x, y)

julia> eq = (∂(x)(t) ~ x(t)*y(t)*sin(t), ∂(y)(t) ~ y(t)^2 * sin(t));
julia> dsolve(eq)
Set{Sym{PythonCall.Py}} with 2 elements:
  Eq(x(t), -exp(C1)/(C2*exp(C1) - cos(t)))
  Eq(y(t), -1/(C1 - cos(t)))
source
SymPyCore.free_symbolsMethod
free_symbols(ex)
free_symbols(ex::Vector{Sym})

Return vector of free symbols of expression or vector of expressions. The results are orderded by sortperm(string.(fs)).

Example:

julia> using SymPyPythonCall

julia> @syms x y z a
(x, y, z, a)

julia> free_symbols(2*x + a*y) # [a, x, y]
3-element Vector{Sym{PythonCall.Py}}:
 a
 x
 y


julia> free_symbols([x^2, x^2 - 2x*y + y^2])
2-element Vector{Sym{PythonCall.Py}}:
 x
 y
source
SymPyCore.lambdifyFunction
lambdify(ex, vars=free_symbols();
         fns=Dict(), values=Dict, use_julia_code=false,
         invoke_latest=true)

Take a symbolic expression and return a Julia function or expression to build a function.

  • ex::Sym a symbolic expression with 0, 1, or more free symbols

  • vars a container of symbols to use for the function arguments. The default is free_symbols which has a specific ordering. Specifying vars allows this default ordering of arguments to be customized. If vars is empty, such as when the symbolic expression has no free symbols, a variable arg constant function is returned.

  • fns::Dict, vals::Dict: Dictionaries that allow customization of the function that walks the expression ex and creates the corresponding AST for a Julia expression. See SymPy.fn_map and SymPy.val_map for the default mappings of sympy functions and values into Julia's AST.

  • use_julia_code::Bool: use SymPy's conversion to an expression, the default is false

  • invoke_latest=true: if true will call eval and Base.invokelatest to return a function that should not have any world age issue. If false will return a Julia expression that can be evaled to produce a function.

Example:

julia> using SymPyPythonCall

julia> @syms x y z
(x, y, z)

julia> ex = x^2 * sin(x)
 2
x ⋅sin(x)

julia> fn = lambdify(ex);

julia> fn(pi)
0.0

julia> ex = x + 2y + 3z
x + 2⋅y + 3⋅z

julia> fn = lambdify(ex);

julia> fn(1,2,3) # order is by free_symbols
14

julia> ex(x=>1, y=>2, z=>3)
14

julia> fn = lambdify(ex, (y,x,z));

julia> fn(1,2,3)
13
Note

The default produces slower functions due to the calls to eval and Base.invokelatest. In the following g2 (which, as seen, requires additional work to compute) is as fast as calling f (on non symbolic types), whereas g1 is an order of magnitude slower in this example.

julia> @syms x
(x,)

julia> f(x) = exp(cot(x))
f (generic function with 1 method)

julia> g1 = lambdify(f(x));

julia> ex = lambdify(f(x), invoke_latest=false);

julia> @eval g2(x) = ($ex)(x)
g2 (generic function with 1 method)

An alternative, say, is to use GeneralizedGenerated's mk_function, as follows:

julia> using GeneralizedGenerated

julia> body = convert(Expr, f(x))
:(exp(cot(x)))

julia> g3 = mk_function((:x,), (), body)
function = (x;) -> begin
    (Main).exp((Main).cot(x))
end

This function will be about 2-3 times slower than f.

source
SymPyCore.lhsFunction
rhs(eqn)
lhs(eqn)

Returns right (or left) side of an equation object. Wrappers around eqn.rhs() and eqn.lhs().

source
SymPyCore.rhsFunction
rhs(eqn)
lhs(eqn)

Returns right (or left) side of an equation object. Wrappers around eqn.rhs() and eqn.lhs().

source
SymPyCore.rootsMethod
roots

Find roots of a polynomial. Not exported, so needs to be qualified, as in sympy.roots.

Example

julia> sympy.roots(x^2 - 2x - 3)
Dict{} with 2 entries:
  3  => 1
  -1 => 1

SymPy documentation

source
SymPyCore.simplifyMethod
simplify

SymPy has dozens of functions to perform various kinds of simplification. There is also one general function called simplify that attempts to apply all of these functions in an intelligent way to arrive at the simplest form of an expression. (See Simplification for details on simplify and other related functionality). Other simplification functions are available through the sympy object.

For non-symbolic expressions, simplify returns its first argument.

source
SymPyCore.solvesetMethod
solveset

Like solve but returns a set object. Finite sets are returned as Set objects in Julia. Infinite sets must be queried.

Example

julia> @syms x
(x,)

julia> u = solveset(sin(x) ~ 1//2, x)
⎧        5⋅π │      ⎫   ⎧        π │      ⎫
⎨2⋅n⋅π + ───  │ n ∊ ℤ⎬ ∪ ⎨2⋅n⋅π + ─ │ n ∊ ℤ⎬
⎩         6  │      ⎭   ⎩        6 │      ⎭

julia> intersect(u, sympy.Interval(0, 2PI))
Set{Sym} with 2 elements:
  pi/6
  5*pi/6

SymPy documentation

source
SymPyCore.subsMethod

subs is used to substitute a value in an expression with another value. Examples:

julia> using SymPyPythonCall



julia> @syms x,y
(x, y)

julia> ex = (x-y)*(x+2y)
(x - y)⋅(x + 2⋅y)

julia> subs(ex, (y, y^2)) |> show
(x - y^2)*(x + 2*y^2)

julia> subs(ex, (x,1), (y,2))
-5

julia> subs(ex, (x,y^3), (y,2))
72

julia> subs(ex, y, 3)
(x - 3)⋅(x + 6)

There is a curried form of subs to use with the chaining |> operator

julia> ex |> subs(x,ℯ)
(ℯ - y)⋅(2⋅y + ℯ)

The use of pairs gives a convenient alternative:

julia> subs(ex, x=>1, y=>2)
-5

julia> ex |> subs(x=>1, y=>2)
-5
source
SymPyCore.walk_expressionMethod
walk_expression(ex; values=Dict(), fns=Dict())

Convert a symbolic SymPy expression into a Julia expression. This is needed to use functions in external packages in lambdified functions.

Extended help

Example

using SymPy
@syms x y
ex = sympy.hyper((2,2),(3,3),x) * y

Calling lambdify(ex) will fail to make a valid function, as hyper is implemented in HypergeometricFunctions.pFq. So, we have:

using HypergeometricFunctions
d = Dict("hyper" => :pFq)
body = SymPy.walk_expression(ex, fns=d)
syms = Symbol.(free_symbols(ex))
fn = eval(Expr(:function, Expr(:call, gensym(), syms...), body));
fn(1,1) # 1.6015187080185656
source