Skip to content

Commit 630d437

Browse files
committed
Fixes to linspace and optimization of arange
1 parent 9e973ec commit 630d437

File tree

4 files changed

+27
-31
lines changed

4 files changed

+27
-31
lines changed

src/blosc2/lazyexpr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2545,7 +2545,7 @@ def __ror__(self, value):
25452545
return self.update_expr(new_op=(value, "|", self))
25462546

25472547
def __invert__(self):
2548-
return self.update_expr(new_op=(None, "~", self))
2548+
return self.update_expr(new_op=(self, "~", None))
25492549

25502550
def __pow__(self, value):
25512551
return self.update_expr(new_op=(self, "**", value))

src/blosc2/ndarray.py

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3701,19 +3701,23 @@ def arange_fill(inputs, output, offset):
37013701
start, _, step = inputs
37023702
start += offset[0] * step
37033703
stop = start + lout * step
3704-
# use linspace to have finer control over exclusion of endpoint
3705-
output[:] = np.linspace(start, stop, num=lout, endpoint=False, dtype=output.dtype)
3704+
if (stop - start) // step == lout: # USE ARANGE IF POSSIBLE (2X FASTER)
3705+
output[:] = np.arange(start, stop, step, dtype=output.dtype)
3706+
else: # use linspace to have finer control over exclusion of endpoint for float types
3707+
output[:] = np.linspace(start, stop, lout, endpoint=False, dtype=output.dtype)
3708+
3709+
NUM = int((stop - start) / step)
37063710

37073711
if step is None: # not array-api compliant but for backwards compatibility
37083712
step = 1
37093713
if stop is None:
37103714
stop = start
37113715
start = 0
3712-
if not shape:
3713-
shape = (int((stop - start) / step),)
3716+
if shape is None:
3717+
shape = (max(NUM, 0),)
37143718
else:
37153719
# Check that the shape is consistent with the start, stop and step values
3716-
if math.prod(shape) != int((stop - start) / step):
3720+
if math.prod(shape) != NUM:
37173721
raise ValueError("The shape is not consistent with the start, stop and step values")
37183722
if dtype is None:
37193723
dtype = (
@@ -3723,13 +3727,10 @@ def arange_fill(inputs, output, offset):
37233727
)
37243728
dtype = _check_dtype(dtype)
37253729

3726-
if is_inside_new_expr():
3730+
if is_inside_new_expr() or NUM < 0:
37273731
# We already have the dtype and shape, so return immediately
37283732
return blosc2.zeros(shape, dtype=dtype)
37293733

3730-
if (stop - start) / step < 0: # return empty array
3731-
return blosc2.empty((0,), dtype=dtype)
3732-
37333734
lshape = (math.prod(shape),)
37343735
lazyarr = blosc2.lazyudf(arange_fill, (start, stop, step), dtype=dtype, shape=lshape)
37353736

@@ -3795,26 +3796,25 @@ def linspace_fill(inputs, output, offset):
37953796
step = (stop - start) / (num - 1) if endpoint and num > 1 else (stop - start) / num
37963797
# Compute proper start and stop values for the current chunk
37973798
# except for 0th iter, have already included start_ in prev iter
3798-
start_ = start + offset[0] * step if offset[0] == 0 else start + (offset[0] + 1) * step
3799+
start_ = start + offset[0] * step
37993800
stop_ = start_ + lout * step
3800-
if offset[0] + lout == num: # reached end
3801+
if offset[0] + lout == num: # reached end, include stop if necessary
38013802
output[:] = np.linspace(start_, stop, lout, endpoint=endpoint, dtype=output.dtype)
3802-
else: # always include start and stop
3803-
output[:] = np.linspace(start_, stop_, lout, endpoint=True, dtype=output.dtype)
3804-
3805-
if num < 0:
3806-
raise ValueError("num must be nonnegative.")
3803+
else:
3804+
output[:] = np.linspace(start_, stop_, lout, endpoint=False, dtype=output.dtype)
38073805

3808-
if shape is None and num is None:
3809-
raise ValueError("Either `shape` or `num` must be specified.")
3810-
if shape is None: # num is not None
3806+
if shape is None:
3807+
if num is None:
3808+
raise ValueError("Either `shape` or `num` must be specified.")
3809+
# num is not None
38113810
shape = (num,)
3812-
else: # num is none
3813-
num = math.prod(shape)
3814-
3815-
# check compatibility of shape and num
3811+
else:
3812+
num = math.prod(shape) if num is None else num
3813+
# check compatibility of shape and num
38163814
if math.prod(shape) != num:
38173815
raise ValueError("The specified shape is not consistent with the specified num value")
3816+
if num < 0:
3817+
raise ValueError("num must be nonnegative.")
38183818

38193819
if dtype is None:
38203820
dtype = (
@@ -3829,10 +3829,8 @@ def linspace_fill(inputs, output, offset):
38293829
# We already have the dtype and shape, so return immediately
38303830
return blosc2.zeros(shape, dtype=dtype) # will return empty array for num == 0
38313831

3832-
lshape = (math.prod(shape),)
3833-
38343832
inputs = (start, stop, num, endpoint)
3835-
lazyarr = blosc2.lazyudf(linspace_fill, inputs, dtype=dtype, shape=lshape)
3833+
lazyarr = blosc2.lazyudf(linspace_fill, inputs, dtype=dtype, shape=(num,))
38363834
if len(shape) == 1:
38373835
# C order is guaranteed, and no reshape is needed
38383836
return lazyarr.compute(**kwargs)

tests/ndarray/test_proxy.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_ndarray(urlpath, shape, chunks, blocks, slices, dtype):
5959
np.testing.assert_almost_equal(cache_slice[slices], a_slice[...])
6060
else:
6161
assert cache_slice.dtype == np.dtype(dtype)
62-
assert b.fields == cache_slice.fields
62+
assert b.fields.keys() == cache_slice.fields.keys()
6363
for field in cache_slice.fields:
6464
np.testing.assert_almost_equal(cache_slice.fields[field][slices], a_slice.fields[field][...])
6565

@@ -69,7 +69,7 @@ def test_ndarray(urlpath, shape, chunks, blocks, slices, dtype):
6969
np.testing.assert_almost_equal(cache_arr[...], a[...])
7070
else:
7171
assert cache_arr.dtype == np.dtype(dtype)
72-
assert b.fields == cache_arr.fields
72+
assert b.fields.keys() == cache_arr.fields.keys()
7373
for field in cache_arr.fields:
7474
np.testing.assert_almost_equal(cache_arr.fields[field][...], a.fields[field][...])
7575
blosc2.remove_urlpath(urlpath)
@@ -99,7 +99,6 @@ def test_open(urlpath, shape, chunks, blocks, slices, dtype):
9999
np.testing.assert_almost_equal(b[...], a[...])
100100
else:
101101
assert b.dtype == np.dtype(dtype)
102-
assert b.fields == a.fields
103102
for field in b.fields:
104103
np.testing.assert_almost_equal(b.fields[field][...], a.fields[field][...])
105104

tests/test_mmap.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ def test_initial_mapping_size(tmp_path, monkeypatch, capfd, initial_mapping_size
7171
mmap_mode="w+",
7272
initial_mapping_size=initial_mapping_size,
7373
)
74-
assert a == nparray
7574
np.testing.assert_almost_equal(a[...], nparray)
7675

7776
captured = capfd.readouterr()

0 commit comments

Comments
 (0)