[yoda-svn] r405 - in trunk/pyext/yoda: . include

blackhole at projects.hepforge.org blackhole at projects.hepforge.org
Tue Nov 8 02:29:59 GMT 2011


Author: davemallows
Date: Tue Nov  8 02:29:58 2011
New Revision: 405

Log:
Updated cython bindings

Added:
   trunk/pyext/yoda/include/00-imports.pyx
   trunk/pyext/yoda/include/40-WriterAIDA.pyx
   trunk/pyext/yoda/include/99-ReaderAIDA.pyx
   trunk/pyext/yoda/shims.h
Deleted:
   trunk/pyext/yoda/imports.pyx
   trunk/pyext/yoda/include/40-ReaderAIDA.pyx
   trunk/pyext/yoda/yoda.cpp
   trunk/pyext/yoda/yoda.pyx
Modified:
   trunk/pyext/yoda/Makefile.am
   trunk/pyext/yoda/include/10-AnalysisObject.pyx
   trunk/pyext/yoda/include/20-Point2D.pyx
   trunk/pyext/yoda/include/30-HistoBin1D.pyx
   trunk/pyext/yoda/include/30-HistoBin2D.pyx
   trunk/pyext/yoda/include/30-Scatter2D.pyx
   trunk/pyext/yoda/include/40-Histo1D.pyx
   trunk/pyext/yoda/include/40-Histo2D.pyx

Modified: trunk/pyext/yoda/Makefile.am
==============================================================================
--- trunk/pyext/yoda/Makefile.am	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/Makefile.am	Tue Nov  8 02:29:58 2011	(r405)
@@ -4,8 +4,9 @@
 yoda.cpp: yoda.pyx
 	$(PYTHON) -m cython --cplus yoda.pyx
 
-yoda.pyx: imports.pyx include/10-AnalysisObject.pyx include/20-Dbn1D.pyx include/20-Point2D.pyx include/30-HistoBin1D.pyx include/30-HistoBin2D.pyx include/30-Reader.pyx include/30-Scatter2D.pyx include/40-Histo1D.pyx include/40-Histo2D.pyx include/40-ReaderAIDA.pyx
-	cat imports.pyx include/*.pyx > yoda.pyx
+yoda.pyx: include/00-imports.pyx include/10-AnalysisObject.pyx include/20-Dbn1D.pyx include/20-Point2D.pyx include/30-HistoBin1D.pyx include/30-HistoBin2D.pyx include/30-Reader.pyx include/30-Scatter2D.pyx include/40-Histo1D.pyx include/40-Histo2D.pyx include/40-WriterAIDA.pyx include/99-ReaderAIDA.pyx
+	cat include/*.pyx > yoda.pyx
 
 clean-local:
 	rm yoda.cpp yoda.pyx
+

Added: trunk/pyext/yoda/include/00-imports.pyx
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/pyext/yoda/include/00-imports.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -0,0 +1,4 @@
+from libcpp.vector cimport vector
+from string cimport string
+from libcpp.pair cimport pair
+from libcpp cimport bool

Modified: trunk/pyext/yoda/include/10-AnalysisObject.pyx
==============================================================================
--- trunk/pyext/yoda/include/10-AnalysisObject.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/10-AnalysisObject.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -2,15 +2,29 @@
     cdef cppclass cAnalysisObject "YODA::AnalysisObject":
         string type()
 
-ctypedef cAnalysisObject* AOptr
+ctypedef cAnalysisObject* AOptr 
 
 cdef class AnalysisObject:
     """Base object class"""
     cdef cAnalysisObject *thisptr
+    cdef bool _dealloc
+
+    def __cinit__(self):
+        self._dealloc = False
 
     @property
     def type(self):
         """The type of this analysis object as a string"""
         return self.thisptr.type().c_str()
 
-    # TODO: Map annotations, etc.
+    def __dealloc__(self):
+        if self._dealloc:
+            del self.thisptr
+
+    cdef AnalysisObject setptr(self, AOptr ptr, dealloc=False):
+        if self._dealloc:
+            del self.thisptr
+
+        self.thisptr = ptr
+        self._dealloc = dealloc
+        return self

Modified: trunk/pyext/yoda/include/20-Point2D.pyx
==============================================================================
--- trunk/pyext/yoda/include/20-Point2D.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/20-Point2D.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -21,10 +21,26 @@
 cdef class Point2D:
     cdef cPoint2D* thisptr
 
+    cdef bool _dealloc
+
+    cdef cPoint2D* ptr(self):
+        return self.thisptr
+
+    cdef Point2D setptr(self, cPoint2D* ptr, dealloc=False):
+        if self._dealloc:
+            del self.thisptr
+
+        self.thisptr = ptr
+        self._dealloc = dealloc
+        return self
+
     def __cinit__(self):
-        self.thisptr = new cPoint2D()
+        self._dealloc = False
 
     def __init__(self,  *args):
+        self.setptr(new cPoint2D(), True)
+        self._dealloc = True
+
         if len(args) == 0:
             self.pos = 0, 0
         elif len(args) == 2 :
@@ -39,18 +55,22 @@
         else:
             raise ValueError(
                 'Wrong number of values: can take 2, 4, or 6 parameters')
+
+    def __dealloc__(self):
+        if self._dealloc:
+            del self.thisptr
         
     def _x(self):
-        return self.thisptr.x()
+        return self.ptr().x()
 
     def _y(self):
-        return self.thisptr.y()
+        return self.ptr().y()
 
     def _setX(self, double x):
-        self.thisptr.setX(x)
+        self.ptr().setX(x)
 
     def _setY(self, double y):
-        self.thisptr.setY(y)
+        self.ptr().setY(y)
 
     x = property(_x, _setX)
     y = property(_y, _setY)
@@ -62,14 +82,14 @@
     def _setPos(self, pos):
         cdef double x, y
         x, y = pos
-        self.thisptr.setX(x)
-        self.thisptr.setY(y)
+        self.ptr().setX(x)
+        self.ptr().setY(y)
 
     pos = property(_pos, _setPos)
 
     def _xErrs(self):
         """The x-errors as a 2-tuple (low, high)"""
-        cdef pair[double, double] xErrs = self.thisptr.xErrs()
+        cdef pair[double, double] xErrs = self.ptr().xErrs()
         return (xErrs.first, xErrs.second)
 
     def _setxErrs(self, arg):
@@ -79,13 +99,13 @@
             low = arg
             high = arg
 
-        self.thisptr.setXErr(low, high)
+        self.ptr().setXErr(low, high)
 
     xErrs = property(_xErrs, _setxErrs)
 
     def _yErrs(self):
         """The y-errors as a 2-tuple (low, high)"""
-        cdef pair[double, double] yErrs = self.thisptr.yErrs()
+        cdef pair[double, double] yErrs = self.ptr().yErrs()
         return (yErrs.first, yErrs.second)
 
     def _setyErrs(self, arg):
@@ -96,12 +116,13 @@
             low = arg
             high = arg
 
-        self.thisptr.setYErr(low, high)
+        self.ptr().setYErr(low, high)
 
     yErrs = property(_yErrs, _setyErrs)
 
     def __repr__(self):
         return 'Point2D({0},{1})'.format(self.x, self.y)
 
-    def __dealloc__(self):
-        del self.thisptr
+cdef Point2D Point2D_fromptr(cPoint2D *ptr, dealloc = False):
+    cdef Point2D p = Point2D.__new__(Point2D)
+    return p.setptr(ptr, dealloc)

Modified: trunk/pyext/yoda/include/30-HistoBin1D.pyx
==============================================================================
--- trunk/pyext/yoda/include/30-HistoBin1D.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/30-HistoBin1D.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -2,6 +2,7 @@
 
     cdef cppclass cHistoBin1D "YODA::HistoBin1D":
         cHistoBin1D (cHistoBin1D &h)
+        cHistoBin1D (double, double)
         double area()
         double height()
         double areaErr()
@@ -31,27 +32,28 @@
         double sumWX()
         double sumWX2()
 
-# Disabled to work with Cython 0.13
-#cdef extern from "YODA/HistoBin1D.h" namespace "YODA::HistoBin1D":
-#    cHistoBin1D operator + (cHistoBin1D &, cHistoBin1D &)
-#    cHistoBin1D operator - (cHistoBin1D &, cHistoBin1D &)"""
-
-# TODO: re-enable these operators using a c++ shim like
-#using namespace YODA
-#Histo1D add__Histo1D(Histo1D a, Histo1D b) 
-#{ 
-#       return YODA::Histo1D::add(a, b); 
-#} 
-
+#Ugly hack using shim header for Cython 0.13
+cdef extern from "shims.h":
+    cHistoBin1D add_HistoBin1D (cHistoBin1D &, cHistoBin1D &)
+    cHistoBin1D subtract_HistoBin1D (cHistoBin1D &, cHistoBin1D &)
 
 cdef class HistoBin1D:
     cdef cHistoBin1D *thisptr
+    cdef bool _dealloc
 
-    cdef setptr(self, cHistoBin1D *ptr):
-        return self
+    def __cinit__(self):
+        self._dealloc = False
+
+    def __dealloc__(self):
+        if self._dealloc:
+            del self.thisptr
 
-    cdef set(self, cHistoBin1D ptr):
-        self.thisptr = new cHistoBin1D(ptr)
+    cdef HistoBin1D setptr(self, cHistoBin1D *ptr, bool dealloc):
+        if self._dealloc:
+            del self.thisptr
+
+        self.thisptr = ptr
+        self._dealloc = dealloc
         return self
 
     cdef cHistoBin1D* ptr(self):
@@ -59,82 +61,144 @@
 
     @property
     def lowEdge(self):
+        """The lower of the two bin edges."""
         return self.ptr().lowEdge()
     
     xMin = lowEdge
 
     @property
     def highEdge(self):
+        """The higher of the two bin edges."""
         return self.ptr().highEdge()
 
     xMax = highEdge
 
     @property
     def width(self):
+        """The width of the bin."""
         return self.ptr().width()
 
     @property
     def focus(self):
+        """The focus of the bin."""
         return self.ptr().focus()
 
     @property
     def midpoint(self):
+        """The point half-way between the bin edges."""
         return self.ptr().midpoint()
 
     @property
     def xMean(self):
+        """The mean of the x-values that have filled the bin."""
         return self.ptr().xMean()
 
     @property
     def xVariance(self):
+        """The variance of the x-values that have filled the bin."""
         return self.ptr().xVariance()
 
     @property
     def xStdDev(self):
+        """The standard deviation of the x-values that have filled the bin."""
         return self.ptr().xStdDev()
 
     @property
     def numEntries(self):
+        """The number of entries in the bin."""
         return self.ptr().numEntries()
 
     @property
     def effNumEntries(self):
+        """The effective number of entries in the bin. This is
+        (s.sumW)**2 / s.sumW2"""
         return self.ptr().effNumEntries()
 
     @property
     def sumW(self):
+        """Sum of weights."""
         return self.ptr().sumW()
 
     @property
     def sumW2(self):
+        """Sum of weights squared."""
         return self.ptr().sumW2()
 
     @property
     def sumWX(self):
+        """Sum of the products of x-values and their weights."""
         return self.ptr().sumWX()
 
     @property
     def sumWX2(self):
+        """Sum of the products of x-values squared and their weights."""
         return self.ptr().sumWX2()
 
     @property
     def area(self):
+        """
+        b.area <==> b.sumW
+        
+        The area of the bin is the sum of weights of the bin; it is
+        independent of width.
+       
+        """
         return self.ptr().area()
 
     @property
     def height(self):
+        """
+        b.height <==> b.area / b.width
+        
+        The height of the bin is defined as the area divided by the
+        width.
+        
+        """
         return self.ptr().height()
 
     @property
+    def areaErr(self):
+        """
+        Error computed using binomial statistics on squared sum of bin weights,
+        i.e. s.areaErr = sqrt(s.sumW2)
+        
+        """
+        return self.ptr().areaErr()
+
+    @property
     def heightErr(self):
+        """
+        Height error - scales the s.areaError by the reciprocal of the
+        bin width.
+
+        """
         return self.ptr().heightErr()
 
-    @property
-    def areaErr(self):
-        return self.ptr().areaErr()
 
     def scaleX(self, double factor):
+        """
+        bin.scaleX(factor) -> bin
+
+        Scale the x-axis of `bin` in-place by `factor`.
+        
+        """
+        self.ptr().scaleX(factor)
+
+    def scaleW(self, double factor):
+        """
+        bin.scaleW(factor) -> bin 
+
+        Scale `bin` in-place as if all weights were scaled by given `factor`
+
+        """
         self.ptr().scaleX(factor)
 
     def __repr__(self):
         return 'HistoBin1D(%r)' % self.area
+
+cdef HistoBin1D HistoBin1D_fromptr(cHistoBin1D *ptr, dealloc=False):
+    # Construct a Python HistoBin1D from a pointer to a cHistoBin1D,
+    # without calling __init__ and excessive memory allocation
+    cdef HistoBin1D bin = HistoBin1D.__new__(HistoBin1D)
+    return bin.setptr(ptr, dealloc)
+

Modified: trunk/pyext/yoda/include/30-HistoBin2D.pyx
==============================================================================
--- trunk/pyext/yoda/include/30-HistoBin2D.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/30-HistoBin2D.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -47,10 +47,23 @@
         double sumWXY()
         double sumWX2()
         double sumWY2()
+
 cdef class HistoBin2D:
     cdef cHistoBin2D *thisptr
 
-    cdef setptr(self, cHistoBin2D *ptr):
+    def __cinit__(self):
+        self._dealloc = False
+
+    def __dealloc__(self):
+        if self._dealloc:
+            del self.thisptr
+
+    cdef HistoBin2D setptr(self, cHistoBin2D *ptr, bool dealloc):
+        if self._dealloc:
+            del self.thisptr
+
+        self.thisptr = ptr
+        self._dealloc = dealloc
         return self
 
     cdef set(self, cHistoBin2D ptr):
@@ -79,7 +92,6 @@
     def scaleW(self, double factor):
         self.ptr().scaleW(factor)
 
-
     @property
     def lowEdgeX(self):
         return self.ptr().lowEdgeX()
@@ -88,7 +100,6 @@
     def highEdgeX(self):
         return self.ptr().highEdgeX()
 
-
     @property
     def lowEdgeY(self):
         return self.ptr().lowEdgeY()
@@ -192,3 +203,9 @@
 
     def __repr__(self):
         return 'HistoBin2D(%r)' % self.volume
+
+cdef HistoBin2D HistoBin2D_fromptr(cHistoBin2D *ptr, dealloc=False):
+    # Construct a Python HistoBin2D from a pointer to a cHistoBin2D,
+    # without calling __init__ and excessive memory allocation
+    cdef HistoBin2D bin = HistoBin2D.__new__(HistoBin2D)
+    return bin.setptr(ptr, dealloc)

Modified: trunk/pyext/yoda/include/30-Scatter2D.pyx
==============================================================================
--- trunk/pyext/yoda/include/30-Scatter2D.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/30-Scatter2D.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -2,37 +2,72 @@
     cdef cppclass cScatter2D "YODA::Scatter2D" (cAnalysisObject):
         size_t numPoints()
         vector[cPoint2D] points()
+        cPoint2D& point(size_t i)
         cScatter2D (cScatter2D &s)
+        cScatter2D (vector[cPoint2D]&, string, string)
+        cScatter2D ()
 
 cdef class Scatter2D(AnalysisObject):
+    cdef tuple _points
 
-    cdef cScatter2D * ptr(self):
-        return <cScatter2D *> self.thisptr
+    def __init__(self, points, char *path="", char *title=""):
+        points = tuple(points)
 
-    cdef setptr(self, cScatter2D *ptr):
-        self.thisptr = ptr
-        return self
+        cdef size_t N = len(points)
+        cdef vector[cPoint2D] point_vector = vector[cPoint2D](N)
+        cdef Point2D item
+        cdef cScatter2D *scatter
+        cdef int i
+        for i in range(N):
+            item = points[i]
+            point_vector[i] = item.ptr()[0]
+        
+        scatter = new cScatter2D(point_vector, string(path), string(title))
+        self.setptr(scatter, True)
+
+        self._points = points
 
     @property
     def numPoints(self):
         return self.ptr().numPoints()
+    
+    cdef cScatter2D * ptr(self):
+        return <cScatter2D *> self.thisptr
+
+    def __getitem__(self, args):
+        return self.points.__getitem__(args)
+
+    def copy(self):
+        return Scatter2D_fromptr(new cScatter2D(self.ptr()[0]), True)
 
     @property
     def points(self):
-        cdef vector[cPoint2D] vec
-        cdef int i
-        cdef cPoint2D *p
-        vec = self.ptr().points()
-        out = []
-        for i in range(vec.size()):
-            pt = Point2D()
-            pt.thisptr[0] = vec[i]
-            out.append(pt)
-
-        return out
+        cdef size_t i
+        cdef Point2D pt
+        if self._points:
+            return self._points
+        else:
+            out = []
+
+            for i in range(self.ptr().numPoints()):
+                pt = Point2D_fromptr(& self.ptr().point(i))
+                out.append(pt)
+
+            out = tuple(out)
+            self._points = out
+            return out
 
     def __repr__(self):
-        return 'Scatter2D%r' % self.points
+        return '<Scatter2D>'
 
-    def __dealloc__(self):
-        del self.thisptr
+        
+# dealloc decides whether or not the python object is responsible for freeing
+# used memory. Most times, it's not - we're just wrapping a C++ instance.
+# However, the same classes should be used for both wrapping and creating.
+
+# It is important that we do free allocated C++ memory, because otherwise we can
+# quickly end up with memory leaks.
+
+cdef Scatter2D Scatter2D_fromptr(cScatter2D* ptr, dealloc = False):
+    cdef Scatter2D scatter = Scatter2D.__new__(Scatter2D)
+    return scatter.setptr(ptr, False)

Modified: trunk/pyext/yoda/include/40-Histo1D.pyx
==============================================================================
--- trunk/pyext/yoda/include/40-Histo1D.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/40-Histo1D.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -1,5 +1,4 @@
 cdef extern from "YODA/Histo1D.h" namespace "YODA":
-    # TODO: We can use these in place of the workaround when Cython 0.15 is available
     #cHisto1D operator + (cHisto1D &, cHisto1D &)
     #cHisto1D operator - (cHisto1D &, cHisto1D &)
     #cScatter2D operator / (cHisto1D &, cHisto1D &)"""
@@ -23,6 +22,7 @@
         double lowEdge()
         double highEdge()
         vector[cHistoBin1D] &bins()
+        cHistoBin1D & bin "bin"(size_t i)
         cDbn1D &underflow()
         cDbn1D &overflow()
         void eraseBin(size_t index)
@@ -35,8 +35,17 @@
         double variance(bool includeoverflows)
         double stdDev(bool includeoverflows)
 
+cdef extern from "shims.h":
+    cHisto1D add_Histo1D (cHisto1D &, cHisto1D &)
+    cHisto1D subtract_Histo1D (cHisto1D &, cHisto1D &)
+    cScatter2D divide_Histo1D (cHisto1D &, cHisto1D &)
+    cScatter2D Scatter2D_mkScatter(cHisto1D &)
+
+from cython.operator cimport dereference as deref
+
 cdef class Histo1D(AnalysisObject):
-    def __cinit__(self, *args, **kwargs):
+    def __init__(self, *args, **kwargs):
+        self._dealloc = True
         cdef:
             size_t nbins
             double lower
@@ -55,89 +64,201 @@
 
     cdef cHisto1D* ptr(self):
         return <cHisto1D *> self.thisptr
-
-    cdef setptr(self, cHisto1D *ptr):
-        self.thisptr = ptr
-        return self
+    
+    def asScatter(self):
+        """
+        h.asScatter() -> Scatter2D
+
+        Return a 2D scatter data object from the histogram's bins and heights
+        
+        """
+        cdef cScatter2D *s = new cScatter2D()
+        s[0] = Scatter2D_mkScatter(self.ptr()[0])
+        return Scatter2D_fromptr(s, True)
 
     def fill(self, double x, double weight=1.0):
+        """
+        h.fill(x[, weight=1.0]) -> self
+
+        Fill the given histogram with value x and optional weighting
+
+        """
         self.ptr().fill(x, weight)
+        return self
 
     def reset(self):
-        """Reset the histogram but leave the bin structure"""
+        """
+        h.reset() -> self
+
+        Reset the histogram but leave the bin structure
+        
+        """
         self.ptr().reset()
+        return self
 
     def scaleW(self, double factor):
-        """Scale the histogram and its statistics by given factor"""
+        """
+        s.scaleW(factor) -> self
+
+        Scale the histogram and its statistics by given factor
+
+        """
         self.ptr().scaleW(factor)
+        return self
+
 
     def mergeBins(self, size_t a, size_t b):
+        """
+        s.mergeBins(from, to) -> self
+
+        Merge bins between indexes from `from` to `to`
+
+        """
         self.ptr().mergeBins(a, b)
 
     def rebin(self, int n):
+        """
+        s.rebin(n) -> self
+
+        Merge every nth bin in the current histogram.
+
+        """
         self.ptr().rebin(n)
 
     @property
     def bins(self):
-        cdef size_t numbins = self.ptr().numBins()
-        cdef size_t i
+        """
+        h.bins -> tuple(HistoBin1D)
+
+        Access the bin objects of this histogram. Bin objects are mutable and
+        changes to the bin objects will be propagated back to the histogram
+        unless the copy() method is called on a bin.
 
-        cdef vector[cHistoBin1D] bins = self.ptr().bins()
+        """
 
-        cdef cHistoBin1D *b
+
+        cdef size_t numbins = self.ptr().numBins()
+        cdef size_t i
+        cdef HistoBin1D bin
 
         out = []
 
         for i in range(numbins):
-            out.append(HistoBin1D().set(bins[i]))
+            bin = HistoBin1D_fromptr(& self.ptr().bins()[i])
+            out.append(bin)
+        self.ptr().bins()
 
         return out
-
+    
     @property
     def lowEdge(self):
+        """
+        h.lowEdge -> float
+
+        The x-value of the lowest edge of the lowest bin of the histogram.
+        
+        """
         return self.ptr().lowEdge()
 
     @property
     def highEdge(self):
-        return self.ptr().highEdge()
+        """
+        h.highEdge -> float
 
+        The x-value of the highest edge of the highest bin of the histogram.
+        
+        """
+        return self.ptr().highEdge()
 
+    @property
     def underflow(self):
+        """
+        h.underflow -> Distribution1D
+
+        Return the Distribution1D object representing the underflow.
+
+        """
         pass
 
     def __delitem__(self, size_t ix):
         self.ptr().eraseBin(ix)
 
     def __getitem__(self, size_t ix):
-        return HistoBin1D().set(self.ptr().bins()[ix])
+        return HistoBin1D_fromptr(& self.ptr().bin(ix))
 
     def integral(self, bool overflows=True):
+        """
+        s.integral([overflows]) -> float
+
+        Return the total area of the histogram. If overflows is False, ignore
+        over-and underflow bins.
+        
+        """
         return self.ptr().integral(overflows)
 
     def sumW(self, bool overflows=True):
+        """
+        s.sumW([overflows]) -> float
+
+        Return the sum of weights of the histogram. If overflows is False,
+        ignore over-and underflow bins.
+
+        """
+
         return self.ptr().sumW(overflows)
 
     def sumW2(self, bool overflows=True):
+        """
+        s.sumW2([overflows]) -> float
+
+        Return the sum of weights squared. If overflows is False, ignore
+        over-and underflow bins.
+        
+        """
         return self.ptr().sumW2(overflows)
 
+    def mean(self, bool overflows=True):
+        """
+        s.mean([overflows]) -> float
+
+        Return the mean. If overflows is False, ignore the over- and underflow
+        bins.
+
+        """
+
     def variance(self, bool overflows=True):
+        """
+        s.variance([overflows]) -> float
+
+        Return the variance. If overflows is False, ignore the over- and
+        underflow bins.
+
+        """
         return self.ptr().variance(overflows)
 
     def stdDev(self, bool overflows=True):
-        return self.ptr().stdDev(overflows)
+        """
+        s.stdDev([overflows]) -> float
 
+        Return the standard deviation. If overflows is False, ignore over-and
+        underflow bins.
+        
+        """
+        return self.ptr().stdDev(overflows)
 
-    """def __add__(Histo1D a, Histo1D b):
-        cdef cHisto1D *res
-        res = new cHisto1D(a.ptr()[0] + b.ptr()[0])
-        return Histo1D().setptr(res)
+    def __add__(Histo1D a, Histo1D b):
+        cdef cHisto1D *res = new cHisto1D(add_Histo1D(a.ptr()[0], b.ptr()[0]))
+        return Histo1D_fromptr(res, True)
 
     def __sub__(Histo1D a, Histo1D b):
-        cdef cHisto1D *res
-        res = new cHisto1D(a.ptr()[0] - b.ptr()[0])
-        return Histo1D().setptr(res)
+        cdef cHisto1D *res = new cHisto1D(subtract_Histo1D(a.ptr()[0], b.ptr()[0]))
+        return Histo1D_fromptr(res, True)
 
     def __mul__(x, y):
+        """
+        Scalar multiplication. Equivalent to scaleW acting on a copy.
+        
+        """
         cdef cHisto1D *res
         tx, ty = type(x), type(y)
         if (tx is int or tx is float) and ty is Histo1D:
@@ -149,31 +270,39 @@
 
         res = new cHisto1D(histo.ptr()[0])
         res.scaleW(factor)
-        return Histo1D().setptr(res)
-
+        return Histo1D_fromptr(res, True)
 
     def _div_scalar(Histo1D x, double y):
-        cdef cHisto1D *res = new cHisto1D(x.ptr()[0])
         if y == 0:
             raise ArithmeticError('Histo1D: Divide by zero scalar')
+
+        cdef cHisto1D *res = new cHisto1D(x.ptr()[0])
+
         res.scaleW(1.0 / y)
-        return Histo1D().setptr(res)
+        return Histo1D_fromptr(res, True)
 
     def _div_histo(Histo1D x, Histo1D y):
-        cdef cScatter2D *res
-
-        res = new cScatter2D(x.ptr()[0] / y.ptr()[0])
-        return Scatter2D().setptr(res)
+        cdef cScatter2D s = divide_Histo1D(x.ptr()[0], y.ptr()[0])
+        return Scatter2D_fromptr(&s)
 
     def __div__(x, y):
+        """
+        Division by scalar (i.e. multiplication by reciprocal) or another
+        1D histogram. 
+        
+        """
         tx = type(x); ty = type(y)
         if tx is Histo1D:
             if ty is int or ty is float:
                 return x._div_scalar(y)
             elif ty is Histo1D:
                 return x._div_histo(y)
-
-        raise RuntimeError('Cannot multiply %r by %r' % (tx, ty))"""
-
+        
+        raise RuntimeError('Cannot multiply %r by %r' % (tx, ty))
+    
     def __repr__(self):
         return 'Histo1D%r' % self.bins
+
+cdef Histo1D Histo1D_fromptr(cHisto1D *ptr, bool dealloc=False):
+    cdef Histo1D histo = Histo1D.__new__(Histo1D)
+    return histo.setptr(ptr, dealloc)

Modified: trunk/pyext/yoda/include/40-Histo2D.pyx
==============================================================================
--- trunk/pyext/yoda/include/40-Histo2D.pyx	Mon Nov  7 09:13:22 2011	(r404)
+++ trunk/pyext/yoda/include/40-Histo2D.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -7,7 +7,6 @@
                  size_t nbinsY, double lowerY, double upperY,
                  string &path, string &title)
         
-        cHisto1D(cHisto1D &h, string &path)
         cHisto2D(cHisto2D &h)
 
         void fill(double x, double y, double weight)
@@ -43,7 +42,13 @@
         double yStdDev(bool includeoverflows)
 
 cdef class Histo2D(AnalysisObject):
-    def __cinit__(self, *args, **kwargs):
+    cdef tuple _bins
+
+    def __cinit__(self):
+        self._bins = None
+        self._dealloc = False
+
+    def __init__(self, *args, **kwargs):
         cdef:
             size_t nbinsX, nbinsY
             double lowX, highX, lowY, highY
@@ -55,16 +60,12 @@
 
             self.setptr(
                 new cHisto2D(nbinsX, lowX, highX, nbinsY, lowY, highY,
-                             string(path), string(title))
+                             string(path), string(title)), True
             )
 
     cdef cHisto2D* ptr(self):
         return <cHisto2D *> self.thisptr
 
-    cdef setptr(self, cHisto2D *ptr):
-        self.thisptr = ptr
-        return self
-    
     def fill(self, double x, double y, double weight=1.0):
         self.ptr().fill(x, y, weight)
 
@@ -86,17 +87,12 @@
     def bins(self):
         cdef size_t numbins = self.ptr().numBins()
         cdef size_t i
-        
-        cdef vector[cHistoBin2D] bins = self.ptr().bins()
 
-        cdef cHistoBin2D *b
+        if self._bins is None:
+            self._bins = tuple([HistoBin2D_fromptr(& self.ptr().bins().at(i))
+                          for i in xrange(numbins)])
 
-        out = []
-
-        for i in range(numbins):
-            out.append(HistoBin2D().set(bins[i]))
-
-        return out
+        return self._bins
     
     @property
     def lowEdgeX(self):
@@ -164,7 +160,11 @@
         res.scaleW(factor)
         return Histo2D().setptr(res)"""
 
-    
     def __repr__(self):
         return 'Histo2D%r' % self.bins
 
+cdef Histo2D Histo2D_fromptr(cHisto2D *ptr, dealloc=False):
+    # Construct a Python Histo2D from a pointer to a cHisto2D,
+    # without calling __init__ and excessive memory allocation
+    cdef Histo2D bin = Histo2D.__new__(Histo2D)
+    return bin.setptr(ptr, dealloc)

Added: trunk/pyext/yoda/include/40-WriterAIDA.pyx
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/pyext/yoda/include/40-WriterAIDA.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -0,0 +1,17 @@
+cdef extern from "shims.h":
+    void WriterAIDA_write (string&, vector[AOptr]&) except +
+
+def __write_AIDA(char* filename, aos):
+    """Takes a file, returns a list of AnalysisObjects"""
+    cdef vector[AOptr] vec = vector[AOptr]()
+    cdef AnalysisObject ana
+
+    for ao in aos:
+        ana = <AnalysisObject> ao
+        vec.push_back(ana.thisptr)
+
+    WriterAIDA_write(string(filename), vec)
+
+class WriterAIDA:
+    """Read AIDA files"""
+    write = staticmethod(__write_AIDA)

Added: trunk/pyext/yoda/include/99-ReaderAIDA.pyx
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/pyext/yoda/include/99-ReaderAIDA.pyx	Tue Nov  8 02:29:58 2011	(r405)
@@ -0,0 +1,27 @@
+cdef extern from "YODA/ReaderAIDA.h" namespace "YODA::ReaderAIDA":
+    cReader createReaderAIDA "YODA::ReaderAIDA::create" () 
+
+def __read_AIDA(char *filename):
+    """Takes a file, returns a list of AnalysisObjects"""
+    cdef vector[AOptr] vec = vector[AOptr]()
+    cdef size_t i
+    cdef AnalysisObject ana, ana_
+
+    createReaderAIDA().read(string(filename), vec)
+    out = []
+
+    ana_ = AnalysisObject()
+
+    for i in range(vec.size()):
+        ana_.thisptr = vec[i]
+
+        if ana_.type == 'Scatter2D':
+            out.append(Scatter2D_fromptr(<cScatter2D*>vec[i], True))
+        elif ana_.type == 'Histo1D':
+            out.append(Scatter2D_fromptr(<cScatter2D*>vec[i], True))
+
+    return out
+
+cdef class ReaderAIDA:
+    """Read AIDA files"""
+    read = staticmethod(__read_AIDA)

Added: trunk/pyext/yoda/shims.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/pyext/yoda/shims.h	Tue Nov  8 02:29:58 2011	(r405)
@@ -0,0 +1,60 @@
+/// This file is purely for backward compatibility with Cython 1.3 and 1.4.
+
+#include "YODA/AnalysisObject.h"
+#include "YODA/Histo1D.h"
+#include "YODA/Scatter2D.h"
+#include "YODA/HistoBin1D.h"
+#include "YODA/Histo2D.h"
+#include "YODA/Scatter3D.h"
+#include "YODA/WriterAIDA.h"
+#include <string>
+#include <vector>
+
+using namespace YODA;
+
+/// Histo1D operators
+
+inline Histo1D add_Histo1D(const Histo1D& a, const Histo1D& b) {
+  return a + b;
+}
+
+inline Histo1D subtract_Histo1D(const Histo1D& a, const Histo1D& b) {
+  return a - b;
+}
+
+inline Scatter2D divide_Histo1D(const Histo1D& a, const Histo1D& b) {
+  return a / b;
+}
+
+/// HistoBin1D Operators
+inline HistoBin1D add_HistoBin1D(const HistoBin1D& a, const HistoBin1D& b) {
+  return a + b;
+}
+
+inline HistoBin1D subtract_HistoBin1D(const HistoBin1D& a, const HistoBin1D& b) {
+  return a - b;
+}
+
+/// Histo2D operators
+
+inline Histo2D add_Histo2D(const Histo2D& a, const Histo2D& b) {
+  return a + b;
+}
+
+inline Histo2D subtract_Histo2D(const Histo2D& a, const Histo2D& b) {
+  return a - b;
+}
+
+inline Scatter3D divide_Histo2D(const Histo2D& a, const Histo2D& b) {
+  return a / b;
+}
+
+void WriterAIDA_write (const std::string& filename, const std::vector<AnalysisObject*>& aos)
+{
+  return WriterAIDA::write(filename, aos);
+}
+
+Scatter2D Scatter2D_mkScatter(const Histo1D& h)
+{
+  return YODA::mkScatter(h);
+}


More information about the yoda-svn mailing list