Model and computation
Source:vignettes/articles/model-and-computation.Rmd
model-and-computation.RmdComposition and dependency direction
An S4 fspec contains two model components:
-
kernel: an emhawkeshspec, without a residual law. -
residual: aresidual_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 , the numeric driver is 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
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 If type fires, the log-likelihood contribution is where and 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.