-
-
Notifications
You must be signed in to change notification settings - Fork 101
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
add integrand interface #497
Conversation
There's no need for it to be a completely separate system from what already exists. Some uniformity would be good here. Make it |
I hadn't used the On the note of uniformity across the ecosystem, is there a |
@ChrisRackauckas I added |
src/scimlfunctions.jl
Outdated
jac = __has_jac(f) ? f.jac : nothing, | ||
paramjac = __has_paramjac(f) ? f.paramjac : nothing, | ||
analytic = __has_analytic(f) ? f.analytic : nothing, | ||
syms = __has_syms(f) ? f.syms : nothing, | ||
jac_prototype = __has_jac_prototype(f) ? f.jac_prototype : nothing, | ||
sparsity = __has_sparsity(f) ? f.sparsity : nothing, | ||
colorvec = __has_colorvec(f) ? f.colorvec : nothing, | ||
observed = __has_observed(f) ? f.observed : nothing) | ||
``` | ||
|
||
Note that only `f` is required, and in the case of inplace integrands a mutable container | ||
`I` to store the result of the integral. | ||
|
||
The remaining functions are optional and mainly used for accelerating the usage of `f`: | ||
- `jac`: unused | ||
- `paramjac`: unused | ||
- `analytic`: unused | ||
- `syms`: unused | ||
- `jac_prototype`: unused | ||
- `sparsity`: unused | ||
- `colorvec`: unused | ||
- `observed`: unused |
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.
Those arguments can be removed.
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.
Yes, thanks
src/scimlfunctions.jl
Outdated
If `I` is present, `f` is interpreted as in-place, and otherwise `f` is assumed to be | ||
out-of-place. |
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.
Why is this needed? This should just be auto-determined.
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.
Also, when passed it's iip
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
or integral_prototype
is presumably an array that could have any element type and dimension specific to an inplace f
, so the caller is basically declaring the output of f
by passing the container. The C libraries assume everything is Vector{Float64}
, with length nout
passed to IntegralProblem
, so that could be a fallback, but I would prefer it as a type assertion in the C wrappers since the user is already taking their time to write something efficient and in-place.
I took a pass through it:
Let me know if there's anything here you'd disagree with. |
Codecov Report
@@ Coverage Diff @@
## master #497 +/- ##
===========================================
+ Coverage 0.00% 39.85% +39.85%
===========================================
Files 50 50
Lines 3635 3756 +121
===========================================
+ Hits 0 1497 +1497
+ Misses 3635 2259 -1376
... and 39 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
Hi Chris, this looks greatly improved! Thank you for looking into it I made a few tweaks and here these are my thoughts:
Let me know if this looks good to you, especially the proposal in 2. |
It's more if the user calls
That might be overthinking it. I think we can just match the C libraries unless we gain some extra feature or performance. |
I see, yes we should avoid race conditions when convenient and that goes with the "prototype" naming convention. I reverted the name back to
Sounds good. For now the documentation recommends the I'm happy with how this looks and would be interested in following up with some PRs on the Integrals.jl side to use these containers to add features. Do most SciML packages wrap the user's input into a |
I missed that part. The problem type always has a default dispatch to wrap in the simplest function type. The IntegralProblem should default to wrapping the |
Ok, I added the wrapper, but this would be breaking behavior unless we make If we are OK with breaking changes, I would also introduce the following:
|
No need for those.
Yes make it callable and just forward the args.
Yes let's go for it.
That sounds good. |
Alright, I committed the breaking changes. Now I should open a pr in Integrals.jl to migrate to this interface |
lb, ub, nout, p, | ||
batch, kwargs) |
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.
We can have a deprecation path where if nout
and batch
are supplied we throw a warning and just define the prototypes as Array
s appropriately sized
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.
Yes, thanks for bringing this up. While implementing it I realized that the BatchIntegralFunction
can let the user pass a two-argument out-of-place form and a 3-argument in-place form, which was allowed before and would match IntegralFunction
. Then I'll remove the output_prototype
field, since we can still query the output type of an out-of-place BatchIntegralFunction
by calling the function on an empty vector of input points. The details of allocating an output_prototype
may differ across libraries, but we have a mechanism to get the output type for both iip and oop forms, so this buffer can be correctly allocated by the solver, and solves our previous issue.
@ChrisRackauckas I added the deprecation methods and added the 2-argument out-of-place form for |
The simple However, I think it's safe to merge this into the v2.0. The reason is because Integrals.jl is the only consumer (that I know of) of the SciMLBase.jl stuff, and so labeling it as a major means that we can do the breaking release and it won't actually be put into action until a PR bumps the lower bound on Integrals.jl. That will give us a little leeway for testing it out in implementation without being breaking to anyone's workflows until it's clear that it works. Because of that, I'm going to merge. Let's do it, and we can fix what comes up during the bump of Integrals.jl |
I think there will be a problem with how the batch keyword is handled. Like nout, it should be given a default value, zero, if it is unset. I can't fix it for another hour, but with that fix I think we should merge |
@ChrisRackauckas The obvious bugs are now fixed in the |
Hi,
As discussed in SciML/Integrals.jl#169 and SciML/Integrals.jl#175, Integrals.jl needs integrand wrapper types to support features such as inplace evaluation, batched evaluation, and inplace and batched evaluation at the same time. This pr adds 3 structs which support these 3 distinct interfaces and are intended as an eventual replacement for the
batch
andnout
keywords toIntegralProblem
. (I don't think that those need to be removed just yet, since we can dispatch on these wrapper types to opt into new behaviors.)InplaceIntegrand(f!, result::AbstractArray)
: the caller provides an inplace functionf!(y, x, p)
and an arrayresult
which will store the solution (i.e. it has the same shape as the integrand output arrayy
, but could have a different type due to units of the limits).BatchIntegrand(f!, y::AbstractVector, x::AbstractVector; max_batch)
: the caller provides an inplace functionf!(y, x, p)
of the formy .= f.(x, Ref(p))
and pre-allocated buffers that parallelize the calculation of the integrand over multiple quadrature nodes. For multi-dimensional integrands, the elements ofx
can be StaticArraysInplaceBatchIntegrand(f!, result::AbstractArray, y::AbstractArray, x::AbstractVector; max_batch)
: the caller provides an inplace functionf!(y, x, p)
that evaluates an array-valued inplace integrand at multiple points simultaneously. The solution is written toresult
. The buffer y is of size(size(result)..., size(x)...)
and should be resize-able in its outer dimension (i.e. anElasticArray
)I would appreciate any feedback on this pr. In particular, for multidimensional batched integrands it is nice to allow
x
to be a vector ofSVector
s instead of aMatrix
, which is the current style. For the C libraries that only useMatrix
we can usereinterpret(reshape, ...)
to bring it intoSVector
form.