### Install HiddenMarkovModels.jl Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable Use Julia's package manager to add the HiddenMarkovModels package. ```julia pkg> add HiddenMarkovModels ``` -------------------------------- ### Get Initial State Probabilities Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Retrieves the initial state probabilities for a given HMM. ```julia initialization(hmm) ``` -------------------------------- ### Initialize PeriodicHMM Guess Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Sets up an initial guess for a PeriodicHMM, including initial probabilities, transition matrices per period, and emission distributions per period. This is used as a starting point for the Baum-Welch algorithm. ```julia init_guess = [0.4, 0.2, 0.3] trans_per_guess = ntuple(_ -> [ 0.4 0.3 0.3 0.3 0.4 0.3 0.3 0.3 0.4 ], Val(3)) dists_per_guess = ( [Normal(1.5), Normal(2.2), Normal(2.5)], [Normal(3.5), Normal(4.2), Normal(4.5)], [Normal(5.5), Normal(6.2), Normal(6.5)], ) hmm_guess = PeriodicHMM(init_guess, trans_per_guess, dists_per_guess); ``` -------------------------------- ### Get Log Initial State Probabilities Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Returns the vector of initial state log-probabilities for an HMM. Falls back on the `initialization` function if direct log-probabilities are not available. ```julia log_initialization(hmm) ``` -------------------------------- ### Get State Transition Probabilities Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Retrieves the state transition probabilities for an HMM, optionally considering a control input. ```julia transition_matrix(hmm) transition_matrix(hmm, control) ``` -------------------------------- ### Get Log Transition Matrix Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Returns the matrix of state transition log-probabilities for an HMM. Can optionally consider a control input, which influences transitions from the previous time step. ```julia log_transition_matrix(hmm) ``` ```julia log_transition_matrix(hmm, control) ``` -------------------------------- ### Baum-Welch with Sparse Transition Guess Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Apply the Baum-Welch algorithm to estimate HMM parameters from observed sequences, starting with an initial guess that maintains the correct sparsity pattern. ```julia init_guess = [0.3, 0.4, 0.3] trans_guess = sparse([ 0.6 0.4 0 0 0.6 0.4 0.4 0 0.6 ]) dists_guess = [Normal(1.1), Normal(2.1), Normal(3.1)] hmm_guess = HMM(init_guess, trans_guess, dists_guess) ``` ```julia hmm_est, loglikelihood_evolution = baum_welch(hmm_guess, obs_seq) first(loglikelihood_evolution), last(loglikelihood_evolution) ``` -------------------------------- ### Get Number of States Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Returns the total number of states in the HMM. ```julia length(hmm) ``` -------------------------------- ### Estimate HMM Parameters with Baum-Welch Algorithm Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Use `baum_welch` to estimate HMM parameters from observation sequences, starting with an initial guess. It returns the estimated HMM and the log-likelihood evolution. Convergence criteria like `atol` and `max_iterations` can be specified. ```julia baum_welch(hmm_guess, obs_seq; ...) ``` ```julia baum_welch( hmm_guess, obs_seq, control_seq; seq_ends, atol, max_iterations, loglikelihood_increasing ) ``` -------------------------------- ### Generate Multiple Observation Sequences Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Generates a specified number of long observation sequences with random lengths. This is a setup step for processing multiple sequences. ```julia nb_seqs = 1000 long_obs_seqs = [last(rand(rng, hmm, rand(rng, 100:200))) for k in 1:nb_seqs]; typ_of(long_obs_seqs) ``` ```julia Vector{Vector{Vector{Float64}}} (alias for Array{Array{Array{Float64, 1}, 1}, 1}) ``` -------------------------------- ### Get Observation Distributions Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Retrieves the observation distributions for each state of an HMM, optionally considering a control input. These distributions must support sampling and log-density calculation. ```julia obs_distributions(hmm) obs_distributions(hmm, control) ``` -------------------------------- ### Create a Basic Hidden Markov Model (HMM) Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable Initialize a Hidden Markov Model with given initial probabilities, transition matrix, and observation distributions. Requires Distributions and HiddenMarkovModels packages. ```julia using Distributions, HiddenMarkovModels init = [0.6, 0.4] trans = [0.7 0.3; 0.2 0.8] dists = [Normal(-1.0), Normal(1.0)] hmm = HMM(init, trans, dists) ``` -------------------------------- ### Get Subsequence Indices Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Calculates the start and end indices for a specific subsequence within a concatenated sequence, given the sequence end markers. ```julia seq_limits(seq_ends, k) ``` -------------------------------- ### Initialize Guess for HMM Parameters Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Sets up initial guesses for the HMM parameters, including initial state probabilities, transition matrix, and custom observation distributions, to be used in the Baum-Welch algorithm. ```julia init_guess = [0.5, 0.5] trans_guess = [0.6 0.4; 0.3 0.7] dists_guess = [StuffDist(-1.1), StuffDist(+1.1)] hmm_guess = HMM(init_guess, trans_guess, dists_guess); ``` -------------------------------- ### Create Periodic HMM Instance Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Sets up the parameters for a periodic HMM, including initial state probabilities, transition matrices for each period, and observation distributions for each period. Then, it instantiates the `PeriodicHMM`. ```julia init = [0.6, 0.3, 0.1] trans_per = ( [ # l = 1 -> mostly switch to next state 0.2 0.8 0.0 0.0 0.2 0.8 0.8 0.0 0.2 ], [ # l = 2 -> mostly switch to previous state 0.2 0.0 0.8 0.8 0.2 0.0 0.0 0.8 0.2 ], [ # l = 3 -> mostly stay in current state 0.8 0.1 0.1 0.1 0.8 0.1 0.1 0.1 0.8 ], ) dists_per = ( [Normal(1.0), Normal(2.0), Normal(3.0)], [Normal(3.0), Normal(4.0), Normal(5.0)], [Normal(5.0), Normal(6.0), Normal(7.0)], ) hmm = PeriodicHMM(init, trans_per, dists_per); ``` -------------------------------- ### Initialize Random Number Generator Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Sets up a stable random number generator for reproducible simulations. ```julia rng = StableRNG(63); ``` -------------------------------- ### Initialize Guess for Learning Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Sets up an initial guess for the HMM parameters to be used in the Baum-Welch learning algorithm. ```julia init_guess = [0.5, 0.5] trans_guess = [0.6 0.4; 0.3 0.7] dist_coeffs_guess = [-2 * ones(d), 2 * ones(d)] hmm_guess = ControlledGaussianHMM(init_guess, trans_guess, dist_coeffs_guess); ``` -------------------------------- ### seq_limits Function Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Calculates the start and end indices for a specific subsequence within a set of sequences defined by their end points. ```APIDOC ## Function: `seq_limits` ```julia seq_limits(seq_ends, k) ``` Return a tuple `(t1, t2)` giving the begin and end indices of subsequence `k` within a set of sequences ending at `seq_ends`. ``` -------------------------------- ### Instantiate and Fit Custom PriorHMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Demonstrates how to instantiate a `PriorHMM` with initial guesses and then fit it to observation sequences using the `baum_welch` function. This shows the practical application of the custom HMM structure. ```julia trans_prior_count = 10 prior_hmm_guess = PriorHMM(init_guess, trans_guess, dists_guess, trans_prior_count); prior_hmm_est, prior_logl_evolution = baum_welch(prior_hmm_guess, obs_seq) first(prior_logl_evolution), last(prior_logl_evolution) ``` -------------------------------- ### Initialize Forward Algorithm Storage Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api The `initialize_forward` function prepares the storage for the forward algorithm, taking the HMM, observation sequence, and optional control sequence and sequence ends as input. ```julia initialize_forward(hmm, obs_seq, control_seq; seq_ends) ``` -------------------------------- ### Initialize Forward-Backward Storage Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Initializes the storage for forward-backward algorithm computations. Requires the HMM, observation sequence, and control sequence. ```julia initialize_forward_backward( hmm, obs_seq, control_seq; seq_ends, transition_marginals ) ``` -------------------------------- ### Implement AbstractHMM Interface Methods Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Implement the core methods required by the AbstractHMM interface: `initialization`, `transition_matrix`, and `obs_distributions`. These methods provide access to the HMM's parameters. ```julia HiddenMarkovModels.initialization(hmm::PriorHMM) = hmm.init HiddenMarkovModels.transition_matrix(hmm::PriorHMM) = hmm.trans HiddenMarkovModels.obs_distributions(hmm::PriorHMM) = hmm.dists ``` -------------------------------- ### Compare Estimated and Original HMM Parameters Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Compares the transition matrix, observation distributions, and initializations of the estimated HMM with the original HMM. This helps assess the accuracy of the parameter estimation. ```julia cat(transition_matrix(hmm_est_concat), transition_matrix(hmm); dims=3) ``` ```julia 2×2×2 Array{Float64, 3}: [:, :, 1] = 0.700421 0.299579 0.203473 0.796527 [:, :, 2] = 0.7 0.3 0.2 0.8 ``` ```julia map(mean, hcat(obs_distributions(hmm_est_concat), obs_distributions(hmm))) ``` ```julia 2×2 Matrix{Vector{Float64}}: [-0.502073, -0.800874] [-0.5, -0.8] [0.504019, 0.801399] [0.5, 0.8] ``` ```julia hcat(initialization(hmm_est_concat), initialization(hmm)) ``` ```julia 2×2 Matrix{Float64}: 0.605645 0.6 0.394355 0.4 ``` -------------------------------- ### Calculate Prior Log-Likelihood of HMM Parameters Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Use `logdensityof` to get the prior log-likelihood of the HMM parameters. It can be called with or without control sequences and sequence end indicators. ```julia logdensityof(hmm) ``` ```julia logdensityof(hmm, obs_seq; ...) ``` ```julia logdensityof(hmm, obs_seq, control_seq; seq_ends) ``` -------------------------------- ### HiddenMarkovModels.baum_welch Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Applies the Baum-Welch algorithm to estimate the parameters of an HMM given an observation sequence, starting from an initial guess. Returns the estimated HMM and the evolution of the log-likelihood over iterations. ```APIDOC ## baum_welch ### Description Apply the Baum-Welch algorithm to estimate the parameters of an HMM on `obs_seq`, starting from `hmm_guess`. ### Signature ```julia baum_welch(hmm_guess, obs_seq; ...) baum_welch( hmm_guess, obs_seq, control_seq; seq_ends, atol, max_iterations, loglikelihood_increasing ) ``` ### Returns Return a tuple `(hmm_est, loglikelihood_evolution)` where `hmm_est` is the estimated HMM and `loglikelihood_evolution` is a vector of loglikelihood values, one per iteration of the algorithm. ### Keyword Arguments * `atol`: minimum loglikelihood increase at an iteration of the algorithm (otherwise the algorithm is deemed to have converged) * `max_iterations`: maximum number of iterations of the algorithm * `loglikelihood_increasing`: whether to throw an error if the loglikelihood decreases ``` -------------------------------- ### Import necessary packages Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Import the required packages for using Hidden Markov Models, including distributions, linear algebra, and random number generation. ```julia using Distributions using HiddenMarkovModels using LinearAlgebra using Random using StableRNGs ``` -------------------------------- ### HiddenMarkovModels.initialize_viterbi Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Initializes the storage for the Viterbi algorithm. ```APIDOC ## initialize_viterbi ### Description Initialize the storage for the Viterbi algorithm. ### Signature ```julia initialize_viterbi(hmm, obs_seq, control_seq; seq_ends) ``` ``` -------------------------------- ### Retrieve Sequence Limits Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Uses `seq_limits` to find the start and end indices of a specific sequence within the concatenated observation vector. This is useful for analyzing individual sequence results. ```julia start2, stop2 = seq_limits(seq_ends, 2) ``` ```julia (175, 279) ``` ```julia best_state_seq_concat[start2:stop2] == first(viterbi(hmm, long_obs_seqs[2])) ``` ```julia true ``` -------------------------------- ### Instantiate DiffusionHMM and generate sequences Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/autodiff Creates an instance of DiffusionHMM and generates observation and control sequences. ```julia init = [0.6, 0.4] trans = [0.7 0.3; 0.3 0.7] means = [-1.0, 1.0] hmm = DiffusionHMM(init, trans, means); ``` ```julia control_seqs = [rand(rng, 3), rand(rng, 5)]; obs_seqs = [rand(rng, hmm, control_seqs[k]).obs_seq for k in 1:2]; control_seq = reduce(vcat, control_seqs) obs_seq = reduce(vcat, obs_seqs) seq_ends = cumsum(length.(obs_seqs)); ``` -------------------------------- ### Check Possible and Impossible Transitions Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Verify that transitions defined in the sparse matrix occur during simulation, while transitions that are structurally forbidden (zero in the sparse matrix) do not. ```julia count(isequal((2, 2)), state_transitions) ``` ```julia count(isequal((2, 1)), state_transitions) ``` -------------------------------- ### Display Log-Likelihood Evolution Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Shows the initial and final log-likelihood values obtained during the Baum-Welch estimation. ```julia first(loglikelihood_evolution), last(loglikelihood_evolution) ``` -------------------------------- ### initialization Function Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Retrieves the initial state probabilities for a given HMM. ```APIDOC ## Function: `initialization` ```julia initialization(hmm) ``` Return the vector of initial state probabilities for `hmm`. ``` -------------------------------- ### Generate Data from a Vanilla HMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Define a standard HMM with initial probabilities, transition matrix, and normal distributions, then generate a state and observation sequence. ```julia init = [0.6, 0.4] trans = [0.7 0.3; 0.2 0.8] dists = [Normal(-1.0), Normal(1.0)] hmm = HMM(init, trans, dists) state_seq, obs_seq = rand(rng, hmm, 100); ``` -------------------------------- ### Simulate HMM Sequence with Sparse Transitions Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Simulate a sequence of states and observations from an HMM defined with a sparse transition matrix. Transitions outside the non-zero coefficients are impossible. ```julia state_seq, obs_seq = rand(rng, hmm, 1000) state_transitions = collect(zip(state_seq[1:(end - 1)], state_seq[2:end])) ``` -------------------------------- ### HiddenMarkovModels.initialize_forward Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Initializes the storage for the forward algorithm. ```APIDOC ## initialize_forward ### Description Initialize the storage for the forward algorithm. ### Signature ```julia initialize_forward(hmm, obs_seq, control_seq; seq_ends) ``` ``` -------------------------------- ### Initialize Viterbi Algorithm Storage Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api The `initialize_viterbi` function sets up the storage for the Viterbi algorithm, requiring the HMM, observation sequence, and optional control sequence and sequence end indicators. ```julia initialize_viterbi(hmm, obs_seq, control_seq; seq_ends) ``` -------------------------------- ### Forward-Backward Algorithm Initialization Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Initializes the storage for the forward-backward algorithm. This function prepares the necessary data structures to hold intermediate results. ```APIDOC ## Function: initialize_forward_backward ### Description Initializes the storage for the forward-backward algorithm. ### Signature ```julia initialize_forward_backward(hmm, obs_seq, control_seq; seq_ends, transition_marginals) ``` ### Parameters * `hmm`: The Hidden Markov Model object. * `obs_seq`: The sequence of observations. * `control_seq`: The sequence of control inputs. * `seq_ends` (Optional): Specifies the end of sequences. * `transition_marginals` (Optional): Specifies transition marginals. ``` -------------------------------- ### Compare Estimated and True Transition Matrices Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Compares the transition matrix estimated by the Baum-Welch algorithm with the true transition matrix used for simulation. ```julia cat(hmm_est.trans, hmm.trans; dims=3) ``` -------------------------------- ### Sample Observation Sequence from HMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Generates a sequence of states and observations from the HMM. The observations will be of the custom `Stuff` type. ```julia state_seq, obs_seq = rand(rng, hmm, 100) ``` -------------------------------- ### Create HMM with Custom Distributions Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Initializes an HMM object using custom initial state probabilities, transition matrix, and custom observation distributions. ```julia init = [0.6, 0.4] trans = [0.7 0.3; 0.2 0.8] dists = [StuffDist(-1.0), StuffDist(+1.0)] hmm = HMM(init, trans, dists); ``` -------------------------------- ### Log-likelihood Evolution Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Displays the initial and final log-likelihood values obtained during the Baum-Welch estimation. This indicates the convergence of the algorithm. ```julia (-255695.48690011754, -243058.7258113099) ``` -------------------------------- ### Instantiate ControlledGaussianHMM Model Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Creates an instance of the ControlledGaussianHMM with specified dimensions, initial probabilities, transition matrix, and distribution coefficients. ```julia d = 3 init = [0.6, 0.4] trans = [0.7 0.3; 0.2 0.8] dist_coeffs = [-ones(d), ones(d)] hmm = ControlledGaussianHMM(init, trans, dist_coeffs); ``` -------------------------------- ### Compare Estimated and True Distribution Coefficients (State 1) Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Compares the estimated distribution coefficients for the first state with the true coefficients. ```julia hcat(hmm_est.dist_coeffs[1], hmm.dist_coeffs[1]) ``` -------------------------------- ### Compare Transition Matrices of HMMs Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Compares the transition matrices of a standard HMM and a custom `PriorHMM` after estimation. This visualization helps understand the effect of the prior on the transition probabilities. ```julia cat(transition_matrix(hmm_est), transition_matrix(prior_hmm_est); dims=3) ``` -------------------------------- ### Run Baum-Welch Algorithm with Custom Observations Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Executes the Baum-Welch algorithm to estimate HMM parameters from the observed sequence of custom `Stuff` objects. It returns the estimated HMM and the evolution of the log-likelihood. ```julia hmm_est, loglikelihood_evolution = baum_welch(hmm, obs_seq) ``` -------------------------------- ### Preallocate gradient storage for Enzyme.jl Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/autodiff Enzyme.jl requires preallocated storage for gradients. Use `Enzyme.make_zero` to create zero-initialized arrays matching the types and shapes of the parameters to be differentiated. ```julia ∇parameters_enzyme = Enzyme.make_zero(parameters) ∇obs_enzyme = Enzyme.make_zero(obs_seq) ∇control_enzyme = Enzyme.make_zero(control_seq); ``` -------------------------------- ### Display first three states of the sequence Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Show the first three elements of the simulated state sequence. The state sequence is a vector of integers. ```julia state_seq[1:3] ``` -------------------------------- ### Implement HMM Interface for ControlledGaussianHMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Provides the necessary methods for the AbstractHMM interface: initialization, transition matrix, and observation distributions. The observation distributions depend on the provided control vector. ```julia function HMMs.initialization(hmm::ControlledGaussianHMM) return hmm.init end function HMMs.transition_matrix(hmm::ControlledGaussianHMM, control::AbstractVector) return hmm.trans end function HMMs.obs_distributions(hmm::ControlledGaussianHMM, control::AbstractVector) return [Normal(dot(hmm.dist_coeffs[i], control), 1.0) for i in 1:length(hmm)] end ``` -------------------------------- ### Run Baum-Welch Learning and Check Likelihood Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Executes the Baum-Welch algorithm to estimate the HMM parameters from the data and reports the initial and final log-likelihood values. ```julia hmm_est, loglikelihood_evolution = baum_welch(hmm_guess, obs_seq, control_seq; seq_ends) first(loglikelihood_evolution), last(loglikelihood_evolution) ``` -------------------------------- ### Run Baum-Welch Algorithm Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Executes the Baum-Welch algorithm to estimate HMM parameters. Requires an initial guess of the HMM, the observation sequence, and the control sequence. Returns the estimated HMM and the evolution of the log-likelihood. ```julia hmm_est, loglikelihood_evolution = baum_welch(hmm_guess, obs_seq, control_seq; seq_ends); first(loglikelihood_evolution), last(loglikelihood_evolution) ``` -------------------------------- ### Run Baum-Welch Algorithm Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Executes the Baum-Welch algorithm for parameter estimation. Updates the forward-backward storage and log-likelihood evolution in-place. Supports custom convergence criteria. ```julia baum_welch!( fb_storage, logL_evolution, hmm, obs_seq, control_seq; seq_ends, atol, max_iterations, loglikelihood_increasing ) ``` -------------------------------- ### Import Necessary Packages Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Imports the required Julia packages for working with distributions, HiddenMarkovModels, random number generation, and statistics. ```julia using Distributions using HiddenMarkovModels import HiddenMarkovModels as HMMs using Random using StableRNGs using StatsAPI ``` -------------------------------- ### Sequence Formatting Utilities Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Helper functions and explanations for formatting observation and control sequences, especially when dealing with multiple sequences concatenated into a single vector. ```APIDOC ## Sequence Formatting Most algorithms ingest data with `obs_seq` (mandatory), `control_seq` (optional), and `seq_ends` (optional). For single sequences, `obs_seq` and `control_seq` are vectors, and `seq_ends` is not needed. For multiple sequences: ```julia obs_seq = reduce(vcat, obs_seqs) control_seq = reduce(vcat, control_seqs) seq_ends = cumsum(length.(obs_seqs)) ``` ``` -------------------------------- ### Compare Estimated vs True Transition Matrices (Period 1) Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Compares the estimated transition matrix for the first period of the HMM with the true transition matrix. This helps in evaluating the accuracy of the learned parameters. ```julia cat(transition_matrix(hmm_est, 1), transition_matrix(hmm, 1); dims=3) ``` -------------------------------- ### Implement In-Place Fitting for Custom Distribution Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Implements the `StatsAPI.fit!` method for in-place fitting of the custom distribution using weighted observation sequences. This method updates the distribution's parameters. ```julia function StatsAPI.fit!( dist::StuffDist, obs_seq::AbstractVector{<:Stuff}, weight_seq::AbstractVector{<:Real} ) dist.quantity_mean = sum(weight_seq[k] * obs_seq[k].quantity for k in eachindex(obs_seq, weight_seq)) / sum(weight_seq) return nothing end ``` -------------------------------- ### Perform Forward-Backward Algorithm In-Place Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Performs the forward-backward algorithm and updates the provided storage object in-place. Requires the storage, HMM, observation sequence, and control sequence. ```julia forward_backward!( storage, hmm, obs_seq, control_seq; seq_ends, transition_marginals ) ``` -------------------------------- ### Log Initial State Probabilities Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Returns the vector of initial state log-probabilities for a given HMM. ```APIDOC ## Function: log_initialization ### Description Return the vector of initial state log-probabilities for `hmm`. ### Signature ```julia log_initialization(hmm) ``` ### Parameters * `hmm`: The Hidden Markov Model object. ``` -------------------------------- ### Inspect Estimated Observation Distributions Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Retrieves and displays the observation distributions from the HMM estimated by the Baum-Welch algorithm, showing the updated parameters of the custom `StuffDist`. ```julia obs_distributions(hmm_est) ``` -------------------------------- ### HiddenMarkovModels.forward! Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Performs the forward algorithm in-place, updating the provided storage with alpha values and log-likelihoods. ```APIDOC ## forward! ### Description Perform the forward algorithm in-place. ### Signature ```julia forward!( storage, hmm, obs_seq, control_seq; seq_ends, error_if_not_finite ) ``` ``` -------------------------------- ### Compare Estimated and True Distribution Coefficients (State 2) Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Compares the estimated distribution coefficients for the second state with the true coefficients. ```julia hcat(hmm_est.dist_coeffs[2], hmm.dist_coeffs[2]) ``` -------------------------------- ### Import Necessary Packages Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Import required packages for using HiddenMarkovModels.jl, including distributions, linear algebra, and specialized number types. ```julia using Distributions using HiddenMarkovModels using LinearAlgebra using LogarithmicNumbers using Measurements using Random using SparseArrays using StableRNGs ``` -------------------------------- ### Import Necessary Packages Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Imports required packages for working with custom distributions and HMMs. ```julia using DensityInterface using Distributions using HiddenMarkovModels import HiddenMarkovModels as HMMs using LinearAlgebra using Random: Random, AbstractRNG using StableRNGs using StatsAPI ``` -------------------------------- ### Log Transition Matrix Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Returns the matrix of state transition log-probabilities for an HMM, optionally considering control inputs. ```APIDOC ## Function: log_transition_matrix ### Description Return the matrix of state transition log-probabilities for `hmm` (possibly when `control` is applied). ### Signature ```julia log_transition_matrix(hmm) log_transition_matrix(hmm, control) ``` ### Parameters * `hmm`: The Hidden Markov Model object. * `control` (Optional): The control input. ``` -------------------------------- ### Construct HMM with Uncertain Parameters Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Create a new HMM using Measurements.jl to introduce uncertainty in the observation means. Note that uncertainty in transition parameters is not supported. ```julia dists_guess = [Normal(-1.0 ± 0.1), Normal(1.0 ± 0.2)] hmm_uncertain = HMM(init, trans, dists_guess) ``` -------------------------------- ### Run Forward Algorithm for Log-Likelihood Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api The `forward` function computes the log-likelihood of an observation sequence using the forward algorithm. It can optionally use control sequences and specify error handling for non-finite values. ```julia forward(hmm, obs_seq; ...) ``` ```julia forward( hmm, obs_seq, control_seq; seq_ends, error_if_not_finite ) ``` -------------------------------- ### Implement HMM interface methods for DiffusionHMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/autodiff Implements initialization, transition matrix, and observation distribution methods for the DiffusionHMM, incorporating a control parameter λ. ```julia HMMs.initialization(hmm::DiffusionHMM) = hmm.init function HMMs.transition_matrix(hmm::DiffusionHMM, λ::Number) N = length(hmm) return (1 - λ) * hmm.trans + λ * ones(N, N) / N end function HMMs.obs_distributions(hmm::DiffusionHMM, λ::Number) return [Normal((1 - λ) * hmm.means[i] + λ * 0) for i in 1:length(hmm)] end ``` -------------------------------- ### Prepare Data for Inference Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Generates a collection of observation sequences (`obs_seqs`) and their corresponding control sequences (`control_seqs`) of variable lengths. These are then concatenated into single `obs_seq` and `control_seq` vectors, with `seq_ends` marking the boundaries of the original sequences. ```julia control_seqs = [1:rand(rng, 100:200) for k in 1:1000] obs_seqs = [rand(rng, hmm, control_seqs[k]).obs_seq for k in eachindex(control_seqs)] obs_seq = reduce(vcat, obs_seqs) control_seq = reduce(vcat, control_seqs) seq_ends = cumsum(length.(obs_seqs)); ``` -------------------------------- ### Baum-Welch Algorithm for Parameter Estimation Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Estimates HMM parameters (initialization, transition matrix, observation distributions) using the Expectation-Maximization algorithm. Requires an initial guess. ```julia init_guess = [0.5, 0.5] trans_guess = [0.6 0.4; 0.3 0.7] dists_guess = [MvNormal([-0.4, -0.7], I), MvNormal([0.4, 0.7], I)] hmm_guess = HMM(init_guess, trans_guess, dists_guess); ``` ```julia _, long_obs_seq = rand(rng, hmm, 200) hmm_est, loglikelihood_evolution = baum_welch(hmm_guess, long_obs_seq); ``` ```julia first(loglikelihood_evolution), last(loglikelihood_evolution) ``` ```text (-613.0225125416881, -605.3027257918021) ``` ```julia cat(transition_matrix(hmm_est), transition_matrix(hmm); dims=3) ``` ```text 2×2×2 Array{Float64, 3}: [:, :, 1] = 0.676764 0.323236 0.197387 0.802613 [:, :, 2] = 0.7 0.3 0.2 0.8 ``` ```julia map(mean, hcat(obs_distributions(hmm_est), obs_distributions(hmm))) ``` ```text 2×2 Matrix{Vector{Float64}}: [-0.256414, -0.563875] [-0.5, -0.8] [0.652218, 0.841332] [0.5, 0.8] ``` ```julia hcat(initialization(hmm_est), initialization(hmm)) ``` ```text 2×2 Matrix{Float64}: 1.91765e-19 0.6 1.0 0.4 ``` -------------------------------- ### Generate Random Transition Matrix Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Generates a random transition matrix of a specified size with normalized uniform entries. ```APIDOC ## Function: rand_trans_mat ### Description Generate a random transition matrix of size `(N, N)` with normalized uniform entries. ### Signature ```julia rand_trans_mat([rng, ::Type{R},] N) ``` ### Parameters * `rng` (Optional): Random number generator. * `R` (Optional): Type of the elements. * `N`: The size of the transition matrix (N x N). ``` -------------------------------- ### Implement Log-Density Calculation for Custom Distribution Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/interfaces Implements the `DensityInterface.logdensityof` method to compute the log-probability density of an observation given the custom distribution. The calculation can be up to an additive constant. ```julia function DensityInterface.logdensityof(dist::StuffDist, obs::Stuff) return -abs2(obs.quantity - dist.quantity_mean) / 2 end ``` -------------------------------- ### Perform Forward Algorithm In-Place Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api The `forward!` function executes the forward algorithm in-place, updating the provided `storage` object. It requires the HMM, observation sequence, and optional control sequence and sequence end indicators. ```julia forward!( storage, hmm, obs_seq, control_seq; seq_ends, error_if_not_finite ) ``` -------------------------------- ### Import necessary packages Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/autodiff Imports required Julia packages for automatic differentiation, component arrays, distributions, and HiddenMarkovModels. ```julia using ComponentArrays using DensityInterface using Distributions using Enzyme: Enzyme using ForwardDiff: ForwardDiff using HiddenMarkovModels import HiddenMarkovModels as HMMs using LinearAlgebra using Random: Random, AbstractRNG using StableRNGs using StatsAPI using Zygote: Zygote ``` -------------------------------- ### Simulate Sequence with Control Sequence Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Simulates a state and observation sequence from the `PeriodicHMM`. Unlike standard HMMs, this requires providing a `control_seq` which dictates the time-dependent parameters used at each step. ```julia control_seq = 1:10 state_seq, obs_seq = rand(rng, hmm, control_seq); ``` -------------------------------- ### Compare Estimated vs True Transition Matrices (Period 2) Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Compares the estimated transition matrix for the second period of the HMM with the true transition matrix. This helps in evaluating the accuracy of the learned parameters. ```julia cat(transition_matrix(hmm_est, 2), transition_matrix(hmm, 2); dims=3) ``` -------------------------------- ### Simulate state and observation sequences Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Simulate a pair of state and observation sequences from a defined HMM for a specified duration T. ```julia T = 20 state_seq, obs_seq = rand(rng, hmm, T); ``` -------------------------------- ### Import Dependencies for Controlled HMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Imports necessary Julia packages for working with distributions, HiddenMarkovModels, linear algebra, random number generation, and statistics. ```julia using Distributions using HiddenMarkovModels import HiddenMarkovModels as HMMs using LinearAlgebra using Random using StableRNGs using StatsAPI ``` -------------------------------- ### Generate Control Sequences and Observation Sequences Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Generates multiple sequences of control inputs and corresponding observation sequences using the defined HMM. Each sequence has a random length. ```julia control_seqs = [[randn(rng, d) for t in 1:rand(100:200)] for k in 1:1000]; obs_seqs = [rand(rng, hmm, control_seq).obs_seq for control_seq in control_seqs]; obs_seq = reduce(vcat, obs_seqs) control_seq = reduce(vcat, control_seqs) seq_ends = cumsum(length.(obs_seqs)); ``` -------------------------------- ### Verify Uncertainty Propagation Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Check if the computed log-density for the HMM with uncertainties is approximately equal to the log-density of the vanilla HMM. ```julia Measurements.value(logdensityof(hmm_uncertain, obs_seq)) ≈ logdensityof(hmm, obs_seq) ``` -------------------------------- ### Implement Learning Function for ControlledGaussianHMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/controlled Overrides the `fit!` function to implement the learning algorithm for the ControlledGaussianHMM. It updates initial probabilities, transition matrix, and observation coefficients using forward-backward results and weighted least squares. ```julia function StatsAPI.fit!( hmm::ControlledGaussianHMM{T}, fb_storage::HMMs.ForwardBackwardStorage, obs_seq::AbstractVector, control_seq::AbstractVector; seq_ends, ) where {T} (; γ, ξ) = fb_storage N = length(hmm) hmm.init .= 0 hmm.trans .= 0 for k in eachindex(seq_ends) t1, t2 = HMMs.seq_limits(seq_ends, k) hmm.init .+= γ[:, t1] hmm.trans .+= sum(ξ[t1:t2]) end hmm.init ./= sum(hmm.init) for row in eachrow(hmm.trans) row ./= sum(row) end U = reduce(hcat, control_seq)' y = obs_seq for i in 1:N W = sqrt.(Diagonal(γ[i, :])) hmm.dist_coeffs[i] = (W * U) \ (W * y) end end ``` -------------------------------- ### Compare Estimated vs True Transition Matrices (Period 3) Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Compares the estimated transition matrix for the third period of the HMM with the true transition matrix. This helps in evaluating the accuracy of the learned parameters. ```julia cat(transition_matrix(hmm_est, 3), transition_matrix(hmm, 3); dims=3) ``` -------------------------------- ### Simulate HMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Generates a state and observation sequence by simulating the HMM for a specified number of time steps or based on a control sequence. ```julia rand([rng,] hmm, T) rand([rng,] hmm, control_seq) ``` -------------------------------- ### Implement Periodic HMM Interface Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Implements the necessary interface functions for `PeriodicHMM`. This includes defining the period, initialization, and time-dependent transition matrices and observation distributions by using the modulo operator on the time step. ```julia period(::PeriodicHMM{T,D,L}) where {T,D,L} = L function HMMs.initialization(hmm::PeriodicHMM) return hmm.init end function HMMs.transition_matrix(hmm::PeriodicHMM, t::Integer) l = (t - 1) % period(hmm) + 1 return hmm.trans_per[l] end function HMMs.obs_distributions(hmm::PeriodicHMM, t::Integer) l = (t - 1) % period(hmm) + 1 return hmm.dists_per[l] end ``` -------------------------------- ### Log-likelihood of Observation Sequence Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics A wrapper around the forward algorithm to directly compute the log-likelihood of an observation sequence P(Y1:T). ```julia logdensityof(hmm, obs_seq) ``` ```text -54.214899298272634 ``` -------------------------------- ### Update HMM In-Place using Forward-Backward Storage Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api The `StatsAPI.fit!` function updates an HMM in-place using pre-computed forward-backward statistics. The `fb_storage` is used as scratch space and its contents are not guaranteed after the call. ```julia StatsAPI.fit!( hmm, fb_storage::ForwardBackwardStorage, obs_seq, [control_seq]; seq_ends, ) ``` -------------------------------- ### Base Overloads Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Overloads for Base package functions. ```APIDOC ## Base Overloads Functions from the Base package that are extended for HiddenMarkovModels. ### `Base.eltype(hmm)` Returns the element type of the HMM. ### `Base.length(hmm)` Returns the number of states in the HMM. ``` -------------------------------- ### Forward-Backward Algorithm Execution Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Executes the forward-backward algorithm in-place, updating the provided storage with computed values. ```APIDOC ## Function: forward_backward! ### Description Executes the forward-backward algorithm in-place. ### Signature ```julia forward_backward!(storage, hmm, obs_seq, control_seq; seq_ends, transition_marginals) ``` ### Parameters * `storage`: The storage object to be updated with results. * `hmm`: The Hidden Markov Model object. * `obs_seq`: The sequence of observations. * `control_seq`: The sequence of control inputs. * `seq_ends` (Optional): Specifies the end of sequences. * `transition_marginals` (Optional): Specifies transition marginals. ``` -------------------------------- ### Retrieve Estimated Sparse Transition Matrix Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Inspect the transition matrix of the HMM estimated by the Baum-Welch algorithm. The sparsity pattern from the initial guess is preserved in the estimated model. ```julia transition_matrix(hmm_est) ``` -------------------------------- ### Forward-Backward Algorithm for Smoothed State Marginals Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Computes smoothed state marginals (probability of current state given all observations) and the observation sequence log-likelihood. Useful for learning. ```julia smoothed_state_marginals, obs_seq_loglikelihood_fb = forward_backward(hmm, obs_seq); only(obs_seq_loglikelihood_fb) ``` ```text -54.214899298272634 ``` ```julia filtered_state_marginals[:, T - 1] ≈ smoothed_state_marginals[:, T - 1] ``` ```text false ``` ```julia filtered_state_marginals[:, T] ≈ smoothed_state_marginals[:, T] ``` ```text true ``` -------------------------------- ### StatsAPI.fit! Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Updates an HMM in-place using information computed during the forward-backward algorithm. The provided storage object may be reused as scratch space and its contents should not be trusted afterwards. ```APIDOC ## StatsAPI.fit! ### Description Update `hmm` in-place based on information generated during forward-backward. ### Signature ```julia StatsAPI.fit!( hmm, fb_storage::ForwardBackwardStorage, obs_seq, [control_seq]; seq_ends, ) ``` ### Details This function is allowed to reuse `fb_storage` as a scratch space, so its contents should not be trusted afterwards. ``` -------------------------------- ### Verify gradient results with forward diff Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/autodiff Compare the computed gradients from Enzyme.jl (reverse mode) with those obtained from forward-mode differentiation to ensure correctness. ```julia ∇parameters_enzyme ≈ ∇parameters_forwarddiff ``` ```julia ∇obs_enzyme ≈ ∇obs_forwarddiff ``` ```julia ∇control_enzyme ≈ ∇control_forwarddiff ``` -------------------------------- ### HMM Type Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api A concrete implementation of a basic Hidden Markov Model, storing initial probabilities, transition matrices, and observation distributions. ```APIDOC ## Type: `HMM` Basic implementation of an HMM. ### Fields * `init::AbstractVector` : initial state probabilities * `trans::AbstractMatrix`: state transition probabilities * `dists::AbstractVector`: observation distributions * `loginit::AbstractVector`: logarithms of initial state probabilities * `logtrans::AbstractMatrix`: logarithms of state transition probabilities ``` -------------------------------- ### HiddenMarkovModels.forward_backward Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Applies the forward-backward algorithm to compute posterior state and transition marginals for an HMM given an observation sequence. Returns the posterior marginals (gamma) and the log-likelihood. ```APIDOC ## forward_backward ### Description Apply the forward-backward algorithm to infer the posterior state and transition marginals during sequence `obs_seq` for `hmm`. ### Signature ```julia forward_backward(hmm, obs_seq; ...) forward_backward(hmm, obs_seq, control_seq; seq_ends) ``` ### Returns Return a tuple `(storage.γ, storage.logL)` where `storage` is of type `ForwardBackwardStorage`. ``` -------------------------------- ### Calculate Log-Density of Observations Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Compute the log-density of the observation sequence using both the original HMM and the HMM with uncertain parameters. ```julia logdensityof(hmm, obs_seq) ``` ```julia logdensityof(hmm_uncertain, obs_seq) ``` -------------------------------- ### Construct Sparse Transition Matrix for HMM Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/types Define an HMM with a sparse transition matrix to represent structurally forbidden transitions. This is useful for large models where not all state transitions are possible. ```julia trans = sparse([ 0.7 0.3 0 0 0.7 0.3 0.3 0 0.7 ]) ``` ```julia init = [0.2, 0.6, 0.2] dists = [Normal(1.0), Normal(2.0), Normal(3.0)] hmm = HMM(init, trans, dists) ``` -------------------------------- ### Define a Hidden Markov Model Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/basics Define an HMM with initial state probabilities, transition probabilities, and observation distributions. Any scalar- or vector-valued distribution from Distributions.jl can be used. ```julia init = [0.6, 0.4] trans = [0.7 0.3; 0.2 0.8] dists = [MvNormal([-0.5, -0.8], I), MvNormal([0.5, 0.8], I)] hmm = HMM(init, trans, dists) ``` -------------------------------- ### Validate Zygote gradients against ForwardDiff gradients Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/autodiff Compares the gradients computed by Zygote.jl (reverse mode) with those computed by ForwardDiff.jl (forward mode) to ensure correctness. ```julia ∇parameters_zygote ≈ ∇parameters_forwarddiff ``` ```julia ∇obs_zygote ≈ ∇obs_forwarddiff ``` ```julia ∇control_zygote ≈ ∇control_forwarddiff ``` -------------------------------- ### Generate Random Transition Matrix Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Generates a random transition matrix of size (N, N) with normalized uniform entries. Optionally accepts a random number generator and element type. ```julia rand_trans_mat([rng, ::Type{R},] N) ``` -------------------------------- ### HiddenMarkovModels.viterbi! Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/api Performs the Viterbi algorithm in-place, updating the provided storage with the most likely state sequence and its log-likelihood. ```APIDOC ## viterbi! ### Description Perform the Viterbi algorithm in-place. ### Signature ```julia viterbi!(storage, hmm, obs_seq, control_seq; seq_ends) ``` ``` -------------------------------- ### Display Simulated Observations Source: https://gdalle.github.io/HiddenMarkovModels.jl/stable/examples/temporal Displays the transpose of the simulated observation sequence. The output shows a sequence of floating-point numbers representing the observed values. ```julia obs_seq' ```