Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/_multiprocess/__init__.py +8 -0
- lib/python3.12/site-packages/_multiprocess/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/big_modeling.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/checkpointing.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/data_loader.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/hooks.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/inference.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/launchers.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/local_sgd.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/logging.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/memory_utils.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/optimizer.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/scheduler.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/state.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/__pycache__/tracking.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/test_utils/scripts/__pycache__/test_cli.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/accelerate/test_utils/scripts/__pycache__/test_script.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/blinker/__init__.py +17 -0
- lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/blinker/_utilities.py +64 -0
- lib/python3.12/site-packages/blinker/base.py +512 -0
- lib/python3.12/site-packages/blinker/py.typed +0 -0
- lib/python3.12/site-packages/einops-0.8.2.dist-info/INSTALLER +1 -0
- lib/python3.12/site-packages/einops-0.8.2.dist-info/METADATA +394 -0
- lib/python3.12/site-packages/einops-0.8.2.dist-info/RECORD +58 -0
- lib/python3.12/site-packages/einops-0.8.2.dist-info/WHEEL +4 -0
- lib/python3.12/site-packages/einops-0.8.2.dist-info/licenses/LICENSE +21 -0
- lib/python3.12/site-packages/functorch/__init__.py +39 -0
- lib/python3.12/site-packages/functorch/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/_src/__init__.py +0 -0
- lib/python3.12/site-packages/functorch/_src/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/_src/aot_autograd/__init__.py +8 -0
- lib/python3.12/site-packages/functorch/_src/aot_autograd/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/_src/eager_transforms/__init__.py +7 -0
- lib/python3.12/site-packages/functorch/_src/eager_transforms/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/_src/make_functional/__init__.py +4 -0
- lib/python3.12/site-packages/functorch/_src/make_functional/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/_src/vmap/__init__.py +16 -0
- lib/python3.12/site-packages/functorch/_src/vmap/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/compile/__init__.py +30 -0
- lib/python3.12/site-packages/functorch/compile/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/dim/__init__.py +181 -0
- lib/python3.12/site-packages/functorch/dim/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/dim/__pycache__/batch_tensor.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/dim/__pycache__/delayed_mul_tensor.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/dim/__pycache__/dim.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/functorch/dim/__pycache__/magic_trace.cpython-312.pyc +0 -0
lib/python3.12/site-packages/_multiprocess/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
#
|
| 3 |
+
# Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
|
| 4 |
+
# Copyright (c) 2022-2024 The Uncertainty Quantification Foundation.
|
| 5 |
+
# License: 3-clause BSD. The full license text is available at:
|
| 6 |
+
# - https://github.com/uqfoundation/multiprocess/blob/master/LICENSE
|
| 7 |
+
|
| 8 |
+
from _multiprocessing import *
|
lib/python3.12/site-packages/_multiprocess/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (232 Bytes). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (1.3 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/big_modeling.cpython-312.pyc
ADDED
|
Binary file (35.4 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/checkpointing.cpython-312.pyc
ADDED
|
Binary file (15 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/data_loader.cpython-312.pyc
ADDED
|
Binary file (64.5 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/hooks.cpython-312.pyc
ADDED
|
Binary file (33.7 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/inference.cpython-312.pyc
ADDED
|
Binary file (7.51 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/launchers.cpython-312.pyc
ADDED
|
Binary file (12.3 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/local_sgd.cpython-312.pyc
ADDED
|
Binary file (5.07 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/logging.cpython-312.pyc
ADDED
|
Binary file (5.68 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/memory_utils.cpython-312.pyc
ADDED
|
Binary file (490 Bytes). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/optimizer.cpython-312.pyc
ADDED
|
Binary file (11.7 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/scheduler.cpython-312.pyc
ADDED
|
Binary file (4.65 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/state.cpython-312.pyc
ADDED
|
Binary file (62.3 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/__pycache__/tracking.cpython-312.pyc
ADDED
|
Binary file (52.6 kB). View file
|
|
|
lib/python3.12/site-packages/accelerate/test_utils/scripts/__pycache__/test_cli.cpython-312.pyc
ADDED
|
Binary file (690 Bytes). View file
|
|
|
lib/python3.12/site-packages/accelerate/test_utils/scripts/__pycache__/test_script.cpython-312.pyc
ADDED
|
Binary file (48.1 kB). View file
|
|
|
lib/python3.12/site-packages/blinker/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from .base import ANY
|
| 4 |
+
from .base import default_namespace
|
| 5 |
+
from .base import NamedSignal
|
| 6 |
+
from .base import Namespace
|
| 7 |
+
from .base import Signal
|
| 8 |
+
from .base import signal
|
| 9 |
+
|
| 10 |
+
__all__ = [
|
| 11 |
+
"ANY",
|
| 12 |
+
"default_namespace",
|
| 13 |
+
"NamedSignal",
|
| 14 |
+
"Namespace",
|
| 15 |
+
"Signal",
|
| 16 |
+
"signal",
|
| 17 |
+
]
|
lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (498 Bytes). View file
|
|
|
lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc
ADDED
|
Binary file (2.73 kB). View file
|
|
|
lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (22 kB). View file
|
|
|
lib/python3.12/site-packages/blinker/_utilities.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import collections.abc as c
|
| 4 |
+
import inspect
|
| 5 |
+
import typing as t
|
| 6 |
+
from weakref import ref
|
| 7 |
+
from weakref import WeakMethod
|
| 8 |
+
|
| 9 |
+
T = t.TypeVar("T")
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class Symbol:
|
| 13 |
+
"""A constant symbol, nicer than ``object()``. Repeated calls return the
|
| 14 |
+
same instance.
|
| 15 |
+
|
| 16 |
+
>>> Symbol('foo') is Symbol('foo')
|
| 17 |
+
True
|
| 18 |
+
>>> Symbol('foo')
|
| 19 |
+
foo
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
symbols: t.ClassVar[dict[str, Symbol]] = {}
|
| 23 |
+
|
| 24 |
+
def __new__(cls, name: str) -> Symbol:
|
| 25 |
+
if name in cls.symbols:
|
| 26 |
+
return cls.symbols[name]
|
| 27 |
+
|
| 28 |
+
obj = super().__new__(cls)
|
| 29 |
+
cls.symbols[name] = obj
|
| 30 |
+
return obj
|
| 31 |
+
|
| 32 |
+
def __init__(self, name: str) -> None:
|
| 33 |
+
self.name = name
|
| 34 |
+
|
| 35 |
+
def __repr__(self) -> str:
|
| 36 |
+
return self.name
|
| 37 |
+
|
| 38 |
+
def __getnewargs__(self) -> tuple[t.Any, ...]:
|
| 39 |
+
return (self.name,)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def make_id(obj: object) -> c.Hashable:
|
| 43 |
+
"""Get a stable identifier for a receiver or sender, to be used as a dict
|
| 44 |
+
key or in a set.
|
| 45 |
+
"""
|
| 46 |
+
if inspect.ismethod(obj):
|
| 47 |
+
# The id of a bound method is not stable, but the id of the unbound
|
| 48 |
+
# function and instance are.
|
| 49 |
+
return id(obj.__func__), id(obj.__self__)
|
| 50 |
+
|
| 51 |
+
if isinstance(obj, (str, int)):
|
| 52 |
+
# Instances with the same value always compare equal and have the same
|
| 53 |
+
# hash, even if the id may change.
|
| 54 |
+
return obj
|
| 55 |
+
|
| 56 |
+
# Assume other types are not hashable but will always be the same instance.
|
| 57 |
+
return id(obj)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]:
|
| 61 |
+
if inspect.ismethod(obj):
|
| 62 |
+
return WeakMethod(obj, callback) # type: ignore[arg-type, return-value]
|
| 63 |
+
|
| 64 |
+
return ref(obj, callback)
|
lib/python3.12/site-packages/blinker/base.py
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import collections.abc as c
|
| 4 |
+
import sys
|
| 5 |
+
import typing as t
|
| 6 |
+
import weakref
|
| 7 |
+
from collections import defaultdict
|
| 8 |
+
from contextlib import contextmanager
|
| 9 |
+
from functools import cached_property
|
| 10 |
+
from inspect import iscoroutinefunction
|
| 11 |
+
|
| 12 |
+
from ._utilities import make_id
|
| 13 |
+
from ._utilities import make_ref
|
| 14 |
+
from ._utilities import Symbol
|
| 15 |
+
|
| 16 |
+
F = t.TypeVar("F", bound=c.Callable[..., t.Any])
|
| 17 |
+
|
| 18 |
+
ANY = Symbol("ANY")
|
| 19 |
+
"""Symbol for "any sender"."""
|
| 20 |
+
|
| 21 |
+
ANY_ID = 0
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class Signal:
|
| 25 |
+
"""A notification emitter.
|
| 26 |
+
|
| 27 |
+
:param doc: The docstring for the signal.
|
| 28 |
+
"""
|
| 29 |
+
|
| 30 |
+
ANY = ANY
|
| 31 |
+
"""An alias for the :data:`~blinker.ANY` sender symbol."""
|
| 32 |
+
|
| 33 |
+
set_class: type[set[t.Any]] = set
|
| 34 |
+
"""The set class to use for tracking connected receivers and senders.
|
| 35 |
+
Python's ``set`` is unordered. If receivers must be dispatched in the order
|
| 36 |
+
they were connected, an ordered set implementation can be used.
|
| 37 |
+
|
| 38 |
+
.. versionadded:: 1.7
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
@cached_property
|
| 42 |
+
def receiver_connected(self) -> Signal:
|
| 43 |
+
"""Emitted at the end of each :meth:`connect` call.
|
| 44 |
+
|
| 45 |
+
The signal sender is the signal instance, and the :meth:`connect`
|
| 46 |
+
arguments are passed through: ``receiver``, ``sender``, and ``weak``.
|
| 47 |
+
|
| 48 |
+
.. versionadded:: 1.2
|
| 49 |
+
"""
|
| 50 |
+
return Signal(doc="Emitted after a receiver connects.")
|
| 51 |
+
|
| 52 |
+
@cached_property
|
| 53 |
+
def receiver_disconnected(self) -> Signal:
|
| 54 |
+
"""Emitted at the end of each :meth:`disconnect` call.
|
| 55 |
+
|
| 56 |
+
The sender is the signal instance, and the :meth:`disconnect` arguments
|
| 57 |
+
are passed through: ``receiver`` and ``sender``.
|
| 58 |
+
|
| 59 |
+
This signal is emitted **only** when :meth:`disconnect` is called
|
| 60 |
+
explicitly. This signal cannot be emitted by an automatic disconnect
|
| 61 |
+
when a weakly referenced receiver or sender goes out of scope, as the
|
| 62 |
+
instance is no longer be available to be used as the sender for this
|
| 63 |
+
signal.
|
| 64 |
+
|
| 65 |
+
An alternative approach is available by subscribing to
|
| 66 |
+
:attr:`receiver_connected` and setting up a custom weakref cleanup
|
| 67 |
+
callback on weak receivers and senders.
|
| 68 |
+
|
| 69 |
+
.. versionadded:: 1.2
|
| 70 |
+
"""
|
| 71 |
+
return Signal(doc="Emitted after a receiver disconnects.")
|
| 72 |
+
|
| 73 |
+
def __init__(self, doc: str | None = None) -> None:
|
| 74 |
+
if doc:
|
| 75 |
+
self.__doc__ = doc
|
| 76 |
+
|
| 77 |
+
self.receivers: dict[
|
| 78 |
+
t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any]
|
| 79 |
+
] = {}
|
| 80 |
+
"""The map of connected receivers. Useful to quickly check if any
|
| 81 |
+
receivers are connected to the signal: ``if s.receivers:``. The
|
| 82 |
+
structure and data is not part of the public API, but checking its
|
| 83 |
+
boolean value is.
|
| 84 |
+
"""
|
| 85 |
+
|
| 86 |
+
self.is_muted: bool = False
|
| 87 |
+
self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class)
|
| 88 |
+
self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class)
|
| 89 |
+
self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {}
|
| 90 |
+
|
| 91 |
+
def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F:
|
| 92 |
+
"""Connect ``receiver`` to be called when the signal is sent by
|
| 93 |
+
``sender``.
|
| 94 |
+
|
| 95 |
+
:param receiver: The callable to call when :meth:`send` is called with
|
| 96 |
+
the given ``sender``, passing ``sender`` as a positional argument
|
| 97 |
+
along with any extra keyword arguments.
|
| 98 |
+
:param sender: Any object or :data:`ANY`. ``receiver`` will only be
|
| 99 |
+
called when :meth:`send` is called with this sender. If ``ANY``, the
|
| 100 |
+
receiver will be called for any sender. A receiver may be connected
|
| 101 |
+
to multiple senders by calling :meth:`connect` multiple times.
|
| 102 |
+
:param weak: Track the receiver with a :mod:`weakref`. The receiver will
|
| 103 |
+
be automatically disconnected when it is garbage collected. When
|
| 104 |
+
connecting a receiver defined within a function, set to ``False``,
|
| 105 |
+
otherwise it will be disconnected when the function scope ends.
|
| 106 |
+
"""
|
| 107 |
+
receiver_id = make_id(receiver)
|
| 108 |
+
sender_id = ANY_ID if sender is ANY else make_id(sender)
|
| 109 |
+
|
| 110 |
+
if weak:
|
| 111 |
+
self.receivers[receiver_id] = make_ref(
|
| 112 |
+
receiver, self._make_cleanup_receiver(receiver_id)
|
| 113 |
+
)
|
| 114 |
+
else:
|
| 115 |
+
self.receivers[receiver_id] = receiver
|
| 116 |
+
|
| 117 |
+
self._by_sender[sender_id].add(receiver_id)
|
| 118 |
+
self._by_receiver[receiver_id].add(sender_id)
|
| 119 |
+
|
| 120 |
+
if sender is not ANY and sender_id not in self._weak_senders:
|
| 121 |
+
# store a cleanup for weakref-able senders
|
| 122 |
+
try:
|
| 123 |
+
self._weak_senders[sender_id] = make_ref(
|
| 124 |
+
sender, self._make_cleanup_sender(sender_id)
|
| 125 |
+
)
|
| 126 |
+
except TypeError:
|
| 127 |
+
pass
|
| 128 |
+
|
| 129 |
+
if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers:
|
| 130 |
+
try:
|
| 131 |
+
self.receiver_connected.send(
|
| 132 |
+
self, receiver=receiver, sender=sender, weak=weak
|
| 133 |
+
)
|
| 134 |
+
except TypeError:
|
| 135 |
+
# TODO no explanation or test for this
|
| 136 |
+
self.disconnect(receiver, sender)
|
| 137 |
+
raise
|
| 138 |
+
|
| 139 |
+
return receiver
|
| 140 |
+
|
| 141 |
+
def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]:
|
| 142 |
+
"""Connect the decorated function to be called when the signal is sent
|
| 143 |
+
by ``sender``.
|
| 144 |
+
|
| 145 |
+
The decorated function will be called when :meth:`send` is called with
|
| 146 |
+
the given ``sender``, passing ``sender`` as a positional argument along
|
| 147 |
+
with any extra keyword arguments.
|
| 148 |
+
|
| 149 |
+
:param sender: Any object or :data:`ANY`. ``receiver`` will only be
|
| 150 |
+
called when :meth:`send` is called with this sender. If ``ANY``, the
|
| 151 |
+
receiver will be called for any sender. A receiver may be connected
|
| 152 |
+
to multiple senders by calling :meth:`connect` multiple times.
|
| 153 |
+
:param weak: Track the receiver with a :mod:`weakref`. The receiver will
|
| 154 |
+
be automatically disconnected when it is garbage collected. When
|
| 155 |
+
connecting a receiver defined within a function, set to ``False``,
|
| 156 |
+
otherwise it will be disconnected when the function scope ends.=
|
| 157 |
+
|
| 158 |
+
.. versionadded:: 1.1
|
| 159 |
+
"""
|
| 160 |
+
|
| 161 |
+
def decorator(fn: F) -> F:
|
| 162 |
+
self.connect(fn, sender, weak)
|
| 163 |
+
return fn
|
| 164 |
+
|
| 165 |
+
return decorator
|
| 166 |
+
|
| 167 |
+
@contextmanager
|
| 168 |
+
def connected_to(
|
| 169 |
+
self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY
|
| 170 |
+
) -> c.Generator[None, None, None]:
|
| 171 |
+
"""A context manager that temporarily connects ``receiver`` to the
|
| 172 |
+
signal while a ``with`` block executes. When the block exits, the
|
| 173 |
+
receiver is disconnected. Useful for tests.
|
| 174 |
+
|
| 175 |
+
:param receiver: The callable to call when :meth:`send` is called with
|
| 176 |
+
the given ``sender``, passing ``sender`` as a positional argument
|
| 177 |
+
along with any extra keyword arguments.
|
| 178 |
+
:param sender: Any object or :data:`ANY`. ``receiver`` will only be
|
| 179 |
+
called when :meth:`send` is called with this sender. If ``ANY``, the
|
| 180 |
+
receiver will be called for any sender.
|
| 181 |
+
|
| 182 |
+
.. versionadded:: 1.1
|
| 183 |
+
"""
|
| 184 |
+
self.connect(receiver, sender=sender, weak=False)
|
| 185 |
+
|
| 186 |
+
try:
|
| 187 |
+
yield None
|
| 188 |
+
finally:
|
| 189 |
+
self.disconnect(receiver)
|
| 190 |
+
|
| 191 |
+
@contextmanager
|
| 192 |
+
def muted(self) -> c.Generator[None, None, None]:
|
| 193 |
+
"""A context manager that temporarily disables the signal. No receivers
|
| 194 |
+
will be called if the signal is sent, until the ``with`` block exits.
|
| 195 |
+
Useful for tests.
|
| 196 |
+
"""
|
| 197 |
+
self.is_muted = True
|
| 198 |
+
|
| 199 |
+
try:
|
| 200 |
+
yield None
|
| 201 |
+
finally:
|
| 202 |
+
self.is_muted = False
|
| 203 |
+
|
| 204 |
+
def send(
|
| 205 |
+
self,
|
| 206 |
+
sender: t.Any | None = None,
|
| 207 |
+
/,
|
| 208 |
+
*,
|
| 209 |
+
_async_wrapper: c.Callable[
|
| 210 |
+
[c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any]
|
| 211 |
+
]
|
| 212 |
+
| None = None,
|
| 213 |
+
**kwargs: t.Any,
|
| 214 |
+
) -> list[tuple[c.Callable[..., t.Any], t.Any]]:
|
| 215 |
+
"""Call all receivers that are connected to the given ``sender``
|
| 216 |
+
or :data:`ANY`. Each receiver is called with ``sender`` as a positional
|
| 217 |
+
argument along with any extra keyword arguments. Return a list of
|
| 218 |
+
``(receiver, return value)`` tuples.
|
| 219 |
+
|
| 220 |
+
The order receivers are called is undefined, but can be influenced by
|
| 221 |
+
setting :attr:`set_class`.
|
| 222 |
+
|
| 223 |
+
If a receiver raises an exception, that exception will propagate up.
|
| 224 |
+
This makes debugging straightforward, with an assumption that correctly
|
| 225 |
+
implemented receivers will not raise.
|
| 226 |
+
|
| 227 |
+
:param sender: Call receivers connected to this sender, in addition to
|
| 228 |
+
those connected to :data:`ANY`.
|
| 229 |
+
:param _async_wrapper: Will be called on any receivers that are async
|
| 230 |
+
coroutines to turn them into sync callables. For example, could run
|
| 231 |
+
the receiver with an event loop.
|
| 232 |
+
:param kwargs: Extra keyword arguments to pass to each receiver.
|
| 233 |
+
|
| 234 |
+
.. versionchanged:: 1.7
|
| 235 |
+
Added the ``_async_wrapper`` argument.
|
| 236 |
+
"""
|
| 237 |
+
if self.is_muted:
|
| 238 |
+
return []
|
| 239 |
+
|
| 240 |
+
results = []
|
| 241 |
+
|
| 242 |
+
for receiver in self.receivers_for(sender):
|
| 243 |
+
if iscoroutinefunction(receiver):
|
| 244 |
+
if _async_wrapper is None:
|
| 245 |
+
raise RuntimeError("Cannot send to a coroutine function.")
|
| 246 |
+
|
| 247 |
+
result = _async_wrapper(receiver)(sender, **kwargs)
|
| 248 |
+
else:
|
| 249 |
+
result = receiver(sender, **kwargs)
|
| 250 |
+
|
| 251 |
+
results.append((receiver, result))
|
| 252 |
+
|
| 253 |
+
return results
|
| 254 |
+
|
| 255 |
+
async def send_async(
|
| 256 |
+
self,
|
| 257 |
+
sender: t.Any | None = None,
|
| 258 |
+
/,
|
| 259 |
+
*,
|
| 260 |
+
_sync_wrapper: c.Callable[
|
| 261 |
+
[c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]
|
| 262 |
+
]
|
| 263 |
+
| None = None,
|
| 264 |
+
**kwargs: t.Any,
|
| 265 |
+
) -> list[tuple[c.Callable[..., t.Any], t.Any]]:
|
| 266 |
+
"""Await all receivers that are connected to the given ``sender``
|
| 267 |
+
or :data:`ANY`. Each receiver is called with ``sender`` as a positional
|
| 268 |
+
argument along with any extra keyword arguments. Return a list of
|
| 269 |
+
``(receiver, return value)`` tuples.
|
| 270 |
+
|
| 271 |
+
The order receivers are called is undefined, but can be influenced by
|
| 272 |
+
setting :attr:`set_class`.
|
| 273 |
+
|
| 274 |
+
If a receiver raises an exception, that exception will propagate up.
|
| 275 |
+
This makes debugging straightforward, with an assumption that correctly
|
| 276 |
+
implemented receivers will not raise.
|
| 277 |
+
|
| 278 |
+
:param sender: Call receivers connected to this sender, in addition to
|
| 279 |
+
those connected to :data:`ANY`.
|
| 280 |
+
:param _sync_wrapper: Will be called on any receivers that are sync
|
| 281 |
+
callables to turn them into async coroutines. For example,
|
| 282 |
+
could call the receiver in a thread.
|
| 283 |
+
:param kwargs: Extra keyword arguments to pass to each receiver.
|
| 284 |
+
|
| 285 |
+
.. versionadded:: 1.7
|
| 286 |
+
"""
|
| 287 |
+
if self.is_muted:
|
| 288 |
+
return []
|
| 289 |
+
|
| 290 |
+
results = []
|
| 291 |
+
|
| 292 |
+
for receiver in self.receivers_for(sender):
|
| 293 |
+
if not iscoroutinefunction(receiver):
|
| 294 |
+
if _sync_wrapper is None:
|
| 295 |
+
raise RuntimeError("Cannot send to a non-coroutine function.")
|
| 296 |
+
|
| 297 |
+
result = await _sync_wrapper(receiver)(sender, **kwargs)
|
| 298 |
+
else:
|
| 299 |
+
result = await receiver(sender, **kwargs)
|
| 300 |
+
|
| 301 |
+
results.append((receiver, result))
|
| 302 |
+
|
| 303 |
+
return results
|
| 304 |
+
|
| 305 |
+
def has_receivers_for(self, sender: t.Any) -> bool:
|
| 306 |
+
"""Check if there is at least one receiver that will be called with the
|
| 307 |
+
given ``sender``. A receiver connected to :data:`ANY` will always be
|
| 308 |
+
called, regardless of sender. Does not check if weakly referenced
|
| 309 |
+
receivers are still live. See :meth:`receivers_for` for a stronger
|
| 310 |
+
search.
|
| 311 |
+
|
| 312 |
+
:param sender: Check for receivers connected to this sender, in addition
|
| 313 |
+
to those connected to :data:`ANY`.
|
| 314 |
+
"""
|
| 315 |
+
if not self.receivers:
|
| 316 |
+
return False
|
| 317 |
+
|
| 318 |
+
if self._by_sender[ANY_ID]:
|
| 319 |
+
return True
|
| 320 |
+
|
| 321 |
+
if sender is ANY:
|
| 322 |
+
return False
|
| 323 |
+
|
| 324 |
+
return make_id(sender) in self._by_sender
|
| 325 |
+
|
| 326 |
+
def receivers_for(
|
| 327 |
+
self, sender: t.Any
|
| 328 |
+
) -> c.Generator[c.Callable[..., t.Any], None, None]:
|
| 329 |
+
"""Yield each receiver to be called for ``sender``, in addition to those
|
| 330 |
+
to be called for :data:`ANY`. Weakly referenced receivers that are not
|
| 331 |
+
live will be disconnected and skipped.
|
| 332 |
+
|
| 333 |
+
:param sender: Yield receivers connected to this sender, in addition
|
| 334 |
+
to those connected to :data:`ANY`.
|
| 335 |
+
"""
|
| 336 |
+
# TODO: test receivers_for(ANY)
|
| 337 |
+
if not self.receivers:
|
| 338 |
+
return
|
| 339 |
+
|
| 340 |
+
sender_id = make_id(sender)
|
| 341 |
+
|
| 342 |
+
if sender_id in self._by_sender:
|
| 343 |
+
ids = self._by_sender[ANY_ID] | self._by_sender[sender_id]
|
| 344 |
+
else:
|
| 345 |
+
ids = self._by_sender[ANY_ID].copy()
|
| 346 |
+
|
| 347 |
+
for receiver_id in ids:
|
| 348 |
+
receiver = self.receivers.get(receiver_id)
|
| 349 |
+
|
| 350 |
+
if receiver is None:
|
| 351 |
+
continue
|
| 352 |
+
|
| 353 |
+
if isinstance(receiver, weakref.ref):
|
| 354 |
+
strong = receiver()
|
| 355 |
+
|
| 356 |
+
if strong is None:
|
| 357 |
+
self._disconnect(receiver_id, ANY_ID)
|
| 358 |
+
continue
|
| 359 |
+
|
| 360 |
+
yield strong
|
| 361 |
+
else:
|
| 362 |
+
yield receiver
|
| 363 |
+
|
| 364 |
+
def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None:
|
| 365 |
+
"""Disconnect ``receiver`` from being called when the signal is sent by
|
| 366 |
+
``sender``.
|
| 367 |
+
|
| 368 |
+
:param receiver: A connected receiver callable.
|
| 369 |
+
:param sender: Disconnect from only this sender. By default, disconnect
|
| 370 |
+
from all senders.
|
| 371 |
+
"""
|
| 372 |
+
sender_id: c.Hashable
|
| 373 |
+
|
| 374 |
+
if sender is ANY:
|
| 375 |
+
sender_id = ANY_ID
|
| 376 |
+
else:
|
| 377 |
+
sender_id = make_id(sender)
|
| 378 |
+
|
| 379 |
+
receiver_id = make_id(receiver)
|
| 380 |
+
self._disconnect(receiver_id, sender_id)
|
| 381 |
+
|
| 382 |
+
if (
|
| 383 |
+
"receiver_disconnected" in self.__dict__
|
| 384 |
+
and self.receiver_disconnected.receivers
|
| 385 |
+
):
|
| 386 |
+
self.receiver_disconnected.send(self, receiver=receiver, sender=sender)
|
| 387 |
+
|
| 388 |
+
def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None:
|
| 389 |
+
if sender_id == ANY_ID:
|
| 390 |
+
if self._by_receiver.pop(receiver_id, None) is not None:
|
| 391 |
+
for bucket in self._by_sender.values():
|
| 392 |
+
bucket.discard(receiver_id)
|
| 393 |
+
|
| 394 |
+
self.receivers.pop(receiver_id, None)
|
| 395 |
+
else:
|
| 396 |
+
self._by_sender[sender_id].discard(receiver_id)
|
| 397 |
+
self._by_receiver[receiver_id].discard(sender_id)
|
| 398 |
+
|
| 399 |
+
def _make_cleanup_receiver(
|
| 400 |
+
self, receiver_id: c.Hashable
|
| 401 |
+
) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]:
|
| 402 |
+
"""Create a callback function to disconnect a weakly referenced
|
| 403 |
+
receiver when it is garbage collected.
|
| 404 |
+
"""
|
| 405 |
+
|
| 406 |
+
def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None:
|
| 407 |
+
# If the interpreter is shutting down, disconnecting can result in a
|
| 408 |
+
# weird ignored exception. Don't call it in that case.
|
| 409 |
+
if not sys.is_finalizing():
|
| 410 |
+
self._disconnect(receiver_id, ANY_ID)
|
| 411 |
+
|
| 412 |
+
return cleanup
|
| 413 |
+
|
| 414 |
+
def _make_cleanup_sender(
|
| 415 |
+
self, sender_id: c.Hashable
|
| 416 |
+
) -> c.Callable[[weakref.ref[t.Any]], None]:
|
| 417 |
+
"""Create a callback function to disconnect all receivers for a weakly
|
| 418 |
+
referenced sender when it is garbage collected.
|
| 419 |
+
"""
|
| 420 |
+
assert sender_id != ANY_ID
|
| 421 |
+
|
| 422 |
+
def cleanup(ref: weakref.ref[t.Any]) -> None:
|
| 423 |
+
self._weak_senders.pop(sender_id, None)
|
| 424 |
+
|
| 425 |
+
for receiver_id in self._by_sender.pop(sender_id, ()):
|
| 426 |
+
self._by_receiver[receiver_id].discard(sender_id)
|
| 427 |
+
|
| 428 |
+
return cleanup
|
| 429 |
+
|
| 430 |
+
def _cleanup_bookkeeping(self) -> None:
|
| 431 |
+
"""Prune unused sender/receiver bookkeeping. Not threadsafe.
|
| 432 |
+
|
| 433 |
+
Connecting & disconnecting leaves behind a small amount of bookkeeping
|
| 434 |
+
data. Typical workloads using Blinker, for example in most web apps,
|
| 435 |
+
Flask, CLI scripts, etc., are not adversely affected by this
|
| 436 |
+
bookkeeping.
|
| 437 |
+
|
| 438 |
+
With a long-running process performing dynamic signal routing with high
|
| 439 |
+
volume, e.g. connecting to function closures, senders are all unique
|
| 440 |
+
object instances. Doing all of this over and over may cause memory usage
|
| 441 |
+
to grow due to extraneous bookkeeping. (An empty ``set`` for each stale
|
| 442 |
+
sender/receiver pair.)
|
| 443 |
+
|
| 444 |
+
This method will prune that bookkeeping away, with the caveat that such
|
| 445 |
+
pruning is not threadsafe. The risk is that cleanup of a fully
|
| 446 |
+
disconnected receiver/sender pair occurs while another thread is
|
| 447 |
+
connecting that same pair. If you are in the highly dynamic, unique
|
| 448 |
+
receiver/sender situation that has lead you to this method, that failure
|
| 449 |
+
mode is perhaps not a big deal for you.
|
| 450 |
+
"""
|
| 451 |
+
for mapping in (self._by_sender, self._by_receiver):
|
| 452 |
+
for ident, bucket in list(mapping.items()):
|
| 453 |
+
if not bucket:
|
| 454 |
+
mapping.pop(ident, None)
|
| 455 |
+
|
| 456 |
+
def _clear_state(self) -> None:
|
| 457 |
+
"""Disconnect all receivers and senders. Useful for tests."""
|
| 458 |
+
self._weak_senders.clear()
|
| 459 |
+
self.receivers.clear()
|
| 460 |
+
self._by_sender.clear()
|
| 461 |
+
self._by_receiver.clear()
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
class NamedSignal(Signal):
|
| 465 |
+
"""A named generic notification emitter. The name is not used by the signal
|
| 466 |
+
itself, but matches the key in the :class:`Namespace` that it belongs to.
|
| 467 |
+
|
| 468 |
+
:param name: The name of the signal within the namespace.
|
| 469 |
+
:param doc: The docstring for the signal.
|
| 470 |
+
"""
|
| 471 |
+
|
| 472 |
+
def __init__(self, name: str, doc: str | None = None) -> None:
|
| 473 |
+
super().__init__(doc)
|
| 474 |
+
|
| 475 |
+
#: The name of this signal.
|
| 476 |
+
self.name: str = name
|
| 477 |
+
|
| 478 |
+
def __repr__(self) -> str:
|
| 479 |
+
base = super().__repr__()
|
| 480 |
+
return f"{base[:-1]}; {self.name!r}>" # noqa: E702
|
| 481 |
+
|
| 482 |
+
|
| 483 |
+
class Namespace(dict[str, NamedSignal]):
|
| 484 |
+
"""A dict mapping names to signals."""
|
| 485 |
+
|
| 486 |
+
def signal(self, name: str, doc: str | None = None) -> NamedSignal:
|
| 487 |
+
"""Return the :class:`NamedSignal` for the given ``name``, creating it
|
| 488 |
+
if required. Repeated calls with the same name return the same signal.
|
| 489 |
+
|
| 490 |
+
:param name: The name of the signal.
|
| 491 |
+
:param doc: The docstring of the signal.
|
| 492 |
+
"""
|
| 493 |
+
if name not in self:
|
| 494 |
+
self[name] = NamedSignal(name, doc)
|
| 495 |
+
|
| 496 |
+
return self[name]
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
class _PNamespaceSignal(t.Protocol):
|
| 500 |
+
def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ...
|
| 501 |
+
|
| 502 |
+
|
| 503 |
+
default_namespace: Namespace = Namespace()
|
| 504 |
+
"""A default :class:`Namespace` for creating named signals. :func:`signal`
|
| 505 |
+
creates a :class:`NamedSignal` in this namespace.
|
| 506 |
+
"""
|
| 507 |
+
|
| 508 |
+
signal: _PNamespaceSignal = default_namespace.signal
|
| 509 |
+
"""Return a :class:`NamedSignal` in :data:`default_namespace` with the given
|
| 510 |
+
``name``, creating it if required. Repeated calls with the same name return the
|
| 511 |
+
same signal.
|
| 512 |
+
"""
|
lib/python3.12/site-packages/blinker/py.typed
ADDED
|
File without changes
|
lib/python3.12/site-packages/einops-0.8.2.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
lib/python3.12/site-packages/einops-0.8.2.dist-info/METADATA
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: einops
|
| 3 |
+
Version: 0.8.2
|
| 4 |
+
Summary: A new flavour of deep learning operations
|
| 5 |
+
Project-URL: Homepage, https://github.com/arogozhnikov/einops
|
| 6 |
+
Author: Alex Rogozhnikov
|
| 7 |
+
License: MIT
|
| 8 |
+
License-File: LICENSE
|
| 9 |
+
Keywords: deep learning,einops,machine learning,neural networks,scientific computations,tensor manipulation
|
| 10 |
+
Classifier: Intended Audience :: Science/Research
|
| 11 |
+
Classifier: License :: OSI Approved :: MIT License
|
| 12 |
+
Classifier: Programming Language :: Python :: 3
|
| 13 |
+
Requires-Python: >=3.9
|
| 14 |
+
Description-Content-Type: text/markdown
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
<!--
|
| 18 |
+
<a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4' >
|
| 19 |
+
<div align="center">
|
| 20 |
+
<img src="http://arogozhnikov.github.io/images/einops/einops_video.gif" alt="einops package examples" />
|
| 21 |
+
<br>
|
| 22 |
+
<small><a href='http://arogozhnikov.github.io/images/einops/einops_video.mp4'>This video in high quality (mp4)</a></small>
|
| 23 |
+
<br><br>
|
| 24 |
+
</div>
|
| 25 |
+
</a>
|
| 26 |
+
-->
|
| 27 |
+
|
| 28 |
+
<!-- this link magically rendered as video on github readme, unfortunately not in docs -->
|
| 29 |
+
|
| 30 |
+
https://user-images.githubusercontent.com/6318811/177030658-66f0eb5d-e136-44d8-99c9-86ae298ead5b.mp4
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# einops
|
| 36 |
+
[](https://github.com/arogozhnikov/einops/actions/workflows/run_tests.yml)
|
| 37 |
+
[](https://badge.fury.io/py/einops)
|
| 38 |
+
[](https://einops.rocks/)
|
| 39 |
+

|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
Flexible and powerful tensor operations for readable and reliable code. <br />
|
| 43 |
+
Supports numpy, pytorch, tensorflow, jax, and [others](#supported-frameworks).
|
| 44 |
+
|
| 45 |
+
## Recent updates:
|
| 46 |
+
|
| 47 |
+
- 0.8.0: tinygrad backend added, small fixes
|
| 48 |
+
- 0.7.0: no-hassle `torch.compile`, support of [array api standard](https://data-apis.org/array-api/latest/API_specification/index.html) and more
|
| 49 |
+
- 10'000🎉: github reports that more than 10k project use einops
|
| 50 |
+
- einops 0.6.1: paddle backend added
|
| 51 |
+
- einops 0.6 introduces [packing and unpacking](https://github.com/arogozhnikov/einops/blob/main/docs/4-pack-and-unpack.ipynb)
|
| 52 |
+
- einops 0.5: einsum is now a part of einops
|
| 53 |
+
- [Einops paper](https://openreview.net/pdf?id=oapKSVM2bcj) is accepted for oral presentation at ICLR 2022 (yes, it worth reading).
|
| 54 |
+
Talk recordings are [available](https://iclr.cc/virtual/2022/oral/6603)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
<details markdown="1">
|
| 58 |
+
<summary>Previous updates</summary>
|
| 59 |
+
- flax and oneflow backend added
|
| 60 |
+
- torch.jit.script is supported for pytorch layers
|
| 61 |
+
- powerful EinMix added to einops. [Einmix tutorial notebook](https://github.com/arogozhnikov/einops/blob/main/docs/3-einmix-layer.ipynb)
|
| 62 |
+
</details>
|
| 63 |
+
|
| 64 |
+
<!--<div align="center">
|
| 65 |
+
<img src="http://arogozhnikov.github.io/images/einops/einops_logo_350x350.png"
|
| 66 |
+
alt="einops package logo" width="250" height="250" />
|
| 67 |
+
<br><br>
|
| 68 |
+
</div> -->
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
## Tweets
|
| 72 |
+
|
| 73 |
+
> In case you need convincing arguments for setting aside time to learn about einsum and einops...
|
| 74 |
+
[Tim Rocktäschel](https://twitter.com/_rockt/status/1230818967205425152)
|
| 75 |
+
|
| 76 |
+
> Writing better code with PyTorch and einops 👌
|
| 77 |
+
[Andrej Karpathy](https://twitter.com/karpathy/status/1290826075916779520)
|
| 78 |
+
|
| 79 |
+
> Slowly but surely, einops is seeping in to every nook and cranny of my code. If you find yourself shuffling around bazillion dimensional tensors, this might change your life
|
| 80 |
+
[Nasim Rahaman](https://twitter.com/nasim_rahaman/status/1216022614755463169)
|
| 81 |
+
|
| 82 |
+
[More testimonials](https://einops.rocks/pages/testimonials/)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
## Contents
|
| 86 |
+
|
| 87 |
+
- [Installation](#Installation)
|
| 88 |
+
- [Documentation](https://einops.rocks/)
|
| 89 |
+
- [Tutorial](#Tutorials)
|
| 90 |
+
- [API micro-reference](#API)
|
| 91 |
+
- [Why use einops](#Why-use-einops-notation)
|
| 92 |
+
- [Supported frameworks](#Supported-frameworks)
|
| 93 |
+
- [Citing](#Citing)
|
| 94 |
+
- [Repository](https://github.com/arogozhnikov/einops) and [discussions](https://github.com/arogozhnikov/einops/discussions)
|
| 95 |
+
|
| 96 |
+
## Installation <a name="Installation"></a>
|
| 97 |
+
|
| 98 |
+
Plain and simple:
|
| 99 |
+
```bash
|
| 100 |
+
pip install einops
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
(`uv pip install einops` works as well)
|
| 104 |
+
|
| 105 |
+
## Tutorials <a name="Tutorials"></a>
|
| 106 |
+
|
| 107 |
+
Tutorials are the most convenient way to see `einops` in action
|
| 108 |
+
|
| 109 |
+
- part 1: [einops fundamentals](https://github.com/arogozhnikov/einops/blob/main/docs/1-einops-basics.ipynb)
|
| 110 |
+
- part 2: [einops for deep learning](https://github.com/arogozhnikov/einops/blob/main/docs/2-einops-for-deep-learning.ipynb)
|
| 111 |
+
- part 3: [packing and unpacking](https://github.com/arogozhnikov/einops/blob/main/docs/4-pack-and-unpack.ipynb)
|
| 112 |
+
- part 4: [improve pytorch code with einops](http://einops.rocks/pytorch-examples.html)
|
| 113 |
+
|
| 114 |
+
Kapil Sachdeva recorded a small [intro to einops](https://www.youtube.com/watch?v=xGy75Pjsqzo).
|
| 115 |
+
|
| 116 |
+
## API <a name="API"></a>
|
| 117 |
+
|
| 118 |
+
`einops` has a minimalistic yet powerful API.
|
| 119 |
+
|
| 120 |
+
Three core operations provided ([einops tutorial](https://github.com/arogozhnikov/einops/blob/main/docs/)
|
| 121 |
+
shows those cover stacking, reshape, transposition, squeeze/unsqueeze, repeat, tile, concatenate, view and numerous reductions)
|
| 122 |
+
|
| 123 |
+
```python
|
| 124 |
+
from einops import rearrange, reduce, repeat
|
| 125 |
+
# rearrange elements according to the pattern
|
| 126 |
+
output_tensor = rearrange(input_tensor, 't b c -> b c t')
|
| 127 |
+
# combine rearrangement and reduction
|
| 128 |
+
output_tensor = reduce(input_tensor, 'b c (h h2) (w w2) -> b h w c', 'mean', h2=2, w2=2)
|
| 129 |
+
# copy along a new axis
|
| 130 |
+
output_tensor = repeat(input_tensor, 'h w -> h w c', c=3)
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
Later additions to the family are `pack` and `unpack` functions (better than stack/split/concatenate):
|
| 134 |
+
|
| 135 |
+
```python
|
| 136 |
+
from einops import pack, unpack
|
| 137 |
+
# pack and unpack allow reversibly 'packing' multiple tensors into one.
|
| 138 |
+
# Packed tensors may be of different dimensionality:
|
| 139 |
+
packed, ps = pack([class_token_bc, image_tokens_bhwc, text_tokens_btc], 'b * c')
|
| 140 |
+
class_emb_bc, image_emb_bhwc, text_emb_btc = unpack(transformer(packed), ps, 'b * c')
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
Finally, einops provides einsum with a support of multi-lettered names:
|
| 144 |
+
|
| 145 |
+
```python
|
| 146 |
+
from einops import einsum, pack, unpack
|
| 147 |
+
# einsum is like ... einsum, generic and flexible dot-product
|
| 148 |
+
# but 1) axes can be multi-lettered 2) pattern goes last 3) works with multiple frameworks
|
| 149 |
+
C = einsum(A, B, 'b t1 head c, b t2 head c -> b head t1 t2')
|
| 150 |
+
```
|
| 151 |
+
|
| 152 |
+
### EinMix
|
| 153 |
+
|
| 154 |
+
`EinMix` is a generic linear layer, perfect for MLP Mixers and similar architectures.
|
| 155 |
+
|
| 156 |
+
### Layers
|
| 157 |
+
|
| 158 |
+
Einops provides layers (`einops` keeps a separate version for each framework) that reflect corresponding functions
|
| 159 |
+
|
| 160 |
+
```python
|
| 161 |
+
from einops.layers.torch import Rearrange, Reduce
|
| 162 |
+
from einops.layers.tensorflow import Rearrange, Reduce
|
| 163 |
+
from einops.layers.flax import Rearrange, Reduce
|
| 164 |
+
from einops.layers.paddle import Rearrange, Reduce
|
| 165 |
+
```
|
| 166 |
+
|
| 167 |
+
<details markdown="1">
|
| 168 |
+
<summary>Example of using layers within a pytorch model</summary>
|
| 169 |
+
Example given for pytorch, but code in other frameworks is almost identical
|
| 170 |
+
|
| 171 |
+
```python
|
| 172 |
+
from torch.nn import Sequential, Conv2d, MaxPool2d, Linear, ReLU
|
| 173 |
+
from einops.layers.torch import Rearrange
|
| 174 |
+
|
| 175 |
+
model = Sequential(
|
| 176 |
+
...,
|
| 177 |
+
Conv2d(6, 16, kernel_size=5),
|
| 178 |
+
MaxPool2d(kernel_size=2),
|
| 179 |
+
# flattening without need to write forward
|
| 180 |
+
Rearrange('b c h w -> b (c h w)'),
|
| 181 |
+
Linear(16*5*5, 120),
|
| 182 |
+
ReLU(),
|
| 183 |
+
Linear(120, 10),
|
| 184 |
+
)
|
| 185 |
+
```
|
| 186 |
+
|
| 187 |
+
No more flatten needed!
|
| 188 |
+
|
| 189 |
+
Additionally, torch layers as those are script-able and compile-able.
|
| 190 |
+
Operations [are torch.compile-able](https://github.com/arogozhnikov/einops/wiki/Using-torch.compile-with-einops),
|
| 191 |
+
but not script-able due to limitations of torch.jit.script.
|
| 192 |
+
</details>
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
## Naming <a name="Naming"></a>
|
| 198 |
+
|
| 199 |
+
`einops` stands for Einstein-Inspired Notation for operations
|
| 200 |
+
(though "Einstein operations" is more attractive and easier to remember).
|
| 201 |
+
|
| 202 |
+
Notation was loosely inspired by Einstein summation (in particular by `numpy.einsum` operation).
|
| 203 |
+
|
| 204 |
+
## Why use `einops` notation?! <a name="Why-use-einops-notation"></a>
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
### Semantic information (being verbose in expectations)
|
| 208 |
+
|
| 209 |
+
```python
|
| 210 |
+
y = x.view(x.shape[0], -1)
|
| 211 |
+
y = rearrange(x, 'b c h w -> b (c h w)')
|
| 212 |
+
```
|
| 213 |
+
While these two lines are doing the same job in *some* context,
|
| 214 |
+
the second one provides information about the input and output.
|
| 215 |
+
In other words, `einops` focuses on interface: *what is the input and output*, not *how* the output is computed.
|
| 216 |
+
|
| 217 |
+
The next operation looks similar:
|
| 218 |
+
|
| 219 |
+
```python
|
| 220 |
+
y = rearrange(x, 'time c h w -> time (c h w)')
|
| 221 |
+
```
|
| 222 |
+
but it gives the reader a hint:
|
| 223 |
+
this is not an independent batch of images we are processing,
|
| 224 |
+
but rather a sequence (video).
|
| 225 |
+
|
| 226 |
+
Semantic information makes the code easier to read and maintain.
|
| 227 |
+
|
| 228 |
+
### Convenient checks
|
| 229 |
+
|
| 230 |
+
Reconsider the same example:
|
| 231 |
+
|
| 232 |
+
```python
|
| 233 |
+
y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
|
| 234 |
+
y = rearrange(x, 'b c h w -> b (c h w)')
|
| 235 |
+
```
|
| 236 |
+
The second line checks that the input has four dimensions,
|
| 237 |
+
but you can also specify particular dimensions.
|
| 238 |
+
That's opposed to just writing comments about shapes since comments don't prevent mistakes,
|
| 239 |
+
not tested, and without code review tend to be outdated
|
| 240 |
+
```python
|
| 241 |
+
y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
|
| 242 |
+
y = rearrange(x, 'b c h w -> b (c h w)', c=256, h=19, w=19)
|
| 243 |
+
```
|
| 244 |
+
|
| 245 |
+
### Result is strictly determined
|
| 246 |
+
|
| 247 |
+
Below we have at least two ways to define the depth-to-space operation
|
| 248 |
+
```python
|
| 249 |
+
# depth-to-space
|
| 250 |
+
rearrange(x, 'b c (h h2) (w w2) -> b (c h2 w2) h w', h2=2, w2=2)
|
| 251 |
+
rearrange(x, 'b c (h h2) (w w2) -> b (h2 w2 c) h w', h2=2, w2=2)
|
| 252 |
+
```
|
| 253 |
+
There are at least four more ways to do it. Which one is used by the framework?
|
| 254 |
+
|
| 255 |
+
These details are ignored, since *usually* it makes no difference,
|
| 256 |
+
but it can make a big difference (e.g. if you use grouped convolutions in the next stage),
|
| 257 |
+
and you'd like to specify this in your code.
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
### Uniformity
|
| 261 |
+
|
| 262 |
+
```python
|
| 263 |
+
reduce(x, 'b c (x dx) -> b c x', 'max', dx=2)
|
| 264 |
+
reduce(x, 'b c (x dx) (y dy) -> b c x y', 'max', dx=2, dy=3)
|
| 265 |
+
reduce(x, 'b c (x dx) (y dy) (z dz) -> b c x y z', 'max', dx=2, dy=3, dz=4)
|
| 266 |
+
```
|
| 267 |
+
These examples demonstrated that we don't use separate operations for 1d/2d/3d pooling,
|
| 268 |
+
those are all defined in a uniform way.
|
| 269 |
+
|
| 270 |
+
Space-to-depth and depth-to space are defined in many frameworks but how about width-to-height? Here you go:
|
| 271 |
+
|
| 272 |
+
```python
|
| 273 |
+
rearrange(x, 'b c h (w w2) -> b c (h w2) w', w2=2)
|
| 274 |
+
```
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
### Framework independent behavior
|
| 278 |
+
|
| 279 |
+
Even simple functions are defined differently by different frameworks
|
| 280 |
+
|
| 281 |
+
```python
|
| 282 |
+
y = x.flatten() # or flatten(x)
|
| 283 |
+
```
|
| 284 |
+
|
| 285 |
+
Suppose `x`'s shape was `(3, 4, 5)`, then `y` has shape ...
|
| 286 |
+
|
| 287 |
+
- numpy, pytorch, cupy, chainer, jax: `(60,)`
|
| 288 |
+
- keras, tensorflow.layers, gluon: `(3, 20)`
|
| 289 |
+
|
| 290 |
+
`einops` works the same way in all frameworks.
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
### Independence of framework terminology
|
| 294 |
+
|
| 295 |
+
Example: `tile` vs `repeat` causes lots of confusion. To copy image along width:
|
| 296 |
+
```python
|
| 297 |
+
np.tile(image, (1, 2)) # in numpy
|
| 298 |
+
image.repeat(1, 2) # pytorch's repeat ~ numpy's tile
|
| 299 |
+
```
|
| 300 |
+
|
| 301 |
+
With einops you don't need to decipher which axis was repeated:
|
| 302 |
+
```python
|
| 303 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in numpy
|
| 304 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in pytorch
|
| 305 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in tf
|
| 306 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in jax
|
| 307 |
+
repeat(image, 'h w -> h (tile w)', tile=2) # in cupy
|
| 308 |
+
... (etc.)
|
| 309 |
+
```
|
| 310 |
+
|
| 311 |
+
[Testimonials](https://einops.rocks/pages/testimonials/) provide users' perspective on the same question.
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
## Supported frameworks <a name="Supported-frameworks"></a>
|
| 315 |
+
|
| 316 |
+
Einops works with ...
|
| 317 |
+
|
| 318 |
+
- [numpy](http://www.numpy.org/)
|
| 319 |
+
- [pytorch](https://pytorch.org/)
|
| 320 |
+
- [tensorflow](https://www.tensorflow.org/)
|
| 321 |
+
- [jax](https://github.com/google/jax)
|
| 322 |
+
- [cupy](https://github.com/cupy/cupy)
|
| 323 |
+
- [flax](https://github.com/google/flax) (community)
|
| 324 |
+
- [paddle](https://github.com/PaddlePaddle/Paddle) (community)
|
| 325 |
+
- [oneflow](https://github.com/Oneflow-Inc/oneflow) (community)
|
| 326 |
+
- [tinygrad](https://github.com/tinygrad/tinygrad) (community)
|
| 327 |
+
- [pytensor](https://github.com/pymc-devs/pytensor) (community)
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
```python
|
| 332 |
+
from einops import rearrange
|
| 333 |
+
=> from einops.array_api import rearrange
|
| 334 |
+
```
|
| 335 |
+
|
| 336 |
+
But actually it is even better: einops can be used with *any* framework that supports
|
| 337 |
+
[Python array API standard](https://data-apis.org/array-api/latest/API_specification/index.html),
|
| 338 |
+
to name a few:
|
| 339 |
+
|
| 340 |
+
- numpy >= 2.0
|
| 341 |
+
- [MLX](https://github.com/ml-explore/mlx) # yes, einops works with apple's framework
|
| 342 |
+
- [pydata/sparse](https://github.com/pydata/sparse) >= 0.15 # and works with sparse tensors
|
| 343 |
+
- [cubed](https://github.com/cubed-dev/cubed) # and with distributed tensors too
|
| 344 |
+
- [quantco/ndonnx](https://github.com/Quantco/ndonnx)
|
| 345 |
+
- jax
|
| 346 |
+
- cupy
|
| 347 |
+
- dask is supported via [array-api-compat](https://github.com/data-apis/array-api-compat)
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
## Development
|
| 351 |
+
|
| 352 |
+
Devcontainer is provided, this environment can be used locally, or on your server,
|
| 353 |
+
or within github codespaces.
|
| 354 |
+
To start with devcontainers in vs code, clone repo, and click 'Reopen in Devcontainer'.
|
| 355 |
+
|
| 356 |
+
Starting from einops 0.8.1, einops distributes tests as a part of package.
|
| 357 |
+
|
| 358 |
+
```bash
|
| 359 |
+
# pip install einops pytest
|
| 360 |
+
python -m einops.tests.run_tests numpy pytorch jax --pip-install
|
| 361 |
+
```
|
| 362 |
+
|
| 363 |
+
`numpy pytorch jax` is an _example_, any subset of testable frameworks can be provided.
|
| 364 |
+
Every framework is tested against numpy, so it is a requirement for tests.
|
| 365 |
+
|
| 366 |
+
Specifying `--pip-install` will install requirements in current virtualenv,
|
| 367 |
+
and should be omitted if dependencies are installed locally.
|
| 368 |
+
|
| 369 |
+
To build/test docs:
|
| 370 |
+
|
| 371 |
+
```bash
|
| 372 |
+
hatch run docs:serve # Serving on http://localhost:8000/
|
| 373 |
+
```
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
## Citing einops <a name="Citing"></a>
|
| 377 |
+
|
| 378 |
+
Please use the following bibtex record
|
| 379 |
+
|
| 380 |
+
```text
|
| 381 |
+
@inproceedings{
|
| 382 |
+
rogozhnikov2022einops,
|
| 383 |
+
title={Einops: Clear and Reliable Tensor Manipulations with Einstein-like Notation},
|
| 384 |
+
author={Alex Rogozhnikov},
|
| 385 |
+
booktitle={International Conference on Learning Representations},
|
| 386 |
+
year={2022},
|
| 387 |
+
url={https://openreview.net/forum?id=oapKSVM2bcj}
|
| 388 |
+
}
|
| 389 |
+
```
|
| 390 |
+
|
| 391 |
+
|
| 392 |
+
## Supported python versions
|
| 393 |
+
|
| 394 |
+
`einops` works with python 3.9 or later.
|
lib/python3.12/site-packages/einops-0.8.2.dist-info/RECORD
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
einops-0.8.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 2 |
+
einops-0.8.2.dist-info/METADATA,sha256=C9ZdsENoikT0opYIwculIcky9_928ji72GlEHhUBJlM,13724
|
| 3 |
+
einops-0.8.2.dist-info/RECORD,,
|
| 4 |
+
einops-0.8.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
| 5 |
+
einops-0.8.2.dist-info/licenses/LICENSE,sha256=MNmENkKW9R_67K1LAe4SfpUlDFBokY1LZvyWIGcj5DQ,1073
|
| 6 |
+
einops/__init__.py,sha256=MwPcYWGHKsJE0Uxlhf7YMv_Sf6vu9W9Y98hy1mRM6zk,438
|
| 7 |
+
einops/__pycache__/__init__.cpython-312.pyc,,
|
| 8 |
+
einops/__pycache__/_backends.cpython-312.pyc,,
|
| 9 |
+
einops/__pycache__/_torch_specific.cpython-312.pyc,,
|
| 10 |
+
einops/__pycache__/array_api.cpython-312.pyc,,
|
| 11 |
+
einops/__pycache__/einops.cpython-312.pyc,,
|
| 12 |
+
einops/__pycache__/packing.cpython-312.pyc,,
|
| 13 |
+
einops/__pycache__/parsing.cpython-312.pyc,,
|
| 14 |
+
einops/_backends.py,sha256=v4snGd66fVWeK0M8e3lNJ9j7_qmd8RMRyJVUTQB5slc,22528
|
| 15 |
+
einops/_torch_specific.py,sha256=QXgLFLDIgDa_Iqtv5gcucEeD3LHALYHJhaXRKgC5f4A,4329
|
| 16 |
+
einops/array_api.py,sha256=7mQ-4yhlWtqmtvcTZyI-pmDOSDbk3qpSCExl4-Vm1-o,5236
|
| 17 |
+
einops/einops.py,sha256=vmx5IWde_ePuzrPDLZZVw_-0Qsare1k8YRRaKt5ZL-8,38079
|
| 18 |
+
einops/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 19 |
+
einops/experimental/__pycache__/__init__.cpython-312.pyc,,
|
| 20 |
+
einops/experimental/__pycache__/indexing.cpython-312.pyc,,
|
| 21 |
+
einops/experimental/indexing.py,sha256=yFFflW3-kV6_5PPJU7_jOJsJBCWCWlE4dGlu9gwSPXo,121
|
| 22 |
+
einops/layers/__init__.py,sha256=jijwEY07Yr3rBx8N5zwZ-5qfbl-KX2BcRDK8NJFDaWA,3705
|
| 23 |
+
einops/layers/__pycache__/__init__.cpython-312.pyc,,
|
| 24 |
+
einops/layers/__pycache__/_einmix.cpython-312.pyc,,
|
| 25 |
+
einops/layers/__pycache__/flax.cpython-312.pyc,,
|
| 26 |
+
einops/layers/__pycache__/keras.cpython-312.pyc,,
|
| 27 |
+
einops/layers/__pycache__/oneflow.cpython-312.pyc,,
|
| 28 |
+
einops/layers/__pycache__/paddle.cpython-312.pyc,,
|
| 29 |
+
einops/layers/__pycache__/tensorflow.cpython-312.pyc,,
|
| 30 |
+
einops/layers/__pycache__/torch.cpython-312.pyc,,
|
| 31 |
+
einops/layers/_einmix.py,sha256=MQr6rymfMw-nzFmhvaLCcee0o7Ai8a1lmluxndWDAjU,11075
|
| 32 |
+
einops/layers/flax.py,sha256=Hk7L31wR2BHL63950-0hy3ivw4rc8NkgGW9jn1AKs-8,2518
|
| 33 |
+
einops/layers/keras.py,sha256=jxD9ZgYLWsKMkCIwojbBNSrY6c1pfXYhE2AMZa0pNXA,217
|
| 34 |
+
einops/layers/oneflow.py,sha256=djcKEZRJrWvxTuSsO4jJVZojieKiDPdUpP4SOpg_zTM,1864
|
| 35 |
+
einops/layers/paddle.py,sha256=YCHffUB4ha7wG-xEOeR9XcTPl48Kr57k_nBEx-J6FVA,1907
|
| 36 |
+
einops/layers/tensorflow.py,sha256=MjGApMbkb_gwAdGya7uGfPZ7olyETsRzbwymfJHii9E,3322
|
| 37 |
+
einops/layers/torch.py,sha256=BV-PzjoijGU9RGea1HCFuIMx4yccicz767M0jJDIH6U,2405
|
| 38 |
+
einops/packing.py,sha256=EZeGLgMRD78hB-0e80ubXvWHukh0_O_wJCf0Hbbdylo,7660
|
| 39 |
+
einops/parsing.py,sha256=vNPYcAs54-KLX1RtbkypGpsSpujzVkj_dQkZlUinLYw,6805
|
| 40 |
+
einops/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 41 |
+
einops/tests/__init__.py,sha256=CpSdrOGBSspTwuG6cAsYMGAwkTq0VuIBrehM7K-SYwU,3531
|
| 42 |
+
einops/tests/__pycache__/__init__.cpython-312.pyc,,
|
| 43 |
+
einops/tests/__pycache__/run_tests.cpython-312.pyc,,
|
| 44 |
+
einops/tests/__pycache__/test_einsum.cpython-312.pyc,,
|
| 45 |
+
einops/tests/__pycache__/test_examples.cpython-312.pyc,,
|
| 46 |
+
einops/tests/__pycache__/test_layers.cpython-312.pyc,,
|
| 47 |
+
einops/tests/__pycache__/test_ops.cpython-312.pyc,,
|
| 48 |
+
einops/tests/__pycache__/test_other.cpython-312.pyc,,
|
| 49 |
+
einops/tests/__pycache__/test_packing.cpython-312.pyc,,
|
| 50 |
+
einops/tests/__pycache__/test_parsing.cpython-312.pyc,,
|
| 51 |
+
einops/tests/run_tests.py,sha256=efJ2apHPOw1BKNIv5qZSNjHpgjSv0rJ4v9hbPbE7yNE,3072
|
| 52 |
+
einops/tests/test_einsum.py,sha256=Nycwg4a-4_Vz7l5f7mj2KIQ7QVs8P2SQIy1rnDcMOG8,11022
|
| 53 |
+
einops/tests/test_examples.py,sha256=6VVkHgov6hpEyoUGbMzFvRfoWTdP1Wr8RPji7G4pPlw,11510
|
| 54 |
+
einops/tests/test_layers.py,sha256=m8RqmBojvVMgr_ET6mhcGpbfYPasg60jUYux7ZlXhSM,18667
|
| 55 |
+
einops/tests/test_ops.py,sha256=4nxEGJWrmEG6cctYHGYuVVdEs5nUN9ziH7ukQYar44M,26884
|
| 56 |
+
einops/tests/test_other.py,sha256=vkWSJr7sn-COewksivTPaLe-GAmzLt7IEZF9TMnt360,13521
|
| 57 |
+
einops/tests/test_packing.py,sha256=AIBNiy8RftTj8dLv1AdNijkTXfrjCOTSw43fuD6Pfjc,10408
|
| 58 |
+
einops/tests/test_parsing.py,sha256=-YAJeJlhDb3U6xYIDRrtm6p4MSNWogeH6l3-np1wUCA,4389
|
lib/python3.12/site-packages/einops-0.8.2.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: hatchling 1.27.0
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
lib/python3.12/site-packages/einops-0.8.2.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2018 Alex Rogozhnikov
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
lib/python3.12/site-packages/functorch/__init__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Facebook, Inc. and its affiliates.
|
| 2 |
+
# All rights reserved.
|
| 3 |
+
#
|
| 4 |
+
# This source code is licensed under the BSD-style license found in the
|
| 5 |
+
# LICENSE file in the root directory of this source tree.
|
| 6 |
+
import torch
|
| 7 |
+
from torch._functorch.deprecated import (
|
| 8 |
+
combine_state_for_ensemble,
|
| 9 |
+
functionalize,
|
| 10 |
+
grad,
|
| 11 |
+
grad_and_value,
|
| 12 |
+
hessian,
|
| 13 |
+
jacfwd,
|
| 14 |
+
jacrev,
|
| 15 |
+
jvp,
|
| 16 |
+
make_functional,
|
| 17 |
+
make_functional_with_buffers,
|
| 18 |
+
vjp,
|
| 19 |
+
vmap,
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
# utilities. Maybe these should go in their own namespace in the future?
|
| 23 |
+
from torch._functorch.make_functional import (
|
| 24 |
+
FunctionalModule,
|
| 25 |
+
FunctionalModuleWithBuffers,
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
# Was never documented
|
| 29 |
+
from torch._functorch.python_key import make_fx
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# Top-level APIs. Please think carefully before adding something to the
|
| 33 |
+
# top-level namespace:
|
| 34 |
+
# - private helper functions should go into torch._functorch
|
| 35 |
+
# - very experimental things should go into functorch.experimental
|
| 36 |
+
# - compilation related things should go into functorch.compile
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
__version__ = torch.__version__
|
lib/python3.12/site-packages/functorch/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (756 Bytes). View file
|
|
|
lib/python3.12/site-packages/functorch/_src/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/functorch/_src/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (193 Bytes). View file
|
|
|
lib/python3.12/site-packages/functorch/_src/aot_autograd/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file has moved to under torch/_functorch. It is not public API.
|
| 2 |
+
# If you are not a PyTorch developer and you are relying on the following
|
| 3 |
+
# imports, please file an issue.
|
| 4 |
+
from torch._functorch.aot_autograd import (
|
| 5 |
+
aot_autograd_decompositions,
|
| 6 |
+
KNOWN_TYPES,
|
| 7 |
+
PytreeThunk,
|
| 8 |
+
)
|
lib/python3.12/site-packages/functorch/_src/aot_autograd/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (341 Bytes). View file
|
|
|
lib/python3.12/site-packages/functorch/_src/eager_transforms/__init__.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file has moved to under torch/_functorch. It is not public API.
|
| 2 |
+
# If you are not a PyTorch developer and you are relying on the following
|
| 3 |
+
# imports, please file an issue.
|
| 4 |
+
from torch._functorch.eager_transforms import (
|
| 5 |
+
_assert_wrapped_functional,
|
| 6 |
+
_unwrap_functional_tensor,
|
| 7 |
+
)
|
lib/python3.12/site-packages/functorch/_src/eager_transforms/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (340 Bytes). View file
|
|
|
lib/python3.12/site-packages/functorch/_src/make_functional/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file has moved to under torch/_functorch. It is not public API.
|
| 2 |
+
# If you are not a PyTorch developer and you are relying on the following
|
| 3 |
+
# imports, please file an issue.
|
| 4 |
+
from torch._functorch.make_functional import _swap_state
|
lib/python3.12/site-packages/functorch/_src/make_functional/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (282 Bytes). View file
|
|
|
lib/python3.12/site-packages/functorch/_src/vmap/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file has moved to under torch/_functorch. It is not public API.
|
| 2 |
+
# If you are not a PyTorch developer and you are relying on the following
|
| 3 |
+
# imports, please file an issue.
|
| 4 |
+
from torch._functorch.vmap import (
|
| 5 |
+
_add_batch_dim,
|
| 6 |
+
_broadcast_to_and_flatten,
|
| 7 |
+
_create_batched_inputs,
|
| 8 |
+
_get_name,
|
| 9 |
+
_process_batched_inputs,
|
| 10 |
+
_remove_batch_dim,
|
| 11 |
+
_unwrap_batched,
|
| 12 |
+
_validate_and_get_batch_size,
|
| 13 |
+
Tensor,
|
| 14 |
+
tree_flatten,
|
| 15 |
+
tree_unflatten,
|
| 16 |
+
)
|
lib/python3.12/site-packages/functorch/_src/vmap/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (559 Bytes). View file
|
|
|
lib/python3.12/site-packages/functorch/compile/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from torch._functorch import config
|
| 2 |
+
from torch._functorch.aot_autograd import (
|
| 3 |
+
aot_function,
|
| 4 |
+
aot_module,
|
| 5 |
+
aot_module_simplified,
|
| 6 |
+
compiled_function,
|
| 7 |
+
compiled_module,
|
| 8 |
+
get_aot_compilation_context,
|
| 9 |
+
get_aot_graph_name,
|
| 10 |
+
get_graph_being_compiled,
|
| 11 |
+
make_boxed_compiler,
|
| 12 |
+
make_boxed_func,
|
| 13 |
+
)
|
| 14 |
+
from torch._functorch.compilers import (
|
| 15 |
+
debug_compile,
|
| 16 |
+
default_decompositions,
|
| 17 |
+
draw_graph_compile,
|
| 18 |
+
memory_efficient_fusion,
|
| 19 |
+
nnc_jit,
|
| 20 |
+
nop,
|
| 21 |
+
print_compile,
|
| 22 |
+
ts_compile,
|
| 23 |
+
)
|
| 24 |
+
from torch._functorch.fx_minifier import minifier
|
| 25 |
+
from torch._functorch.partitioners import (
|
| 26 |
+
default_partition,
|
| 27 |
+
draw_graph,
|
| 28 |
+
min_cut_rematerialization_partition,
|
| 29 |
+
)
|
| 30 |
+
from torch._functorch.python_key import pythonkey_decompose
|
lib/python3.12/site-packages/functorch/compile/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (1.12 kB). View file
|
|
|
lib/python3.12/site-packages/functorch/dim/__init__.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import dis
|
| 2 |
+
import inspect
|
| 3 |
+
from typing import Sequence, Union
|
| 4 |
+
|
| 5 |
+
import functorch._C
|
| 6 |
+
import torch
|
| 7 |
+
from functorch._C import dim as _C
|
| 8 |
+
|
| 9 |
+
from .tree_map import tree_flatten, tree_map
|
| 10 |
+
from .wrap_type import wrap_type
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
_C._patch_tensor_class()
|
| 14 |
+
dims, DimList, dimlists = _C.dims, _C.DimList, _C.dimlists
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class DimensionMismatchError(Exception):
|
| 18 |
+
pass
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class DimensionBindError(Exception):
|
| 22 |
+
pass
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
from . import op_properties
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# use dict to avoid writing C++ bindings for set
|
| 29 |
+
pointwise = dict.fromkeys(op_properties.pointwise, True)
|
| 30 |
+
|
| 31 |
+
use_c = True
|
| 32 |
+
if not use_c:
|
| 33 |
+
from . import reference
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class _Tensor:
|
| 37 |
+
# fast path around slow wrapping/unwrapping logic for simply queries used
|
| 38 |
+
# by the implementation...
|
| 39 |
+
|
| 40 |
+
@property
|
| 41 |
+
def dims(self):
|
| 42 |
+
return tuple(d for d in self._levels if isinstance(d, Dim))
|
| 43 |
+
|
| 44 |
+
def dim(self):
|
| 45 |
+
return self.ndim
|
| 46 |
+
|
| 47 |
+
if use_c:
|
| 48 |
+
__torch_function__ = classmethod(_C.__torch_function__)
|
| 49 |
+
expand = _C._instancemethod(_C.expand)
|
| 50 |
+
else:
|
| 51 |
+
__torch_function__ = reference.__torch_function__
|
| 52 |
+
expand = reference.expand
|
| 53 |
+
|
| 54 |
+
index = _C._instancemethod(_C.index)
|
| 55 |
+
|
| 56 |
+
def __repr__(self):
|
| 57 |
+
tensor, levels, ndim = self._tensor, self._levels, self.ndim
|
| 58 |
+
return f"{tensor}\nwith dims={tuple(l + ndim if isinstance(l, int) else l for l in levels)} sizes={tuple(tensor.size())}"
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
TensorLike = (_Tensor, torch.Tensor)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
class Dim(_C.Dim, _Tensor):
|
| 65 |
+
# note that _C.Dim comes before tensor because we want the Dim API for things like size to take precendence.
|
| 66 |
+
# Tensor defines format, but we want to print Dims with special formatting
|
| 67 |
+
__format__ = object.__format__
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
class Tensor(_Tensor, _C.Tensor):
|
| 71 |
+
if not use_c:
|
| 72 |
+
from_batched = staticmethod(_C.Tensor_from_batched)
|
| 73 |
+
from_positional = staticmethod(_C.Tensor_from_positional)
|
| 74 |
+
sum = _C._instancemethod(_C.Tensor_sum)
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def cat(tensors, dim, new_dim):
|
| 78 |
+
n = dims()
|
| 79 |
+
return stack(tensors, n, dim).index([n, dim], new_dim)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
if use_c:
|
| 83 |
+
_wrap = _C._wrap
|
| 84 |
+
|
| 85 |
+
def _def(name, *args, **kwargs):
|
| 86 |
+
orig = getattr(torch.Tensor, name)
|
| 87 |
+
setattr(_Tensor, name, _C._instancemethod(_wrap(orig, *args, **kwargs)))
|
| 88 |
+
|
| 89 |
+
t__getitem__ = _C._instancemethod(_C.__getitem__)
|
| 90 |
+
stack = _C.stack
|
| 91 |
+
split = _C._instancemethod(_C.split)
|
| 92 |
+
else:
|
| 93 |
+
_wrap, _def = reference._wrap, reference._def
|
| 94 |
+
t__getitem__ = reference.t__getitem__
|
| 95 |
+
stack = reference.stack
|
| 96 |
+
split = reference.split
|
| 97 |
+
|
| 98 |
+
# note: there is no python reference
|
| 99 |
+
t__setitem__ = _C._instancemethod(_C.__setitem__)
|
| 100 |
+
# this is patched in the C API because otherwise torch.Tensor will
|
| 101 |
+
# no longer be considered a sequence and things will break
|
| 102 |
+
# torch.Tensor.__getitem__ = t__getitem__
|
| 103 |
+
|
| 104 |
+
_Tensor.__getitem__ = t__getitem__
|
| 105 |
+
# torch.Tensor.__setitem__ = t__setitem__
|
| 106 |
+
_Tensor.__setitem__ = t__setitem__
|
| 107 |
+
|
| 108 |
+
torch.Tensor.split = split
|
| 109 |
+
_Tensor.split = split
|
| 110 |
+
torch.Tensor.expand = _C._instancemethod(_C.expand)
|
| 111 |
+
torch.Tensor.index = _C._instancemethod(_C.index)
|
| 112 |
+
wrap_type(use_c, _Tensor, torch.Tensor, _Tensor.__torch_function__)
|
| 113 |
+
del _Tensor.ndim
|
| 114 |
+
|
| 115 |
+
if use_c:
|
| 116 |
+
_Tensor.order = _C._instancemethod(_C.order)
|
| 117 |
+
else:
|
| 118 |
+
_Tensor.order = reference.positional
|
| 119 |
+
|
| 120 |
+
_def("mean")
|
| 121 |
+
_def("sum")
|
| 122 |
+
_def("all")
|
| 123 |
+
_def("amax")
|
| 124 |
+
_def("amin")
|
| 125 |
+
_def("aminmax")
|
| 126 |
+
_def("any")
|
| 127 |
+
_def("count_nonzero")
|
| 128 |
+
_def("logsumexp")
|
| 129 |
+
_def("nanmean")
|
| 130 |
+
_def("nansum")
|
| 131 |
+
_def("prod")
|
| 132 |
+
_def("std", keepdim_offset=2)
|
| 133 |
+
_def("var", keepdim_offset=2)
|
| 134 |
+
_def("max", single_dim=True)
|
| 135 |
+
_def("min", single_dim=True)
|
| 136 |
+
_def("argmax", single_dim=True)
|
| 137 |
+
_def("argmin", single_dim=True)
|
| 138 |
+
_def("kthvalue", single_dim=True)
|
| 139 |
+
_def("median", single_dim=True)
|
| 140 |
+
_def("nanmedian", single_dim=True)
|
| 141 |
+
_def("mode", single_dim=True)
|
| 142 |
+
_def("sort", reduce=False)
|
| 143 |
+
_def("argsort", reduce=False)
|
| 144 |
+
_def("unbind", single_dim=True)
|
| 145 |
+
_def("chunk", dim_offset=1, reduce=False)
|
| 146 |
+
_def("cummax", single_dim=True, reduce=False)
|
| 147 |
+
_def("cummin", single_dim=True, reduce=False)
|
| 148 |
+
_def("cumprod", single_dim=True, reduce=False)
|
| 149 |
+
_def("cumprod_", single_dim=True, reduce=False)
|
| 150 |
+
_def("cumsum", single_dim=True, reduce=False)
|
| 151 |
+
_def("cumsum_", single_dim=True, reduce=False)
|
| 152 |
+
_def("logcumsumexp", single_dim=True, reduce=False)
|
| 153 |
+
_def("renorm", dim_offset=1, single_dim=True, reduce=False)
|
| 154 |
+
_def("softmax", single_dim=True, reduce=False)
|
| 155 |
+
softmax = _wrap(torch.nn.functional.softmax, single_dim=True, reduce=False)
|
| 156 |
+
|
| 157 |
+
# stuff to handle in the future, because they require special
|
| 158 |
+
# binding logic for dims
|
| 159 |
+
# cross
|
| 160 |
+
# diag_embed
|
| 161 |
+
# diagonal
|
| 162 |
+
# diagonal_scatter
|
| 163 |
+
# diff
|
| 164 |
+
# nanquantile
|
| 165 |
+
# quantile
|
| 166 |
+
# roll
|
| 167 |
+
# rot90
|
| 168 |
+
# topk (new dimes on output)
|
| 169 |
+
# should these all be subsumed by inplace indexing?
|
| 170 |
+
# index_add_
|
| 171 |
+
# index_add
|
| 172 |
+
# index_copy
|
| 173 |
+
# index_copy_
|
| 174 |
+
# index_fill
|
| 175 |
+
# index_fill_
|
| 176 |
+
# index_select
|
| 177 |
+
# scatter
|
| 178 |
+
# scatter_
|
| 179 |
+
# scatter_add
|
| 180 |
+
# scatter_add_
|
| 181 |
+
# scatter_reduce
|
lib/python3.12/site-packages/functorch/dim/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (7.16 kB). View file
|
|
|
lib/python3.12/site-packages/functorch/dim/__pycache__/batch_tensor.cpython-312.pyc
ADDED
|
Binary file (1.13 kB). View file
|
|
|
lib/python3.12/site-packages/functorch/dim/__pycache__/delayed_mul_tensor.cpython-312.pyc
ADDED
|
Binary file (4.95 kB). View file
|
|
|
lib/python3.12/site-packages/functorch/dim/__pycache__/dim.cpython-312.pyc
ADDED
|
Binary file (6.36 kB). View file
|
|
|
lib/python3.12/site-packages/functorch/dim/__pycache__/magic_trace.cpython-312.pyc
ADDED
|
Binary file (2.26 kB). View file
|
|
|