Skip to content

Public Documentation ​

Documentation for LoweredDistributions's public interface.

LoweredDistributions.LoweredDistributions Module
julia
LoweredDistributions

A distribution-lowering hub: lower maps a Distributions Distribution onto a backend-agnostic dynamical-systems representation, an AbstractLowering.

Two branches populate the hierarchy:

  • the phase-type branch, AbstractChainTrick — ErlangChain, Coxian, and PhaseType, all built from a finite absorbing Markov chain over exponential phases, and all convertible to the canonical PhaseType(α, S) view;

  • the memoryless generator, CTMC, built with ctmc.

lower dispatches a Distribution to one of these; phase_type is the adaptive two-moment fit (ErlangChain for c² ≤ 1, PhaseType for c² > 1) lower uses for anything without an exact lowering. Four weak-dependency extensions turn any AbstractLowering into a backend object: Catalyst.jl (reaction-network Reactions via linear_chain_reactions, or a full ReactionSystem via reaction_system), SciMLBase.jl (the linear forward-Kolmogorov ODEProblem via ode_problem), AlgebraicPetri.jl (a LabelledPetriNet via petri_net), and JumpProcesses.jl (an exact-simulation JumpProblem via jump_problem).

julia
using LoweredDistributions, Distributions

lower(Exponential(2.0))
lower(Gamma(3.0, 1.5))
source

Contents ​

Index ​

Public API ​

LoweredDistributions.AbstractChainTrick Type
julia
abstract type AbstractChainTrick <: LoweredDistributions.AbstractLowering

Phase-type branch of AbstractLowering.

Representations built from a finite absorbing Markov chain over exponential phases: ErlangChain, Coxian, and PhaseType. Every concrete subtype converts to the canonical PhaseType(α, S) view (see PhaseType(::AbstractChainTrick) methods), which is what a downstream backend (e.g. the Catalyst extension) consumes.


Fields

source
LoweredDistributions.AbstractLowering Type
julia
abstract type AbstractLowering

Root of the distribution-lowering hierarchy.

A backend-agnostic dynamical-systems representation that lower produces from a Distributions.Distribution. CTMC subtypes this directly; the phase-type representations subtype it through AbstractChainTrick.


Fields

source
LoweredDistributions.CTMC Type
julia
struct CTMC{St<:Tuple, M<:(AbstractMatrix)} <: LoweredDistributions.AbstractLowering

A continuous-time Markov chain generator over states.

CTMC holds a transition-intensity (generator) matrix Q over an ordered set of states. Off-diagonal Q[i, j] is the i -> j transition rate, and each diagonal is Q[i, i] = -sum_{j != i} Q[i, j]. Holding times are exponential, so the transition-probability matrix is P(t) = exp(Q t) in closed form (see transition_probability).

Build it with ctmc.

See also


Fields

  • states::Tuple: Ordered state names; the Q rows / columns follow this order.

  • Q::AbstractMatrix: The generator matrix (rows sum to zero).

source
LoweredDistributions.ChainStage Type
julia
struct ChainStage{T<:Real}

A single Erlang stage of a linear-chain delay representation.

An Erlang(, ) delay is stages = k Exponential sub-compartments in series, each leaving at rate = 1/\theta. An Exponential() delay is the stages = 1 case. The mean dwell time is stages / rate; name records which step of a chain the stage came from (:delay for a single leaf).

See also


Fields

  • name::Symbol: Step name this stage was extracted from.

  • rate::Real: Per-stage exit rate .

  • stages::Int64: Number of Exponential sub-compartments .

source
LoweredDistributions.Coxian Type
julia
struct Coxian{R<:(AbstractVector{<:Real}), P<:(AbstractVector{<:Real})} <: LoweredDistributions.AbstractChainTrick

A Coxian phase-type: stages exponential phases visited in order, each absorbing with probability 1 - probs[i] instead of continuing to phase i + 1 (probs[end] is ignored — the last phase always absorbs on exit).

A sequential (never-branching) chain like this can only reach a squared coefficient of variation c² ≤ 1 (the same regime as ErlangChain, which it generalises to heterogeneous per-phase rates); an over-dispersed c² > 1 delay needs the branching a general PhaseType allows (see phase_type).

See also

  • PhaseType: PhaseType(::Coxian) gives the canonical (α, S) embedding.

Fields

  • rates::AbstractVector{<:Real}: Per-phase exit rate.

  • probs::AbstractVector{<:Real}: Per-phase probability of continuing to the next phase.

