# Defining diffusion

The main utility macro introduced in this package is `@diffusion_process`

. It facilitates very concise definitions of structs characterizing diffusion processes.

There are two (optionally three) parts expected by the macro:

- the name of the diffusion (which, optionally, may contain template parameters in the curly brackets)
- and the recipe for defining a struct

```
@diffusion_process NAME{TEMPLATE_PARAMETERS} begin
RECIPE
end
```

the snippet of code above creates a struct named `NAME`

according to specifications listed in the `RECIPE`

.

## Customization of a struct

The `RECIPE`

may contain information pertinent to five distinct categories:

- Specification of
`:dimensions`

- Specification of
`:parameters`

(their names and datatypes) - Specification of
`:constant_parameters`

(their names and datatypes) - Specification of
`:auxiliary_info`

`:additional`

information

Each type needs to be announced to `julia`

by starting the list with the corresponding `Symbol`

(or `QuoteNode`

).

For many users knowing only about `:dimensions`

, `:parameters`

and `:additional`

will be sufficient and the other categories will not be of much importance.

### Example

It's best to look at a simple example. Consider the definition of a Lorenz system:

```
@diffusion_process Lorenz{T} begin
:dimensions
process --> 3
wiener --> 3
:parameters
_ --> (3, T)
σ --> Float64
:additional
constdiff --> true
diagonaldiff --> true
end
```

The macro above expands to:

```
mutable struct Lorenz{T} <: DiffusionProcess{Float64, 3, 3, UnboundedStateSpace()}
p1::T
p2::T
p3::T
σ::Float64
function Lorenz(p1::T, p2::T, p3::T, σ::Float64) where T
new{T}(p1, p2, p3, σ)
end
function Lorenz(; p1::T, p2::T, p3::T, σ::Float64) where T
new{T}(p1, p2, p3, σ)
end
end
```

which defines a parametric type`Lorenz{T}`

, together with some handy auxiliary functions specific to any instance of `Lorenz{T}`

. We may now instantiate the newly defined struct as in

```
P_f64 = Lorenz(10.0, 28.0, 8.0/3.0, 0.2)
# or
P_f32 = Lorenz(10.0f0, 28.0f0, 8.0f0/3.0f0, 0.2)
```

We can also call some functions that were auto-generated for the newly defined `Lorenz`

struct, for instance

```
DD.parameter_names(Lorenz) == (:p1, :p2, :p3, :σ)
DD.parameter_names(P_f64) == (:p1, :p2, :p3, :σ)
DD.parameters(P_f64) == Dict(:p1 => 10.0, :p2 => 28.0, :p3 => 8.0/3.0, :σ => 0.2)
```

More functions are automatically defined in the background for each generated `DiffusionProcess`

, to learn more about them see the list of Utility Functions.

## Systematic explanations

The following information can be specified in the definition of a diffusion law when calling a macro `@diffusion_process`

.

All keywords read by `@diffusion_process`

are **case-insensitive**.

#### Category 1: `:dimensions`

Specification of the dimension of the process and the dimension of the driving Brownian motion. Must be written in a format:

`process --> dimension`

OR`wiener --> dimension`

(eg.`process --> 4`

).

In both cases, if left unspecified then defaults to `dimension=1`

.

`:dimensions`

is not the only keyword that will be recognized by `@diffusion_process`

as declaring the dimensions of the process. Alternative names that could be used in place of `:dimensions`

are: `:dim`

, `:dims`

, `:dimension`

#### Category 2: `:parameters`

List of all parameters that the law depends on.

`@diffusion_process`

understands `_`

as "*the user doesn't care about the name, so let's use a generic name based on the letter p and append it with a disambiguation number so that if there are more than one p's they are not confused with each other*"

The parameters must be specified in one of the following formats:

`single-parameter-name --> single-data-type`

, (eg.`σ --> Float64`

or`σ --> T`

(if`T`

is one of the template's labels) or`_ --> Vector{Int32}`

).

`single-parameter-name --> (multiple-data-types,)`

(eg.`σ --> (Float64, Int64)`

,`_ --> (Int32, T)`

).

`single-parameter-name --> (number-of-parameters, data-type)`

(eg.`σ --> (3, Float64)`

)

`number-of-parameters`

-many parameters of the same data type.`(multiple-parameter-names,) --> single-data-type`

(eg.`(α, β, γ) --> Int64`

)

`(multiple-parameter-names,) --> (multiple-data-types,)`

(eg.`(α, β, γ) --> (Float64, Int64, T)`

)

`AssertionError`

otherwise) and sets them to be of the corresponding type.

