-
-
Notifications
You must be signed in to change notification settings - Fork 154
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
Use Python's typing instead of attaching Type
objects to Variable
s
#134
Comments
@LegrandNico, since you're becoming Aesara's type expert, I would like to introduce you to this potentially revolutionary refactoring topic... |
Type
objects to Variable
s
The issue fixed in #892 could possibly have been caught by Mypy's type checking if the approach described here was in place. In that example, the problematic |
Type
objects to Variable
sType
objects to Variable
s
Type
objects to Variable
sType
objects to Variable
s
It looks like we would need to do something exactly like NumPy is currently doing with its Here's a simple example: import numpy as np
import typing
import typing_inspect
DataType = typing.TypeVar("DataType")
class TensorType(typing.Generic[DataType]):
@classmethod
@property
def dtype(cls) -> DataType:
generic_bases = typing_inspect.get_generic_bases(cls)
type_base = next((b for b in generic_bases if typing_inspect.get_origin(b) == TensorType))
dtype = typing_inspect.get_args(type_base)[0]
return dtype
Float32TensorType = TensorType[np.float32]
assert Float32TensorType == TensorType[np.float32]
class Float32Variable(Float32TensorType):
pass
scalar_float_inst = Float32Variable()
assert scalar_float_inst.dtype is np.float32
assert isinstance(scalar_float_inst, TensorType)
assert isinstance(scalar_float_inst, Float32Variable) Unfortunately, checks based on the parameterized # Fails
assert isinstance(scalar_float_inst, Float32TensorType) |
There might possibly be some useful typing examples in the |
To clarify, adding this kind of parameterized typing will allow type checking (i.e. Mypy) to catch issues involving incompatible dtypes and (static) shapes. Currently, these kinds of issues require explicit unit tests to catch, and that's quite a burden on our testing requirements. Also, it should be possible to add this on top of the existing codebase without making the changes implied by this issue. In other words, we don't need to make the change from using |
Based on @brandonwillard's code example above I developed a more complete example of how a https://github.com/markusschmaus/Documents/blob/main/aesara_typing_demo.py One key difference between his code and mine, is that @brandonwillard used inspection to extract the The demo passes mypy without errors and contains a few asserts which also succeed. I tried to get Based on this demo I believe that implementing this suggestion is possible and I would be interested in working on this. However this would be a major refactoring and only makes sense if there is support from existing aesara developers. One aspect I would like to explore, when working on this, is the role of |
Yes, that example was completely experimental; we definitely don't need to take an approach like that. As long as what we're currently calling
I'm ready to make these changes sooner than later, so, if you want to work on this, we can start now. A draft PR is the next step.
Be sure to read the comments here: #1013 (reply in thread). In other words, we shouldn't need anything at the type-level to support most kinds of dimension tracking. Regardless, these changes would help any related efforts a lot. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Before I forget, here's some related (and interesting) work on Python typing for shapes: https://peps.python.org/pep-0646/ |
Come to think of it, we could start using |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Here is the PR |
Instead of creating "type" classes (i.e.
Type
s) and manually attaching them to Aesara objects (i.e. viaVariable.type
), we should actual use Python's built-in type/class inheritance. I'm not immediately aware of any required functionality in the current Aesara type system that wouldn't allow this.Here's an illustration of the current situation:
We created a simple Aesara vector,
x
; now, let's inspect its (Python) types:Oddly, there's also a separate
Variable.type
field/member/property introduced by inheriting fromVariable
:As we can see, this extra
Type
object holds information about the variable'sdtype
and broadcastable dimensions (i.e. thevector
meansx.type.broadcastable
equals[False]
/[True]
). From the latter two properties, it's also clear that the actual Python type (i.e.TensorVariable
) is directly associated with the Aesara type (i.e.TensorType
) as illustrated by the value ofTensorType.Variable
.This leads to the question: why doesn't
TensorVariable
just inherit from itsx.type
type/class (i.e. someTensorType
)?If anything, the mechanics behind such inheritance might seem non-standard, as it could require some form of automatic type generation for sub-classes like
TensorVariable
, but—even so—that's pretty straightforward to do in a__new__
class method (e.g. we already do that insymbolic-pymc
).Regarding actual code changes, it seems like we would at least need to change all the
Variable.type
invocations with the standardtype(...)
calls, and/or more direct calls toisinstance(x, TensorType)
instead of things likex.type == TensorType(...)
.We could also keep
Variable.type
and have it returntype(self)
just to make the initial transition easy.The text was updated successfully, but these errors were encountered: