[h5py] 191/455: More selections work

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:31 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to annotated tag 1.3.0
in repository h5py.

commit b28ff80ca7450fc8feb51a124ac56994f62f4a20
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Thu Jan 22 00:42:11 2009 +0000

    More selections work
---
 h5py/highlevel.py  |  23 ++++++----
 h5py/selections.py | 126 +++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 112 insertions(+), 37 deletions(-)

diff --git a/h5py/highlevel.py b/h5py/highlevel.py
index c209306..f157e37 100644
--- a/h5py/highlevel.py
+++ b/h5py/highlevel.py
@@ -915,17 +915,24 @@ class Dataset(HLObject):
             else:
                 raise NotImplementedError("Field name selections are not yet allowed for write.")
 
-            # 3. Perform the dataspace selection
-            selection = sel.FancySelection(self.shape)
-            selection[args] = sel.SET
-
-            # 4. Validate the input array
+            # 3. Validate the input array.  Also convert scalars for broadcast.
             val = numpy.asarray(val, order='C')
+            if val.shape == () and self.shape != ():
+                fastest = self.shape[-1]
+                if fastest < 1e6:
+                    val = numpy.repeat(val, fastest)
+
+            # 4. Perform the dataspace selection
+            if sel.is_simple(args):
+                selection = sel.RectSelection(self.shape)
+            else:
+                selection = sel.FancySelection(self.shape)
+            selection[args]
 
-            # 5. Perform the write
-            fspace = selection._id
+            # 5. Perform the write, with broadcasting
             mspace = h5s.create_simple(val.shape, (h5s.UNLIMITED,)*len(val.shape))
-            self.id.write(mspace, fspace, val)
+            for fspace in selection.shape_broadcast(val.shape):
+                self.id.write(mspace, fspace, val)
 
     def read_direct(self, dest, source_sel=None, dest_sel=None):
         """ Read data directly from HDF5 into a NumPy array.
diff --git a/h5py/selections.py b/h5py/selections.py
index 846f6f4..9480031 100644
--- a/h5py/selections.py
+++ b/h5py/selections.py
@@ -14,6 +14,14 @@ from h5py.h5s import SELECT_XOR  as XOR
 from h5py.h5s import SELECT_NOTB as NOTB
 from h5py.h5s import SELECT_NOTA as NOTA
 
+def is_simple(args):
+    for arg in args:
+        if not isinstance(arg, slice):
+            try:
+                long(arg)
+            except Exception:
+                return False
+    return True
 
 class Selection(object):
 
@@ -48,6 +56,11 @@ class Selection(object):
 
         raise TypeError("Selection invalid")
 
+    def shape_broadcast(self, shape):
+        """ Stub broadcasting method """
+        if not shape == self.shape:
+            raise TypeError("Broadcasting is only supported for simple selections")
+        yield self._id
 
 class PointSelection(Selection):
 
@@ -72,8 +85,90 @@ class PointSelection(Selection):
     def prepend(self, points):
         self._perform_selection(points, h5s.SELECT_PREPEND)
 
+    def set(self, points):
+        self._perform_selection(points, h5s.SELECT_SET)
+
 
-class HyperSelection(Selection):
+class RectSelection(Selection):
+
+    """ A single "rectangular" (regular) selection composed of only slices
+        and integer arguments.  Can participate in broadcasting.
+    """
+
+    def __init__(self, *args, **kwds):
+        Selection.__init__(self, *args, **kwds)
+        self._sel = ((0,)*len(self.shape), self.shape, (1,)*len(self.shape))
+
+    def __getitem__(self, args):
+        if not isinstance(args, tuple):
+            args = (args,)
+  
+        start, count, step = self._handle_args(args)
+
+        self._id.select_hyperslab(start, count, step)
+
+        self._sel = (start, count, step)
+
+        return self._id
+
+    def shape_broadcast(self, cshape):
+        """ Return an iterator over target dataspaces for broadcasting """
+
+        # count = (10,10,10)
+        # cshape = (1,1,5)
+
+        start, count, step = self._sel
+        rank = len(self.shape)
+        diff = rank - len(cshape)
+        if diff > 0:
+            cshape = (1,)*diff + cshape
+        elif diff < 0:
+            raise TypeError("Cannot broadcast %s -> %s (too big)" % (count, cshape))
+            
+        if any(x%y != 0 for x, y in zip(count, cshape)):
+            raise TypeError("Cannot broadcast %s -> %s" % (count, cshape))
+
+        chunks = tuple(x/y for x, y in zip(count, cshape))
+        nchunks = np.product(chunks)
+
+        sid = self._id.copy()
+        sid.select_hyperslab((0,)*rank, cshape, step)
+
+        for idx in xrange(nchunks):
+            offset = tuple(x*y*z + s for x, y, z, s in zip(np.unravel_index(idx, chunks), cshape, step, start))
+            sid.offset_simple(offset)
+            yield sid
+
+    def _handle_args(self, args):
+        """ Process a "simple" selection tuple, containing only slices and
+            integer objects.  Return is a 3-tuple with start, count, step tuples.
+
+            If "args" is shorter than "shape", the remaining axes are fully
+            selected.
+        """
+        args = _broadcast(args, len(self.shape))
+
+        def handle_arg(arg, length):
+            if isinstance(arg, slice):
+                return _translate_slice(arg, length)
+            try:
+                return _translate_int(int(arg), length)
+            except TypeError:
+                raise TypeError("Illegal index (must be a slice or number)")
+
+        start = []
+        count = []
+        step  = []
+
+        for a, length in zip(args, self.shape):
+            x,y,z = handle_arg(a, length)
+            start.append(x)
+            count.append(y)
+            step.append(z)
+
+        return tuple(start), tuple(count), tuple(step)
+
+class HyperSelection(RectSelection):
 
     """
         Represents multiple overlapping rectangular selections, combined
@@ -131,34 +226,7 @@ class HyperSelection(Selection):
 
         self._id.select_hyperslab(start, count, step, op=op)
 
-    def _handle_args(self, args):
-        """ Process a "simple" selection tuple, containing only slices and
-            integer objects.  Return is a 3-tuple with start, count, step tuples.
-
-            If "args" is shorter than "shape", the remaining axes are fully
-            selected.
-        """
-        args = _broadcast(args, len(self.shape))
-
-        def handle_arg(arg, length):
-            if isinstance(arg, slice):
-                return _translate_slice(arg, length)
-            try:
-                return _translate_int(int(arg), length)
-            except TypeError:
-                raise TypeError("Illegal index (must be a slice or number)")
 
-        start = []
-        count = []
-        step  = []
-
-        for a, length in zip(args, self.shape):
-            x,y,z = handle_arg(a, length)
-            start.append(x)
-            count.append(y)
-            step.append(z)
-
-        return tuple(start), tuple(count), tuple(step)
 
 class FancySelection(HyperSelection):
 
@@ -298,7 +366,7 @@ def _translate_int(exp, length):
     if exp < 0:
         exp = length+exp
 
-    if not 0<exp<(length-1):
+    if not 0<=exp<(length-1):
         raise ValueError("Index out of range")
 
     return exp, 1, 1

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/h5py.git



More information about the debian-science-commits mailing list