Skip to content

Commit

Permalink
Merge pull request #1066 from JuliaSymbolics/docs
Browse files Browse the repository at this point in the history
Improve the documentation of symbolic arrays and functions
  • Loading branch information
YingboMa authored Feb 21, 2024
2 parents 3020097 + 1da70ee commit b1fcc72
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 5 deletions.
15 changes: 13 additions & 2 deletions docs/src/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,20 @@ end
f([x, y, z]) # Recall that z = x^2 + y
```

Or we can build an array variable and use it to trace the function:
Or we can build an array of variables and use it to trace the function:

```@example symbolic_basics
@variables u[1:4]
u = Symbolics.variables(:u, 1:5)
f(u)
```

!!! note
`Symbolics.variables(:u, 1:5)` creates a Julia array of symbolic variables. This uses
O(n) compute and memory but is a very general representation. Symbolics.jl also has the
ability to represent symbolic arrays which gives an O(1) representation but is more
limited in its functionality. For more information, see the
[Symbolic Arrays](@symbolic_arrays) page.

## Derivatives

One common thing to compute in a symbolic system is derivatives. In
Expand Down Expand Up @@ -263,6 +270,10 @@ Symbolics.derivative(h(x, y) + y^2, x)
Symbolics.derivative(h(x, y) + y^2, y)
```

!!! note
`@register_symbolic` only allows for scalar outputs. If full array functions are needed,
then see `@register_array_symbolic` for registering functions of symbolic arrays.

## Building Functions

The function for building functions from symbolic expressions is the aptly-named `build_function`.
Expand Down
63 changes: 61 additions & 2 deletions docs/src/manual/arrays.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,63 @@
# Symbolic arrays
# [Symbolic Arrays](@id symbolic_arrays)

## Symbolic Arrays vs Arrays of Symbolic Expressions

Symbolics.jl contains two forms for handling symbolic arrays:

1. Arrays of symbolic expressions: these are Julia arrays with Symbolics.jl objects in them.
2. Symbolic Arrays: these are symbolic (O(1)) representations of arrays.

Arrays of symbolic expressions are simply Symbolics.jl objects put into Julia arrays. For
example:

```@example arrays
using Symbolics
@variables x y
u = [x,y]
```

is a vector of two symbolic variables. As shorthand,

```@example arrays
u2 = Symbolics.variables(:x, 1:3, 3:6)
```

creates a Julia matrix of symbolic variables. Indexing `u` or `u2` gives symbolic values
which act as a normal scalar symbolic value. This form these uses Julia's array functionality
and performs symbolic operations on the scalar values.

On the otherhand, Julia's symbolic array form is an O(1) representation of the whole array.

```@example arrays
@variables A[1:5, 1:3]
```

When using this form, `A[1,1]` is not a symbolic variable but a symbolic expression for
indexing the variable `A`. This representation holds linear algebra expressions in a
non-expanded form. For example:

```@example arrays
@variables B[1:3, 1:3]
A * B
```

in comparison to:

```@example arrays
a = Symbolics.variables(:a, 1:5, 1:3)
b = Symbolics.variables(:b, 1:3, 1:3)
a * b
```

This makes the symbolic array form much more efficient, but requires that the expressions
uses things with registered symbolic array functions which currently has much lower coverage.
Also, there are many fallbacks for which arrays of symbolics which makes this approach
more accessible but with larger expressions.

We recommend defaulting to arrays of symbolics unless you need the expression symplifications
of the symbolic array approach.

## Using Symbolic Arrays

Symbolic array-valued expressions (symbolic arrays) are supported by Symbolics. Symbolic array expressions propagate useful metadata that depends on input arrays: array dimension, element type and shape.

Expand Down Expand Up @@ -71,7 +130,7 @@ A .* b'
```@example arrays
map(asin, (A*b))
```
```@example arrays
```julia
#sum(A) #latexify not working
```
```@example arrays
Expand Down
4 changes: 4 additions & 0 deletions docs/src/manual/build_function.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ Symbolics._build_function(target::Symbolics.CTarget,eqs::Array{<:Equation},args.
Symbolics._build_function(target::Symbolics.StanTarget,eqs::Array{<:Equation}, vs, ps, iv;kwargs...)
Symbolics._build_function(target::Symbolics.MATLABTarget,eqs::Array{<:Equation},args...;kwargs...)
```

## Limitations

`build_function`
5 changes: 5 additions & 0 deletions docs/src/manual/derivatives.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ Differential
expand_derivatives
```

!!! note
For symbolic differentiation, all registered functions in the symbolic expression
need a registered derivative. For more information, see the
[function registration](@ref function_registration) page.

## High-Level Differentiation Functions

The following functions are not exported and thus must be accessed in a namespaced
Expand Down
28 changes: 28 additions & 0 deletions docs/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,34 @@ and pre-defines their derivatives. However, the user can utilize the
[`@register_symbolic`](@ref) macro to add their function to allowed functions
of the computation graph.

Additionally, [`@register_array_symbolic`](@ref) can be used to define array functions.
For size propagation it's required that a computation of how the sizes are computed is
also supplied.

## Defining Derivatives of Registered Functions

In order for symbolic differentiation to work, an overload of `Symbolics.derivative` is
required. The syntax is `derivative(typeof(f), args::NTuple{i,Any}, ::Val{j})` where
`i` is the number of arguments to the function and `j` is which argument is being
differentiated. So for example:

```julia
function derivative(::typeof(min), args::NTuple{2,Any}, ::Val{1})
x, y = args
IfElse.ifelse(x < y, one(x), zero(x))
end
```

is the partial derivative of the Julia `min(x,y)` function with respect to `x`.

!!! note
Downstream symbolic derivative functionality only work if every partial derivative that
is required in the derivative expression is defined. Note that you only need to define
the partial derivatives which are actually computed.

## Registration API

```@docs
@register_symbolic
@register_array_symbolic
```
5 changes: 4 additions & 1 deletion docs/src/manual/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ written as `op1 ~ op2`, defines the symbolic equality between two operations.

## Types

`Sym`, `Term`, and `FnType` are from [SymbolicUtils.jl](https://juliasymbolics.github.io/SymbolicUtils.jl/api/). Note that in
`Sym`, `Term`, and `FnType` are from
[SymbolicUtils.jl](https://juliasymbolics.github.io/SymbolicUtils.jl/api/). Note that in
Symbolics, we always use `Sym{Real}`, `Term{Real}`, and
`FnType{Tuple{Any}, Real}`. To get the arguments of an `istree` object, use
`arguments(t::Term)`, and to get the operation, use `operation(t::Term)`.
Expand All @@ -20,6 +21,8 @@ Instead, one needs to use `SymbolicUtils.istree` to check if `arguments` and

```@docs
@variables
Symbolics.variable
Symbolics.variables
Equation
Base.:~(::Num, ::Num)
```
Expand Down

0 comments on commit b1fcc72

Please sign in to comment.