Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation for array symbolic registration #1119

Merged
merged 1 commit into from
Apr 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/src/manual/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,77 @@ is the partial derivative of the Julia `min(x,y)` function with respect to `x`.
is required in the derivative expression is defined. Note that you only need to define
the partial derivatives which are actually computed.

## Registration of Array Functions

Similar to scalar functions, array functions can be registered to define new primitives for
functions which either take in or return arrays. This is done by using the `@register_array_symbolic`
macro. It acts similarly to the scalar function registration but requires a calculation of the
input and output sizes. For example, let's assume we wanted to have a function that computes the
solution to `Ax = b`, i.e. a linear solve, using an SVD factorization. In Julia, the code for this
would be `svdsolve(A,b) = svd(A)\b`. We would create this function as follows:

```@example array_registration
using LinearAlgebra, Symbolics

svdsolve(A, b) = svd(A)\b
@register_array_symbolic svdsolve(A::AbstractMatrix, b::AbstractVector) begin
size = size(b)
eltype = promote_type(eltype(A), eltype(b))
end
```

Now using the function `svdsolve` with symbolic array variables will be kept lazy:

```@example array_registration
@variables A[1:3, 1:3] b[1:3]
svdsolve(A,b)
```

Note that at this time array derivatives cannot be defined.

## Registration API

```@docs
@register_symbolic
@register_array_symbolic
```

## Direct Registration API (Advanced, Experimental)

!!! warn

This is a lower level API which is not as stable as the macro APIs.

In some circumstances you may need to use the direct API in order to define
registration on functions or types without using the macro. This is done
by directly defining dispatches on symbolic objects.

A good exmample of this is DataInterpolations.jl's interpolations object.
On an interpolation by a symbolic variable, we generate the symbolic
function (the `term`) for the interpolation function. This looks like:

```julia
using DataInterpolations, Symbolics, SymbolicUtils
(interp::AbstractInterpolation)(t::Num) = SymbolicUtils.term(interp, unwrap(t))
```

In order for this to work, it is required that we define the `symtype` for the
symbolic type inference. This is done via:

```julia
SymbolicUtils.promote_symtype(t::AbstractInterpolation, args...) = Real
```

Additionally a symbolic name is required:

```julia
Base.nameof(interp::AbstractInterpolation) = :Interpolation
```

The derivative is defined similarly to the macro case:

```julia
function Symbolics.derivative(interp::AbstractInterpolation, args::NTuple{1, Any}, ::Val{1})
Symbolics.unwrap(derivative(interp, Symbolics.wrap(args[1])))
end
```
Loading