Revision: 4662
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4662&view=rev
Author:   jdh2358
Date:     2007-12-06 20:43:36 -0800 (Thu, 06 Dec 2007)

Log Message:
-----------
updates to the pyrex examples

Modified Paths:
--------------
    trunk/py4science/examples/pyrex/movavg/Makefile
    trunk/py4science/examples/pyrex/movavg/movavg.pyx
    trunk/py4science/examples/pyrex/movavg/ringbuf.pyx
    trunk/py4science/examples/pyrex/movavg/ringbuf_demo.py
    trunk/py4science/examples/pyrex/movavg/setup.py

Added Paths:
-----------
    trunk/py4science/examples/pyrex/movavg/README
    trunk/py4science/examples/pyrex/movavg/movavg_bruteforce.py
    trunk/py4science/examples/pyrex/movavg/movavg_fast.py
    trunk/py4science/examples/pyrex/movavg/movavg_ringbuf.py
    trunk/py4science/examples/pyrex/movavg/ringbufnan.c

Removed Paths:
-------------
    trunk/py4science/examples/pyrex/movavg/circbuffer.py
    trunk/py4science/examples/pyrex/movavg/movavg_test.py
    trunk/py4science/examples/pyrex/movavg/numpyx.pyx
    trunk/py4science/examples/pyrex/movavg/run_test.py