`:parameters`

keyword alternatives: `:param`

, `:params`

#### Category 3: `:constant_parameters`

These can be defined in exactly the same way as `:parameters`

. The only purpose for splitting the parameters into `:constant_parameters`

and `:parameters`

is to indicate to `Julia`

that the set of all parameters may be split into two conceptually different groups. In particular, `@diffusion_process`

defines utility functions that act differently with `:constant_parameters`

and `:parameters`

:

`DiffusionDefinition.parameters`

— Function`parameters(P::DiffusionProcess)`

Return a tuple of pairs of `parameter_name`

=> `parameter_value`

.

`DiffusionDefinition.const_parameters`

— Function`const_parameters(P::DiffusionProcess)`

Return a tuple of pairs of `parameter_name`

=> `parameter_value`

. Return only those parameteres that are considered to be `constant`

.

`DiffusionDefinition.var_parameters`

— Function`var_parameters(P::DiffusionProcess)`

Return a tuple of pairs of `parameter_name`

=> `parameter_value`

. Return only those parameteres that are considered to be `variable`

.

`DiffusionDefinition.parameter_names`

— Function`parameter_names(P::DiffusionProcess)`

Return a tuple with the names of all paremeters.

`parameter_names(::Type{<:DiffusionProcess})`

Return a tuple with the names of all paremeters.

`DiffusionDefinition.const_parameter_names`

— Function`const_parameter_names(P::DiffusionProcess)`

Return a tuple with the names of all paremeters that are considered to be `constant`

.

`const_parameter_names(P::Type{<:DiffusionProcess})`

Return a tuple with the names of all paremeters that are considered to be `constant`

.

`DiffusionDefinition.var_parameter_names`

— Function`var_parameter_names(P::DiffusionProcess)`

Return a tuple with the names of all paremeters that are considered to be `variable`

.

`var_parameter_names(P::Type{<:DiffusionProcess})`

Return a tuple with the names of all paremeters that are considered to be `variable`

.

The split into `constant`

and `variable`

parameters is not done at a compile time and can also be done by hand after the `struct`

with the diffusion has been constructed. For instance, in the `Lorenz`

example above we have:

```
julia> DD.parameters(P_f64)
Dict{Symbol,Float64} with 4 entries:
:p2 => 28.0
:σ => 0.2
:p1 => 10.0
:p3 => 2.66667
julia> DD.const_parameters(P_f64)
Dict{Any,Any} with 0 entries
julia> DD.var_parameters(P_f64)
Dict{Symbol,Float64} with 4 entries:
:p2 => 28.0
:σ => 0.2
:p1 => 10.0
:p3 => 2.66667
```

If we wanted to change our mind and define, say, `:p1`

and `:p3`

as `constant`

parameters we could do that by overwriting the definition of the `const_parameter_names(::Type{<:CustomDiffusionLaw})`

method, as all other functions of this type are computed as a byproduct of `parameter_names(::Type{<:CustomDiffusionLaw})`

and `const_parameter_names(::Type{<:CustomDiffusionLaw})`

and the former one should never change.

`DD.const_parameter_names(::Type{<:Lorenz}) = (:p1, :p3)`

That's all that needs to be changed.

`:constant_parameters`

keyword alternatives: `const_parameters`

, `:const_param`

, `:const_params`

, `:constparameters`

, `:constparam`

, `:constparams`

, `:constant_param`

, `:constant_params`

, `:constantparameters`

, `:constantparam`

, and `:constantparams`

.

#### Category 4: `:auxiliary_info`

Information about the end-points of the diffusion. This is a useful feature for guided proposals or simulation of diffusion bridges, where the process is conditioned to hit a certain end-point. In particular, it is used quite extensively in the package GuidedProposals.jl. The following fields can be defined:

`t0`

(also accepts`:t_0`

): the starting time-point`T`

