From 19b678574728bbd34f301ae8f069fe595d9ac904 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Thu, 21 Nov 2024 10:10:33 -0800 Subject: [PATCH 1/4] MAINT: remove NumPy dependency --- marray/__init__.py | 55 ++++++++++++++++++++++++++++++++++++---------- pyproject.toml | 4 ++-- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/marray/__init__.py b/marray/__init__.py index b89c5cd..6cfd068 100644 --- a/marray/__init__.py +++ b/marray/__init__.py @@ -4,7 +4,7 @@ __version__ = "0.0.4" -import numpy as np # temporarily used in __repr__ and __str__ +import re def masked_array(xp): @@ -79,20 +79,51 @@ def __setitem__(self, key, other): self.mask[key] = getattr(other, 'mask', False) return self.data.__setitem__(key, getattr(other, 'data', other)) + def _mask_integer(self, fun): + data = xp.asarray(self.data, dtype=xp.int64, copy=True) + min = xp.min(self.data) + sentinel = min - 1 + assert not xp.any(data == sentinel) + data[self.mask] = sentinel + mask = "-" * len(str(sentinel)) + temp = fun(data).replace(str(sentinel), mask) + if self.dtype != xp.int64: + temp = temp[:-1] + f", dtype={self.dtype})" + return temp + + def _mask_bool(self, fun): + data = xp.asarray(self.data, dtype=xp.uint16, copy=True) + data[data == 0] = 11111 + data[data == 1] = 22222 + data[self.mask] = 33333 + temp = fun(data).replace("11111", "False") + temp = temp.replace("22222", " True") + temp = temp.replace("33333", "-----") + return temp.replace("uint16", str(self.dtype)) + + def _mask_float(self, fun): + data = xp.asarray(self.data, copy=True) + data[data == 0] = 0 + data[self.mask] = float("-0") + pattern = re.compile(r'-0(?:\.0+)?(?:[eE][+-]?\d+)?\.?') + return pattern.sub('---', fun(data)) + + def _mask_string(self, fun): + if xp.isdtype(self.dtype, "bool"): + return self._mask_bool(fun) + elif xp.isdtype(self.dtype, "integral"): + return self._mask_integer(fun) + elif xp.isdtype(self.dtype, "real floating"): + return self._mask_float(fun) + else: + raise NotImplementedError("No complex right now.") + ## Visualization ## def __repr__(self): - # temporary: fix for CuPy - # eventually: rewrite to avoid masked array - data = np.asarray(self.data) - mask = np.asarray(self.mask) - return np.ma.masked_array(data, mask).__repr__() + return self._mask_string(repr) def __str__(self): - # temporary: fix for CuPy - # eventually: rewrite to avoid masked array - data = np.asarray(self.data) - mask = np.asarray(self.mask) - return np.ma.masked_array(data, mask).__str__() + return self._mask_string(str) ## Linear Algebra Methods ## def __matmul__(self, other): @@ -444,7 +475,7 @@ def var(x, axis=None, correction=0, keepdims=False): mod.count = count mod.mean = mean mod.var = var - mod.std = lambda *args, **kwargs: np.sqrt(mod.var(*args, **kwargs)) + mod.std = lambda *args, **kwargs: mod.var(*args, **kwargs)**0.5 search_names = ['argmax', 'argmin'] statfun_names = ['max', 'min', 'sum', 'prod'] diff --git a/pyproject.toml b/pyproject.toml index 5f12446..050cbb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,11 +14,11 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dynamic = ["version", "description"] -dependencies = ["numpy"] +dependencies = [] requires-python = ">=3.10" [project.optional-dependencies] -test = ["pytest"] +test = ["numpy", "pytest"] [project.urls] Home = "https://github.com/mdhaber/marray" From 480cb492063794ddd2f33f0e7116dfa0b87db1d5 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Thu, 21 Nov 2024 11:24:45 -0800 Subject: [PATCH 2/4] MAINT: simplify __repr__, __str__ --- marray/__init__.py | 55 +++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/marray/__init__.py b/marray/__init__.py index 6cfd068..b61e5e5 100644 --- a/marray/__init__.py +++ b/marray/__init__.py @@ -4,7 +4,7 @@ __version__ = "0.0.4" -import re +import textwrap def masked_array(xp): @@ -79,51 +79,26 @@ def __setitem__(self, key, other): self.mask[key] = getattr(other, 'mask', False) return self.data.__setitem__(key, getattr(other, 'data', other)) - def _mask_integer(self, fun): - data = xp.asarray(self.data, dtype=xp.int64, copy=True) - min = xp.min(self.data) - sentinel = min - 1 - assert not xp.any(data == sentinel) - data[self.mask] = sentinel - mask = "-" * len(str(sentinel)) - temp = fun(data).replace(str(sentinel), mask) - if self.dtype != xp.int64: - temp = temp[:-1] + f", dtype={self.dtype})" - return temp - - def _mask_bool(self, fun): - data = xp.asarray(self.data, dtype=xp.uint16, copy=True) - data[data == 0] = 11111 - data[data == 1] = 22222 - data[self.mask] = 33333 - temp = fun(data).replace("11111", "False") - temp = temp.replace("22222", " True") - temp = temp.replace("33333", "-----") - return temp.replace("uint16", str(self.dtype)) - - def _mask_float(self, fun): - data = xp.asarray(self.data, copy=True) - data[data == 0] = 0 - data[self.mask] = float("-0") - pattern = re.compile(r'-0(?:\.0+)?(?:[eE][+-]?\d+)?\.?') - return pattern.sub('---', fun(data)) - - def _mask_string(self, fun): - if xp.isdtype(self.dtype, "bool"): - return self._mask_bool(fun) - elif xp.isdtype(self.dtype, "integral"): - return self._mask_integer(fun) - elif xp.isdtype(self.dtype, "real floating"): - return self._mask_float(fun) + def _data_mask_string(self, fun): + data_str = fun(self.data) + ", " + mask_str = fun(self.mask) + if len(data_str) + len(mask_str) <= 66: + join_char = "" + components = ["MaskedArray(", data_str, mask_str, ")"] else: - raise NotImplementedError("No complex right now.") + join_char = "\n" + components = ["MaskedArray(", + textwrap.indent(data_str, " " * 4), + textwrap.indent(mask_str, " " * 4), + ")"] + return join_char.join(components) ## Visualization ## def __repr__(self): - return self._mask_string(repr) + return self._data_mask_string(repr) def __str__(self): - return self._mask_string(str) + return self._data_mask_string(str) ## Linear Algebra Methods ## def __matmul__(self, other): From bb606d0b51d02a0ee5c4b79c1750c5adda57dd82 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Sun, 24 Nov 2024 16:06:47 -0800 Subject: [PATCH 3/4] STY: use f-strings for simplicity --- marray/__init__.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/marray/__init__.py b/marray/__init__.py index a181a32..cd60c93 100644 --- a/marray/__init__.py +++ b/marray/__init__.py @@ -87,18 +87,12 @@ def __setitem__(self, key, other): return self.data.__setitem__(key, getattr(other, 'data', other)) def _data_mask_string(self, fun): - data_str = fun(self.data) + ", " + data_str = fun(self.data) mask_str = fun(self.mask) if len(data_str) + len(mask_str) <= 66: - join_char = "" - components = ["MaskedArray(", data_str, mask_str, ")"] + return f"MaskedArray({data_str}, {mask_str})" else: - join_char = "\n" - components = ["MaskedArray(", - textwrap.indent(data_str, " " * 4), - textwrap.indent(mask_str, " " * 4), - ")"] - return join_char.join(components) + return f"MaskedArray(\n {data_str},\n {mask_str}\n)" ## Visualization ## def __repr__(self): @@ -194,6 +188,8 @@ class module: mod = module() + mod.MaskedArray = MaskedArray + ## Constants ## constant_names = ['e', 'inf', 'nan', 'newaxis', 'pi'] for name in constant_names: From 5fcaf6f56f01ae4040b78045a6a0f7cb2b55841a Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Sun, 24 Nov 2024 16:08:20 -0800 Subject: [PATCH 4/4] Update marray/__init__.py --- marray/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/marray/__init__.py b/marray/__init__.py index cd60c93..0eb32e0 100644 --- a/marray/__init__.py +++ b/marray/__init__.py @@ -4,7 +4,6 @@ __version__ = "0.0.4" -import textwrap def masked_array(xp):