Skip to contents

Composition and dependency direction

An S4 fspec contains two model components:

  • kernel: an emhawkes hspec, without a residual law.
  • residual: a residual_law() object.

Use fkernel(model) and fresidual(model) to read components, or the corresponding replacement functions to update them. Replacement validates the specification. Existing $kernel and $residual access remains supported. The class also records the global refresh rule and a representation version; it does not store evolving simulation state. The residual law remains S3. Use methods::is(model, "fspec") for class checks; the new class does not inherit the old S3 frpp_spec class.

The dependency is frpp -> emhawkes. The FRPP object does not inherit from hspec, so Hawkes methods are not silently applied to it. The compatibility adapter as_legacy_hspec() temporarily restores the older FRPP representation.

Supply residual functions as needed

Use the same names as emhawkes: dresidual (density), presidual (CDF), qresidual (quantile) and rresidual (generator). All default to NULL. The constructor needs at least a density or generator; each operation then checks only its own requirements before evaluating callbacks or drawing randomness.

Operation Required residual functions
Simulation rresidual
Univariate likelihood and fitting dresidual
Multivariate likelihood and fitting dresidual, presidual
Residual diagnostics with infer = TRUE dresidual, presidual, qresidual

For simulation alone:

simulation_law <- frpp::residual_law(c(rate = 1), rresidual = stats::rexp)
simulation_model <- frpp::fspec(
  methods::new("hspec", mu = 1, alpha = 0, beta = 1), simulation_law)
simulation_path <- frpp::fsim(simulation_model, size = 5, seed = 73,
  lambda_component0 = 0)
simulation_path$inter_arrival
## [1] 0.00000000 0.75075454 0.24561278 0.07472991 1.48571875

The aliases density, cdf, quantile and rng remain supported without warnings, in that order. You can mix names for different roles, but supplying both non-NULL names for one role is an error. The original six positional arguments retain their order. Saved laws retain their existing internal representation and callback environments/defaults; no conversion is needed.

Exponential state and event mapping

For event type ii, the numeric driver is vi(t)=μi+∑j=1KCij(t). v_i(t) = \mu_i + \sum_{j=1}^K C_{ij}(t). Between events, each component decays exponentially. In the currently supported FRPP simulation interface, the decay rates are equal within each row.

An event’s type identifies a row of the driver. Its type_col_map entry selects the columns updated after the event. Entries can contain several columns and can overlap across event types. With numeric marked effects, a selected component receives αij+ηij(m−1). \alpha_{ij} + \eta_{ij}(m-1). Rows are event types; columns are kernels. They need not have the same count.

The state layer can represent signed components without clipping them. Simulation still requires a valid nonnegative driver and arrival calculation; a valid component shape alone does not establish simulation support.

The residual refresh rule

After every event in the combined process, the simulator draws a candidate residual for every dimension, inverts each integrated driver and selects the earliest event. All candidates are refreshed at the next global event.

This is not a model where a dimension keeps its own residual clock until that dimension fires. Carrying candidates across other dimensions’ events would change the model for a general residual law.

For an inter-event interval, let Ai=∫vi(t)dt. A_i = \int v_i(t)\,dt. If type jj fires, the log-likelihood contribution is log⁡vj+log⁡f(Aj)+∑i≠jlog⁡S(Ai), \log v_j + \log f(A_j) + \sum_{i\ne j}\log S(A_i), where ff and SS are the residual density and survival function. Unit-exponential residuals reduce this expression to a Hawkes contribution.

For other laws, the driver is not automatically the conditional intensity: the residual hazard also matters. The current observation API ends at the last recorded event; it does not add a separate terminal observation interval.

Computation backends

Operation Current implementation
Default simulation, bridge Uses the existing public emhawkes FRPP event loop
Optional simulation, state FRPP owns the event loop, using public event-wise kernel calculations
Default likelihood, bridge Uses emhawkes’s existing FRPP likelihood
Experimental likelihood, state Uses public kernel replay, then assembles FRPP density and survival contributions
Default estimation, fit_backend = "bridge" ffit() supplies an FRPP objective to public emhawkes fitting
Optional independent estimation FRPP prepares observations, registers parameters through the public plan, runs maxLik or stats directly and reconstructs its model

The state backend requires numeric baseline and kernel parameters, equal decay rates within a row, and no impact or mark-density callbacks. Numeric eta, observed marks and kernel mappings are supported. It requires the public shared-kernel API available in GitHub development emhawkes 1.0.1.9000 and reports an explicit error when that API is absent. The shared-kernel guide defines its input and output contract.

Replay supplies kernel-only interval integrals, pre-event sums and a final component state. FRPP adds the baseline contribution. Full component histories are requested only for infer = TRUE; interval integrals and sums still require storage proportional to observations times event types.

The default bridge remains available for callback models. The existing emhawkes.engine option retains its Hawkes likelihood meaning; it does not select a native FRPP likelihood.

Initialization and inference boundaries

FRPP automatic initialization uses zero components and recommends an explicit state. A Hawkes unconditional mean is not assumed for arbitrary residual laws.

