From 79d65e7afef7f3f3ec149e4cdb35a75bcc14e912 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Mon, 18 Nov 2024 23:42:42 +0000 Subject: [PATCH] build based on 98bb9e6 --- dev/.documenter-siteinfo.json | 2 +- dev/assets/Manifest.toml | 14 +- dev/assets/documenter.js | 302 ++++++++++++++++--------------- dev/index.html | 10 +- dev/interface/index.html | 34 ++-- dev/premade_operators/index.html | 20 +- dev/sciml/index.html | 2 +- dev/tutorials/fftw/index.html | 2 +- 8 files changed, 203 insertions(+), 183 deletions(-) diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index 58930e3..3e66cb9 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-02T09:57:37","documenter_version":"1.7.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.1","generation_timestamp":"2024-11-18T23:42:35","documenter_version":"1.8.0"}} \ No newline at end of file diff --git a/dev/assets/Manifest.toml b/dev/assets/Manifest.toml index 48d793b..ca2691d 100644 --- a/dev/assets/Manifest.toml +++ b/dev/assets/Manifest.toml @@ -71,15 +71,16 @@ version = "1.1.2" [[deps.ArrayInterface]] deps = ["Adapt", "LinearAlgebra"] -git-tree-sha1 = "3640d077b6dafd64ceb8fd5c1ec76f7ca53bcf76" +git-tree-sha1 = "d5140b60b87473df18cf4fe66382b7c3596df047" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.16.0" +version = "7.17.1" [deps.ArrayInterface.extensions] ArrayInterfaceBandedMatricesExt = "BandedMatrices" ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" ArrayInterfaceCUDAExt = "CUDA" ArrayInterfaceCUDSSExt = "CUDSS" + ArrayInterfaceChainRulesCoreExt = "ChainRulesCore" ArrayInterfaceChainRulesExt = "ChainRules" ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" ArrayInterfaceReverseDiffExt = "ReverseDiff" @@ -93,6 +94,7 @@ version = "7.16.0" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" @@ -155,9 +157,9 @@ version = "0.9.3" [[deps.Documenter]] deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "CodecZlib", "Dates", "DocStringExtensions", "Downloads", "Git", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "TOML", "Test", "Unicode"] -git-tree-sha1 = "5a1ee886566f2fa9318df1273d8b778b9d42712d" +git-tree-sha1 = "d0ea2c044963ed6f37703cead7e29f70cba13d7e" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "1.7.0" +version = "1.8.0" [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] @@ -166,9 +168,9 @@ version = "1.6.0" [[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1c6317308b9dc757616f0b5cb379db10494443a7" +git-tree-sha1 = "cc5231d52eb1771251fbd37171dbc408bcc8a1b6" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.6.2+0" +version = "2.6.4+0" [[deps.FFTW]] deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] diff --git a/dev/assets/documenter.js b/dev/assets/documenter.js index 82252a1..7d68cd8 100644 --- a/dev/assets/documenter.js +++ b/dev/assets/documenter.js @@ -612,176 +612,194 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) { }; } -// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! -const filters = [ - ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), -]; -const worker_str = - "(" + - worker_function.toString() + - ")(" + - JSON.stringify(documenterSearchIndex["docs"]) + - "," + - JSON.stringify(documenterBaseURL) + - "," + - JSON.stringify(filters) + - ")"; -const worker_blob = new Blob([worker_str], { type: "text/javascript" }); -const worker = new Worker(URL.createObjectURL(worker_blob)); - /////// SEARCH MAIN /////// -// Whether the worker is currently handling a search. This is a boolean -// as the worker only ever handles 1 or 0 searches at a time. -var worker_is_running = false; - -// The last search text that was sent to the worker. This is used to determine -// if the worker should be launched again when it reports back results. -var last_search_text = ""; - -// The results of the last search. This, in combination with the state of the filters -// in the DOM, is used compute the results to display on calls to update_search. -var unfiltered_results = []; - -// Which filter is currently selected -var selected_filter = ""; - -$(document).on("input", ".documenter-search-input", function (event) { - if (!worker_is_running) { - launch_search(); - } -}); - -function launch_search() { - worker_is_running = true; - last_search_text = $(".documenter-search-input").val(); - worker.postMessage(last_search_text); -} - -worker.onmessage = function (e) { - if (last_search_text !== $(".documenter-search-input").val()) { - launch_search(); - } else { - worker_is_running = false; - } - - unfiltered_results = e.data; - update_search(); -}; +function runSearchMainCode() { + // `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! + const filters = [ + ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), + ]; + const worker_str = + "(" + + worker_function.toString() + + ")(" + + JSON.stringify(documenterSearchIndex["docs"]) + + "," + + JSON.stringify(documenterBaseURL) + + "," + + JSON.stringify(filters) + + ")"; + const worker_blob = new Blob([worker_str], { type: "text/javascript" }); + const worker = new Worker(URL.createObjectURL(worker_blob)); + + // Whether the worker is currently handling a search. This is a boolean + // as the worker only ever handles 1 or 0 searches at a time. + var worker_is_running = false; + + // The last search text that was sent to the worker. This is used to determine + // if the worker should be launched again when it reports back results. + var last_search_text = ""; + + // The results of the last search. This, in combination with the state of the filters + // in the DOM, is used compute the results to display on calls to update_search. + var unfiltered_results = []; + + // Which filter is currently selected + var selected_filter = ""; + + $(document).on("input", ".documenter-search-input", function (event) { + if (!worker_is_running) { + launch_search(); + } + }); -$(document).on("click", ".search-filter", function () { - if ($(this).hasClass("search-filter-selected")) { - selected_filter = ""; - } else { - selected_filter = $(this).text().toLowerCase(); + function launch_search() { + worker_is_running = true; + last_search_text = $(".documenter-search-input").val(); + worker.postMessage(last_search_text); } - // This updates search results and toggles classes for UI: - update_search(); -}); + worker.onmessage = function (e) { + if (last_search_text !== $(".documenter-search-input").val()) { + launch_search(); + } else { + worker_is_running = false; + } -/** - * Make/Update the search component - */ -function update_search() { - let querystring = $(".documenter-search-input").val(); + unfiltered_results = e.data; + update_search(); + }; - if (querystring.trim()) { - if (selected_filter == "") { - results = unfiltered_results; + $(document).on("click", ".search-filter", function () { + if ($(this).hasClass("search-filter-selected")) { + selected_filter = ""; } else { - results = unfiltered_results.filter((result) => { - return selected_filter == result.category.toLowerCase(); - }); + selected_filter = $(this).text().toLowerCase(); } - let search_result_container = ``; - let modal_filters = make_modal_body_filters(); - let search_divider = `
`; + // This updates search results and toggles classes for UI: + update_search(); + }); - if (results.length) { - let links = []; - let count = 0; - let search_results = ""; - - for (var i = 0, n = results.length; i < n && count < 200; ++i) { - let result = results[i]; - if (result.location && !links.includes(result.location)) { - search_results += result.div; - count++; - links.push(result.location); - } - } + /** + * Make/Update the search component + */ + function update_search() { + let querystring = $(".documenter-search-input").val(); - if (count == 1) { - count_str = "1 result"; - } else if (count == 200) { - count_str = "200+ results"; + if (querystring.trim()) { + if (selected_filter == "") { + results = unfiltered_results; } else { - count_str = count + " results"; + results = unfiltered_results.filter((result) => { + return selected_filter == result.category.toLowerCase(); + }); } - let result_count = `
${count_str}
`; - search_result_container = ` + let search_result_container = ``; + let modal_filters = make_modal_body_filters(); + let search_divider = `
`; + + if (results.length) { + let links = []; + let count = 0; + let search_results = ""; + + for (var i = 0, n = results.length; i < n && count < 200; ++i) { + let result = results[i]; + if (result.location && !links.includes(result.location)) { + search_results += result.div; + count++; + links.push(result.location); + } + } + + if (count == 1) { + count_str = "1 result"; + } else if (count == 200) { + count_str = "200+ results"; + } else { + count_str = count + " results"; + } + let result_count = `
${count_str}
`; + + search_result_container = ` +
+ ${modal_filters} + ${search_divider} + ${result_count} +
+ ${search_results} +
+
+ `; + } else { + search_result_container = `
${modal_filters} ${search_divider} - ${result_count} -
- ${search_results} -
-
+
0 result(s)
+ +
No result found!
`; - } else { - search_result_container = ` -
- ${modal_filters} - ${search_divider} -
0 result(s)
-
-
No result found!
- `; - } + } - if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { - $(".search-modal-card-body").removeClass("is-justify-content-center"); - } + if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").removeClass("is-justify-content-center"); + } - $(".search-modal-card-body").html(search_result_container); - } else { - if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { - $(".search-modal-card-body").addClass("is-justify-content-center"); + $(".search-modal-card-body").html(search_result_container); + } else { + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(` +
Type something to get started!
+ `); } + } - $(".search-modal-card-body").html(` -
Type something to get started!
- `); + /** + * Make the modal filter html + * + * @returns string + */ + function make_modal_body_filters() { + let str = filters + .map((val) => { + if (selected_filter == val.toLowerCase()) { + return `${val}`; + } else { + return `${val}`; + } + }) + .join(""); + + return ` +
+ Filters: + ${str} +
`; } } -/** - * Make the modal filter html - * - * @returns string - */ -function make_modal_body_filters() { - let str = filters - .map((val) => { - if (selected_filter == val.toLowerCase()) { - return `${val}`; - } else { - return `${val}`; - } - }) - .join(""); - - return ` -
- Filters: - ${str} -
`; +function waitUntilSearchIndexAvailable() { + // It is possible that the documenter.js script runs before the page + // has finished loading and documenterSearchIndex gets defined. + // So we need to wait until the search index actually loads before setting + // up all the search-related stuff. + if (typeof documenterSearchIndex !== "undefined") { + runSearchMainCode(); + } else { + console.warn("Search Index not available, waiting"); + setTimeout(waitUntilSearchIndexAvailable, 1000); + } } +// The actual entry point to the search code +waitUntilSearchIndexAvailable(); + }) //////////////////////////////////////////////////////////////////////////////// require(['jquery'], function($) { diff --git a/dev/index.html b/dev/index.html index b34db45..94f71cb 100644 --- a/dev/index.html +++ b/dev/index.html @@ -25,7 +25,7 @@ # allocation-free evaluation L2(v, u, p, t) # == mul!(v, L2, u) L4(v, u, p, t, α, β) # == mul!(v, L4, u, α, β)

The calling signature L(u, p, t), for out-of-place evaluations, is equivalent to L * u, and the in-place evaluation L(v, u, p, t, args...) is equivalent to LinearAlgebra.mul!(v, L, u, args...), where the arguments p, t are passed to L to update its state. More details are provided in the operator update section below. While overloads to Base.* and LinearAlgebra.mul! are available, where a SciMLOperator behaves like an AbstractMatrix, we recommend sticking with the L(u, p, t), L(v, u, p, t), L(v, u, p, t, α, β) calling signatures as the latter internally update the operator state.

The (u, p, t) calling signature is standardized over the SciML ecosystem and is flexible enough to support use cases such as time-evolution in ODEs, as well as sensitivity computation with respect to the parameter object p.

Features

Contributing

Reproducibility

The documentation of this SciML package was built using these direct dependencies,
Status `~/work/SciMLOperators.jl/SciMLOperators.jl/docs/Project.toml`
-  [e30172f5] Documenter v1.7.0
+  [e30172f5] Documenter v1.8.0
   [7a1cc6ca] FFTW v1.8.0
   [c0aeaf25] SciMLOperators v0.3.12 `~/work/SciMLOperators.jl/SciMLOperators.jl`
and using this machine and Julia version.
Julia Version 1.11.1
 Commit 8f5b7ca12ad (2024-10-16 10:53 UTC)
@@ -42,12 +42,12 @@
   [1520ce14] AbstractTrees v0.4.5
   [7d9f7c33] Accessors v0.1.38
   [79e6a3ab] Adapt v4.1.1
-  [4fba245c] ArrayInterface v7.16.0
+  [4fba245c] ArrayInterface v7.17.1
   [944b1d66] CodecZlib v0.7.6
   [a33af91c] CompositionsBase v0.1.2
   [187b0558] ConstructionBase v1.5.8
   [ffbed154] DocStringExtensions v0.9.3
-  [e30172f5] Documenter v1.7.0
+  [e30172f5] Documenter v1.8.0
   [7a1cc6ca] FFTW v1.8.0
   [d7ba0133] Git v1.3.1
   [b5f81e59] IOCapture v0.2.5
@@ -65,7 +65,7 @@
   [ae029012] Requires v1.3.0
   [c0aeaf25] SciMLOperators v0.3.12 `~/work/SciMLOperators.jl/SciMLOperators.jl`
   [3bb67fe8] TranscodingStreams v0.11.3
-  [2e619515] Expat_jll v2.6.2+0
+  [2e619515] Expat_jll v2.6.4+0
   [f5851436] FFTW_jll v3.3.10+1
   [f8c6e375] Git_jll v2.46.2+0
   [1d5cc7b8] IntelOpenMP_jll v2024.2.1+0
@@ -113,4 +113,4 @@
   [83775a58] Zlib_jll v1.2.13+1
   [8e850b90] libblastrampoline_jll v5.11.0+0
   [8e850ede] nghttp2_jll v1.59.0+0
-  [3f19e933] p7zip_jll v17.4.0+2

You can also download the manifest file and the project file.

+ [3f19e933] p7zip_jll v17.4.0+2

You can also download the manifest file and the project file.

diff --git a/dev/interface/index.html b/dev/interface/index.html index 47f9a48..1b719d8 100644 --- a/dev/interface/index.html +++ b/dev/interface/index.html @@ -73,7 +73,7 @@ t = 1.0 L = update_coefficients(L, u, p, t; scale = 2.0) -L * usource
SciMLOperators.update_coefficients!Function
update_coefficients!(L, u, p, t; kwargs...)
+L * u
source
SciMLOperators.update_coefficients!Function
update_coefficients!(L, u, p, t; kwargs...)
 

Update in-place the state of L based on u, input vector, p parameter object, t, and keyword arguments. Internally, update_coefficients! calls the user-provided mutating update_func! method for every component operator in L with the positional arguments (u, p, t) and keyword arguments corresponding to the symbols provided to the operator via kwarg accepted_kwargs.

Warning

The user-provided update_func[!] must not use u in its computation. Positional argument (u, p, t) to update_func[!] are passed down by update_coefficients[!](L, u, p, t), where u is the input-vector to the composite AbstractSciMLOperator. For that reason, the values of u, or even shape, may not correspond to the input expected by update_func[!]. If an operator's state depends on its input vector, then it is, by definition, a nonlinear operator. We recommend sticking such nonlinearities in FunctionOperator. This topic is further discussed in (this issue)[https://github.com/SciML/SciMLOperators.jl/issues/159].

Example

using SciMLOperator
 
 _A = rand(4, 4)
@@ -88,21 +88,21 @@
 t = 1.0
 
 update_coefficients!(L, u, p, t)
-L * u
source
SciMLOperators.cache_operatorFunction
cache_operator(L, u)
-

Allocate caches for L for in-place evaluation with u-like input vectors.

source
SciMLOperators.concretizeFunction
concretize(L) -> AbstractMatrix
-
-concretize(L) -> Number

Convert SciMLOperator to a concrete type via eager fusion. This method is a no-op for types that are already concrete.

source

Traits

SciMLOperators.isconstantFunction
isconstant(_)
-

Checks if an L's state is constant or needs to be updated by calling update_coefficients.

source
SciMLOperators.iscachedFunction
iscached(L)
-

Checks whether L has preallocated caches for inplace evaluations.

source

Check if SciMLOperator L has preallocated cache-arrays for in-place computation.

source
SciMLOperators.issquareFunction

Checks if size(L, 1) == size(L, 2).

source
SciMLOperators.islinearFunction
islinear(_)
-

Checks if L is a linear operator.

source
SciMLOperators.isconvertibleFunction
isconvertible(L) -> Bool

Checks if L can be cheaply converted to an AbstractMatrix via eager fusion.

source
SciMLOperators.has_adjointFunction
has_adjoint(L)
-

Check if adjoint(L) is lazily defined.

source
SciMLOperators.has_expmvFunction
has_expmv(L)
-

Check if expmv(L, u, t), equivalent to exp(t * A) * u, is defined for Number t, and AbstractArray u of appropriate size.

source
SciMLOperators.has_expmv!Function
has_expmv!(L)
-

Check if expmv!(v, L, u, t), equivalent to mul!(v, exp(t * A), u), is defined for Number t, and AbstractArrays u, v of appropriate sizes.

source
SciMLOperators.has_expFunction
has_exp(L)
-

Check if exp(L) is defined lazily defined.

source
SciMLOperators.has_mulFunction
has_mul(L)
-

Check if L * u is defined for AbstractArray u of appropriate size.

source
SciMLOperators.has_mul!Function
has_mul!(L)
-

Check if mul!(v, L, u) is defined for AbstractArrays u, v of appropriate sizes.

source
SciMLOperators.has_ldivFunction
has_ldiv(L)
-

Check if L \ u is defined for AbstractArray u of appropriate size.

source
SciMLOperators.has_ldiv!Function
has_ldiv!(L)
-

Check if ldiv!(v, L, u) is defined for AbstractArrays u, v of appropriate sizes.

source

Note About Affine Operators

Affine operators are operators that have the action Q*x = A*x + b. These operators have no matrix representation, since if there was, it would be a linear operator instead of an affine operator. You can only represent an affine operator as a linear operator in a dimension of one larger via the operation: [A b] * [u;1], so it would require something modified to the input as well. As such, affine operators are a distinct generalization of linear operators.

While it seems like it might doom the idea of using matrix-free affine operators, it turns out that affine operators can be used in all cases where matrix-free linear solvers are used due to an easy generalization of the standard convergence proofs. If Q is the affine operator $Q(x) = Ax + b$, then solving $Qx = c$ is equivalent to solving $Ax + b = c$ or $Ax = c-b$. If you now do this same “plug-and-chug” handling of the affine operator into the GMRES/CG/etc. convergence proofs, move the affine part to the rhs residual, and show it converges to solving $Ax = c-b$, and thus GMRES/CG/etc. solves $Q(x) = c$ for an affine operator properly.

That same trick can be used mostly anywhere you would've had a linear operator to extend the proof to affine operators, so then $exp(A*t)*v$ operations via Krylov methods work for A being affine as well, and all sorts of things. Thus, affine operators have no matrix representation, but they are still compatible with essentially any Krylov method, which would otherwise be compatible with matrix-free representations, hence their support in the SciMLOperators interface.

Note about keyword arguments to update_coefficients!

In rare cases, an operator may be used in a context where additional state is expected to be provided to update_coefficients! beyond u, p, and t. In this case, the operator may accept this additional state through arbitrary keyword arguments to update_coefficients!. When the caller provides these, they will be recursively propagated downwards through composed operators just like u, p, and t, and provided to the operator. For the premade SciMLOperators, one can specify the keyword arguments used by an operator with an accepted_kwargs argument (by default, none are passed).

In the below example, we create an operator that gleefully ignores u, p, and t and uses its own special scaling.

using SciMLOperators
+L * u
source
SciMLOperators.cache_operatorFunction
cache_operator(L, u)
+

Allocate caches for L for in-place evaluation with u-like input vectors.

source
SciMLOperators.concretizeFunction
concretize(L) -> AbstractMatrix
+
+concretize(L) -> Number

Convert SciMLOperator to a concrete type via eager fusion. This method is a no-op for types that are already concrete.

source

Traits

SciMLOperators.isconstantFunction
isconstant(_)
+

Checks if an L's state is constant or needs to be updated by calling update_coefficients.

source
SciMLOperators.iscachedFunction
iscached(L)
+

Checks whether L has preallocated caches for inplace evaluations.

source

Check if SciMLOperator L has preallocated cache-arrays for in-place computation.

source
SciMLOperators.issquareFunction

Checks if size(L, 1) == size(L, 2).

source
SciMLOperators.islinearFunction
islinear(_)
+

Checks if L is a linear operator.

source
SciMLOperators.isconvertibleFunction
isconvertible(L) -> Bool

Checks if L can be cheaply converted to an AbstractMatrix via eager fusion.

source
SciMLOperators.has_adjointFunction
has_adjoint(L)
+

Check if adjoint(L) is lazily defined.

source
SciMLOperators.has_expmvFunction
has_expmv(L)
+

Check if expmv(L, u, t), equivalent to exp(t * A) * u, is defined for Number t, and AbstractArray u of appropriate size.

source
SciMLOperators.has_expmv!Function
has_expmv!(L)
+

Check if expmv!(v, L, u, t), equivalent to mul!(v, exp(t * A), u), is defined for Number t, and AbstractArrays u, v of appropriate sizes.

source
SciMLOperators.has_expFunction
has_exp(L)
+

Check if exp(L) is defined lazily defined.

source
SciMLOperators.has_mulFunction
has_mul(L)
+

Check if L * u is defined for AbstractArray u of appropriate size.

source
SciMLOperators.has_mul!Function
has_mul!(L)
+

Check if mul!(v, L, u) is defined for AbstractArrays u, v of appropriate sizes.

source
SciMLOperators.has_ldivFunction
has_ldiv(L)
+

Check if L \ u is defined for AbstractArray u of appropriate size.

source
SciMLOperators.has_ldiv!Function
has_ldiv!(L)
+

Check if ldiv!(v, L, u) is defined for AbstractArrays u, v of appropriate sizes.

source

Note About Affine Operators

Affine operators are operators that have the action Q*x = A*x + b. These operators have no matrix representation, since if there was, it would be a linear operator instead of an affine operator. You can only represent an affine operator as a linear operator in a dimension of one larger via the operation: [A b] * [u;1], so it would require something modified to the input as well. As such, affine operators are a distinct generalization of linear operators.

While it seems like it might doom the idea of using matrix-free affine operators, it turns out that affine operators can be used in all cases where matrix-free linear solvers are used due to an easy generalization of the standard convergence proofs. If Q is the affine operator $Q(x) = Ax + b$, then solving $Qx = c$ is equivalent to solving $Ax + b = c$ or $Ax = c-b$. If you now do this same “plug-and-chug” handling of the affine operator into the GMRES/CG/etc. convergence proofs, move the affine part to the rhs residual, and show it converges to solving $Ax = c-b$, and thus GMRES/CG/etc. solves $Q(x) = c$ for an affine operator properly.

That same trick can be used mostly anywhere you would've had a linear operator to extend the proof to affine operators, so then $exp(A*t)*v$ operations via Krylov methods work for A being affine as well, and all sorts of things. Thus, affine operators have no matrix representation, but they are still compatible with essentially any Krylov method, which would otherwise be compatible with matrix-free representations, hence their support in the SciMLOperators interface.

Note about keyword arguments to update_coefficients!

In rare cases, an operator may be used in a context where additional state is expected to be provided to update_coefficients! beyond u, p, and t. In this case, the operator may accept this additional state through arbitrary keyword arguments to update_coefficients!. When the caller provides these, they will be recursively propagated downwards through composed operators just like u, p, and t, and provided to the operator. For the premade SciMLOperators, one can specify the keyword arguments used by an operator with an accepted_kwargs argument (by default, none are passed).

In the below example, we create an operator that gleefully ignores u, p, and t and uses its own special scaling.

using SciMLOperators
 
 γ = ScalarOperator(0.0;
     update_func = (a, u, p, t; my_special_scaling) -> my_special_scaling,
@@ -114,4 +114,4 @@
 
 # Use operator application form
 @show γ([2.0], nothing, nothing; my_special_scaling = 5.0)
γ * [2.0] = [14.0]
-γ([2.0], nothing, nothing; my_special_scaling = 5.0) = [10.0]
+γ([2.0], nothing, nothing; my_special_scaling = 5.0) = [10.0] diff --git a/dev/premade_operators/index.html b/dev/premade_operators/index.html index 1cde56e..d8aeda2 100644 --- a/dev/premade_operators/index.html +++ b/dev/premade_operators/index.html @@ -1,5 +1,5 @@ -Premade Operators · SciMLOperators.jl

Premade SciMLOperators

Direct Operator Definitions

Missing docstring.

Missing docstring for ScalarOperator.IdentityOperator. Check Documenter's build log for details.

SciMLOperators.ScalarOperatorType
ScalarOperator(val; update_func, accepted_kwargs)
+Premade Operators · SciMLOperators.jl

Premade SciMLOperators

Direct Operator Definitions

Missing docstring.

Missing docstring for ScalarOperator.IdentityOperator. Check Documenter's build log for details.

SciMLOperators.ScalarOperatorType
ScalarOperator(val; update_func, accepted_kwargs)
 

Represents a linear scaling operator that may be applied to a Number, or an AbstractArray subtype. Its state is updated by the user-provided update_func during operator evaluation (L([v,] u, p, t)), or by calls to update_coefficients[!]. Both recursively call the update function, update_func which is assumed to have the signature:

update_func(oldval::Number, u, p, t; <accepted kwargs>) -> newval

The set of keyword-arguments accepted by update_func must be provided to ScalarOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func if accepted_kwargs are not provided.

Warning

The user-provided update_func[!] must not use u in its computation. Positional argument (u, p, t) to update_func[!] are passed down by update_coefficients[!](L, u, p, t), where u is the input-vector to the composite AbstractSciMLOperator. For that reason, the values of u, or even shape, may not correspond to the input expected by update_func[!]. If an operator's state depends on its input vector, then it is, by definition, a nonlinear operator. We recommend sticking such nonlinearities in FunctionOperator. This topic is further discussed in (this issue)[https://github.com/SciML/SciMLOperators.jl/issues/159].

Interface

Lazy scalar algebra is defined for AbstractSciMLScalarOperators. The interface supports lazy addition, subtraction, multiplication and division.

Example

v = zero(4)
 u = rand(4)
 p = nothing
@@ -13,7 +13,7 @@
 β(u, p, t; scale = 1.0)
 
 # update L in-place and evaluate
-β(v, u, p, t; scale = 1.0)
source
SciMLOperators.MatrixOperatorType

Represents a linear operator given by an AbstractMatrix that may be applied to an AbstractVecOrMat. Its state is updated by the user-provided update_func during operator evaluation (L([v,], u, p, t)), or by calls to update_coefficients[!](L, u, p, t). Both recursively call the update_function, update_func which is assumed to have the signature

update_func(A::AbstractMatrix, u, p, t; <accepted kwargs>) -> newA

or

update_func!(A::AbstractMatrix, u, p, t; <accepted kwargs>) -> [modifies A]

The set of keyword-arguments accepted by update_func[!] must be provided to MatrixOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func[!] if accepted_kwargs are not provided.

Warning

The user-provided update_func[!] must not use u in its computation. Positional argument (u, p, t) to update_func[!] are passed down by update_coefficients[!](L, u, p, t), where u is the input-vector to the composite AbstractSciMLOperator. For that reason, the values of u, or even shape, may not correspond to the input expected by update_func[!]. If an operator's state depends on its input vector, then it is, by definition, a nonlinear operator. We recommend sticking such nonlinearities in FunctionOperator. This topic is further discussed in (this issue)[https://github.com/SciML/SciMLOperators.jl/issues/159].

Interface

Lazy matrix algebra is defined for AbstractSciMLOperators. The Interface supports lazy addition, subtraction, multiplication, inversion, adjoints, transposes.

Example

Out-of-place update and usage

u = rand(4)
+β(v, u, p, t; scale = 1.0)
source
SciMLOperators.MatrixOperatorType

Represents a linear operator given by an AbstractMatrix that may be applied to an AbstractVecOrMat. Its state is updated by the user-provided update_func during operator evaluation (L([v,], u, p, t)), or by calls to update_coefficients[!](L, u, p, t). Both recursively call the update_function, update_func which is assumed to have the signature

update_func(A::AbstractMatrix, u, p, t; <accepted kwargs>) -> newA

or

update_func!(A::AbstractMatrix, u, p, t; <accepted kwargs>) -> [modifies A]

The set of keyword-arguments accepted by update_func[!] must be provided to MatrixOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func[!] if accepted_kwargs are not provided.

Warning

The user-provided update_func[!] must not use u in its computation. Positional argument (u, p, t) to update_func[!] are passed down by update_coefficients[!](L, u, p, t), where u is the input-vector to the composite AbstractSciMLOperator. For that reason, the values of u, or even shape, may not correspond to the input expected by update_func[!]. If an operator's state depends on its input vector, then it is, by definition, a nonlinear operator. We recommend sticking such nonlinearities in FunctionOperator. This topic is further discussed in (this issue)[https://github.com/SciML/SciMLOperators.jl/issues/159].

Interface

Lazy matrix algebra is defined for AbstractSciMLOperators. The Interface supports lazy addition, subtraction, multiplication, inversion, adjoints, transposes.

Example

Out-of-place update and usage

u = rand(4)
 p = rand(4, 4)
 t = rand()
 
@@ -34,13 +34,13 @@
 L = M * M + 3I
 
 # update L in-place and evaluate
-L(v, u, p, t; scale = 1.0)
source
SciMLOperators.DiagonalOperatorFunction
DiagonalOperator(
     diag;
     update_func,
     update_func!,
     accepted_kwargs
 )
-

Represents an elementwise scaling (diagonal-scaling) operation that may be applied to an AbstractVecOrMat. When diag is an AbstractVector of length N, L = DiagonalOperator(diag, ...) can be applied to AbstractArrays with size(u, 1) == N. Each column of the u will be scaled by diag, as in LinearAlgebra.Diagonal(diag) * u.

When diag is a multidimensional array, L = DiagonalOperator(diag, ...) forms an operator of size (N, N) where N = size(diag, 1) is the leading length of diag. L then is the elementwise-scaling operation on arrays of length(u) = length(diag) with leading length size(u, 1) = N.

Its state is updated by the user-provided update_func during operator evaluation (L([v,], u, p, t)), or by calls to update_coefficients[!](L, u, p, t). Both recursively call the update_function, update_func which is assumed to have the signature

update_func(diag::AbstractVecOrMat, u, p, t; <accepted kwargs>) -> new_diag

or

update_func!(diag::AbstractVecOrMat, u, p, t; <accepted kwargs>) -> [modifies diag]

The set of keyword-arguments accepted by update_func[!] must be provided to MatrixOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func[!] if accepted_kwargs are not provided.

Warning

The user-provided update_func[!] must not use u in its computation. Positional argument (u, p, t) to update_func[!] are passed down by update_coefficients[!](L, u, p, t), where u is the input-vector to the composite AbstractSciMLOperator. For that reason, the values of u, or even shape, may not correspond to the input expected by update_func[!]. If an operator's state depends on its input vector, then it is, by definition, a nonlinear operator. We recommend sticking such nonlinearities in FunctionOperator. This topic is further discussed in (this issue)[https://github.com/SciML/SciMLOperators.jl/issues/159].

Example

source
SciMLOperators.AffineOperatorType

Represents a generalized affine operation (v = A * u + B * b) that may be applied to an AbstractVecOrMat. The user-provided update functions, update_func[!] update the AbstractVecOrMat b, and are called during operator evaluation (L([v,], u, p, t)), or by calls to update_coefficients[!](L, u, p, t). The update functions are assumed to have the syntax

update_func(b::AbstractVecOrMat, u, p, t; <accepted kwargs>) -> new_b

or

update_func!(b::AbstractVecOrMat, u ,p , t; <accepted kwargs>) -> [modifies b]

and B, b are expected to have an appropriate size so that A * u + B * b makes sense. Specifically, size(A, 1) == size(B, 1), and size(u, 2) == size(b, 2).

The set of keyword-arguments accepted by update_func[!] must be provided to AffineOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func[!] if accepted_kwargs are not provided.

Example

u = rand(4)
+

Represents an elementwise scaling (diagonal-scaling) operation that may be applied to an AbstractVecOrMat. When diag is an AbstractVector of length N, L = DiagonalOperator(diag, ...) can be applied to AbstractArrays with size(u, 1) == N. Each column of the u will be scaled by diag, as in LinearAlgebra.Diagonal(diag) * u.

When diag is a multidimensional array, L = DiagonalOperator(diag, ...) forms an operator of size (N, N) where N = size(diag, 1) is the leading length of diag. L then is the elementwise-scaling operation on arrays of length(u) = length(diag) with leading length size(u, 1) = N.

Its state is updated by the user-provided update_func during operator evaluation (L([v,], u, p, t)), or by calls to update_coefficients[!](L, u, p, t). Both recursively call the update_function, update_func which is assumed to have the signature

update_func(diag::AbstractVecOrMat, u, p, t; <accepted kwargs>) -> new_diag

or

update_func!(diag::AbstractVecOrMat, u, p, t; <accepted kwargs>) -> [modifies diag]

The set of keyword-arguments accepted by update_func[!] must be provided to MatrixOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func[!] if accepted_kwargs are not provided.

Warning

The user-provided update_func[!] must not use u in its computation. Positional argument (u, p, t) to update_func[!] are passed down by update_coefficients[!](L, u, p, t), where u is the input-vector to the composite AbstractSciMLOperator. For that reason, the values of u, or even shape, may not correspond to the input expected by update_func[!]. If an operator's state depends on its input vector, then it is, by definition, a nonlinear operator. We recommend sticking such nonlinearities in FunctionOperator. This topic is further discussed in (this issue)[https://github.com/SciML/SciMLOperators.jl/issues/159].

Example

source
SciMLOperators.AffineOperatorType

Represents a generalized affine operation (v = A * u + B * b) that may be applied to an AbstractVecOrMat. The user-provided update functions, update_func[!] update the AbstractVecOrMat b, and are called during operator evaluation (L([v,], u, p, t)), or by calls to update_coefficients[!](L, u, p, t). The update functions are assumed to have the syntax

update_func(b::AbstractVecOrMat, u, p, t; <accepted kwargs>) -> new_b

or

update_func!(b::AbstractVecOrMat, u ,p , t; <accepted kwargs>) -> [modifies b]

and B, b are expected to have an appropriate size so that A * u + B * b makes sense. Specifically, size(A, 1) == size(B, 1), and size(u, 2) == size(b, 2).

The set of keyword-arguments accepted by update_func[!] must be provided to AffineOperator via the kwarg accepted_kwargs as a tuple of Symbols. kwargs cannot be passed down to update_func[!] if accepted_kwargs are not provided.

Example

u = rand(4)
 p = rand(4)
 t = rand()
 
@@ -52,16 +52,16 @@
 L = cache_operator(M, u)
 
 # update L and evaluate
-v = L(u, p, t) # == A * u + B * (p * t)
source
SciMLOperators.AddVectorFunction
AddVector(b; update_func, update_func!, accepted_kwargs)
-

Represents the affine operation v = I * u + I * b. The update functions, update_func[!] update the state of AbstractVecOrMat b. See documentation of AffineOperator for more details.

source
AddVector(B, b; update_func, update_func!, accepted_kwargs)
-

Represents the affine operation v = I * u + B * b. The update functions, update_func[!] update the state of AbstractVecOrMat b. See documentation of AffineOperator for more details.

source
SciMLOperators.FunctionOperatorType

Matrix free operator given by a function

  • op: Function with signature op(u, p, t) and (if isinplace) op(v, u, p, t)

  • op_adjoint: Adjoint operator

  • op_inverse: Inverse operator

  • op_adjoint_inverse: Adjoint inverse operator

  • traits: Traits

  • p: Parameters

  • t: Time

  • cache: Cache

source
SciMLOperators.TensorProductOperatorType

Computes the lazy pairwise Kronecker product, or tensor product, operator of AbstractMatrix, and AbstractSciMLOperator subtypes. Calling ⊗(ops...) is equivalent to Base.kron(ops...). Fast operator evaluation is performed without forming the full tensor product operator.

TensorProductOperator(A, B) = A ⊗ B
+v = L(u, p, t) # == A * u + B * (p * t)
source
SciMLOperators.AddVectorFunction
AddVector(b; update_func, update_func!, accepted_kwargs)
+

Represents the affine operation v = I * u + I * b. The update functions, update_func[!] update the state of AbstractVecOrMat b. See documentation of AffineOperator for more details.

source
AddVector(B, b; update_func, update_func!, accepted_kwargs)
+

Represents the affine operation v = I * u + B * b. The update functions, update_func[!] update the state of AbstractVecOrMat b. See documentation of AffineOperator for more details.

source
SciMLOperators.FunctionOperatorType

Matrix free operator given by a function

  • op: Function with signature op(u, p, t) and (if isinplace) op(v, u, p, t)

  • op_adjoint: Adjoint operator

  • op_inverse: Inverse operator

  • op_adjoint_inverse: Adjoint inverse operator

  • traits: Traits

  • p: Parameters

  • t: Time

  • cache: Cache

source
SciMLOperators.TensorProductOperatorType

Computes the lazy pairwise Kronecker product, or tensor product, operator of AbstractMatrix, and AbstractSciMLOperator subtypes. Calling ⊗(ops...) is equivalent to Base.kron(ops...). Fast operator evaluation is performed without forming the full tensor product operator.

TensorProductOperator(A, B) = A ⊗ B
 TensorProductOperator(A, B, C) = A ⊗ B ⊗ C
 
-(A ⊗ B)(u) = vec(B * reshape(u, M, N) * transpose(A))

where M = size(B, 2), and N = size(A, 2)

source

Lazy Scalar Operator Combination

Lazy Operator Combination

SciMLOperators.ScaledOperatorType
struct ScaledOperator{T, λType, LType} <: SciMLOperators.AbstractSciMLOperator{T}
ScaledOperator
+(A ⊗ B)(u) = vec(B * reshape(u, M, N) * transpose(A))

where M = size(B, 2), and N = size(A, 2)

source

Lazy Scalar Operator Combination

Lazy Operator Combination

+cache = (B*C*u , C*u)
source
diff --git a/dev/sciml/index.html b/dev/sciml/index.html index 0971a3e..79f031b 100644 --- a/dev/sciml/index.html +++ b/dev/sciml/index.html @@ -1,2 +1,2 @@ -Usage with SciML and beyond · SciMLOperators.jl

Usage with SciML and beyond

Why SciMLOperators?

Many functions, from linear solvers to differential equations, require the use of matrix-free operators to achieve maximum performance in many scenarios. SciMLOperators.jl defines the abstract interface for how operators in the SciML ecosystem are supposed to be defined. It gives the common set of functions and traits that solvers can rely on for properly performing their tasks. Along with that, SciMLOperators.jl provides definitions for the basic standard operators that are used as building blocks for most tasks, simplifying the use of operators while also demonstrating to users how such operators can be built and used in practice.

SciMLOperators.jl has the design that is required to be used in all scenarios of equation solvers. For example, Magnus integrators for differential equations require defining an operator $u' = A(t) u$, while Munthe-Kaas methods require defining operators of the form $u' = A(u) u$. Thus, the operators need some form of time and state dependence, which the solvers can update and query when they are non-constant (update_coefficients!). Additionally, the operators need the ability to act like “normal” functions for equation solvers. For example, if A(u,p,t) has the same operation as update_coefficients(A, u, p, t); A * u, then A can be used in any place where a differential equation definition f(u, p, t) is used without requiring the user or solver to do any extra work. Thus while previous good efforts for matrix-free operators have existed in the Julia ecosystem, such as LinearMaps.jl, those operator interfaces lack these aspects to actually be fully seamless with downstream equation solvers. This necessitates the definition and use of an extended operator interface with all of these properties, hence the AbstractSciMLOperator interface.

Some packages providing similar functionality are

Interoperability and extended Julia ecosystem

SciMLOperator.jl overloads the AbstractMatrix interface for AbstractSciMLOperators, allowing seamless compatibility with linear and nonlinear solvers. Further, due to the update functionality, AbstractSciMLOperators can represent an ODEFunction in OrdinaryDiffEq.jl, and downstream packages. See tutorials for examples of usage with OrdinaryDiffEq.jl, LinearSolve.jl, NonlinearSolve.jl.

Further, the nonmutating update functionality allows gradient propagation through AbstractSciMLOperators, and is compatible with automatic-differentiation libraries like Zygote.jl. An example of Zygote.jl usage with Lux.jl is also provided in the tutorials.

Please make an issue here if you come across an unexpected issue while using SciMLOperators.

We provide below a list of packages that make use of SciMLOperators. If you are using SciMLOperators in your work, feel free to create a PR and add your package to this list.

+Usage with SciML and beyond · SciMLOperators.jl

Usage with SciML and beyond

Why SciMLOperators?

Many functions, from linear solvers to differential equations, require the use of matrix-free operators to achieve maximum performance in many scenarios. SciMLOperators.jl defines the abstract interface for how operators in the SciML ecosystem are supposed to be defined. It gives the common set of functions and traits that solvers can rely on for properly performing their tasks. Along with that, SciMLOperators.jl provides definitions for the basic standard operators that are used as building blocks for most tasks, simplifying the use of operators while also demonstrating to users how such operators can be built and used in practice.

SciMLOperators.jl has the design that is required to be used in all scenarios of equation solvers. For example, Magnus integrators for differential equations require defining an operator $u' = A(t) u$, while Munthe-Kaas methods require defining operators of the form $u' = A(u) u$. Thus, the operators need some form of time and state dependence, which the solvers can update and query when they are non-constant (update_coefficients!). Additionally, the operators need the ability to act like “normal” functions for equation solvers. For example, if A(u,p,t) has the same operation as update_coefficients(A, u, p, t); A * u, then A can be used in any place where a differential equation definition f(u, p, t) is used without requiring the user or solver to do any extra work. Thus while previous good efforts for matrix-free operators have existed in the Julia ecosystem, such as LinearMaps.jl, those operator interfaces lack these aspects to actually be fully seamless with downstream equation solvers. This necessitates the definition and use of an extended operator interface with all of these properties, hence the AbstractSciMLOperator interface.

Some packages providing similar functionality are

Interoperability and extended Julia ecosystem

SciMLOperator.jl overloads the AbstractMatrix interface for AbstractSciMLOperators, allowing seamless compatibility with linear and nonlinear solvers. Further, due to the update functionality, AbstractSciMLOperators can represent an ODEFunction in OrdinaryDiffEq.jl, and downstream packages. See tutorials for examples of usage with OrdinaryDiffEq.jl, LinearSolve.jl, NonlinearSolve.jl.

Further, the nonmutating update functionality allows gradient propagation through AbstractSciMLOperators, and is compatible with automatic-differentiation libraries like Zygote.jl. An example of Zygote.jl usage with Lux.jl is also provided in the tutorials.

Please make an issue here if you come across an unexpected issue while using SciMLOperators.

We provide below a list of packages that make use of SciMLOperators. If you are using SciMLOperators in your work, feel free to create a PR and add your package to this list.

diff --git a/dev/tutorials/fftw/index.html b/dev/tutorials/fftw/index.html index 04f4da5..ab2ef1b 100644 --- a/dev/tutorials/fftw/index.html +++ b/dev/tutorials/fftw/index.html @@ -90,4 +90,4 @@ Dx = cache_operator(Dx, x) @show ≈(Dx * u, du; atol = 1e-8) -@show ≈(mul!(copy(u), Dx, u), du; atol = 1e-8)
true
+@show ≈(mul!(copy(u), Dx, u), du; atol = 1e-8)
true