Skip to content

Commit 664c7c9

Browse files
committed
Add optimised compression and tests for constructors
1 parent fe3df2a commit 664c7c9

5 files changed

Lines changed: 76 additions & 2 deletions

File tree

bench/ndarray/stringops_bench.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
cparams = blosc2.cparams_dflts
2323
cparams["filters"][-1] = blosc2.Filter.SHUFFLE
2424
cparams["filters_meta"][-1] = 0 # use default (typesize)
25-
arr1 = blosc2.asarray(nparr, cparams=cparams)
25+
arr1 = blosc2.asarray(nparr)
2626
print(f"cratio without filter: {arr1.cratio}")
2727
cparams["filters_meta"][-1] = 4
2828
arr1 = blosc2.asarray(nparr, cparams=cparams)

src/blosc2/blosc2_ext.pyx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3110,7 +3110,11 @@ cdef b2nd_context_t* create_b2nd_context(shape, chunks, blocks, dtype, kwargs):
31103110
if 'cparams' in kwargs:
31113111
kwargs['cparams']['typesize'] = typesize
31123112
else:
3113-
kwargs['cparams'] = {'typesize': typesize}
3113+
kwargs['cparams'] = {} # last filter is shuffle
3114+
if isinstance(dtype, np.dtypes.StrDType) or dtype == np.str_:
3115+
kwargs['cparams'] = {'filters': [blosc2.Filter.NOFILTER] * 5 + [blosc2.Filter.SHUFFLE],
3116+
'filters_meta': [0] * 5 + [4]} # unicode char bytesize
3117+
kwargs['cparams']['typesize'] = typesize
31143118
if dtype.kind == 'V':
31153119
str_dtype = str(dtype)
31163120
else:

src/blosc2/ndarray.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4996,6 +4996,8 @@ def _check_dtype(dtype):
49964996
dtype = np.dtype(dtype)
49974997
if dtype.itemsize > blosc2.MAX_TYPESIZE:
49984998
raise ValueError(f"dtype itemsize {dtype.itemsize} is too large (>{blosc2.MAX_TYPESIZE})!")
4999+
if dtype == np.str_: # itemsize is 0
5000+
dtype = np.dtype("<U1") # default to 1 char strings
49995001
return dtype
50005002

50015003

tests/ndarray/test_stringarrays.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,61 @@ def test_unicode_on_disk_persistence(tmp_path):
169169

170170
reopened = blosc2.open(path)
171171
assert np.array_equal(reopened, arr2)
172+
173+
174+
@pytest.mark.parametrize(
175+
"constructor",
176+
[
177+
"zeros",
178+
"ones",
179+
"empty",
180+
"full",
181+
# "full_like", these all call ones/empty/full/zeros anyway
182+
# "zeros_like",
183+
# "ones_like",
184+
# "empty_like",
185+
"eye",
186+
],
187+
)
188+
@pytest.mark.parametrize("shape", SHAPES)
189+
def test_constructors(constructor, shape):
190+
if constructor == "full":
191+
arr = getattr(blosc2, constructor)(fill_value="pepe", shape=shape, dtype=np.str_)
192+
nparr = getattr(np, constructor)(fill_value="pepe", shape=shape, dtype=np.str_)
193+
elif constructor == "eye":
194+
arr = getattr(blosc2, constructor)(shape[0], dtype=np.str_)
195+
nparr = getattr(np, constructor)(shape[0], dtype=np.str_)
196+
else:
197+
arr = getattr(blosc2, constructor)(shape=shape, dtype=np.str_)
198+
nparr = getattr(np, constructor)(shape=shape, dtype=np.str_)
199+
np.testing.assert_array_equal(arr[()], nparr)
200+
201+
202+
def test_optimised_string_comp():
203+
N = int(1e5)
204+
nparr = np.repeat(np.array(["josé", "pepe", "francisco"]), N)
205+
cparams = blosc2.cparams_dflts
206+
arr1 = blosc2.asarray(nparr, cparams=cparams)
207+
cratio_subopt = arr1.cratio
208+
# when not providing cparams, blosc2_ext passes an optimised pipeline for string dtypes
209+
arr1 = blosc2.asarray(nparr)
210+
assert arr1.cratio > cratio_subopt
211+
212+
213+
@pytest.mark.parametrize("shape", SHAPES)
214+
def test_frombuffer(shape):
215+
chunks = tuple(max(c // 4, 1) for c in shape)
216+
dtype = np.dtype("<U8")
217+
typesize = dtype.itemsize
218+
# Create a buffer
219+
nparr = make_unicode_array(shape, maxlen=8)
220+
buffer = bytes(nparr)
221+
# Create a NDArray from a buffer with default blocks
222+
arr = blosc2.frombuffer(buffer, shape, chunks=chunks, dtype=dtype)
223+
np.testing.assert_array_equal(arr[()], nparr)
224+
225+
226+
def test_fromiter():
227+
nparr = np.arange(0, 20).astype(np.str_)
228+
arr = blosc2.fromiter(range(20), shape=(20,), dtype=nparr.dtype)
229+
np.testing.assert_array_equal(arr[()], nparr)

tests/ndarray/test_zeros.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@
5656
False,
5757
None,
5858
),
59+
(
60+
(2**31 - 1,),
61+
(2**30,),
62+
None,
63+
np.str_,
64+
{"codec": blosc2.Codec.LZ4, "clevel": 5, "nthreads": 2},
65+
None,
66+
False,
67+
None,
68+
),
5969
],
6070
)
6171
def test_zeros(shape, chunks, blocks, dtype, cparams, urlpath, contiguous, meta):

0 commit comments

Comments
 (0)