The shared state calculation does not establish stationarity, identification or confidence-interval coverage. FRPP fitting uses its own likelihood and optimizer curvature; Hawkes-specific Hessian stabilization is not applied.

The old frpp_spec() constructor and serialized class remain compatible. as_fspec() converts an older FRPP hspec or either saved S3 specification class to S4. Public operations also accept those S3 specifications. Callback functions keep their environments and default bindings during conversion.

Migration from emhawkes

FRPP-specific functionality is planned to move to frpp. The FRPP examples use the new interface; the legacy vignette preserves the full original emhawkes examples, including fitting and reconstruction.

Simple custom-residual models remain available in emhawkes during the transition. No existing residual-law function or slot is removed by this documentation move. Hawkes goodness-of-fit residual diagnostics remain in emhawkes.

Next development steps

The numeric independent FRPP simulator is available as an optional backend. Callback simulation and independent estimation reconstruction remain future work. The current public replay API is a first shared calculation boundary, not a complete separation of the two packages’ engines.

Independent numeric simulation

path <- fsim(model, size = 1000, seed = 73, lambda_component0 = 0,
             backend = "state")

This requires the event-wise APIs in current GitHub development emhawkes. FRPP draws one residual vector for all dimensions, inverts its integrated drivers with a prepared exp_kernel_plan() when available, chooses the first minimum by row, and calls its step() function to decay and update mapped columns. It records the original path fields, counts and component histories. No hsim call or growing-prefix replay occurs in this backend. The plan validates fixed kernel parameters and baseline once; changing components and residual targets remain checked. It stores no current state. Installations with the earlier event-wise API use its checked exp_kernel_wait() and exp_kernel_step() calls instead. The shared calculation layer contains no RNG.

The first scope is plain numeric baseline and kernel parameters, including numeric eta, zero baselines and admissible signed components. No baseline, impact, mark-generator or mark-density event callbacks run in this backend. Marks are one. Residual generators are retained with their existing parameter binding and run once per attempted global event. Current-state validity is checked before each new draw, and an error never restarts the bridge.

bridge remains the default because the reference independent loop is slower for large paths. backend = "auto" is an explicit opt-in selector: it uses state when the model and installed APIs support it, otherwise bridge. Forced state reports unsupported models before drawing. Simulation selection is independent of the likelihood backend and emhawkes.engine.

See the repository’s simulation validation report for exact-result, RNG, timing and allocation checks. Reported allocations are cumulative Rprofmem records, not peak resident memory.

Parameter registration and fitted-model reconstruction

For numeric kernels without event callbacks and raw residual laws, ffit() registers kernel matrices and the residual parameter vector through the public emhawkes parameter_plan() contract. Numeric matrix coordinates retain their existing reduced/full sharing rules; named residual coordinates retain their names. Fixed residual laws stay outside the fitted coordinate set.

Optimization still uses public hfit() with the FRPP objective. The same parameter map rules, fixed selectors, constraints and optimizer controls apply. After optimization, frpp restores numeric components and assembles its own kernel/residual model through the public plan. Callback/bound-law models and older emhawkes versions retain the existing fitted_hspec reconstruction.

The raw optimizer result and saved ffit representation remain available. This step separates registration/restoration; optimizer adapters and legacy objective preparation remain shared. It makes no new confidence-interval coverage or performance claim.

Independent numeric fitting

fit_backend selects who runs estimation; backend selects the likelihood. Both defaults remain "bridge". For example:

model <- frpp::fspec(methods::new("hspec", mu = 1, alpha = 0, beta = 1),
  frpp::residual_law(c(rate = 1), dresidual = stats::dexp))
fit <- frpp::ffit(model, c(0, .2, .3, .5), optimizer = "stats",
  fixed = c(FALSE, TRUE, TRUE), lambda_component0 = 0,
  fit_backend = "independent")
stats::coef(fit)
##    mu1 alpha1  beta1 
##      3      0      1
fit$fitting
## $requested
## [1] "independent"
## 
## $used
## [1] "independent"
## 
## $fallback_reason
## NULL

This path supports plain numeric mu/alpha/beta/eta, kernel mappings and raw residual laws. It owns observation/count validation, explicit initial states, optimizer calls and result assembly. The public parameter plan retains matrix sharing, coordinate order and named residual sharing. Fixed/free selectors, linear constraints, box bounds, optional derivatives and validator rejection follow the existing provider rules. It uses no emhawkes internal functions and does not call hfit. The selected likelihood may still use the public bridge.

Callback kernels, event callbacks, legacy bound residual laws and dependencies without the parameter API retain bridge fitting. An explicit independent request reports unsupported cases; fit_backend = "auto" records its selected route and fallback reason before optimization. A failed optimization is never retried on another path. New results retain the existing ffit accessors. The raw independent stats provider result has its own frpp_stats_fit class; maxLik retains its class. The saved result’s fitting field reports the route, while numerical diagnostics retain their existing meaning. Unavailable Wald covariance remains unavailable.