Modified: trunk/py4science/examples/pyrex/movavg/Makefile
===================================================================
--- trunk/py4science/examples/pyrex/movavg/Makefile     2007-12-07 00:01:46 UTC 
(rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/Makefile     2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -6,4 +6,4 @@
 
 .PHONY: clean
 clean:
-       rm -rf *~ *.so *.c *.o build
+       rm -rf *~ *.so *.o build ringbuf.c

Added: trunk/py4science/examples/pyrex/movavg/README
===================================================================
--- trunk/py4science/examples/pyrex/movavg/README                               
(rev 0)
+++ trunk/py4science/examples/pyrex/movavg/README       2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -0,0 +1,82 @@
+Introduction
+============
+
+This exercise introduces pyrex to wrap a C library for trailing
+statistics.
+
+Computation of trailing windowed statistics is common in many
+quantitative data driven disciplines, particularly where there is
+noisy data.  Common uses of windowed statistics are the trailing
+moving average, standard deviation, minumum and maximum.  Two common
+use cases which pose computational challenges for python: real time
+updating of trailing statistics as live data comes in, and posthoc
+computation of trailing statistics over a large data array.  In the
+second case, for some statistics we can use convolution and related
+techniques for efficient computation, eg of the trailing 30 sample
+average
+
+    numpy.convolve(x, numpy.ones(30), mode=valid')[:len(x)]
+
+but for other statistics like the trailing 30 day maximum at each
+point, efficient routines like convolution are of no help.
+
+This exercise introduces pyrex to efficiently solve the problem of
+trailing statistics over arrays as well as for a live, incoming data
+stream. A pure C library, ringbuf, defines a circular C buffer and
+attached methods for efficiently computing trailing averages, and
+pyrex is used to provide a pythonic API on top of this extension code.
+The rigid segregation between the C library and the python wrappers
+insures that the C code can be used in other projects, be it a matlab
+(TM) extension or some other C library.  The goal of the exericse is
+to compute the trailing statistics mean, median, stddev, min and max
+using three approaches:
+
+  - with brute force using numpy arrays, slices and methods
+    (movavg_bruteforce.py)
+
+  - with python bindings to the ringbuf code ringbuf.Rinbuf
+    (movavg_ringbuf.py).  See ringbuf_demo.py for an example of how to
+    use the ringbuf module
+
+  - using a pyrex extension to the ringbuf runstats code
+    (movavg_fast.py)
+
+pyrex module support
+====================
+
+  - Makefile : simple interface to setup.py so you can just 'make'
+
+  - setup.py : configure and build the python modules
+
+  - c_numpy.pxd : the numpy C API for pyrex
+
+  - c_python.pxd : the python C API for pyrex
+
+  - c_ringbuf.pxi : the ringbuf C API for pyrex
+
+  - ringbuf.pyx : python interface to the ringbuf C API
+
+examples
+========
+
+  - ringbuf_demo.py : basic demo of the python bindings to basic
+    Ringbuf class
+
+  - movavg_bruteforce.py : do the trailing stats with brute force
+    numpy slices and methods
+
+  - movavg_ringbuf.py : do the trailing stats with the Ringbuf code
+
+  - movavg_fast.py : do the trailing stats with the ringbuf runstats wrapper
+
+ringbuf C code
+==============
+
+  - ringbuf.h : pure C ringbuf API headers
+
+  - ringbufnan.c : pure C ringbuf library
+
+Acknowledgements
+================
+
+Thanks to Eric Firing for the ringbuf and runstats code!

Deleted: trunk/py4science/examples/pyrex/movavg/circbuffer.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/circbuffer.py        2007-12-07 
00:01:46 UTC (rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/circbuffer.py        2007-12-07 
04:43:36 UTC (rev 4662)
@@ -1,20 +0,0 @@
-import numpy as npy
-
-class CircularBuffer:
-    def __init__(self, N):
-        self.i = 0
-        self.data = npy.zeros(N)
-        self.N = N
-
-    def add(self, val):
-        self.data[self.i%self.N] = val
-        self.i += 1
-
-    def get_data(self):
-        if self.i<self.N:
-            return self.data[:self.i]
-        else:
-            return self.data
-
-
-

Modified: trunk/py4science/examples/pyrex/movavg/movavg.pyx
===================================================================
--- trunk/py4science/examples/pyrex/movavg/movavg.pyx   2007-12-07 00:01:46 UTC 
(rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/movavg.pyx   2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -1,41 +1,55 @@
-# -*- Mode: Python -*-  Not really, but close enough
+'''
+This is kept as a module separate from pyringbuf so that the
+latter does not depend on numpy.
+'''
 
-cimport c_python
 cimport c_numpy
 import numpy
 
-# Numpy must be initialized
 c_numpy.import_array()
 
+include "c_ringbuf.pxi"
 
 
-def sum_elements(c_numpy.ndarray arr):
-    cdef int i
-    cdef double x, val
+def runstats(data, nrb):
+    '''
+    Compute running stats on 1D array data for odd length nrb
+    '''
 
-    x = 0.
-    val = 0.
-    for i from 0<=i<arr.dimensions[0]:
-        val = (<double*>(arr.data + i*arr.strides[0]))[0]
-        x = x + val
+    cdef c_numpy.ndarray c_data
+    cdef c_numpy.ndarray c_dmean
+    cdef c_numpy.ndarray c_dstd
+    cdef c_numpy.ndarray c_dmin
+    cdef c_numpy.ndarray c_dmax
+    cdef c_numpy.ndarray c_dmedian
+    cdef c_numpy.ndarray c_ng
 
-    return x
 
+    data = numpy.asarray(data, dtype=numpy.float_)
+    if data.ndim != 1:
+        raise ValueError("data must be 1-D for now")
+    nd = data.shape[0]
 
+    dmean = numpy.empty_like(data)
+    dstd = numpy.empty_like(data)
+    dmin = numpy.empty_like(data)
+    dmax = numpy.empty_like(data)
+    dmedian = numpy.empty_like(data)
+    ng = numpy.empty(data.shape, dtype=numpy.int_)
 
-def sum_elements2(c_numpy.ndarray arr):
-    cdef int i
-    cdef double x, val
+    c_data = data
+    c_dmean = dmean
+    c_dstd = dstd
+    c_dmin = dmin
+    c_dmax = dmax
+    c_dmedian = dmedian
+    c_ng = ng
 
-    arr = numpy.asarray(arr, numpy.float_)
-
-    if arr.nd!=1:
-        raise RuntimeError('only 1D arrays supported; found 
shape=%s'%str(arr.shape))
-    assert(arr.nd==1)
-    x = 0.
-    val = 0.
-    for i from 0<=i<arr.dimensions[0]:
-        val = (<double*>(arr.data + i*arr.strides[0]))[0]
-        x = x + val
-
-    return x
+    c_runstats(nrb, nd, <double *>c_data.data,
+                        <double *>c_dmean.data,
+                        <double *>c_dstd.data,
+                        <double *>c_dmin.data,
+                        <double *>c_dmax.data,
+                        <double *>c_dmedian.data,
+                        <int *>c_ng.data)
+    return dmean, dstd, dmin, dmax, dmedian, ng

Added: trunk/py4science/examples/pyrex/movavg/movavg_bruteforce.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/movavg_bruteforce.py                 
        (rev 0)
+++ trunk/py4science/examples/pyrex/movavg/movavg_bruteforce.py 2007-12-07 
04:43:36 UTC (rev 4662)
@@ -0,0 +1,14 @@
+"""
+Use a brute force, slow method
+"""
+import numpy
+
+x = numpy.random.rand(10000)
+
+data = []
+for i in range(len(x)):
+    slice = x[max(0, i-30):i+1]  # slice out the recent history
+    data.append([slice.mean(), slice.std(), slice.min(), slice.max(), 
numpy.median(slice), len(slice)])
+
+r = numpy.rec.fromarrays(data,names='dmean,dstd,dmin,dmax,dmedian,ngood')
+

Added: trunk/py4science/examples/pyrex/movavg/movavg_fast.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/movavg_fast.py                       
        (rev 0)
+++ trunk/py4science/examples/pyrex/movavg/movavg_fast.py       2007-12-07 
04:43:36 UTC (rev 4662)
@@ -0,0 +1,14 @@
+"""
+Use a brute force, slow method
+"""
+import numpy
+import ringbuf
+
+x = numpy.random.rand(10000)
+dmean, dstd, dmin, dmax, dmedian, ng = ringbuf.runstats(x, 30)
+
+r = numpy.rec.fromarrays([dmean, dstd, dmin, dmax, dmedian, ng],
+                         names='dmean,dstd,dmin,dmax,dmedian,ngood')
+
+
+

Added: trunk/py4science/examples/pyrex/movavg/movavg_ringbuf.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/movavg_ringbuf.py                    
        (rev 0)
+++ trunk/py4science/examples/pyrex/movavg/movavg_ringbuf.py    2007-12-07 
04:43:36 UTC (rev 4662)
@@ -0,0 +1,16 @@
+"""
+Use a brute force, slow method
+"""
+import numpy
+import ringbuf
+
+r = ringbuf.Ringbuf(30)
+x = numpy.random.rand(10000)
+
+data = []
+for thisx in x:
+    r.add(thisx)
+    data.append([thisx, r.N_good(), r.min(), r.max(), r.mean(), r.sd()])
+
+r = numpy.rec.fromarrays(data,names='x,ngood,min30,max30,mean30,sd30')
+

Deleted: trunk/py4science/examples/pyrex/movavg/movavg_test.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/movavg_test.py       2007-12-07 
00:01:46 UTC (rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/movavg_test.py       2007-12-07 
04:43:36 UTC (rev 4662)
@@ -1,3 +0,0 @@
-import numpy
-import movavg
-

Deleted: trunk/py4science/examples/pyrex/movavg/numpyx.pyx
===================================================================
--- trunk/py4science/examples/pyrex/movavg/numpyx.pyx   2007-12-07 00:01:46 UTC 
(rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/numpyx.pyx   2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -1,128 +0,0 @@
-# -*- Mode: Python -*-  Not really, but close enough
-
-cimport c_python
-cimport c_numpy
-import numpy
-
-# Numpy must be initialized
-c_numpy.import_array()
-
-def print_array_info(c_numpy.ndarray arr):
-    cdef int i
-
-    print '-='*10
-    print 'printing array info for ndarray at 
0x%0lx'%(<c_python.Py_intptr_t>arr,)
-    print 'print number of dimensions:',arr.nd
-    print 'address of strides: 0x%0lx'%(<c_python.Py_intptr_t>arr.strides,)
-    print 'strides:'
-    for i from 0<=i<arr.nd:
-        # print each stride
-        print '  stride %d:'%i,<c_python.Py_intptr_t>arr.strides[i]
-    print 'memory dump:'
-    print_elements( arr.data, arr.strides, arr.dimensions,
-                    arr.nd, sizeof(double), arr.dtype )
-    print '-='*10
-    print
-
-
-
-def sum_elements(c_numpy.ndarray arr):
-    cdef int i
-    cdef double x, val
-
-    x = 0.
-    val = 0.
-    for i from 0<=i<arr.dimensions[0]:
-        val = (<double*>(arr.data + i*arr.strides[0]))[0]
-        x = x + val
-
-    return x
-
-
-def scale_elements(int N):
-    cdef int i
-    cdef double x, val
-
-    x = 0.
-    val = 0.
-    for i from 0<=i<N:
-        val = 2.5 * i
-        x = x + val
-    return x
-
-
-cdef print_elements(char *data,
-                    c_python.Py_intptr_t* strides,
-                    c_python.Py_intptr_t* dimensions,
-                    int nd,
-                    int elsize,
-                    object dtype):
-    cdef c_python.Py_intptr_t i,j
-    cdef void* elptr
-
-    if dtype not in [numpy.dtype(numpy.object_),
-                     numpy.dtype(numpy.float64)]:
-        print '   print_elements() not (yet) implemented for dtype 
%s'%dtype.name
-        return
-
-    if nd ==0:
-        if dtype==numpy.dtype(numpy.object_):
-            elptr = (<void**>data)[0] #[0] dereferences pointer in Pyrex
-            print '  ',<object>elptr
-        elif dtype==numpy.dtype(numpy.float64):
-            print '  ',(<double*>data)[0]
-    elif nd == 1:
-        for i from 0<=i<dimensions[0]:
-            if dtype==numpy.dtype(numpy.object_):
-                elptr = (<void**>data)[0]
-                print '  ',<object>elptr
-            elif dtype==numpy.dtype(numpy.float64):
-                print '  ',(<double*>data)[0]
-            data = data + strides[0]
-    else:
-        for i from 0<=i<dimensions[0]:
-            print_elements(data, strides+1, dimensions+1, nd-1, elsize, dtype)
-            data = data + strides[0]
-
-
-def test_methods(c_numpy.ndarray arr):
-    """Test a few attribute accesses for an array.
-
-    This illustrates how the pyrex-visible object is in practice a strange
-    hybrid of the C PyArrayObject struct and the python object.  Some
-    properties (like .nd) are visible here but not in python, while others
-    like flags behave very differently: in python flags appears as a separate,
-    object while here we see the raw int holding the bit pattern.
-
-    This makes sense when we think of how pyrex resolves arr.foo: if foo is
-    listed as a field in the c_numpy.ndarray struct description, it will be
-    directly accessed as a C variable without going through Python at all.
-    This is why for arr.flags, we see the actual int which holds all the flags
-    as bit fields.  However, for any other attribute not listed in the struct,
-    it simply forwards the attribute lookup to python at runtime, just like
-    python would (which means that AttributeError can  be raised for
-    non-existent attributes, for example)."""
-
-    print 'arr.any() :',arr.any()
-    print 'arr.nd    :',arr.nd
-    print 'arr.flags :',arr.flags
-
-def test():
-    """this function is pure Python"""
-    arr1 = numpy.array(-1e-30,dtype=numpy.float64)
-    arr2 = numpy.array([1.0,2.0,3.0],dtype=numpy.float64)
-
-    arr3 = numpy.arange(9,dtype=numpy.float64)
-    arr3.shape = 3,3
-
-    four = 4
-    arr4 = numpy.array(['one','two',3,four],dtype=numpy.object_)
-
-    arr5 = numpy.array([1,2,3]) # int types not (yet) supported by 
print_elements
-
-    for arr in [arr1,arr2,arr3,arr4,arr5]:
-        print_array_info(arr)
-
-
-    arr = numpy.arange(10.0)
-    print 'sum el', sum_elements(arr)

Modified: trunk/py4science/examples/pyrex/movavg/ringbuf.pyx
===================================================================
--- trunk/py4science/examples/pyrex/movavg/ringbuf.pyx  2007-12-07 00:01:46 UTC 
(rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/ringbuf.pyx  2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -1,11 +1,16 @@
-''' pyringbuf.pyx Pyrex interface to ringbuf.c
-    It defines a single ring buffer class, Ringbuf,
-    on which various statistics are calculated
-    as each entry is added.
-'''
+"""
+ringbuf.pyx Pyrex interface to ringbuf.c It defines ring buffer class,
+Ringbuf, on which various statistics are calculated as each entry is
+added and a method runstats for computing a host of trailing
+statistics over a numpy array
+"""
 
 include "c_ringbuf.pxi"
 
+# ringbuf is a C library, but we can give it a pythonic object
+# oriented API by managing the ringbuf pointers and function calls in
+# a python class
+
 cdef class Ringbuf:
    cdef ringbuf_t *rb_ptr
 
@@ -132,3 +137,72 @@
 
 
 
+# now we'll provide a numpy interface to the runstats function, which
+# fills predimensioned arrays with the trailing mean, std, max, etc,
+# for a data array
+cimport c_numpy
+import numpy
+c_numpy.import_array()
+
+def runstats(data, nrb):
+    """
+    Compute running stats on 1D array data over window length nrb
+    """
+
+    # we will be calling the ringbuf C function runstats, which
+    # expects a bunch of c data pointers to the data arrays as well as
+    # the output arrays for the mean, std, etc...  Create a array for
+    # each C float array pointer the C function expects.  The type of
+    # the array is c_numpy.ndarray
+    cdef c_numpy.ndarray c_data
+    cdef c_numpy.ndarray c_dmean
+    cdef c_numpy.ndarray c_dstd
+    cdef c_numpy.ndarray c_dmin
+    cdef c_numpy.ndarray c_dmax
+    cdef c_numpy.ndarray c_dmedian
+    cdef c_numpy.ndarray c_ng
+
+    # make sure that the input array is a 1D numpy array of floats.
+    # asarray is used to copy and cast a python sequence or array to
+    # the approriate type, with the advantage that if the data is
+    # already the right type, no copy is performed
+    data = numpy.asarray(data, dtype=numpy.float_)
+    if data.ndim != 1:
+        raise ValueError("data must be 1-D for now")
+    nd = data.shape[0]
+
+    # use numpy.empty_like to create and empty array of the same type
+    # and shape as data for each of the return stats (mean, std, ...)
+    # These are genuine numpy arrays we will be passing back to the
+    # python level. Remember the ng (the number of good elements) is
+    # an int, and everything else is a float
+    dmean = numpy.empty_like(data)
+    dstd = numpy.empty_like(data)
+    dmin = numpy.empty_like(data)
+    dmax = numpy.empty_like(data)
+    dmedian = numpy.empty_like(data)
+    ng = numpy.empty(data.shape, dtype=numpy.int_)
+
+    # now we have to assign the c_data structures and friends to their
+    # corresponding numpy arrays
+    c_data = data
+    c_dmean = dmean
+    c_dstd = dstd
+    c_dmin = dmin
+    c_dmax = dmax
+    c_dmedian = dmedian
+    c_ng = ng
+
+    # now we call the function and pass in the c data pointers to the
+    # arrays.  The syntax <double *>c_data.data tells pyrex to pass
+    # the numpy data memory block as a pointer to a float array.
+    c_runstats(nrb, nd, <double *>c_data.data,
+                        <double *>c_dmean.data,
+                        <double *>c_dstd.data,
+                        <double *>c_dmin.data,
+                        <double *>c_dmax.data,
+                        <double *>c_dmedian.data,
+                        <int *>c_ng.data)
+
+    # all done, return the arrays
+    return dmean, dstd, dmin, dmax, dmedian, ng

Modified: trunk/py4science/examples/pyrex/movavg/ringbuf_demo.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/ringbuf_demo.py      2007-12-07 
00:01:46 UTC (rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/ringbuf_demo.py      2007-12-07 
04:43:36 UTC (rev 4662)
@@ -1,2 +1,14 @@
+"""
+Example code showin how to use the ringbuf extension code from python
+"""
+import random
 import ringbuf
 
+r = ringbuf.Ringbuf(30)
+
+for i in range(100):
+    r.add(random.random())
+    print 'Nadded=%d, Ngood=%d, min=%1.2f, max=%1.2f, mean=%1.2f, std=%1.2f'%(
+        r.N_added(), r.N_good(), r.min(), r.max(), r.mean(), r.sd())
+
+print 'slice', r[:10]

Added: trunk/py4science/examples/pyrex/movavg/ringbufnan.c
===================================================================
--- trunk/py4science/examples/pyrex/movavg/ringbufnan.c                         
(rev 0)
+++ trunk/py4science/examples/pyrex/movavg/ringbufnan.c 2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -0,0 +1,363 @@
+/*
+
+   Use a ring buffer to calculate running statistics of a data stream.
+
+
+
+   compile:
+      gcc -Wall -c -fPIC ringbufnan.c
+
+
+   2003/07/28 EF
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>   /* for debugging printf statements */
+#include <math.h>
+#include "ringbuf.h"
+
+static double NaN = 0.0;
+
+static void sort_ringbuf(ringbuf_t *rb_ptr);
+static void resum_ringbuf(ringbuf_t *rb_ptr);
+
+ringbuf_t *new_ringbuf(int N)
+{
+   if (!isnan(NaN))
+   {
+      NaN = strtod("NaN", NULL);  /* May change for Matlab. */
+   }
+   ringbuf_t *rb_ptr;
+   rb_ptr = calloc(1, sizeof(ringbuf_t));
+   rb_ptr->i_sorted = calloc(N, sizeof(int));
+   rb_ptr->data = calloc(N, sizeof(double));
+   rb_ptr->N_size = N;
+   zero_ringbuf(rb_ptr);
+   return rb_ptr;
+}
+
+void zero_ringbuf(ringbuf_t *rb_ptr)
+{
+   rb_ptr->N_filled = 0;
+   rb_ptr->N_good = 0;
+   rb_ptr->N_added = 0;
+   rb_ptr->i_oldest = 0;
+   rb_ptr->i_next = 0;
+   rb_ptr->sum = 0.0;
+   rb_ptr->sumsq = 0.0;
+}
+
+void delete_ringbuf(ringbuf_t *rb_ptr)
+{
+   free(rb_ptr->data);
+   free(rb_ptr->i_sorted);
+   free(rb_ptr);
+}
+
+int ringbuf_index(ringbuf_t *rb_ptr, int i)
+/* i is a Python-style index; return the actual offset, or -1 for error */
+{
+   /* printf("incoming index: %d", i);*/
+   if (i >= rb_ptr->N_filled) return -1;
+   if (i < -rb_ptr->N_filled) return -1;
+   if (i < 0) i += rb_ptr->i_next;
+   else       i += rb_ptr->i_oldest;
+   i %= rb_ptr->N_size;
+   if (i < 0) i += rb_ptr->N_size;
+   /*printf("changed to offset: %d\n", i);*/
+   return i;
+}
+
+int ringbuf_slice_i(ringbuf_t *rb_ptr, int i)
+/* For slices, out of range indices get clipped.*/
+/* This function is not needed for the pyrex interface. */
+{
+   /*printf("incoming index: %d", i);*/
+   if (i >= rb_ptr->N_filled) i = rb_ptr->N_filled;
+   if (i < -rb_ptr->N_filled) i = 0;
+   if (i < 0) i += rb_ptr->i_next;
+   else       i += rb_ptr->i_oldest;
+   i %= rb_ptr->N_size;
+   if (i < 0) i += rb_ptr->N_size;
+   /*printf("changed to offset: %d\n", i);*/
+   return i;
+}
+
+double ringbuf_getitem(ringbuf_t *rb_ptr, int i)
+{
+   i = ringbuf_index(rb_ptr, i);
+   if (i < 0) return 1e38;
+   return rb_ptr->data[i];
+}
+
+
+void resum_ringbuf(ringbuf_t *rb_ptr)
+{
+   int i;
+   double d;
+   rb_ptr->sum = 0.0;
+   rb_ptr->sumsq = 0.0;
+   for (i = 0; i < rb_ptr->N_filled; i++)
+   {
+      d = rb_ptr->data[i];
+      if (!isnan(d))
+      {
+         rb_ptr->sum += d;
+         rb_ptr->sumsq += d*d;
+      }
+   }
+}
+
+void ringbuf_add(ringbuf_t *rb_ptr, double d)
+{
+
+   double d_old;
+   int i, i_new, good_new, N;
+
+   N = rb_ptr->N_size; /* We need this many times. */
+   i_new = rb_ptr->i_next;
+   /* Save the old value; otherwise, it will be overwritten. */
+   d_old = rb_ptr->data[rb_ptr->i_oldest];
+   rb_ptr->data[i_new] = d;
+   good_new = !isnan(d);
+#if 0
+   printf("new value: %lf  good_new: %d\n", d, good_new);
+   printf("i_next: %d i_oldest: %d N_filled: %d N_good: %d\n",
+            rb_ptr->i_next, rb_ptr->i_oldest,
+            rb_ptr->N_filled, rb_ptr->N_good);
+#endif
+   rb_ptr->i_next++;
+   rb_ptr->i_next %= N;
+
+   if (rb_ptr->N_filled == rb_ptr->N_size) /* already full */
+   {
+      if (!isnan(d_old))
+      {
+         rb_ptr->sum -= d_old;
+         rb_ptr->sumsq -= d_old * d_old;
+         /* Remove the i_oldest entry from i_sorted,
+            and slide the remaining entries down.
+         */
+         for (i = 0; i < rb_ptr->N_good; i++)
+         {
+            if (rb_ptr->i_sorted[i] == rb_ptr->i_oldest)
+               break;
+         }
+         for ( ; i < rb_ptr->N_good - 1; i++)
+         {
+            rb_ptr->i_sorted[i] = rb_ptr->i_sorted[i+1];
+         }
+         rb_ptr->N_good--;
+      }
+      /* The new entry is temporarily put at the end of the array.
+      */
+      if (good_new)
+      {
+         rb_ptr->i_sorted[rb_ptr->N_good] = i_new;
+         rb_ptr->N_good++;
+      }
+      rb_ptr->i_oldest++;
+      rb_ptr->i_oldest %= N;
+   }
+   else  /* not full before adding this element */
+   {
+      if (good_new)
+      {
+         rb_ptr->i_sorted[rb_ptr->N_good] = i_new;
+         rb_ptr->N_good++;
+      }
+      rb_ptr->N_filled++;
+   }
+   if (good_new)
+   {
+      rb_ptr->sum += d;
+      rb_ptr->sumsq += d*d;
+      sort_ringbuf(rb_ptr);
+   }
+   /* To prevent accumulation of truncation error, we
+      recalculate the sums periodically.
+   */
+   rb_ptr->N_added++;
+   if (rb_ptr->N_added % (rb_ptr->N_size + 10000) == 0)
+   {
+      resum_ringbuf(rb_ptr);
+   }
+#if 0
+   printf("i_next: %d i_oldest: %d N_filled: %d N_good: %d\n",
+            rb_ptr->i_next, rb_ptr->i_oldest,
+            rb_ptr->N_filled, rb_ptr->N_good);
+#endif
+}
+
+/* This is not a full sort--it assumes the list is
+   already sorted except for the last entry.  It uses a single
+   pass of bubble sorting to put that entry in its place.
+   The code could be moved bodily into the function above.
+*/
+void sort_ringbuf(ringbuf_t *rb_ptr)
+{
+   int i, i_hold;
+   int *ip;
+   double *dp;
+
+   ip = rb_ptr->i_sorted;
+   dp = rb_ptr->data;
+
+   for (i = rb_ptr->N_good - 1; i > 0; i--)
+   {
+      if (dp[ip[i]] < dp[ip[i-1]])
+      {
+         i_hold = ip[i];
+         ip[i] = ip[i-1];
+         ip[i-1] = i_hold;
+      }
+      else
+      {
+         break;
+      }
+   }
+}
+
+double ringbuf_min(ringbuf_t *rb_ptr)
+{
+   return rb_ptr->data[rb_ptr->i_sorted[0]];
+}
+
+double ringbuf_max(ringbuf_t *rb_ptr)
+{
+   int i_end;
+   i_end = rb_ptr->N_good - 1;
+   return rb_ptr->data[rb_ptr->i_sorted[i_end]];
+}
+
+double ringbuf_median(ringbuf_t *rb_ptr)
+{
+   int i_mid, N;
+   N = rb_ptr->N_good;
+   if (N == 0) return NaN;
+   i_mid = N/2;
+   if (N % 2 == 1)
+   {
+      return rb_ptr->data[rb_ptr->i_sorted[i_mid]];
+   }
+   else
+   {
+      return 0.5 * (rb_ptr->data[rb_ptr->i_sorted[i_mid]]
+                     + rb_ptr->data[rb_ptr->i_sorted[i_mid - 1]]);
+   }
+}
+
+int ringbuf_N_good(ringbuf_t *rb_ptr)
+{
+   return rb_ptr->N_good;
+}
+
+
+int ringbuf_N_filled(ringbuf_t *rb_ptr)
+{
+   return rb_ptr->N_filled;
+}
+
+
+
+int ringbuf_N_added(ringbuf_t *rb_ptr)
+{
+   return rb_ptr->N_added;
+}
+
+
+
+double ringbuf_mean(ringbuf_t *rb_ptr)
+{
+   int N;
+
+   N = rb_ptr->N_good;
+   if (N > 0)
+   {
+      return rb_ptr->sum / N;
+   }
+   else
+   {
+      return NaN;
+   }
+}
+
+double ringbuf_sd(ringbuf_t *rb_ptr)
+{
+   double m, s;
+   int N;
+
+   N = rb_ptr->N_good;
+   if (N == 0)
+      return NaN;
+   m = ringbuf_mean(rb_ptr);
+   s = rb_ptr->sumsq / N - m*m;
+   if (s > 0.0)
+   {
+      return sqrt(s);
+   }
+   else
+   {
+      return 0.0;
+   }
+}
+
+void c_runstats(int nrb, int nd, double *data, double *dmean, double *dstd,
+                double *dmin, double *dmax, double *dmed, int *ng)
+{
+    int i, j;
+    ringbuf_t *rb_ptr;
+
+    rb_ptr = new_ringbuf(nrb);
+
+    for (j=0; j<nd; i++, j++)
+      {
+       ringbuf_add(rb_ptr, data[j]);
+        dmean[j] = ringbuf_mean(rb_ptr);
+        dstd[j] = ringbuf_sd(rb_ptr);
+        dmin[j] = ringbuf_min(rb_ptr);
+        dmax[j] = ringbuf_max(rb_ptr);
+        dmed[j] = ringbuf_median(rb_ptr);
+        ng[j] = rb_ptr->N_good;
+    }
+    delete_ringbuf(rb_ptr);
+}
+
+
+void c_runstats2(int nrb, int nd, int step, int ofs,
+                 double *data, double *dmean, double *dstd,
+                 double *dmin, double *dmax, double *dmed, int *ng)
+{
+    int i, j;
+    int npad = (nrb - 1) / 2;
+    ringbuf_t *rb_ptr;
+
+    data += ofs;
+    dmean += ofs;
+    dstd += ofs;
+    dmin += ofs;
+    dmax += ofs;
+    dmed += ofs;
+    ng += ofs;
+
+    rb_ptr = new_ringbuf(nrb);
+    for (i = 0; i < npad; i++)
+    {
+        ringbuf_add(rb_ptr, data[i*step]);
+    }
+    for (j=0; j<nd; i++, j++)
+    {
+        if (i < nd) {ringbuf_add(rb_ptr, data[i*step]);}
+        else        {ringbuf_add(rb_ptr, NaN);}
+        dmean[j*step] = ringbuf_mean(rb_ptr);
+        dstd[j*step] = ringbuf_sd(rb_ptr);
+        dmin[j*step] = ringbuf_min(rb_ptr);
+        dmax[j*step] = ringbuf_max(rb_ptr);
+        dmed[j*step] = ringbuf_median(rb_ptr);
+        ng[j*step] = rb_ptr->N_good;
+    }
+    delete_ringbuf(rb_ptr);
+}
+
+

Deleted: trunk/py4science/examples/pyrex/movavg/run_test.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/run_test.py  2007-12-07 00:01:46 UTC 
(rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/run_test.py  2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -1,3 +0,0 @@
-#!/usr/bin/env python
-from numpyx import test
-test()

Modified: trunk/py4science/examples/pyrex/movavg/setup.py
===================================================================
--- trunk/py4science/examples/pyrex/movavg/setup.py     2007-12-07 00:01:46 UTC 
(rev 4661)
+++ trunk/py4science/examples/pyrex/movavg/setup.py     2007-12-07 04:43:36 UTC 
(rev 4662)
@@ -18,16 +18,12 @@
 
 ringbufmod = Extension('ringbuf',
                         ['ringbuf.pyx',
-                         'ringbufnan.c'])
+                         'ringbufnan.c'],
+                       include_dirs = [numpy.get_include()])
 
-
-movavgmod = Extension('movavg',
-                      ['movavg.pyx'],
-                      include_dirs = [numpy.get_include()])
-
 # Call the routine which does the real work
-setup(name        = 'movavg',
-      description = 'moveng averages, using a c ring buffer',
-      ext_modules = [movavgmod, ringbufmod,],
+setup(name        = 'ringbuf',
+      description = 'trailing stats using a c ring buffer',
+      ext_modules = [ringbufmod,],
       cmdclass    = {'build_ext': build_ext},
       )


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
SF.Net email is sponsored by: 
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to