Skip to content

Commit

Permalink
WIP Prof of concept adding setitem support to lix.
Browse files Browse the repository at this point in the history
  • Loading branch information
kwgoodman committed May 17, 2012
1 parent 3a68b19 commit 370a09e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 23 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ After you have installed ``la``, run the suite of unit tests::
>>> import la
>>> la.test()
<snip>
Ran 3002 tests in 9.225s
Ran 3009 tests in 9.225s
OK
<nose.result.TextTestResult run=3002 errors=0 failures=0>
<nose.result.TextTestResult run=3009 errors=0 failures=0>
The ``la`` package contains C extensions that speed up common alignment
operations such as adding two unaligned larrys. If the C extensions don't
Expand Down
82 changes: 69 additions & 13 deletions la/deflarry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1926,7 +1926,7 @@ def lix(self):
array([1, 4])
"""
return Getitemlabel(self)
return Lix(self)

def __setitem__(self, index, value):
"""
Expand Down Expand Up @@ -4848,13 +4848,15 @@ def __repr__(self):

# Label indexing support functions for the lix method ------------------------

class Getitemlabel(object):
class Lix(object):
"Utility class for the lix method."

def __init__(self2, self):
self2.lar = self

def __getitem__(self2, index):
# Note: setitem uses the same (slightly modified) code
# So if you update this code update setitem as well
y = self2.lar
if y.shape == (0,):
return self2.lar
Expand All @@ -4866,9 +4868,9 @@ def __getitem__(self2, index):
if typ == list:
# Example: lar.lix[['a', 'b', 'c']]
index2 = labels2indices(y.label[0], index)
if len(index) == 1:
if len(index) == 1:
index2 = index2[0]
return y[index2]
return y[index2]
elif typ == slice:
# Examples: lar.lix[['a']:], lar.lix[['a']:['b']],
# lar.lix[['a']:['b']:2], lar.lix[2:['b']]
Expand All @@ -4881,35 +4883,90 @@ def __getitem__(self2, index):
elif len(index) < y.ndim:
index3 = list(index) + [slice(None)] * (y.ndim - len(index))
else:
raise IndexError, 'Invalid index'
raise IndexError, 'Invalid index'
for ax, idx in enumerate(index3):
typ = type(idx)
if typ == list:
idx2 = labels2indices(y.label[ax], idx)
if len(idx) > 1:
if len(idx) > 1:
label.append(idx)
index2.append(idx2)
elif typ == slice:
elif typ == slice:
s = slicemaker(idx, y.labelindex, ax)
slar = range(*s.indices(y.shape[ax]))
lab = y.label[ax][s]
if len(lab) > 1:
label.append(lab)
label.append(lab)
index2.append(slar)
elif isscalar(idx):
index2.append([idx])
index2.append([idx])
else:
raise IndexError, 'Unsupported indexing operation.'
x = np.squeeze(y.x[np.ix_(*index2)])
if x.ndim == 0:
return x[()]
else:
return larry(x, label)
return larry(x, label)
elif isscalar(index):
# Example: lar.lix[0]
return y[index]
return y[index]
else:
raise IndexError, 'Unsupported indexing operation.'
raise IndexError, 'Unsupported indexing operation.'

def __setitem__(self2, index, value):
# Note: getitem uses the same (slightly modified) code
# So if you update this code update getitem as well
y = self2.lar
if y.shape == (0,):
raise IndexError('index out of bounds')
elif 0 in y.shape:
msg = 'lix does not support shapes that contain 0 '
msg += 'such as (0,) and (2, 0 ,3).'
raise ValueError, msg
typ = type(index)
if typ == list:
# Example: lar.lix[['a', 'b', 'c']]
index2 = labels2indices(y.label[0], index)
if len(index) == 1:
index2 = index2[0]
y[index2] = value
elif typ == slice:
# Examples: lar.lix[['a']:], lar.lix[['a']:['b']],
# lar.lix[['a']:['b']:2], lar.lix[2:['b']]
y[slicemaker(index, y.labelindex, 0)] = value
elif typ == tuple:
index2 = []
label = []
if len(index) == y.ndim:
index3 = index
elif len(index) < y.ndim:
index3 = list(index) + [slice(None)] * (y.ndim - len(index))
else:
raise IndexError, 'Invalid index'
for ax, idx in enumerate(index3):
typ = type(idx)
if typ == list:
idx2 = labels2indices(y.label[ax], idx)
if len(idx) > 1:
label.append(idx)
index2.append(idx2)
elif typ == slice:
s = slicemaker(idx, y.labelindex, ax)
slar = range(*s.indices(y.shape[ax]))
lab = y.label[ax][s]
if len(lab) > 1:
label.append(lab)
index2.append(slar)
elif isscalar(idx):
index2.append([idx])
else:
raise IndexError, 'Unsupported indexing operation.'
y.x[np.ix_(*index2)] = value
elif isscalar(index):
# Example: lar.lix[0]
y[index] = value
else:
raise IndexError, 'Unsupported indexing operation.'

def slicemaker(index, labelindex, axis):
"Convert a slice that may contain labels to a slice with indices."
Expand Down Expand Up @@ -4944,4 +5001,3 @@ def labels2indices(label, labels):
except ValueError:
raise ValueError, 'Could not map label to index value.'
return indices

61 changes: 53 additions & 8 deletions la/tests/lix_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import numpy as np
from numpy.testing import assert_equal

import la
from la import larry
from la.util.misc import isscalar
from la.util.testing import assert_larry_equal as ale

S = slice
N = None
Expand Down Expand Up @@ -106,11 +108,54 @@ def test_lix(si=si):
msg = '\nlix fail on shape %s and index %s\n'
yield assert_equal, actual, desired, msg % (str(shape), str(index))









# ---------------------------------------------------------------------------
# Test lix setitem

def lix_setitem_test_01():
actual = la.lrange(label=[['a', 'b']])
actual.lix[['a']] = 9
desired = la.lrange(label=[['a', 'b']])
desired[0] = 9
ale(actual, desired)

def lix_setitem_test_02():
actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
actual.lix[['a']] = 9
desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
desired[0] = 9
ale(actual, desired)

def lix_setitem_test_03():
actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
actual.lix[0] = 9
desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
desired[0] = 9
ale(actual, desired)

def lix_setitem_test_04():
actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
actual.lix[['a']:['b']] = 9
desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
desired[0:1] = 9
ale(actual, desired)

def lix_setitem_test_05():
actual = la.lrange(label=[['a', 'b'], ['c', 'd']])
actual.lix[['b'], ['d']] = 9
desired = la.lrange(label=[['a', 'b'], ['c', 'd']])
desired[1, 1] = 9
ale(actual, desired)

def lix_setitem_test_06():
actual = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
actual.lix[['a', 'b'], ['1', '2']] = 9
desired = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
desired[:2, :2] = 9
ale(actual, desired)

def lix_setitem_test_07():
actual = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
actual.lix[['a', 'b'], ['1', '2']] = np.arange(4).reshape(2, 2)
desired = la.lrange(label=[['a', 'b', 'c'], ['1', '2', '3']])
desired[:2, :2] = np.arange(4).reshape(2, 2)
ale(actual, desired)

0 comments on commit 370a09e

Please sign in to comment.