Skip to content

Commit 36e6f3e

Browse files
authored
Dask integration (#14)
* better handling of non core dims in einops * add einops daskbackend class * add some docs about dask support * fix checks and docs * update changelog
1 parent 53f237e commit 36e6f3e

File tree

9 files changed

+102
-15
lines changed

9 files changed

+102
-15
lines changed

.pylintrc

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs=1
2222

2323
# List of plugins (as comma separated values of python modules names) to load,
2424
# usually to register additional checkers.
25-
load-plugins=
25+
load-plugins=pylint.extensions.no_self_use
2626

2727
# Pickle collected data for later comparisons.
2828
persistent=yes
@@ -60,7 +60,6 @@ disable=missing-docstring,
6060
too-many-branches,
6161
too-many-statements,
6262
too-few-public-methods,
63-
bad-continuation,
6463
import-outside-toplevel,
6564
unsubscriptable-object,
6665
ungrouped-imports,
@@ -135,13 +134,6 @@ max-line-length=100
135134
# Maximum number of lines in a module
136135
max-module-lines=1000
137136

138-
# List of optional constructs for which whitespace checking is disabled. `dict-
139-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
140-
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
141-
# `empty-line` allows space-only lines.
142-
no-space-check=trailing-comma,
143-
dict-separator
144-
145137
# Allow the body of a class to be on the same line as the declaration if body
146138
# contains single statement.
147139
single-line-class-stmt=no
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{{ fullname | escape | underline}}
2+
3+
.. currentmodule:: {{ module }}
4+
5+
.. autoclass:: {{ objname }}

docs/source/api/einops.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@
1414
raw_reduce
1515
```
1616

17+
```{eval-rst}
18+
.. autosummary::
19+
:toctree: generated/
20+
:template: class-no-members
21+
22+
DaskBackend
23+
```

docs/source/changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Change Log
22

3+
## v.0.x.x (Unreleased)
4+
### New features
5+
* Add `DaskBackend` to support using einops functions on Dask backed DataArrays {pull}`14`
6+
7+
### Documentation
8+
* Add dask support guide {pull}`14`
9+
310
## v0.2.2 (2022 Apr 3)
411
### Maintenance and fixes
512
* Add license file to `pyproject.toml` and remove ignored manifest file {pull}`13`

docs/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@
104104
}
105105

106106
intersphinx_mapping = {
107-
"arviz": ("https://arviz-devs.github.io/arviz", None),
107+
"arviz": ("https://python.arviz.org/en/latest/", None),
108108
"dask": ("https://docs.dask.org/en/latest/", None),
109109
"numba": ("https://numba.pydata.org/numba-doc/dev", None),
110110
"numpy": ("https://numpy.org/doc/stable/", None),
111111
"python": ("https://docs.python.org/3/", None),
112112
"scipy": ("https://docs.scipy.org/doc/scipy/reference/", None),
113-
"xarray": ("http://xarray.pydata.org/en/stable/", None),
113+
"xarray": ("http://docs.xarray.dev/en/stable/", None),
114114
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Dask support
2+
Like xarray, xarray-einstats also aims to support using their functions on
3+
NumPy or Dask backed xarray objects.
4+
5+
Functions in xarray-einstats should support Dask backed xarray objects.
6+
But Dask support is still not extensively tested.
7+
If you have issues using Dask backed xarray objects please open an [issue](https://github.com/arviz-devs/xarray-einstats)
8+
9+
:::{seealso}
10+
{ref}`Xarray documentation <xarray:dask>`
11+
12+
[Dask examples](https://examples.dask.org/xarray.html)
13+
:::

docs/source/tutorials/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ In construction
88
stats_tutorial
99
linalg_tutorial
1010
einops-basics-port
11+
dask_support
1112
:::

src/xarray_einstats/einops.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import einops
1010
import xarray as xr
1111

12-
__all__ = ["rearrange", "raw_rearrange", "reduce", "raw_reduce"]
12+
__all__ = ["rearrange", "raw_rearrange", "reduce", "raw_reduce", "DaskBackend"]
1313

1414

1515
class DimHandler:
@@ -223,8 +223,15 @@ def rearrange(da, out_dims, in_dims=None, **kwargs):
223223
missing_in_dims = [dim for dim in da_dims if dim not in in_names]
224224
expected_missing = set(out_dims).union(in_names).difference(in_dims)
225225
missing_out_dims = [dim for dim in da_dims if dim not in expected_missing]
226-
pattern = f"{handler.get_names(missing_in_dims)} {in_pattern} ->\
227-
{handler.get_names(missing_out_dims)} {out_pattern}"
226+
227+
# avoid using dimensions as core dims unnecesarly
228+
non_core_dims = [dim for dim in missing_in_dims if dim in missing_out_dims]
229+
missing_in_dims = [dim for dim in missing_in_dims if dim not in non_core_dims]
230+
missing_out_dims = [dim for dim in missing_out_dims if dim not in non_core_dims]
231+
232+
non_core_pattern = handler.get_names(non_core_dims)
233+
pattern = f"{non_core_pattern} {handler.get_names(missing_in_dims)} {in_pattern} ->\
234+
{non_core_pattern} {handler.get_names(missing_out_dims)} {out_pattern}"
228235

229236
axes_lengths = {
230237
handler.rename_kwarg(k): v for k, v in kwargs.items() if k in out_names + out_dims
@@ -395,3 +402,58 @@ def raw_reduce(da, pattern, reduction, **kwargs):
395402
in_dims = None
396403
out_dims = translate_pattern(out_pattern)
397404
return reduce(da, reduction, out_dims=out_dims, in_dims=in_dims, **kwargs)
405+
406+
407+
class DaskBackend(einops._backends.AbstractBackend): # pylint: disable=protected-access
408+
"""Dask backend class for einops.
409+
410+
It should be imported before using functions of :mod:`xarray_einstats.einops`
411+
on Dask backed DataArrays.
412+
It doesn't need to be initialized or used explicitly
413+
414+
Notes
415+
-----
416+
Class created from the advise on
417+
`issue einops#120 <https://github.com/arogozhnikov/einops/issues/120>`_ about Dask support.
418+
And from reading
419+
`einops/_backends <https://github.com/arogozhnikov/einops/blob/master/einops/_backends.py>`_,
420+
the source of the AbstractBackend class of which DaskBackend is a subclass.
421+
"""
422+
423+
# pylint: disable=no-self-use
424+
framework_name = "dask"
425+
426+
def __init__(self):
427+
"""Initialize DaskBackend.
428+
429+
Contains the imports to avoid errors when dask is not installed
430+
"""
431+
import dask.array as dsar
432+
433+
self.dsar = dsar
434+
435+
def is_appropriate_type(self, tensor):
436+
"""Recognizes tensors it can handle."""
437+
return isinstance(tensor, self.dsar.core.Array)
438+
439+
def from_numpy(self, x): # noqa: D102
440+
return self.dsar.array(x)
441+
442+
def to_numpy(self, x): # noqa: D102
443+
return x.compute()
444+
445+
def arange(self, start, stop): # noqa: D102
446+
# supplementary method used only in testing, so should implement CPU version
447+
return self.dsar.arange(start, stop)
448+
449+
def stack_on_zeroth_dimension(self, tensors: list): # noqa: D102
450+
return self.dsar.stack(tensors)
451+
452+
def tile(self, x, repeats): # noqa: D102
453+
return self.dsar.tile(x, repeats)
454+
455+
def is_float_type(self, x): # noqa: D102
456+
return x.dtype in ("float16", "float32", "float64", "float128")
457+
458+
def add_axis(self, x, new_position): # noqa: D102
459+
return self.dsar.expand_dims(x, new_position)

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,4 @@ commands =
9292
skip_install = true
9393
allowlist_externals = gnome-open
9494
commands =
95-
gnome-open "{toxworkdir}/docs_out/index.html"
95+
python -m webbrowser "{toxworkdir}/docs_out/index.html"

0 commit comments

Comments
 (0)