: the final time-point`v0`

(also accepts`:obs0`

,`:v_0`

,`:obs_0`

): the starting observation`vT`

(also accepts`:obsT`

,`:v_T`

,`:obs_T`

): the observation at the terminal time

Each one of these fields can be defined in a format `field-name --> field-type`

(e.g. `T --> Float64`

).

`auxiliary_info`

keyword alternatives: `:aux_info`

, `:end_points`

, `:end_point_info`

#### Category 5: `:additional`

The additional information provides some additional decorators that helps the compiler use specialized functions when called on instances of corresponding diffusion processes. The following information can be specified

`constdiff --> true`

(or`false`

) depending on whether the volatility coefficient is independent from the state variable (`false`

by default).- Alternative keywords:
`:constvola`

,`:constdiffusivity`

,`:constvolatility`

,`:constσ`

,`:constantdiff`

,`:constantvola`

,`:constantdiffusivity`

,`:constantvolatility`

,`:constantσ`

.

- Alternative keywords:
`diagonaldiff --> true`

(or`false`

) to indicate that the volatility coefficient is represented by a diagonal matrix (`false`

by default).- Alternative keywords:
`:diagonalvola`

,`:diagonaldiffusivity`

,`:diagonalvolatility`

,`:diagonalσ`

,`:diagdiff`

,`:diagvola`

,`:diagdiffusivity`

,`:diagvolatility`

,`:diagσ`

.

- Alternative keywords:
`sparsediff --> true`

(or`false`

) to indicate that the volatility coefficient is a represented by a sparse matrix (`false`

by default).- Alternative keywords:
`:sparsevola`

,`:sparsediffusivity`

,`:sparsevolatility`

,`:sparseσ`

.

- Alternative keywords:
`linear --> true`

(or`false`

) to indicate that a diffusion has a linear structure (`false`

by default).`diagonalbmat --> true`

(or`false`

) to indicate that a`B`

matrix of a linear diffusion (with a drift`b(x):=Bx+β`

) is diagonal (`false`

by default).- Alternative keywords:
`:diagonalb`

,`:diagonalbmatrix`

.

- Alternative keywords:
`sparsebmat --> true`

(or`false`

) to indicate that a`B`

matrix of a linear diffusion (with a drift`b(x):=Bx+β`

) is sparse (`false`

by default).- Alternative keywords:
`:sparseb`

,`:sparsebmatrix`

.

- Alternative keywords:
`statespace --> type-of-state-space-restrictions`

(eg.`statespace --> UnboundedStateSpace()`

) indicates any restrictions made on the state-space of a diffusion process.`eltype --> type-of-parameter`

(eg.`eltype --> Float64`

) disambiguate the parameter type in case multiple types are used. This is useful for automatic differentiation where the derivatives of only a subset of parameters are taken and it is the eltype of those parameters that is of interest. [**TODO**come back, not sure anymore if it has any use]

`:additional`

keyword alternatives: `:extra`

## Additional functions

For each struct defining a diffusion law we may define some additional functions that are not automatically generated by the `@diffusion_process`

macro. These additional functions can provide us with some extra functionality implemented in other packages of the JuliaDiffusionBayes suite.

There are two groups of extra functions

Functions that are needed for the

*conjugate updates*from the package DiffusionMCMC.jl. They are discussed in detail here.Functions needed for

*blocking*, that can be implemented for instance with the package GuidedProposals.jl or DiffusionMCMC.jl. These need to be overwritten**only if your diffusion is hypoelliptic**, otherwise the defaults will work just fine. The first one is a function`nonhypo`

, with the documentation that can be found here. It can be overwritten directly, or can be defined automatically when defining conjugate updates. The second function is

`DiffusionDefinition.nonhypo_σ`

— Function`nonhypo_σ((t,i)::IndexedTime, x, P::DiffusionProcess)`

Return a sub-matrix of the full volatility matrix `σ`

that consists of non-zero rows of `σ`

.

`nonhypo_σ(t::Float64, x, P)`

Return a sub-matrix of the full volatility matrix `σ`

that consists of non-zero rows of `σ`

.

The functions from the latter group are not discussed any further in this documentation. Please see the tutorial on blocking from GuidedProposals.jl to learn more.