Skip to content

Instantly share code, notes, and snippets.

@darius
Created March 28, 2023 01:58
Show Gist options
  • Save darius/e02873564ed16cc8100d414ee56d26e8 to your computer and use it in GitHub Desktop.
Save darius/e02873564ed16cc8100d414ee56d26e8 to your computer and use it in GitHub Desktop.
withal@gmail.com
I have questions about some Common Lisp code. First, I'm unfamiliar with defsubst. Is it a standard macro?
Yes, defsubst is a standard macro in Common Lisp. It is similar to defun, which is used to define functions, but with a key difference: defsubst is used to define inline functions, also known as "substitute functions" or "substitutions".
When a function is defined with defsubst, the compiler is advised to expand the function at compile-time, essentially inlining the function's body wherever it is called. This can lead to performance improvements, as the function call overhead is eliminated. However, it may also increase the size of the compiled code.
Keep in mind that using defsubst is just a suggestion to the compiler, and it is not guaranteed to inline the function. The decision is ultimately up to the compiler's optimization settings and heuristics.
withal@gmail.com
Thanks. Now some of the function defs are preceded by, apparently a type declaration. I haven't seen this form of that in CL code before:
(-> log-likelihood (double-float double-float double-float) double-float)
(defun log-likelihood (μ σ datum)
"Return the log-likelihood of DATUM for given model parameters."
(values (if (plusp σ)
(gaussian-log-likelihood μ σ datum)
sb-ext:double-float-negative-infinity)))
The code you're seeing appears to be using the -> macro to declare the type of the function's arguments and return value. However, this is not a standard Common Lisp macro. It might be a custom macro defined in the codebase you're working with, or it could be part of a library that is being used.
The -> macro in this example is specifying that the function log-likelihood takes three arguments of type double-float and returns a value of type double-float.
It's important to understand that the -> macro is not part of the standard Common Lisp language. If you're working with a codebase that uses this macro, you'll need to locate its definition or the library it comes from to understand how it works and if it has any side effects.
In standard Common Lisp, you would use the declare form inside the function body to specify the types of the arguments and return values, like this:
lisp
Copy code
(defun log-likelihood (μ σ datum)
"Return the log-likelihood of DATUM for given model parameters."
(declare (type double-float μ σ datum)
(values double-float))
(if (plusp σ)
(gaussian-log-likelihood μ σ datum)
sb-ext:double-float-negative-infinity))
This example uses the declare form to specify that the arguments μ, σ, and datum are of type double-float, and that the function returns a value of type double-float. Note that the values declaration is used to specify the return type.
withal@gmail.com
That's what I thought. The first two lines of the source file are the following. Could the (:use ...) part be related to importing the -> macro? `(defpackage #:permo (:use #:gt))
(in-package #:permo)`
Yes, it's possible that the (:use ...) part in the defpackage form is related to importing the -> macro. The defpackage form is used to define a new package, and the :use option is for specifying a list of packages whose external symbols should be imported into the new package.
In your example, the package being defined is named permo, and it's importing the symbols from the gt package:
lisp
Copy code
(defpackage #:permo (:use #:gt))
If the -> macro is defined in the gt package and has been exported, it would be accessible in the permo package.
After defining the package, the code switches to the permo package using the in-package form:
lisp
Copy code
(in-package #:permo)
This sets the current package to permo, making the symbols imported from the gt package, including the -> macro, available in the code that follows.
withal@gmail.com
This package apparently does sequential monte carlo estimation. Can you give me an overview of that?
Sequential Monte Carlo (SMC) estimation, also known as Particle Filtering, is a family of algorithms used for estimating the state of a dynamic system or time series data, especially when dealing with non-linear and non-Gaussian systems. SMC methods are particularly useful in situations where the system's state evolves over time and is subject to noise, and the observation model is also subject to noise.
The main idea behind SMC is to represent the system's state probability distribution using a set of particles (or samples) and update these particles over time as new observations become available. The algorithm consists of three main steps, which are repeated at each time step:
Prediction: In this step, the particles are propagated forward in time using the known dynamic model of the system. This step usually involves adding process noise to account for the uncertainty in the system dynamics.
Update: When a new observation is available, the particles are updated by computing their weights based on the likelihood of the observation given the particle's state. This step involves evaluating the observation model for each particle, which describes the probability of observing the data given the current state.
Resampling: After updating the particle weights, some particles may have very low weights, and others may have very high weights. To avoid degeneracy, where only a few particles dominate the representation of the state distribution, a resampling step is performed. This step involves generating a new set of particles by drawing from the current set with replacement, with the probability of selecting a particle being proportional to its weight. This results in a new set of equally weighted particles that better represent the updated state distribution.
The main advantage of SMC methods is their ability to handle complex, non-linear, and non-Gaussian systems, as well as their ability to provide an estimate of the system state along with a measure of the associated uncertainty. However, SMC methods can be computationally expensive, especially for high-dimensional systems, due to the need to maintain and update a large number of particles.
Some common applications of SMC include target tracking, robot localization and mapping, and Bayesian inference in dynamic systems.
withal@gmail.com
When do people use the different terms SMC and particle filtering? Do the different ever imply technical differences?
Sequential Monte Carlo (SMC) and Particle Filtering are often used interchangeably in the literature, and both terms refer to the same family of algorithms. However, there are subtle differences in the contexts in which these terms are typically used:
Particle Filtering: This term is more commonly used when discussing the application of SMC methods for state estimation in dynamic systems or time series data. The focus here is on the filtering aspect, which involves estimating the current state of a system given the history of observations up to the present time. In other words, Particle Filtering is often used when discussing the specific application of SMC algorithms to tracking, localization, or other state estimation problems.
Sequential Monte Carlo: This term is more general and is used to describe the broader class of algorithms that use Monte Carlo methods for estimating the state of a system or solving other problems in a sequential manner. This includes not only the filtering problem but also other problems like smoothing (estimating the state of a system at a previous time) or prediction (estimating the state of a system at a future time). The term SMC is also used in the context of more general Bayesian inference problems, where the goal is to estimate the posterior distribution of parameters or latent variables given observed data.
While both terms refer to the same family of algorithms, the choice of term may imply a difference in focus or application. In practice, however, many researchers and practitioners use these terms interchangeably, and the specific technical details of the algorithms are more important than the choice of terminology.
withal@gmail.com
Great, that helps. This code seems to be meant for Bayesian inference. Could you try adding some helpful comments for someone who has only a vague idea of SMC (but a decent background in probability and algorithms) to these function definitions? Please leave out the body of the code -- just the def lines are enough to identify what these comments would be referring to. Code follows: ;;;; Types
;; Short-hand types.
;; Leaky abstractions: no secret what the concrete representations are.
(deftype R (&rest args) "Real number." `(double-float ,@args))
(deftype P () "Probability." '(R 0d0 1d0))
(deftype L () "Log-likelihood." '(R * #.(log 1)))
;;;; Models written by hand
(defun smc/gaussian (&optional
(n-particles 1000)
(observations (loop repeat 1000 collect (+ 1d0 (* 2d0 (gaussian-random))))
#+nil (loop repeat 1000 collect 100d0)))
(local
;; Particles are represented as indices into these arrays.
(def μ (make-array (list n-particles) :element-type 'double-float))
(def σ (make-array (list n-particles) :element-type 'double-float))
(loop for i below n-particles
do (setf (aref μ i) (- 10d0 (random 20d0))
(aref σ i) (random 10d0)))
(-> log-likelihood (double-float double-float double-float) double-float)
(defun log-likelihood (μ σ datum)
"Return the log-likelihood of DATUM for given model parameters."
(values (if (plusp σ)
(gaussian-log-likelihood μ σ datum)
sb-ext:double-float-negative-infinity)))
(defun particle-log-likelihood (particle datum)
"Return the log-likelihood of DATUM given the parameters of PARTICLE."
(log-likelihood (aref μ particle) (aref σ particle) datum))
(defun respawn! (parent-indices)
"Re-initialize the particles by copying values from PARENT-INDICES.
(PARENT-INDICES were chosen by resampling.)"
(loop with μ₀ = (copy-array μ)
with σ₀ = (copy-array σ)
for i from 0
for p in parent-indices
do (setf (aref μ i) (aref μ₀ p)
(aref σ i) (aref σ₀ p))))
(defun jitter! (metropolis-accept?)
"Jitter (rejuvenate) the parameters of all particles using one or more metropolis steps.
Function (METROPOLIS-ACCEPT? OLD PROPOSED) uses the supplied log-likelihood functions
to accept or reject the proposed state."
;; Try a series of moves of different relative sizes.
(loop for proposal-stddev in '(0.01d0 0.10d0 0.25d0) do
;; Add gaussian noise to both parameters. Scaled to a fraction of current value.
(loop for i below n-particles
for μ.i = (aref μ i)
for σ.i = (aref σ i)
for μ.p = (+ μ.i (* μ.i proposal-stddev (gaussian-random)))
for σ.p = (+ σ.i (* σ.i proposal-stddev (gaussian-random)))
for old-log-likelihood = (partial #'log-likelihood μ.i σ.i)
for new-log-likelihood = (partial #'log-likelihood μ.p σ.p)
when (funcall metropolis-accept? old-log-likelihood new-log-likelihood)
do (setf (aref μ i) μ.p
(aref σ i) σ.p))))
(values μ σ (smc/likelihood-tempering n-particles observations
:log-likelihood #'particle-log-likelihood
:respawn! #'respawn!
:jitter! #'jitter!))))
;;;; Sequential Monte Carlo (Particle Filter) sampler
(defun smc (&key log-mean-likelihood resample! rejuvenate! step! weight!)
"Run a callback-driven Sequential Monte Carlo particle filter simulation.
Return the log marginal likelihood estimate.
Callbacks:
(WEIGHT!)
Calculate and associate weights with particles.
(LOG-MEAN-LIKELIHOOD) ⇒ double-float
Return the log mean likelihood for all particles.
(RESAMPLE!)
Resample weighted particles into equally-weighted replacements.
(REJUVENATE!)
Jitter particles without changing their distribution.
(STEP!) ⇒ boolean
Advance the simulation. Return true on success, false on a completed simulation."
(loop do (funcall weight!)
sum (funcall log-mean-likelihood)
while (funcall step!)
do (funcall resample!)
(funcall rejuvenate!)))
(defsubst smc/likelihood-tempering (n-particles observations
&key
log-likelihood respawn! jitter!
(initial-temp 0.01d0)
(temp-step 0.01d0))
"Run a callback-driven Sequential Monte Carlo simulation using likelihood tempering.
Callbacks:
(PARTICLE-LOG-LIKELIHOOD particle datum) ⇒ log-likelihood
Return log-likelihood of DATUM given the parameters of PARTICLE.
(RESPAWN! parent-indices)
Replace particles by overwriting them with the resampled PARENT-INDICES.
(JITTER! metropolis-accept?)
Rejuvenate particles by proposing moves to the function
(METROPOLIS-ACCEPT? OLD-LOG-LIKELIHOOD-FN NEW-LOG-LIKELIHOOD-FN)
which compares the likelihood ratios and returns true if the move is accepted."
(local
(def temp initial-temp)
(def log-weights (make-array (list n-particles) :element-type 'double-float))
(defun tempered-log-likelihood (log-likelihood-fn)
"Return the log-likelihood tempered with the current temperature."
(handler-case
(loop for o in observations
summing (funcall log-likelihood-fn o) into ll
finally (return (logexpt ll temp)))
#+nil (floating-point-overflow () sb-ext:double-float-negative-infinity)))
(defun log-mean-likelihood ()
"Return the log mean likelihood of all particles."
(log/ (logsumexp log-weights) (log n-particles)))
(defun weight! ()
"Calculate and set the weight of each particle."
(loop for i below n-particles
do (setf (aref log-weights i)
(tempered-log-likelihood (partial log-likelihood i))))
(format t "~&w = ~a~%" log-weights))
(defun resample! ()
"Replace old particles by resampling them into new ones."
(funcall respawn! (systematic-resample log-weights)))
(defun step! ()
"Advance the tempering schedule (unless finished.)"
(and (< temp 1d0)
(setf temp (min 1d0 (+ temp temp-step)))))
(defun metropolis-accept? (old-log-likelihood new-log-likelihood)
(< (log (random 1d0)) (log/ (tempered-log-likelihood new-log-likelihood)
(tempered-log-likelihood old-log-likelihood))))
(defun rejuvenate! ()
(funcall jitter! #'metropolis-accept?))
(smc :log-mean-likelihood #'log-mean-likelihood
:resample! #'resample!
:rejuvenate! #'rejuvenate!
:step! #'step!
:weight! #'weight!)))
;; Helpers for arithmetic in the log domain.
;; Used sparingly when it helps to clarify intent.
(defsubst log/ (&rest numbers) (apply #'- numbers))
;;(defun log* (&rest numbers) (apply #'+ numbers))
(defsubst logexpt (a b)
"Raise A (a log-domain number) to the power B (which is not log!)"
(* a b))
;;;; Systematic resampling
(-> systematic-resample (vector) list)
(defun systematic-resample (log-weights)
(systematic-resample/normalized (loop with normalizer = (logsumexp log-weights)
for lw across log-weights
collect (exp (- lw normalizer)))))
(-> systematic-resample/normalized (list) list)
(defun systematic-resample/normalized (weights)
(loop with n = (length weights)
with cdf = (coerce (loop for weight in weights
sum weight into cumulative
collect cumulative)
'vector)
with index = 0
repeat n
;; Pick a starting offset into the CDF
for u = (random (/ 1d0 n)) then (+ u (/ 1d0 n))
;; Step forward through the CDF
do (loop while (and (> u (aref cdf (min index (1- n))))) do (incf index))
(minf index (1- n))
collect (min index (1- n))))
;;;; Probability distributions and utilities
(defun gaussian-log-likelihood (μ σ x)
"Return the likelihood of Normal(μ,σ) at X."
(if (plusp σ)
(let ((z (/ (- x μ) σ)))
(- 0
(log σ)
(/ (+ (* z z) (log (* pi 2))) 2)))
most-negative-double-float))
(-> logsumexp (R[]) R)
(defun logsumexp (vec)
;; utility for numerically stable addition of log quantities e.g. for normalization
;; see e.g. https://gregorygundersen.com/blog/2020/02/09/log-sum-exp/
(loop with max = (reduce #'max vec)
for x across vec
summing (if (sb-ext:float-infinity-p x) 0d0 (exp (- x max))) into acc
finally (return (+ max (log acc)))))
Here are comments for the functions you provided. These comments are intended to give a brief explanation of the purpose of each function for someone with a general understanding of SMC, probability, and algorithms:
lisp
Copy code
;;; Types
;; ...
;;;; Models written by hand
;; Main entry point for a Gaussian model SMC simulation.
;; Returns μ, σ, and the log likelihoods for the given observations.
(defun smc/gaussian ...)
;; Calculate the log-likelihood of a datum given model parameters μ and σ.
(defun log-likelihood ...)
;; Calculate the log-likelihood of a datum given the parameters of a particle.
(defun particle-log-likelihood ...)
;; Re-initialize the particles by copying values from the given parent indices.
(defun respawn! ...)
;; Jitter (rejuvenate) the parameters of all particles using Metropolis steps.
(defun jitter! ...)
;;;; Sequential Monte Carlo (Particle Filter) sampler
;; Run a callback-driven SMC particle filter simulation, return log marginal likelihood estimate.
(defun smc ...)
;; Run a callback-driven SMC simulation using likelihood tempering.
(defun smc/likelihood-tempering ...)
;; Helper functions for arithmetic in the log domain
;; ...
;;;; Systematic resampling
;; Perform systematic resampling on a vector of log-weights.
(defun systematic-resample ...)
;; Perform systematic resampling on a list of normalized weights.
(defun systematic-resample/normalized ...)
;;;; Probability distributions and utilities
;; Return the log-likelihood of a Gaussian distribution with given μ, σ at point x.
(defun gaussian-log-likelihood ...)
;; Compute the numerically stable sum of exponentials of a vector of log-domain numbers.
(defun logsumexp ...)
These comments should help in understanding the general purpose of each function in the provided code.
withal@gmail.com
What's systematic about the resampling?
Systematic resampling is a method used in particle filtering and Sequential Monte Carlo (SMC) to resample a set of particles (also known as "samples" or "points") based on their importance weights. The "systematic" aspect refers to the structured way the resampling procedure is carried out.
In systematic resampling, the following steps are taken:
Divide the unit interval [0, 1) into N equal segments, where N is the number of particles.
Choose a random starting point, U, uniformly from the first segment (i.e., between 0 and 1/N).
Compute the cumulative distribution function (CDF) of the importance weights.
For each subsequent segment (from U + 1/N, U + 2/N, ..., U + (N-1)/N), find the index in the CDF that corresponds to the segment value. The particle associated with that index is selected for resampling.
The systematic resampling method ensures a more even coverage of the particles with high importance weights. It helps maintain diversity in the resampled particles and reduces the risk of sample impoverishment compared to other methods, such as multinomial resampling.
In the provided code, the systematic-resample function performs systematic resampling on a vector of log-weights, while the systematic-resample/normalized function performs systematic resampling on a list of normalized weights.
withal@gmail.com
Let's see if I understand. Critique this claim: `systematic-resample` takes a list of weights (in the log domain). Each weight is associated with a particle (i.e. weight #i goes with particle #i). This function generates a new list of particle indices, of the same length, but picking from the original particles at random with replacement, each with a chance proportional to its weight.
Your claim is almost correct, but there is a slight misunderstanding. The systematic-resample function takes a vector of log-weights (not a list) as an input. Other than that, your claim is accurate. The function generates a new list of particle indices of the same length, picking from the original particles at random with replacement, with each particle's chance of being selected proportional to its weight. The systematic resampling method ensures a more even coverage of particles with high importance weights and helps maintain diversity in the resampled particles.
withal@gmail.com
Oh yes, thanks. Spelled out in a similar style, what's the purpose of the likelihood tempering function? I guess it's a kind of simulated annealing.
Yes, you're correct. The likelihood tempering function is a variant of Sequential Monte Carlo (SMC) that incorporates a simulated annealing-like technique to improve the performance of the algorithm, particularly in high-dimensional and complex problems.
The purpose of the likelihood tempering function is to perform SMC sampling while gradually increasing the influence of the observed data on the particles. This is done by "tempering" the likelihood function using a temperature parameter. The temperature parameter starts at a small value (close to 0) and is incrementally increased towards 1 during the SMC process. When the temperature is close to 0, the particles explore the prior distribution, and as the temperature approaches 1, the particles are increasingly influenced by the observed data.
The likelihood tempering function aims to achieve the following:
Facilitate the exploration of the particles in the parameter space by starting with a low influence of the observed data and increasing it gradually.
Improve the efficiency and robustness of the SMC algorithm in high-dimensional or complex problems.
Provide better estimates of the posterior distribution and reduce the risk of getting trapped in local optima.
In the provided code, the smc/likelihood-tempering function carries out the likelihood tempering process. It takes several callback functions as arguments, such as log-likelihood, respawn!, and jitter!, which are used to compute the tempered log-likelihood, resample the particles, and rejuvenate the particles, respectively. The function also accepts initial-temp and temp-step as optional arguments to control the starting temperature and the increment at each step.
withal@gmail.com
Do you think the purpose of smc/gaussian is then: you call it with a list of observations of a real random variable (according to your mental model). You get back three values: (1 and 2:) vectors of mu and sigma values for particles that are sampled from the normal distribution that is, we hope, the most likely to produce the observations; and (3) the likelihood of that distribution (in the log domain again, I guess).
Yes, your understanding is mostly correct. The purpose of smc/gaussian is to estimate the parameters of an underlying Gaussian distribution (mean and standard deviation, represented by mu and sigma) that might have generated the given list of observations of a real random variable.
The function returns three values:
A vector of mu (mean) values for the particles sampled from the most likely Gaussian distribution.
A vector of sigma (standard deviation) values for the particles sampled from the most likely Gaussian distribution.
The log marginal likelihood (not the likelihood of the distribution) of the most likely Gaussian distribution. The log marginal likelihood is useful for model comparison and selection.
The Sequential Monte Carlo (SMC) method with likelihood tempering is used in smc/gaussian to achieve these goals. It starts with an initial set of particles that are sampled from a prior distribution for the Gaussian parameters (mu and sigma). These particles are then updated iteratively using the SMC algorithm, incorporating the information from the observations and gradually converging to the most likely Gaussian distribution that could have generated the data.
withal@gmail.com
By marginal likelihood you mean the probability of the data, given the model whose mu and sigma are from the mean of the particle values returned?
I apologize for the confusion. You are correct that the marginal likelihood, also known as the model evidence, refers to the probability of the data given the model. However, I should clarify that the value returned by the smc/gaussian function is not the marginal likelihood directly.
In the context of the smc/gaussian function, the value returned is the estimate of the log marginal likelihood using the Sequential Monte Carlo (SMC) method with likelihood tempering. This estimate is obtained by summing the log mean likelihoods computed at each step of the SMC algorithm.
While it doesn't directly give you the log marginal likelihood for a specific set of mu and sigma values (such as the mean of the particle values returned), it provides an estimate of the log marginal likelihood for the entire model, which considers the uncertainty in the mu and sigma values. This estimate can be useful for model comparison and selection purposes.
If you want to compute the likelihood of the data given a specific set of mu and sigma values (e.g., the mean of the particle values returned), you would need to calculate the product of the likelihoods for each observation under that specific Gaussian distribution and take the logarithm of the result.
withal@gmail.com
Let's backtrack. It's clear I was confused about the meaning of the third returned value. Let's both forget your first two explanations. Can you explain it again, in Bayesian modeling terms, without using the word 'likelihood' (which seems to be confusing since it has some different senses in bayesian and frequentist stats)?
Certainly! In Bayesian modeling terms, the Sequential Monte Carlo (SMC) method, as implemented in the smc/gaussian function, aims to approximate the posterior distribution of the model parameters (mu and sigma) given the observed data. The method uses a set of particles, each representing a candidate set of parameter values, to explore the parameter space.
The third value returned by the smc/gaussian function is an estimate of the log model evidence. Model evidence, also known as the marginal likelihood, represents the probability of the observed data given the model. It serves as a normalization factor in Bayes' theorem and is used for model comparison and selection.
In the context of the SMC method, the log model evidence is estimated by summing the log mean weights computed at each step of the algorithm. This estimate doesn't directly give you the log probability of the data given a specific set of mu and sigma values (e.g., the mean of the particle values returned), but rather provides an estimate of the log model evidence for the entire model, taking into account the uncertainty in the mu and sigma values.
So, the main purpose of the smc/gaussian function is to provide an approximation of the posterior distribution of the model parameters (mu and sigma) given the observed data, as well as an estimate of the log model evidence for model comparison and selection purposes.
withal@gmail.com
Doesn't the posterior depend on a choice of prior?
Yes, you're absolutely right. The posterior distribution depends on both the likelihood of the data given the model parameters and the prior distribution of the model parameters. The choice of prior can have a significant impact on the resulting posterior, especially when the observed data is limited or the likelihood is relatively flat.
In the provided code, the prior distribution for the model parameters (mu and sigma) is not explicitly specified. However, the initial values of the particles are generated with the following code:
lisp
Copy code
(loop for i below n-particles
do (setf (aref μ i) (- 10d0 (random 20d0))
(aref σ i) (random 10d0)))
This implies that the initial particles (i.e., the candidate parameter values) are sampled uniformly from a range of mu (-10 to 10) and sigma (0 to 10). The choice of prior is implicitly encoded in this initialization step. The SMC algorithm then proceeds to iteratively update the particles based on the likelihood of the data and the prior assumptions, resulting in an approximation of the posterior distribution given the chosen prior and the observed data.
withal@gmail.com
I'm not sure of this; couldn't this algorithm settle on (a sample of) the same distribution regardless of the initial assignment?
You're correct that the Sequential Monte Carlo (SMC) algorithm has the potential to converge to the same posterior distribution even if the initial assignments are different, as long as the initialization is compatible with the target distribution. However, the initial assignment does play a role in the exploration of the parameter space, and the algorithm's ability to find the correct posterior distribution might be affected by the quality of the initial assignments.
In practice, the SMC algorithm does not guarantee convergence to the true posterior distribution, but it aims to approximate it. The quality of the approximation depends on various factors, such as the number of particles, the choice of the proposal distribution, and the resampling and rejuvenation steps.
If the initial assignment is very far from the true posterior distribution, it might take a longer time for the SMC algorithm to converge or even fail to converge to the correct distribution. Therefore, it is generally beneficial to have a good initial guess or prior for the model parameters to improve the efficiency and accuracy of the algorithm.
To summarize, while the SMC algorithm can potentially settle on the same distribution regardless of the initial assignment, the quality and efficiency of the approximation are influenced by the initialization, among other factors.
withal@gmail.com
OK, but this initialization doesn't at first glance look like the role of a prior distribution.
You're right. In the code you provided, the initialization of the particles does not explicitly incorporate a prior distribution for the model parameters (μ and σ). The particles are initialized randomly within specific bounds:
lisp
Copy code
(loop for i below n-particles
do (setf (aref μ i) (- 10d0 (random 20d0))
(aref σ i) (random 10d0)))
This random initialization serves as a simple, implicit, and non-informative prior, assuming that the true values of the parameters are likely to lie within the given bounds. In this case, the prior is not explicitly defined in terms of a probability distribution but rather through the bounds of the initial assignments.
In a more sophisticated Bayesian modeling approach, you would typically define an explicit prior distribution for the model parameters and initialize the particles by sampling from this prior distribution. This would allow you to incorporate prior knowledge about the parameters and potentially improve the efficiency and accuracy of the SMC algorithm.
To incorporate a prior distribution in the current code, you would need to modify the initialization of the particles to sample from the desired prior distribution instead of using the fixed bounds.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment