Fitting

fit(times, types, ..., M=..., T=...) maximises the log-likelihood over \(\mu\), \(\alpha\) and \(\beta\) and returns a FitResult. This page lists the choices and what each one costs or hides. The reference entry is Reference.

Inputs

times must be sorted and non-negative, types integers in 0..M-1 (at most 256 types). M is required unless mu or alpha is passed. T is the end of the observation window and defaults to the last event time; pass it explicitly when the window runs past the last event, because the likelihood depends on it through the compensator.

Optimiser and start values

The optimiser is L-BFGS-B on the log of every parameter, with the analytic gradient, so positivity is built in. The search for each \(\beta\) is confined to \([1/(10T),\; 10 / g_{\min}]\), where \(g_{\min}\) is the smallest positive gap between events. A coordinate that stops on either end is a boundary value, not a stationary point; bound_hit is True and bound_coordinates names it.

The first start is a moment estimate: baselines from event counts, a rank-one branching matrix with \(\rho = 0.5\), and a decay set from the median gap. With n_starts > 1 the extra starts perturb it in log space and the best likelihood wins. That is the best of the starts, not a proof of a global optimum: along the alpha-beta ridge several parameter vectors can have the same likelihood. seed makes a multi-start and a bootstrap reproducible; seed=None does not.

Model options

  • shared_decay=True estimates one decay per source (\(\beta_{ij} = \beta_j\), beta of shape (M,)). This is a different model from the pair-decay one, with \(M\) decay rates instead of \(M^2\). The calibration study measured pair decay only, so trust_lookup says nothing about a shared-decay fit.

  • zero_diagonal=True fixes \(\alpha_{ii} = 0\) by removing those coordinates from the free vector.

  • mu=, alpha= or beta= hold a whole block fixed. A block is fixed entirely or estimated entirely.

Standard errors

se_method="hessian" (the default) differentiates the analytic gradient to get the observed information and inverts it. When the matrix cannot be inverted to the stated tolerance, se and cov are None and notes says why; no number is invented. The calibration study measured this method.

se_method="bootstrap" simulates from the fitted model and refits n_bootstrap times (default 200). It is slow. From the capability table, at two types and \(N = 10^5\) with \(B = 200\) it took 70 s on one worker; at four types and \(N = 10^5\) it took 8.5 min on one worker and 86 s on the default pool of that machine’s 24 logical cores. The calibration study did not measure this method, so nothing here says it is more honest than the Hessian one. On Windows and macOS it starts worker processes and the calling script needs an if __name__ == "__main__": guard. Without one, Python 3.11 and later raise an error that names it; Python 3.10 on Windows can hang instead, because of a CPython defect, so use the guard there. It computes no Hessian condition number, so hessian_condition is None and the conditioning checks in reliable are skipped.

se_method=None computes no standard errors, and reliable is then "unreliable" by construction.

se_method="auto" lets the calibration map choose between the two. After the fit it looks the regime up and acts on what was measured there: where an estimated block’s two-standard-error interval around the measured q excludes 1, it runs the bootstrap and reports its interval; where the map has no measurement for the regime it keeps the Hessian interval and says the interval is uncalibrated; where the map reports the estimator undefined it returns no interval at all. The choice is recorded: fit.se_source is "hessian", "bootstrap" or "none", fit.se_note is one sentence saying why, and fit.auto carries the whole decision — the cell, the distance to it, the q it read per block, the threshold, the projected cost and the action. auto_max_seconds (default 120) caps the projected cost of a bootstrap auto would choose; above it the Hessian interval is kept, the note says what was indicated, and a RuntimeWarning is raised. The full policy, including why the threshold is two Monte Carlo standard errors and why the limit is 120 s, is The se_method="auto" policy.

For the Hessian method, the measured ratio of mean reported standard error to empirical standard deviation is on Limits.

Reading the result

converged is true when the gradient of the log-parameterised objective, recomputed at the returned point, is below \(10^{-6}\max(1, |\ell|)\) and the optimiser did not stop on its iteration limit. It is a statement about the optimiser.

reliable is a conditioning report, nothing more. It reads the Hessian condition number, whether a coordinate hit a bound, how close \(\rho\) is to 1, the largest correlation between a log-\(\alpha\) and a log-\(\beta\) coordinate, and the number of events per free parameter, against thresholds that are engineering judgement (hawkes_engine.trust.THRESHOLDS). The study measured it. It separates coverage mostly because fits it labels unreliable mostly have no standard error, and it labelled 3211 fits reliable whose \(\hat\beta\) was more than ten times the largest true \(\beta\). Both are on Limits with their evidence.

rho_ci is a first-order delta-method interval for \(\rho\), and is None when no covariance exists.

Assumptions the fit does not check

All events are observed: no censoring, no missing data. The kernel is a sum of exponentials with non-negative weights; inhibition is not modelled. The events are a single realisation on one window. None of this is tested on the input.