Closed ChrisRackauckas closed 1 year ago
Merging #198 (8b8f195) into master (24609db) will decrease coverage by
61.11%
. The diff coverage is100.00%
.
@@ Coverage Diff @@
## master #198 +/- ##
==========================================
- Coverage 68.51% 7.40% -61.11%
==========================================
Files 11 11
Lines 1515 1512 -3
==========================================
- Hits 1038 112 -926
- Misses 477 1400 +923
Impacted Files | Coverage Δ | |
---|---|---|
src/func.jl | 44.75% <100.00%> (-35.92%) |
:arrow_down: |
... and 9 files with indirect coverage changes
:mega: We’re building smart automated test selection to slash your CI/CD build times. Learn more
input/output can be (N, K) matrices, where the operator is being applied coulmn-wise
This is the correct implementation of brusselator https://github.com/SciML/OrdinaryDiffEq.jl/blob/master/test/interface/preconditioners.jl#L8-L52
In OrdinaryDiffEq, if u0
is a matrix, each column is a separate ODE that is being evolved. For that reason, the brusselator u0
should be vec
'd before being passed to OrdinaryDiffEq
https://github.com/SciML/OrdinaryDiffEq.jl/blob/master/test/interface/preconditioners.jl#L51
Inside the ODEFunction
, the you can reshape u, du
to be matrices
https://github.com/SciML/OrdinaryDiffEq.jl/blob/master/test/interface/preconditioners.jl#L17-L18
with that in mind, a SciMLOperator
with size (M, N)
has been designed to act on AbstractVecOrMat
s with size(u, 1) = N
. That way, we can take advantage of BLAS in fitting K
batches in an (N, K)
matrix. That's why size is set to (size(output, 1), size(input, 1))
, because the second dimension refers to the batch
.
Tests in the above Brusselator example are passing for me locally with master branch of ODE, SciMLOperators with changes mentioned in the above comment
This is the correct implementation of brusselator https://github.com/SciML/OrdinaryDiffEq.jl/blob/master/test/interface/preconditioners.jl#L8-L52
No it's not. It should allow for a higher dimensional tensor. Did you change that test? I don't remember it being vec
d and it shouldn't be. That test is supposed to be finding this bug.
In OrdinaryDiffEq, if u0 is a matrix, each column is a separate ODE that is being evolved.
No it's not. That can be true by the way that the ODE is defined, but it can also be a matrix ODE. You only have separate ODEs if the Jacobian has a block diagonal sparsity pattern, which is not guaranteed.
Inside the ODEFunction, the you can reshape u, du to be matrices
You shouldn't need to, otherwise lots of code would be broken.
with that in mind, a SciMLOperator with size (M, N) has been designed to act on AbstractVecOrMats with size(u, 1) = N. That way, we can take advantage of BLAS in fitting K batches in an (N, K) matrix. That's why size is set to (size(output, 1), size(input, 1)), because the second dimension refers to the batch.
If that's the case then we'd need to be diligent about vec and reshaping inside of the OrdinaryDiffEq code, otherwise many PDE tutorials will break. A lot of PDE codes will have issues right now because of this, so we need to fast track the bug fix.
Ok, thanks explaining. If ODE.jl design allows for matrix ODEs and AbstractArray{N}
ODEs, we need a way to differentiate the batch dimension. Batch dimension needs to be determined only for FunctionOperator
, as it is equal to 2
for all others, eg. MatrixOperator
applies the same matrix to u[:, i]
for all i
, but the operation is fast thanks to BLAS.
I'll add a keyword argument to FunctionOperator
for batch_dim
and internally do size computation involving dims 1:batch_dim-1
.
Being able to apply SciMLOperators
on (N, K)
matrices, where K
is batch size, is pretty fundamental to scimlops. Not just because BLAS mul!, *
are much faster than broadcasting, but also because the lazy tensor product operator internally reshapes AbstractVector
s to AbstractMatrix
for fast evaluation.
@ChrisRackauckas LMK if that makes sense before I follow up with a PR
I'll add a keyword argument to FunctionOperator for batch_dim and internally do size computation involving dims 1:batch_dim-1.
That makes sense. Default to not batching but allow for it.
If a function operator takes in an MxNxO tensor and spits out an MxNxO tensor, then it's an MNO x MNO operator, not an MxM operator. It can be interpreted in the
vec(input)
->vec(output)
sense and thuslength
is the right measure to use. This fixes downstream use cases like: