Think of it as decomposing a signal into a basis of exponentially decaying (or growing) oscillations e^{st} where s = \sigma + i\omega. The real part \sigma captures growth/decay rates, while the imaginary part \omega captures oscillation frequencies. This generalizes the Fourier transform, which only handles pure oscillations.
Why it’s useful
The transform turns calculus into algebra. Differentiation becomes multiplication: \mathcal{L}\{f'(t)\} = sF(s) - f(0)
This means differential equations become polynomial equations in s, which are far easier to solve. You transform, solve algebraically, then invert back.
This matrix form makes computations tractable—moments, convolutions, and fitting all become linear algebra rather than integrals. The transform essentially encodes the entire distribution in a compact algebraic object.
Want me to go deeper on any aspect—the inversion formula, specific applications in PH distributions, or the connection to moment generating functions?
Phase-type distributions
In the matrix formulation, the Laplace transform for a continuous phase-type distribution is defined as:
where \mathbf{s} is a vector of ones for states with non-zero rates to absorbing states and zeros otherwise. The \theta is time-homogeneous, so it can only represent a global mutation rate if there are only two sequences. So, here we pretend it is a recombination rate in an ARG and that we are interested in the probability that two loci separated by recombination distance \theta are represented by the same tree in our sample.
from phasic import Graph, with_ipv # ALWAYS import phasic first to set jax backend correctlyimport numpy as npimport matplotlib.pyplot as pltfrom matplotlib.colors import LogNormimport seaborn as snsfrom vscodenb import set_vscode_themenp.random.seed(42)set_vscode_theme()sns.set_palette('tab10')
Overriding theme from NOTEBOOK_THEME environment variable. <phasic._DeviceListFilter object at 0x17a3f0e90>
nr_samples =4@with_ipv([nr_samples]+[0]*(nr_samples-1))def coalescent(state): transitions = []for i inrange(state.size):for j inrange(i, state.size): same =int(i == j)if same and state[i] <2:continueifnot same and (state[i] <1or state[j] <1):continue new = state.copy() new[i] -=1 new[j] -=1 new[i+j+1] +=1 transitions.append((new, state[i]*(state[j]-same)/(1+same)))return transitions
In the phasic library, Laplace transform can be implemented by: 1. Adding edges from each transient state to the absorbing state with weight θ 2. Creating a reward vector that is 1 for states with edges to absorption 3. Computing expectations using reward transformation
This is equivalent to the matrix formulation: E[e^{-\theta \tau}] = \mathbf{\alpha} (\theta\, \mathbf{I} − \mathbf{S})^{−1}\mathbf{s}