aarrgg!

I cleaned up the doc string a bit, but didn't save before sending -- here it is again, Sorry about that.

-Chris




--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

chris.bar...@noaa.gov
#!/usr/bin/env python

"""
accumulator class

Designed to be used as an expandable numpy array, to accumulate values, rather
than a python list.

Note that slices return copies, rather than views, unlike regular numpy arrays.

This is so that the buffer can be re-allocated without messing up any views.

Only appends to the first dimension

"""
import numpy as np

class accumulator:
    #A few parameters
    DEFAULT_BUFFER_SIZE = 128
    BUFFER_EXTEND_SIZE = 1.25 # array.array uses 1+1/16 -- that seems small to 
me.
    def __init__(self, object=None, dtype=np.float, block_shape=()):
        """
        proper docs here
        
        note: a scalar accumulator doesn't really sense, so you get a length-1 
array instead.

        block_shape specifies the other dimensions of the array, so that it 
will be of shape:
          (n,) + block_shape. For example, block_shape = (4,) would result in a 
nX4 array.

        block_shape is ignored if object is provided, and the shape of the array
        is determined from the shape of the provided object.
        
        If neither object nor block_shape is provided, and empty 1-d array is 
created
        """
        if object is None:
            buffer = np.empty((0,)+block_shape, dtype = dtype)
        else:
            buffer = np.array(object, dtype=dtype, copy=True)
            if buffer.shape == ():# to make sure we don't have a scalar
                buffer.shape = (1,)
        self._length      = buffer.shape[0]
        self._block_shape = buffer.shape[1:]
        ## add the padding to the buffer
        shape = ( max(self.DEFAULT_BUFFER_SIZE, 
buffer.shape[0]*self.BUFFER_EXTEND_SIZE), ) + buffer.shape[1:]
        buffer.resize( shape )
        self.__buffer = buffer

        
    ##fixme: 
    ## using @property seems to give a getter, but setting then overrides it
    ## which seems terribly prone to error.
    @property
    def dtype(self):
        return self.__buffer.dtype

    @property
    def bufferlength(self):
        """
        the size of the internal buffer
        """
        return self.__buffer.shape[0]

    @property
    def shape(self):
        """
        To be compatible with ndarray.shape
        (only the getter!) 
        """
        return (self._length,) + self._block_shape
    
    def __len__(self):
        return self._length
        
    def __array__(self, dtype=None):
        """
        a.__array__(|dtype) -> copy of array.
    
        Always returns a copy array, so that buffer doesn't have any references 
to it.
        """
        return np.array(self.__buffer[:self._length], dtype=dtype, copy=True)

    def append(self, item):
        """
        add a new item to the end of the array.
        
        It should be one less dimension than the array: i.e. a.shape[1:]
        if the itme is a smaller shape, it needs to be broadcastable to that 
shape. 
        """
        try:
            self.__buffer[self._length] = item
            self._length += 1
        except IndexError: # the buffer is not big enough or wrong shape entries
            #fixme: test for wrong shape?
            self.resize(self._length*self.BUFFER_EXTEND_SIZE,)
            self.append(item)

    def extend(self, items):
        """
        add a sequence of new items to the end of the array
        """
        try:
            self.__buffer[self._length:self._length+len(items)] = items
            self._length += len(items)
        except ValueError: # the buffer is not big enough, or wrong shape
            items = np.asarray(items, dtype=self.dtype)
            if items.shape[1:] <> self._block_shape:
                raise 
            self.resize( (self._length+len(items)) * self.BUFFER_EXTEND_SIZE )
            self.extend(items)

    def resize(self, newsize):
        """
        resize the internal buffer
        
        it takes a scalar for the length of the the first axis appropriately.
        
        You might want to do this to speed things up if you know you want it
        to be a lot bigger eventually
        """
        if newsize < self._length:
            raise ValueError("accumulator buffer cannot be made smaller that 
the data")
        shape = (newsize,) + self._block_shape
        self.__buffer.resize(shape)

    def fitbuffer(self):
        """
        re-sizes the buffer so that it fits the data, rather than having extra 
space

        """
        self.__buffer.resize( (self._length,) + self._block_shape )
        
    def __getitem__(self, index):
        ## fixme -- this needs to be expanded to n-d!
        if index > self._length-1:
            raise IndexError("index out of bounds")
        elif index < 0:
            index = self._length - 1
        return self.__buffer[index]
    
    ## apparently __getslice__ is depricated!
    def __getslice__(self, i, j):
        """
        a.__getslice__(i, j) <==> a[i:j]
    
        Use of negative indices is not supported.
        
        This returns a COPY, not a view, unlike numpy arrays
        This is required as the data buffer needs to be able to change.
        """
        #fixme -- this needs to be updated: it should be in __getitem__
        #         and support 2d
        j  = min(j, self._length)
        return self.__buffer[i:j].copy()
    def __delitem__(self):
        raise NotImplimentedError
    def __eq__(self, other):
        return self.__buffer[:self._length] == other
    ## fixme: other comparison method here 
    def __str__(self):
        return self.__buffer[:self.shape[0]].__str__()
    def __repr__(self):
        return "accumulator%s"%self.__buffer[:self.shape[0]].__repr__()[5:]
        
_______________________________________________
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion

Reply via email to