-
Notifications
You must be signed in to change notification settings - Fork 156
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
Automatic wrapping of specialized methods, solve many ambiguities #813
Draft
manuelbb-upb
wants to merge
3
commits into
JuliaSymbolics:master
Choose a base branch
from
manuelbb-upb:specialize_methods
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,4 +23,6 @@ function __init__() | |
end | ||
|
||
end # SymPy | ||
|
||
specialize_methods((LinearAlgebra,)) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
""" | ||
specialize_methods(func, abstract_arg_types, inner_func, mods=nothing) | ||
|
||
For any method that implements `func` with signature | ||
fitting `abstract_arg_types`, define methods for corresponding | ||
symbolic types that pass all arguments to `inner_func`. | ||
`mods` is an optional list of modules to look for methods in. | ||
""" | ||
function specialize_methods(func, abstract_arg_types, inner_func, mods=nothing) | ||
ms = isnothing(mods) ? methods(func, abstract_arg_types) : methods(func, abstract_arg_types, mods) | ||
for m in ms | ||
mod = m.module | ||
if mod != @__MODULE__ # do not overwrite method definitions from within this module itself, else: precompilation warnings | ||
sig = ExprTools.signature(m; extra_hygiene=true) | ||
fname = sig[:name] | ||
args = sig[:args] | ||
kwargs = get(sig, :kwargs, Symbol[]) | ||
whereparams = get(sig, :whereparams, Symbol[]) | ||
args_names = expr_argname.(args) | ||
kwargs_names = expr_kwargname.(kwargs) | ||
body = :($(inner_func)($(args_names...); $(kwargs_names...))) | ||
Base.eval( | ||
@__MODULE__, | ||
wrap_func_expr( | ||
mod, fname, args, kwargs, args_names, kwargs_names, whereparams, body; | ||
abstract_arg_types | ||
) | ||
) | ||
end#of `mod != @__MODULE__` | ||
end#of `for m in ms` | ||
end | ||
|
||
""" | ||
specialize_methods(mods=nothing) | ||
|
||
Define specialized methods accepting symbolic types for the following functions and | ||
signatures found in modules `mods` via `methods(...)`: | ||
|
||
* `Base.:(*)` for arguments of `(AbstractMatrix, AbstractVector)` to redirect to `_matvec`. | ||
* `Base.:(*)` for arguments of `(AbstractMatrix, AbstractMetrax)` to redirect to `_matmul`. | ||
""" | ||
function specialize_methods(mods=nothing) | ||
specialize_methods(Base.:(*), (AbstractMatrix, AbstractVector), _matvec, mods) | ||
specialize_methods(Base.:(*), (AbstractMatrix, AbstractMatrix), _matmul, mods) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
What happens if methods are added by a third party package after
@warpped
has executed?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.
Then
specialize_methods
would have to be called again. This sort of load-order dependence is also observed in Hyperspecialize, and the only way around it seems the Cassette approach.Actually, the code in this pull request is not too different from what Hyperspecialize can do, except that some of the Matrix or Vector types occurring in method definitions can be super special, so I had to either traverse the whole type tree and gather every possible subtype for Hyperspecialize's
@concretize
or inspect the method signatures (what is done now).However, there are a few things we can do with respect to the points in your other comment:
specialize_methods
accepts a list of modules with argumentmods
. When calling it in__init__()
we can restrict ourselves toLinearAlgebra
and other relevant standard modules.Whenever a user has custom array types defined in a module, or there is a package with custom array types,
specialize_methods
can be called withmods
set accordingly to automatically “widen”/wrap the relevant definitions to have a generic fallback. This way, the developer does not have to know thatBase.:(*)(::AbstractMatrix, ::AbstractVector)
should redirect to_matmul
most of the time.If, for example, I get a
StaticMatrix
somewhere in my computations, then I cannot use it with symbolic arrays:But after
Symbolics.specialize_methods(StaticArrays)
it just works.
For some widely used packages (such as StaticArrays) we could even do this ourselves with
@require
. Conversely, a package author could opt to placeSymbolics.specialize_methods(@__MODULE__)
in their__init__
, though I have to think about scopes andexport
statements a bit more.Going forward, I can try to benchmark the impact of
specialize_methods
in__init__
(for different values ofmods
) and maybe devise some tests.