source
LoweredDistributions.ErlangChain Type
julia
struct ErlangChain{S<:(AbstractVector{<:ChainStage})} <: LoweredDistributions.AbstractChainTrick

An exact or moment-matched Erlang chain: compartment_stages wrapped as an AbstractChainTrick.

See also


Fields

  • stages::AbstractVector{<:ChainStage}: The per-step stages, in chain order.
source
LoweredDistributions.PhaseType Type
julia
struct PhaseType{A<:(AbstractVector{<:Real}), M<:(AbstractMatrix{<:Real})} <: LoweredDistributions.AbstractChainTrick

A general phase-type distribution: an initial distribution α over transient phases plus a sub-generator S (the absorbing continuous-time Markov chain of a finite mixture / chain of exponential phases).

α sums to one; S has non-positive diagonal, non-negative off-diagonal, and row sums ≤ 0 (the shortfall -sum(S[i, :]) is phase i's exit rate to the absorbing state).

See also

  • Coxian, ErlangChain: narrower representations this type generalises; both convert here via PhaseType(::Coxian) / PhaseType(::ErlangChain).

  • phase_type: the adaptive fit that returns this for c² > 1.


Fields

  • α::AbstractVector{<:Real}: Initial distribution over phases.

  • S::AbstractMatrix{<:Real}: Sub-generator over the transient phases.

source
LoweredDistributions.compartment_stages Function
julia
compartment_stages(
    d::Distributions.Distribution;
    name,
    moment_match
) -> Vector{T} where T<:ChainStage

Lower a delay distribution to its compartment-stage structure.

An Exponential(θ) leaf gives one stage at rate ; an Erlang(k, θ) leaf (an integer-shape Gamma) gives k stages at rate . Exact only for Exponential / Erlang leaves; any other family throws unless moment_match = true, which lowers to the nearest Erlang chain by matching the mean and squared coefficient of variation c² = var / mean² (stages = round(1 / c²), rate = stages / mean). An over-dispersed delay (c² > 1) still throws — see phase_type for that case.

Arguments

  • d: an Exp/Erlang delay leaf to lower.

Keyword Arguments

  • name: the ChainStage name (default :delay).

  • moment_match: lower a non-Erlang leaf to the nearest Erlang chain instead of throwing (default false).

Examples

julia
using LoweredDistributions, Distributions

compartment_stages(Gamma(3.0, 1.5))

See also

source
LoweredDistributions.ctmc Function
julia
ctmc(
    specs::Pair...
) -> CTMC{St, M} where {St<:Tuple{Vararg{Symbol}}, M<:(Matrix)}

Build a CTMC from from => (to => rate, ...) transition-rate specs.

Each argument is from => transitions, where transitions lists the outgoing to => rate edges of state from (a single edge or a tuple / NamedTuple of them). The state order is the order of first appearance (each from, then any to-only absorbing states).

Enzyme

ctmc(specs...) does not differentiate under Enzyme (forward or reverse): the heterogeneous Pair vararg spec parsing hits an upstream Enzyme compiler limitation. ForwardDiff, ReverseDiff, and Mooncake (both modes) differentiate it correctly; the plain _matrix_exp / transition_probability kernel differentiates cleanly under every backend including Enzyme (see the ADFixtures :recurrent scenarios), which isolates the break to this builder's spec parsing rather than the matrix exponential.

Arguments

  • specs: from => transitions pairs; transitions is a single to => rate edge or a tuple / NamedTuple of to => rate edges (rate >= 0).

Examples

julia
using LoweredDistributions

model = ctmc(
    :well => (:ill => 0.2),
    :ill => (:well => 0.3, :dead => 0.1))
transition_probability(model, 5.0)

See also

source
LoweredDistributions.jump_problem Function
julia
jump_problem(m::AbstractLowering, tspan; u0 = nothing)

Build a JumpProcesses.JumpProblem that exactly simulates a single individual jumping between m's states at its generator rates (a Gillespie/Doob sample path of the underlying continuous-time Markov chain). Solving it (e.g. with SSAStepper()) draws one such path over tspan.

Every off-diagonal generator entry Q[i, j] > 0 becomes one JumpProcesses.MassActionJump transition state_i -> state_j at that constant rate, applied to a per-state population count (u, integers), not the occupation-probability vector ode_problem and petri_net use.

Distributional interpretation. For an m produced by lower started from its default u0 (a single individual deterministically in the first/entry state — every ErlangChain/Coxian/CTMC lowering, and any PhaseType with a one-hot α), the chain is guaranteed to reach the absorbing state, and the time it first does so is one exact draw from the Distribution that m lowers. This does NOT hold for an arbitrary m: a hand-built ctmc need not have an absorbing state at all (the simulation then just runs until tspan ends), and a PhaseType with a genuine mixture α (e.g. from phase_type's hyperexponential fit) has no single deterministic starting state to default from — an explicit u0 there fixes the simulation to start from that one state, giving a draw from the distribution conditional on that starting phase, not from the mixture itself. To draw an exact mixture sample, sample the starting phase from α yourself (e.g. rand(Categorical(α))) and pass the matching one-hot u0.

Only defined when JumpProcesses is loaded (using JumpProcesses); the method lives in the LoweredDistributionsJumpProcessesExt package extension.

Arguments

  • m: the AbstractLowering to build the jump process for, or a Distribution that lowers to one.

  • tspan: the (t0, t1) simulation span.

Keyword Arguments

  • u0: the initial per-state population counts (a Vector{<:Integer}). Defaults to a single individual in the first state, which is what every ErlangChain/Coxian/CTMC lowering starts from; a general PhaseType with a mixture initial distribution α (e.g. from phase_type's hyperexponential fit) has no single deterministic starting state, so it needs an explicit u0 here — see "Distributional interpretation" above for what that u0 does and does not guarantee.

Examples

julia
using LoweredDistributions, JumpProcesses

model = ctmc(:well => (:ill => 0.2), :ill => (:well => 0.3, :dead => 0.1))
prob = jump_problem(model, (0.0, 5.0))
sol = solve(prob, SSAStepper())
sol.u[end]

See also

source
LoweredDistributions.linear_chain_reactions Function
julia
linear_chain_reactions(chain::AbstractChainTrick, from, to; prefix = :stage)
linear_chain_reactions(dist::Distribution, from, to; kwargs...)

Build the Catalyst reactions threading from, through one species per phase of chain (or lower(dist)), to to.

Only defined when Catalyst.jl is loaded (using Catalyst); the methods live in the LoweredDistributionsCatalystExt package extension.

The Distribution form needs lower(dist) isa AbstractChainTrick; a distribution lowering to a bare CTMC (e.g. lower(::Exponential), the degenerate two-state form) is not a from -> to compartment pipe and is out of scope for this bridge — pass ErlangChain(dist) explicitly, or lower it via phase_type / compartment_stages directly, for the Exponential/Erlang case.

Arguments

  • chain: the AbstractChainTrick to build reactions for, or a Distribution that lowers to one.

  • from, to: the upstream and downstream Catalyst species.

Keyword Arguments

  • prefix: a Symbol prefixing the generated sub-compartment species names (default :stage).

Examples

julia
using LoweredDistributions, Distributions, Catalyst

t = Catalyst.default_t()
@species From(t) To(t)
built = linear_chain_reactions(Gamma(3.0, 1.5), From, To; prefix = :I)
length(built.species)

See also

source
LoweredDistributions.lower Function
julia
lower(
    d::Distributions.Exponential
) -> CTMC{St, M} where {St<:Tuple{Vararg{Symbol}}, M<:(Matrix)}
julia
lower(dist::Distribution)

Lower a Distribution to a backend-agnostic dynamical-systems representation (an AbstractLowering).

  • Exponential lowers to a two-state degenerate CTMC (on -> absorbed at the exponential's rate) — the trivial case of the CTMC fast path.

  • Gamma (including integer-shape Erlang) lowers to an ErlangChain when c² = var / mean² ≤ 1 (always true for shape ≥ 1), and to a phase_type fit otherwise.

  • Any other Distribution lowers via the adaptive phase_type fit.

Which representation comes back therefore depends on dist's value, not only on its type, so this method's return type is a Union. When the structural parameter is fixed — the usual fitting case, where the phase count is held constant and only the continuous rate is inferred — the branch is decided at compile time, the Union folds to that one concrete type, and lower(dist) differentiates on every backend (Enzyme included). Fix the structural parameter and the result carries an AD dual through its rate. When the structural parameter itself varies at runtime the Union is genuine; reach for lower(dist, PhaseType) below, the unconditionally type-stable form.

Arguments

  • dist: the Distribution to lower.

Examples

julia
using LoweredDistributions, Distributions

lower(Exponential(2.0))               # CTMC(2 states)
lower(Gamma(3.0, 1.5))                # ErlangChain(3 compartments)
lower(Gamma(0.5, 1.0))                # PhaseType(2 phases), c² = 2 > 1

See also

source
julia
lower(
    d::Distributions.Distribution,
    ::Type{PhaseType};
    phases,
    max_phases
) -> PhaseType
julia
lower(dist::Distribution, ::Type{PhaseType}; max_phases = 1_000)

Lower dist to the canonical PhaseType (α, S) form, whatever its dispersion — the type-stable lowering, and the one to differentiate through.

lower(dist) picks its representation from dist's value (an ErlangChain for c² ≤ 1, a PhaseType for c² > 1, a CTMC for an Exponential), so its return type is a Union that only resolves at runtime. With a fixed structural parameter that Union folds to a single concrete branch and lower(dist) itself differentiates on every backend — an ErlangChain now carries its rate's element type through to the canonical (α, S), so the c² ≤ 1 branch takes an AD dual too. This method is for when the structure varies at runtime (the Union is then genuine, and Enzyme cannot analyse it), or when you want the canonical (α, S), or a fixed phase count via phases, directly. It always returns the same concrete type regardless of the value, so it never depends on the branch folding, and differentiates on every backend the package tests (ForwardDiff, ReverseDiff, both Mooncake modes, both Enzyme modes).

The fit is the same two-moment fit lower performs — an Erlang chain of round(1 / c²) phases for c² ≤ 1, the balanced-means hyperexponential for c² > 1 — so the phase-type agrees with PhaseType(lower(dist)) to floating-point tolerance wherever that conversion exists. It is not always bit-identical: for an exact Exponential/Erlang leaf, compartment_stages reads the rate straight off the distribution's scale (1 / θ), while this method recomputes it from the moments (k / mean(dist)), which can differ in the last unit in the last place. The structure — phase count, chain shape, matched mean — is the same.

What the canonical form does cost is memory. It holds an explicit k × k sub-generator, where the c² ≤ 1 fit needs k = round(1 / c²) phases, so a tight (near-deterministic) delay asks for a very large dense matrix: Normal(5, 0.001) has c² = 4e-8, hence 25 million phases. An ErlangChain stores the same chain as a phase count and does not grow with k at all. max_phases caps the fit so that case raises an actionable error rather than exhausting memory; raise it if a long chain is genuinely wanted.

Arguments

  • dist: the Distribution to lower.

  • PhaseType: the PhaseType type itself, selecting the canonical form.

Keyword Arguments

  • phases: fix the Erlang phase count instead of deriving it from the distribution's dispersion. With phases = k the result is always a k-stage Erlang whose rate matches mean(dist) (rate = k / mean), so the phase count — and hence the (α, S) dimension — is independent of the distribution's value. This is the AD-stable path for fitting under Turing: the number of compartments is a discrete quantity you cannot differentiate through, so fix it and infer only the (continuous) rate; the result then differentiates on every backend, Enzyme included. The default (nothing) keeps the adaptive two-moment fit, whose phase count round(1 / c²) does depend on the value and so steps discontinuously as a parameter crosses a rounding boundary. When set, phases overrides max_phases.

  • max_phases: the largest Erlang phase count to build a sub-generator for (default 1_000, a 1_000 × 1_000 matrix). Only the c² ≤ 1 branch can reach it; the c² > 1 hyperexponential fit is always two phases. Ignored when phases is set.

Examples

julia
using LoweredDistributions, Distributions

lower(Gamma(3.0, 1.5), PhaseType)     # PhaseType(3 phases), was an ErlangChain
lower(Gamma(0.5, 1.0), PhaseType)     # PhaseType(2 phases), c² = 2 > 1
lower(Gamma(3.0, 1.5), PhaseType; phases = 5)   # a fixed 5-phase Erlang
lower(Exponential(2.0), PhaseType)    # PhaseType(1 phase), was a CTMC

See also

source
LoweredDistributions.ode_problem Function
julia
ode_problem(m::AbstractLowering, tspan; u0 = nothing)

Build the linear forward-Kolmogorov ODE du/dt = Q' u for m as a SciMLBase.ODEProblem, ready to solve with any OrdinaryDiffEq-compatible algorithm.

u is the state-occupation probability vector: one entry per state (m.states order) for a CTMC, or one entry per transient phase plus a trailing absorbed-mass entry for an AbstractChainTrick (its canonical PhaseType view, extended with the absorbing state). sum(u) is conserved at 1 for every t.

Only defined when SciMLBase is loaded (using SciMLBase, or any package that depends on it, e.g. using OrdinaryDiffEq); the method lives in the LoweredDistributionsSciMLBaseExt package extension.

Arguments

  • m: the AbstractLowering to build the ODE for.

  • tspan: the (t0, t1) integration span.

Keyword Arguments

  • u0: the initial state-occupation vector. Defaults to a point mass on the first state (CTMC) or the phase-type's own initial distribution α (AbstractChainTrick, absorbed mass 0).

Examples

julia
using LoweredDistributions, SciMLBase, OrdinaryDiffEqTsit5

model = ctmc(:well => (:ill => 0.2), :ill => (:well => 0.3, :dead => 0.1))
prob = ode_problem(model, (0.0, 5.0))
sol = solve(prob, Tsit5())
sol.u[end]

See also

source
LoweredDistributions.parameters Function

The continuous parameters of a lowered object as a NamedTuple, its structure held fixed. Paired with update: update(l, parameters(l)) == l.

The keys are per lowered type:

  • ErlangChain, Coxian, CTMC: (; rates) — the per-stage / per-phase / per-transition rates. For a CTMC these are the existing (structurally present) off-diagonal rates only, in row-major order.

  • PhaseType: (; α, S) — the raw initial distribution and sub-generator entries.

Arguments

  • l: the lowered object to read parameters from.

Examples

julia
using LoweredDistributions, Distributions

e = lower(Gamma(3.0, 1.0))      # a 3-stage ErlangChain, structure fixed
parameters(e)                   # (; rates = [...]) — the per-stage rates
update(e, parameters(e)) == e   # the round-trip this pairs with

See also

  • update: the structure-preserving rebuild this inverts.
source
LoweredDistributions.petri_net Function
julia
petri_net(m::AbstractLowering; prefix = :state)

Build an AlgebraicPetri.LabelledPetriNet for m's full state-space generator, plus the name-indexed rate and initial-condition Dicts AlgebraicPetri.vectorfield's own mass-action ODE function needs (it indexes u/p by species/transition name, not position).

Every off-diagonal generator entry Q[i, j] > 0 becomes one Petri net transition state_i -> state_j at that constant rate. Only defined when AlgebraicPetri.jl is loaded (using AlgebraicPetri); the method lives in the LoweredDistributionsAlgebraicPetriExt package extension.

AlgebraicPetri's own vectorfield also accepts a time/state-varying Function rate per transition (its mass-action kinetics is more general than this package needs), but every AbstractLowering's generator is constant in practice — a PhaseType's S is type-constrained to <: AbstractMatrix{<:Real} at construction, and a CTMC's Q is runtime-validated the same way by _validate_generator — so a Function-valued rate should never reach here. The extension asserts this explicitly at the entry point rather than relying on either upstream guarantee alone.

Arguments

  • m: the AbstractLowering to build the Petri net for, or a Distribution that lowers to one.

Keyword Arguments

  • prefix: a Symbol prefixing the generated state names (default :state).

Examples

julia
using LoweredDistributions, Distributions, AlgebraicPetri

built = petri_net(Gamma(3.0, 1.5))
f! = vectorfield(built.petri_net)
du = Dict(k => 0.0 for k in keys(built.u0))
f!(du, built.u0, built.rates, 0.0)

Not a live @example: AlgebraicPetri's own Catalyst weakdep extension caps Catalyst at a version incompatible with this package's own Catalyst extension, so the two cannot load in the same doctest session. This exact sequence — default prefix, vectorfield, and the f! call — is exercised by name in the isolated test/algebraic_petri test environment instead (see test/algebraic_petri/petri.jl).

See also

source
LoweredDistributions.phase_type Function
julia
phase_type(
    d::Distributions.Distribution
) -> Union{ErlangChain{S} where S<:(Vector{T} where T<:ChainStage), PhaseType}

Adaptively fit a phase-type representation to d by matching its first two moments.

Under-dispersed or exactly-dispersed (c² = var(d) / mean(d)² ≤ 1) delays fit an ErlangChain exactly on the mean (the same moment match compartment_stages performs). Over-dispersed delays (c² > 1) fit a two-phase hyperexponential PhaseType (a mixture of two Exponentials) by the balanced-means method: with p = (1 + sqrt((c² - 1) / (c² + 1))) / 2, rates λ₁ = 2p / mean(d) and λ₂ = 2(1 - p) / mean(d) give a mixture with p/1 - p phase weights that matches mean(d) and c² exactly. A sequential chain (an ErlangChain or Coxian) cannot reach c² > 1 — only a branching (mixture) structure can, hence the different representation.

Examples

julia
using LoweredDistributions, Distributions

phase_type(Gamma(2.5, 1.0))     # c² = 0.4 ≤ 1 -> ErlangChain
phase_type(Gamma(0.5, 1.0))     # c² = 2 > 1   -> PhaseType (hyperexponential)

See also

source
LoweredDistributions.reaction_system Function
julia
reaction_system(chain::AbstractChainTrick, from, to; prefix = :stage, name = :lowered)
reaction_system(dist::Distribution, from, to; kwargs...)

Build a Catalyst ReactionSystem for chain (or lower(dist)) between the from and to species — linear_chain_reactions wrapped into a complete model, ready for the Catalyst/ModelingToolkit ODE, SDE, or jump conversion.

Only defined when Catalyst.jl is loaded (using Catalyst); the method lives in the LoweredDistributionsCatalystExt package extension.

Arguments

  • chain: the AbstractChainTrick to build the system for, or a Distribution that lowers to one (see linear_chain_reactions for the scope of that form).

  • from, to: the upstream and downstream Catalyst species.

Keyword Arguments

  • prefix: a Symbol prefixing the generated sub-compartment species names (default :stage).

  • name: the ReactionSystem's name (default :lowered).

Examples

julia
using LoweredDistributions, Distributions, Catalyst

t = Catalyst.default_t()
@species From(t) To(t)
rs = reaction_system(Gamma(3.0, 1.5), From, To; name = :chain)
Catalyst.reactions(rs)

See also

source
LoweredDistributions.state_index Function
julia
state_index(m::CTMC, s::Symbol) -> Union{Nothing, Int64}
julia
state_index(m::CTMC, s::Symbol)

The index of state s in m.states, or nothing if s is not present.

Arguments

  • m: the CTMC model.

  • s: the state name to look up.

Examples

julia
using LoweredDistributions

m = ctmc(:well => (:ill => 0.2), :ill => (:well => 0.3, :dead => 0.1))
state_index(m, :ill)
source
LoweredDistributions.transition_probability Function
julia
transition_probability(m::CTMC, t::Real) -> Any

The transition-probability matrix P(t) = exp(Q t) of a CTMC over a time gap t.

P[i, j] is the probability of being in state j a time t after being in state i, marginalising over every intermediate jump.

Examples

julia
using LoweredDistributions

model = ctmc(:well => (:ill => 0.2), :ill => (:well => 0.3, :dead => 0.1))
P = transition_probability(model, 2.0)
sum(P; dims = 2)  # each row sums to one

See also

  • CTMC: the model type.
source
LoweredDistributions.update Function

Rebuild a lowered object with new continuous params, preserving its structure (phase count, transition topology, state set). Pure — it returns a new object of the same concrete type and never mutates l.

params is either a NamedTuple matching parameters's keys for l's type, or a flat AbstractVector in that type's canonical order:

  • ErlangChain / Coxian: the rates, in stage / phase order.

  • CTMC: the existing off-diagonal transition rates, row-major (state i outer, j inner, skipping absent transitions). Editing an existing transition is a parameter change; introducing a new one is a structural change and needs a fresh lower, not update.

  • PhaseType: [α; vec(S)] — the initial distribution followed by the column-major sub-generator entries.

The eltype of a flat vector flows into the rebuilt object, so a differentiated parameter carries straight through; this is the AD-stable form for fitting. The rebuild goes through the object's own constructor, so its validity checks (a PhaseType's α summing to one and S being a sub-generator, a CTMC's rows summing to zero) still apply — update enforces nothing beyond them.

Arguments

  • l: the lowered object whose structure to preserve.

  • params: a NamedTuple or flat AbstractVector of new continuous values.

Examples

julia
using LoweredDistributions, Distributions

e = lower(Gamma(3.0, 1.0))          # a 3-stage ErlangChain, structure fixed
update(e, [0.5])                    # same structure, new per-stage rate
parameters(e)                       # (; rates = [...])

See also

  • parameters: the read-back pair, update(l, parameters(l)) == l.

  • lower: chooses the structure update then holds fixed.

source