Automatic wrapping of specialized methods, solve many ambiguities#813
Automatic wrapping of specialized methods, solve many ambiguities#813manuelbb-upb wants to merge 3 commits intoJuliaSymbolics:masterfrom
Conversation
`specialize_methods`, apparently working for matrix-vector and matrix-matrix products.
| an `AbstractMatrix` and an `VecOrMat` (type union), then we accidentally redirect | ||
| a matrix-vector-product to `_matmul` without `typeintersect`. | ||
| =# | ||
| typeintersect($(atype), $(arg.args[2]) where {$(wparams...)}) |
There was a problem hiding this comment.
What happens if methods are added by a third party package after @warpped has executed?
There was a problem hiding this comment.
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:
All relevant types in Base/stdlib should be made to work with the wrapped types defined in this package
specialize_methods accepts a list of modules with argument mods. When calling it in __init__() we can restrict ourselves to LinearAlgebra and other relevant standard modules.
Taking this further if a new package wants to use its array or number types with Symbolics, wherever necessary, it should return the specializations manually or using a different macro.
What happens if methods are added by a third party package after @Warpped has executed?
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 with mods set accordingly to automatically “widen”/wrap the relevant definitions to have a generic fallback. This way, the developer does not have to know that Base.:(*)(::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:
using Symbolics
using StaticArrays
A = @SMatrix(rand(2,2)) # imagine this is obtained somewhere else
@variables (x::Real)[1:2]
A * x # ERROR: MethodError: *(::SMatrix{2, 2, Float64, 4}, ::Symbolics.Arr{Num, 1}) is ambiguous.
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 place Symbolics.specialize_methods(@__MODULE__) in their __init__, though I have to think about scopes and export statements a bit more.
Going forward, I can try to benchmark the impact of specialize_methods in __init__ (for different values of mods) and maybe devise some tests.
|
Quick update for anyone following/reading: There are pre-compilation issues. I'll try to work them out, and maybe try avoiding working with |
This is a WIP/proposal to solve some ambiguity issues, like #575 or #635.
These arise, because the methods defined with the
@wrapedmacro compete with very specialized methods, possibly from sub-modules.In contrast to #811, this approach does not need a dedicated dispatch context.
Instead, the function
specialize_methodslooks up all methods currently available for a specified function and iteratively defines methods for the corresponding symbolically wrapped types.Thus, the behavior of
specialize_methodsis load order dependent.We could call it ourselves or leave it up to the user.
In this first draft:
specialize_methodsonly creates definitions for matrix-vector and matrix-matrix products and delegates the work to_matvecand_matmul, respectively. The examples from the issues above seem to work now.ExprTools.jlis used to parse method information. I started usingExprToolsbecause of convenience and to leverage the existing code for@wrapped, which is only slightly modified.specialize_methods()is executed in the modules__init__function and the tests appear to pass locally.