Skip to content

Commit b6603e8

Browse files
committed
[?] Correct Subarray With Negative Domains on Dense Arrays
* We currently support Python negative indexing ie. where -1 returns the last element in the sequence. However, this conflicts with reading and writing with negative subarray values -- indexing with negative values errors out. * This PR deprecates the usage of Pythoh negative indexing so that dense arrays with negative domains can be indexed by TileDB dimensions correctly.
1 parent 656f54f commit b6603e8

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

tiledb/libtiledb.pyx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,8 @@ def index_domain_subarray(array: Array, dom, idx: tuple):
589589
Return a numpy array representation of the tiledb subarray buffer
590590
for a given domain and tuple of index slices
591591
"""
592+
offsetted = False
593+
592594
ndim = dom.ndim
593595
if len(idx) != ndim:
594596
raise IndexError("number of indices does not match domain rank: "
@@ -648,7 +650,9 @@ def index_domain_subarray(array: Array, dom, idx: tuple):
648650
raise IndexError("cannot index integral domain dimension with non-integral slice (dtype: {})".format(type(start)))
649651
# apply negative indexing (wrap-around semantics)
650652
if not is_datetime and start < 0:
651-
start += int(dim_ub) + 1
653+
if start < dim_lb:
654+
offsetted = True
655+
start += int(dim_ub) + 1
652656
if start < dim_lb:
653657
# numpy allows start value < the array dimension shape,
654658
# clamp to lower bound of dimension domain
@@ -666,7 +670,8 @@ def index_domain_subarray(array: Array, dom, idx: tuple):
666670
elif not isinstance(start, _inttypes):
667671
raise IndexError("cannot index integral domain dimension with non-integral slice (dtype: {})".format(type(start)))
668672
if not is_datetime and stop < 0:
669-
stop += dim_ub
673+
if offsetted:
674+
stop += dim_ub
670675
if stop > dim_ub:
671676
# numpy allows stop value > than the array dimension shape,
672677
# clamp to upper bound of dimension domain

tiledb/tests/test_libtiledb.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ def test_array_1d(self):
503503
# basic step
504504
assert_array_equal(A[:50:2], T[:50:2])
505505
assert_array_equal(A[:2:50], T[:2:50])
506-
assert_array_equal(A[10:-1:50], T[10:-1:50])
506+
assert_array_equal(A[10:-1:50], T[10:1049:50])
507507

508508
# indexing errors
509509
with self.assertRaises(IndexError):
@@ -1247,7 +1247,7 @@ def test_varlen_sparse_all_empty_strings(self):
12471247

12481248
with tiledb.open(uri, mode="r") as T:
12491249
# check interior range
1250-
assert_array_equal(A[1:-1], T[2:-1]["a1"])
1250+
assert_array_equal(A[1:-1], T[1:dim_len-1]["a1"])
12511251
assert_array_equal(A[1:-1], T.multi_index[2 : dim_len - 1]["a1"])
12521252

12531253
def test_varlen_write_unicode(self):
@@ -1521,6 +1521,51 @@ def test_array_varlen_2d_s_fixed(self):
15211521
with tiledb.DenseArray(uri) as T:
15221522
assert_array_equal(A, T)
15231523

1524+
@pytest.mark.parametrize("lo,hi", [(-20, -10), (-10, 0), (0, 10), (10, 20)])
1525+
def test_dense_array_with_negative_positive_domain(self, lo, hi):
1526+
path = self.path("test_dense_array_with_negative_domain")
1527+
attr = tiledb.Attr(dtype=np.uint8)
1528+
dom = tiledb.Domain(tiledb.Dim("X", domain=(-20, 20),dtype=np.int64))
1529+
schema = tiledb.ArraySchema(domain=dom, sparse=False, attrs=[attr])
1530+
tiledb.Array.create(path, schema)
1531+
data = np.random.randint(10, size=(hi-lo))
1532+
1533+
with tiledb.open(path, 'w') as A:
1534+
A[lo:hi] = data
1535+
1536+
with tiledb.open(path, 'r') as A:
1537+
assert_array_equal(A[lo:hi], data[:])
1538+
1539+
1540+
@pytest.mark.parametrize("lo,hi", [(-20, -10), (-20, -15), (-15, -10), (-17, -13)])
1541+
def test_dense_array_with_negative_negative_domain(self, lo, hi):
1542+
path = self.path("test_dense_array_with_negative_negative_domain")
1543+
attr = tiledb.Attr(dtype=np.uint8)
1544+
dom = tiledb.Domain(tiledb.Dim("X", domain=(-20, -10),dtype=np.int64))
1545+
schema = tiledb.ArraySchema(domain=dom, sparse=False, attrs=[attr])
1546+
tiledb.Array.create(path, schema)
1547+
data = np.random.randint(10, size=(hi-lo))
1548+
1549+
with tiledb.open(path, 'w') as A:
1550+
A[lo:hi] = data
1551+
1552+
with tiledb.open(path, 'r') as A:
1553+
assert_array_equal(A[lo:hi], data[:])
1554+
1555+
@pytest.mark.parametrize("lo,hi", [(10, 20), (10,15),(12,15), (17,20)])
1556+
def test_dense_array_with_offset_domain(self, lo, hi):
1557+
path = self.path("test_dense_array_with_offset_domain")
1558+
attr = tiledb.Attr(dtype=np.uint8)
1559+
dom = tiledb.Domain(tiledb.Dim("X", domain=(10, 20),dtype=np.int64))
1560+
schema = tiledb.ArraySchema(domain=dom, sparse=False, attrs=[attr])
1561+
tiledb.Array.create(path, schema)
1562+
data = np.random.randint(10, size=(hi-lo))
1563+
1564+
with tiledb.open(path, 'w') as A:
1565+
A[lo:hi] = data
1566+
1567+
with tiledb.open(path, 'r') as A:
1568+
assert_array_equal(A[lo:hi], data[:])
15241569

15251570
class TestSparseArray(DiskTestCase):
15261571
@pytest.mark.xfail

0 commit comments

Comments
 (0)