pointprocesses/temporal/
hawkes.rs1use super::traits::*;
3use rand::prelude::*;
4
5use ndarray::prelude::*;
6
7use crate::poisson::{PoissonProcess, VariablePoissonProcess};
8
9
10pub trait Kernel {
12 fn eval(&self, t: f64) -> f64;
13}
14
15#[derive(Debug)]
20pub struct Hawkes<T, K: Kernel> {
21 background: T,
22 kernel: K
23}
24
25impl<T, K: Kernel> Hawkes<T, K> {
26 pub fn get_kernel(&self) -> &K {
28 &self.kernel
29 }
30
31 pub fn get_background(&self) -> &T {
33 &self.background
34 }
35}
36
37
38pub type ConstBackground = PoissonProcess;
42
43
44pub type DeterministicBackground<F> = VariablePoissonProcess<F>;
46
47
48#[derive(Debug)]
51pub struct ExpKernel {
52 pub alpha: f64,
53 pub beta: f64
54}
55
56impl Kernel for ExpKernel {
57 fn eval(&self, t: f64) -> f64 {
58 self.alpha * (-self.beta * t).exp()
59 }
60}
61
62#[derive(Debug)]
67pub struct SumExpKernel {
68 num_exp: usize,
69 alphas: Vec<f64>,
70 betas: Vec<f64>
71}
72
73impl SumExpKernel {
74 pub fn new(alphas: Vec<f64>, betas: Vec<f64>) -> Self {
76 assert_eq!(alphas.len(), betas.len());
78
79 SumExpKernel {
80 num_exp: alphas.len(),
81 alphas,
82 betas
83 }
84 }
85}
86
87impl Kernel for SumExpKernel {
88 fn eval(&self, t: f64) -> f64 {
89 let alphabetazip = self.alphas.iter().zip(self.betas.iter());
90 let mut res = 0.;
91 for (alpha,beta) in alphabetazip {
92 res += alpha * (-beta*t).exp();
93 }
94 res
95 }
96}
97
98
99#[derive(Debug)]
104pub struct PowerLawKernel {
105 alpha: f64,
106 beta: f64,
107 delta: f64
108}
109
110impl Kernel for PowerLawKernel {
111 fn eval(&self, t: f64) -> f64 {
112 self.alpha / (self.delta + t).powf(self.beta)
113 }
114}
115
116pub type PowerLawHawkes = Hawkes<ConstBackground, PowerLawKernel>;
118
119impl PowerLawHawkes {
120 pub fn new(alpha: f64, beta: f64, delta: f64, lambda0: f64) -> Self {
122 let kernel = PowerLawKernel {
124 alpha, beta, delta
125 };
126 Self {
127 background: ConstBackground::new(lambda0), kernel
128 }
129 }
130}
131
132pub type ExpHawkes = Hawkes<ConstBackground, ExpKernel>;
136
137impl ExpHawkes {
138 pub fn new(alpha: f64, beta: f64, lambda0: f64) -> Self {
139 let kernel = ExpKernel {
140 alpha, beta
141 };
142 let background = ConstBackground::new(lambda0);
143
144 Self {
145 background, kernel
146 }
147 }
148}
149
150impl TemporalProcess for ExpHawkes {
151 fn sample(&self, tmax: f64) -> TimeProcessResult {
152 simulate_hawkes_exp_const_bk(self, tmax)
153 }
154}
155
156impl<F> Hawkes<DeterministicBackground<F>, ExpKernel>
157where F: Fn(f64) -> f64 + Send + Sync {
158 pub fn new(alpha: f64, beta: f64, func: F, max_lbda0: f64) -> Self {
159 let kernel = ExpKernel { alpha, beta };
160 let background = DeterministicBackground::new(func, max_lbda0);
161 Self {
162 background, kernel
163 }
164 }
165}
166
167impl<F> TemporalProcess for Hawkes<DeterministicBackground<F>, ExpKernel>
168where F: Fn(f64) -> f64 + Send + Sync {
169 fn sample(&self, tmax: f64) -> TimeProcessResult {
170 simulate_hawkes_exp_var_bk(self, tmax)
171 }
172}
173
174fn simulate_hawkes_exp_const_bk(model: &ExpHawkes, tmax: f64) -> TimeProcessResult {
180 let kernel = &model.kernel;
181 let alpha = kernel.alpha;
182 let decay = kernel.beta;
183 let lambda0 = &model.background.intensity(0.);
184
185 let mut rng = thread_rng(); let mut timestamps = Vec::new();
187 let mut intensities = Vec::new();
188 let mut s = -1.0/lambda0*rng.gen::<f64>().ln();
191 let mut cur_lambda = lambda0 + alpha;
192 let mut lbda_max = cur_lambda;
193
194 while s < tmax {
195 let u: f64 = rng.gen();
196 let ds = -1.0/lbda_max*u.ln();
198 cur_lambda = lambda0 + (cur_lambda-lambda0)*(-decay*ds).exp();
201 s += ds; if s > tmax {
203 break;
205 }
206
207 let d: f64 = rng.gen();
209 if d < cur_lambda/lbda_max {
210 cur_lambda = cur_lambda + alpha; timestamps.push(s);
213 intensities.push(cur_lambda);
214 }
215 lbda_max = cur_lambda;
217 }
218
219 let timestamps = Array1::from_vec(timestamps);
220 let intensities = Array1::from_vec(intensities);
221
222 TimeProcessResult {
223 timestamps, intensities
224 }
225}
226
227fn simulate_hawkes_exp_var_bk<F>(
228 model: &Hawkes<DeterministicBackground<F>, ExpKernel>,
229 tmax: f64
230) -> TimeProcessResult where F: Fn(f64) -> f64 + Send + Sync
231{
232 let kernel = &model.kernel;
233 let alpha = kernel.alpha;
234 let beta = kernel.beta;
235 let lambda0 = &model.background; let max_lbda0 = model.background.get_max_lambda();
237
238 let mut rng = thread_rng(); let mut timestamps = Vec::new();
240 let mut intensities = Vec::new();
241
242 let mut max_lbda = max_lbda0;
248 let mut s = 0.;
249 let mut cur_slbda = 0.; while s < tmax {
252 let u: f64 = rng.gen();
253 let ds = -u.ln()/max_lbda;
255 s += ds;
256 let cur_blbda = lambda0.intensity(s);
258 cur_slbda = cur_slbda * (-beta * ds).exp();
260 let cur_lbda = cur_blbda + cur_slbda; if s > tmax {
263 break;
265 }
266
267 let acceptance = cur_lbda / max_lbda;
269 let d: f64 = rng.gen();
270 if d < acceptance {
271 cur_slbda += alpha; let cur_lbda = cur_blbda + cur_slbda;
275 timestamps.push(s);
276 intensities.push(cur_lbda);
277 }
278 max_lbda = max_lbda0 + cur_slbda; }
280
281 let timestamps = Array1::from_vec(timestamps);
282 let intensities = Array1::from_vec(intensities);
283
284 TimeProcessResult {
285 timestamps, intensities
286 }
287}
288