You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Systematization of returned types in .*intensity methods #72
Currently the return types of the methods related to intensity do not follow any explicit logic.
As an example, If I have a process pp = PoissonProcess(Float32(1), Uniform()), then ground_intensity(pp) = 10f0, but intensity(pp, 0.5) = 1.0. Not too bad, but makes it hard to reason about types, especially considering other methods may include marks or other user input.
What are sensible return types for these methods? I think the process should be the only argument to determine the type of the intensity, so using pp as in the example above, the methods intensity, ground_intensity and integrated_ground_intensity should all return a Float32.
The only caveat is that, in general, the intensity is a Float, even if the process parameters are Ints. So, if pp = PoissonProcess(T(1), Uniform()), where T<:Real, then the return type of the three methods above should be float(T).
I agree with this. I think we want to promote to the type of the parameters. Though yes, I can see how an issue might arise if a user provides an Int as a parameter, in which case it’s a bit nonsensical for the intensities themselves to be integer-typed. That said, this also raises the question of why a user would want an Int as a parameter type in the first place.
So, to your point, we probably need to define how this edge case should be handled. Admittedly, I’m not completely sure what the best choice is. In practice, the most reasonable parameter types are things like Float32, Float64, BigFloat, etc. Given that, the possible options seem to be:
Make the intensity type match the parameter type, except in the case where the parameter type is an Int, in which case we promote to float(T).
Always make the intensity type match the parameter type and simply accept that using an Int parameter is a strange (but technically allowed) choice.
Restrict parameter types to <: AbstractFloat.
My instinct is that (3) is not a great solution, since it unnecessarily constrains users and makes assumptions about what they might want to do, and would also mess up AD. Between (1) and (2), I lean toward (1): it gives sensible behavior in the common case, avoids obviously nonsensical return types, and still preserves the idea that the process parameters determine the numeric type of the intensity.
(2) has the problem that if the parameters are Integers, then groind_intensity(pp, t) would produce a InexactError. So (1) seems like the best approach.
Or we could use the idea of (3), but without actually restricting the types, just converting them before instantiation. At least for the cases we implemented, it does not make much sense for the types of the parameter to be Int anyway.
I did not yet check the other methods, like simulate or fit. I believe fit is fine, but I think simulate has issues because of Distributions.jl.
@gdalle I bet would have good insight here. He is the typing wizard. But yes, my gut says that something like (1) would be good/give the least friction between user desires and things that are reasonable in this context
In functions like intensity(process, history), which of the arguments should determine the return type?
If the process has integer parameters, should we modify the return type ourselves?
For both, I suggest you let Julia do its job and promote arguments to the more generic type.
If the process is in Float32 and the history in Float64, then you'll get Float64.
If the process has Int components and Float32 components, you'll get Float32.
You'll save yourselves many headaches while preserving full type generality. Anything else will dramatically reduce the possibilities of your package. For instance, if you decide that only the process determines the type of the output, then you won't be able to differentiate a log-likelihood with respect to history dates, only with respect to process parameters.
In functions like intensity(process, history), which of the arguments should determine the return type?
I would argue that only the process should determine the return type, but if this is detrimental to the package, then it is not worth it.
If the process has Int components and Float32 components, you'll get Float32.
The parameters of a process are already promoted to a single type, so this is not a problem. The issue is only if all the parameters are Int. HawkesProcess(1.0, 2, 3) returns a HawkesProcess{Float64}, but HawkesProcess(1, 2, 3)returns aHawkesProcess{Int}`.
Then we just leave as it is and let the return types be determined by whatever calculations are done inside the methods, letting Julia promote the types when needed.
I really wouldn't give too much thought to the case where the user inputs an integer for quantities like a Hawkes intensity or a history start date. In most cases is semantically wrong to use that type, so they'll find out soon enough either way
Activity
rsenne commentedon Dec 20, 2025
I agree with this. I think we want to promote to the type of the parameters. Though yes, I can see how an issue might arise if a user provides an
Intas a parameter, in which case it’s a bit nonsensical for the intensities themselves to be integer-typed. That said, this also raises the question of why a user would want anIntas a parameter type in the first place.So, to your point, we probably need to define how this edge case should be handled. Admittedly, I’m not completely sure what the best choice is. In practice, the most reasonable parameter types are things like
Float32,Float64,BigFloat, etc. Given that, the possible options seem to be:Make the intensity type match the parameter type, except in the case where the parameter type is an
Int, in which case we promote tofloat(T).Always make the intensity type match the parameter type and simply accept that using an Int parameter is a strange (but technically allowed) choice.
Restrict parameter types to
<: AbstractFloat.My instinct is that (3) is not a great solution, since it unnecessarily constrains users and makes assumptions about what they might want to do, and would also mess up AD. Between (1) and (2), I lean toward (1): it gives sensible behavior in the common case, avoids obviously nonsensical return types, and still preserves the idea that the process parameters determine the numeric type of the intensity.
JoseKling commentedon Dec 21, 2025
I agree that (3) is not ideal.
(2) has the problem that if the parameters are Integers, then
groind_intensity(pp, t)would produce aInexactError. So (1) seems like the best approach.Or we could use the idea of (3), but without actually restricting the types, just converting them before instantiation. At least for the cases we implemented, it does not make much sense for the types of the parameter to be
Intanyway.I did not yet check the other methods, like
simulateorfit. I believefitis fine, but I thinksimulatehas issues because ofDistributions.jl.rsenne commentedon Dec 21, 2025
@gdalle I bet would have good insight here. He is the typing wizard. But yes, my gut says that something like (1) would be good/give the least friction between user desires and things that are reasonable in this context
gdalle commentedon Jan 6, 2026
There are two questions here:
intensity(process, history), which of the arguments should determine the return type?For both, I suggest you let Julia do its job and promote arguments to the more generic type.
Float32and the history inFloat64, then you'll getFloat64.Intcomponents andFloat32components, you'll getFloat32.You'll save yourselves many headaches while preserving full type generality. Anything else will dramatically reduce the possibilities of your package. For instance, if you decide that only the process determines the type of the output, then you won't be able to differentiate a log-likelihood with respect to history dates, only with respect to process parameters.
JoseKling commentedon Jan 6, 2026
I would argue that only the process should determine the return type, but if this is detrimental to the package, then it is not worth it.
The parameters of a process are already promoted to a single type, so this is not a problem. The issue is only if all the parameters are
Int.HawkesProcess(1.0, 2, 3)returns aHawkesProcess{Float64}, butHawkesProcess(1, 2, 3)returns aHawkesProcess{Int}`.Then we just leave as it is and let the return types be determined by whatever calculations are done inside the methods, letting Julia promote the types when needed.
gdalle commentedon Jan 9, 2026
I really wouldn't give too much thought to the case where the user inputs an integer for quantities like a Hawkes intensity or a history start date. In most cases is semantically wrong to use that type, so they'll find out soon enough either way