-
Notifications
You must be signed in to change notification settings - Fork 2
Inhomogeneous point process #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Introduces InhomogeneousPoissonProcess and related intensity function types (Polynomial, Exponential, Sinusoidal, PiecewiseConstant, LinearCovariate). Adds fitting methods, analytical/numerical integration and bounds, and comprehensive tests. Updates exports and test runner to include new functionality.
Adds link function support to PolynomialIntensity, enforcing positivity via log link. ExponentialIntensity and SinusoidalIntensity constructors now validate parameters to ensure positive intensity. Updates tests to cover new link functionality and positivity enforcement, and improves display methods.
Introduces maximum likelihood estimation (MLE) with automatic differentiation for fitting inhomogeneous Poisson processes with parametric intensities (polynomial, exponential, sinusoidal). Adds generic MLE infrastructure, updates fitting methods to use Optim.jl, and extends tests to cover MLE-based fitting for supported intensity functions. Also improves type compatibility for intensity constructors to support automatic differentiation.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
JoseKling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the structure. Just to see if I get it.
If I want to define a point process with an arbitrary intensity function f(t), I just need to define, for example,
ipp = InhomogeneousPointProcess(f, Uniform())and if I want to use the fit method, I just need to define the methods param_to_intensity and intensity_to_param and call the fit method with some initial guess. Is that it?
That's basically it with a small caveat--as you pointed out, assuming you have an arbitrary ipp = InhomogeneousPointProcess(f, Uniform())and you need to provide |
|
So, I think this abstract type ParametricIntensity end
struct ExponentialIntensity{R<:Real} <: ParametricIntensity
a::R # Could also store parameters as Vector or StaticVector and drop the 'mutable'
b::R
end
StatsAPI.params(f::ExponentialIntensity) = (f.a, f.b)Then in the What do you think about this approach? |
Improves handling of empty history in fit_mle by defining a literal zero-intensity function. Removes redundant default bin fit method. Adds a convenience constructor for InhomogeneousPoissonProcess with no marks. Cleans up unused log_intensity function.
Yeah I agree something cleaner would be better. The one thing we will need to handle is how exactly we handle the parameters. The initial reason for my approach, was to handle how certain parameters get optimized. E.g., if a param needed to be postive we could optimize the log of the parameter. But we could do this maybe: """
Optimization parameters for ExponentialIntensity.
Optimize over θ = [log(a), b] so that a = exp(θ[1]) > 0.
"""
function StatsAPI.params(f::ExponentialIntensity)
return [log(f.a), f.b]
end
"""
Construct ExponentialIntensity from optimization parameters θ.
θ[1] = log(a), θ[2] = b.
"""
function StatsAPI.from_params(::Type{ExponentialIntensity{R}}, θ) where {R<:Real}
@assert length(θ) == 2
a = exp(θ[1])
b = θ[2]
return ExponentialIntensity(R(a), R(b))
end
"""
negative_loglikelihood_ipp(θ, ::Type{F}, times, tmin, tmax)
Negative log-likelihood for an inhomogeneous Poisson process with
parametric intensity `F` and event times `times` on [tmin, tmax].
"""
function negative_loglikelihood_ipp(θ, ::Type{F}, times, tmin, tmax) where {F<:ParametricIntensity}
# Build intensity from optimization params
f = StatsAPI.from_params(F, θ)
# ∫ λ(t) dt over [tmin, tmax]
Λ = integrated_intensity(f, tmin, tmax)
# Sum of log intensities at event times
log_sum = zero(eltype(θ))
for t in times
λ = f(t)
if λ <= 0
return typeof(log_sum)(Inf) # invalid params
end
log_sum += log(λ)
end
return Λ - log_sum
end |
|
Hmmm, now I understand the problem. The issue is when some prior transformation need to be done prior to the optimization. I guess your idea works. We just define a default function from_optimized_params(PI::Type{<:ParametricIntensity}, θ)
return PI(θ...)
end |
Introduces IntegrationConfig for numerical integration using Integrals.jl and updates all inhomogeneous Poisson process code to support configurable integration. Refactors parametric intensity fitting to use trait-based interfaces (to_params, from_params, initial_params) for PolynomialIntensity, ExponentialIntensity, and SinusoidalIntensity, eliminating manual closures. Updates constructors and fitting methods to accept integration configuration and parametric intensity traits, improving extensibility and numerical stability.
Eliminates the to_params function and its implementations from the ParametricIntensity trait and related intensity types. This simplifies the interface, leaving only from_params and initial_params for parameter handling.
|
Okay so I tried to integrate our discussions a bit. In the most recent commit we do the following:
Let me know which things aren't resolved/you'd like other changes on! |
Co-authored-by: José Kling <jose.kling@pm.me>
|
So, I was playing around a bit to see if I could find a way to simplify everything. I came up with what is the new branch The main idea was to simplify the methods related to h = History(rand(10), 0, 1, rand(10))
intensity = fit(PolynomialIntensity{Float64}, h, [1.0, 1.0, 1.0, 1.0]; link=:log)
ipp = fit(InhomogeneousPoissonProcess{PolynomialIntensity{Float64}, Uniform}, h, [30.0, 20.0]; link=:identity)or struct Constant{R} <: ParametricIntensity
a::R
end where {R<:Real}
(f::Constant, t) = f.a
# Might error because optimizer tests negative parameters, but works
fit(Constant, h, [4.0])
from_params(::Type{<:Constant}, params) = Constant(exp(params[1])
fit(Constant, h, [log(4.0)]) # No errorsThere is actually no need to restrict And you will see that I got rid of all the specific |
|
Okay, i looked at the branch and overall I agree the fit architecture has been improved. There are only a few remaining pinch points i think. 1.) 2.) I think if we want to allow things like Thoughts? |
|
I was not very thorough, so I apparently deleted/changed stuff I should not have.
The thing is that the derivatives of |
|
Okay i re-added the and not I myself actually prefer this as if a user has a reason to fit some other model it leaves these concerns up to them. |
Documents the InhomogeneousPoissonProcess and related intensity functions, as well as configuration options. This improves API documentation coverage for Poisson process variants.
JoseKling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if our goal is to reasonably avoid all errors, then i think the solution is to make sure all
Parametricmodels are fit as:
$$Poisson(\lambda t(t) = expf(\theta))$$
I think this is reasonable, but I also think this is not an obvious behavior an user would expect. If I created an intensity, I would not expect it to be transformed in any way without me choosing it.
An alternative would be to set up something similar to the IntegrationConfig(). We could have a OptimizationConfig() for the to choose the solver, the constrains, or even add gradients. Not sure how exactly this would look like.
Anyway, I am fine leaving it as is or with this transformation you proposed for now. What you did is already a lot of functionality added, and we can improve this in the future.
Updated all intensity_bound methods to accept an additional History argument for future extensibility. Also refactored InhomogeneousPoissonProcess fit methods to separate handling of breakpoints and n_bins, improving API flexibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds comprehensive support for inhomogeneous Poisson processes (IPPs) to the point process modeling library. The implementation introduces time-varying intensity functions with both parametric and custom forms, numerical integration infrastructure, and maximum likelihood estimation with automatic differentiation for model fitting.
Key changes include:
- Five new parametric intensity function types (Polynomial, Exponential, Sinusoidal, PiecewiseConstant, LinearCovariate) with analytical optimizations where possible
- A flexible
InhomogeneousPoissonProcesstype that supports arbitrary callable intensity functions - MLE-based fitting infrastructure using Optim.jl with automatic differentiation support via ForwardDiff
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
Project.toml |
Adds Integrals.jl and Optim.jl dependencies for numerical integration and optimization |
test/Project.toml |
Adds Optim.jl to test dependencies |
src/PointProcesses.jl |
Exports new IPP types, intensity functions, and configuration; includes new IPP modules |
src/poisson/inhomogeneous/integration_config.jl |
Defines IntegrationConfig for configurable numerical integration |
src/poisson/inhomogeneous/parametric_intensity.jl |
Trait interface for parametric intensity functions supporting MLE fitting |
src/poisson/inhomogeneous/intensity_functions.jl |
Implements five parametric intensity types and their parameter transformations |
src/poisson/inhomogeneous/intensity_methods.jl |
Provides analytical and numerical methods for integration and bounds computation |
src/poisson/inhomogeneous/inhomogeneous_poisson_process.jl |
Main IPP type implementing AbstractPointProcess interface with time-varying intensity |
src/poisson/inhomogeneous/fit.jl |
MLE fitting methods for parametric intensities and specialized fitting for piecewise constant |
test/runtests.jl |
Adds test suite inclusion for inhomogeneous Poisson processes |
test/inhomogeneous_poisson_process.jl |
Comprehensive tests covering all intensity types, fitting, simulation, and interface methods |
docs/src/api.md |
Documents new IPP types, intensity functions, and configuration in API reference |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Standardized argument names for integrated_intensity methods to use lb/ub instead of a/b/t_start/t_end, improving clarity and consistency. Updated function signatures in inhomogeneous_poisson_process.jl to require explicit History arguments. Fixed typos and improved documentation in parametric_intensity.jl. No changes to core logic, but improves maintainability and API clarity.
This commit adds comprehensive test coverage for fitting inhomogeneous Poisson processes with multiple histories, including piecewise constant, exponential, and polynomial intensities. It also introduces tests for intensity type constructors, show methods, integrated intensity edge cases, and intensity bounds for various intensity functions. These additions improve robustness and ensure correct behavior across a range of scenarios.
|
Okay all tests now pass. Let me know if there is anything else you would like |
JoseKling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only problem I see are the intensity_bound methods. Left comments on each of the methods.
The rest looks fine.
…ookahead Refactored intensity_bound methods for various intensity types to use keyword arguments for lookahead and n_samples, and added history-aware overloads that scale lookahead with the duration of the process history. Updated tests to check for the new lookahead logic and expected bounds.
…ne/PointProcesses.jl into inhomogeneous_point_process
|
Should be all done @JoseKling let me know if anything else pops up |
JoseKling
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good. I just suggested not having the min_lookahead keyword. I just don't see why we should have it. If the length of the process is of this order, I don't see the problem of letting lookahead be smaller than 1e-3, especially since the user cannot control this in the simulate_ogata method.
I am approving the PR, just either accept the suggestions or, if I am overlooking something, ignore them.
Start of a PR for adding IPP models. Should resolve #33. I think this is a reasonably good start but before continuing, I think I'd like an extra set of eyes to make sure everyone is happy with the current structure. We can almsot certainly do better on the numerical integration so am open to suggestions. I also feel we may want to expand the AutoDiff support (maybe via DifferentationInterface).
This pull request introduces support for inhomogeneous Poisson processes (IPPs) to the point process modeling library. It adds new intensity function types, a flexible process type for IPPs, and comprehensive fitting methods using maximum likelihood estimation (MLE) with automatic differentiation. These changes enable modeling, simulation, and fitting of temporal Poisson processes with non-constant, parametric, or piecewise intensity functions.
Inhomogeneous Poisson Process Support
InhomogeneousPoissonProcesstype, representing Poisson processes with time-varying intensity and mark distributions, along with interface methods and documentation.InhomogeneousPoissonProcessand several new intensity function types (PolynomialIntensity,ExponentialIntensity,SinusoidalIntensity,PiecewiseConstantIntensity,LinearCovariateIntensity) to the main package API.Intensity Function Infrastructure
Fitting and Estimation
Integration and Simulation