Cleaned up Python bindings to restore functionality: dev
authorDmitriy Morozov <dmitriy@mrzv.org>
Tue, 14 Apr 2009 14:38:08 -0700
branchdev
changeset 129 95454ea3f9c0
parent 128 a5fd0c2a1c88
child 130 580eaa850c4f
Cleaned up Python bindings to restore functionality: * StaticPersistence is iterable, its nodes are usable (sign, pair, cycle) * StaticPersistence knows how to map its nodes into Filtration indices * moved PythonCmp into utils.h * minor cosmetic changes
bindings/python/chain.cpp
bindings/python/chain.h
bindings/python/dionysus/__init__.py
bindings/python/filtration.cpp
bindings/python/filtration.h
bindings/python/static-persistence.cpp
bindings/python/static-persistence.h
bindings/python/utils.h
examples/triangle/triangle.py
--- a/bindings/python/chain.cpp	Mon Apr 13 20:44:31 2009 -0700
+++ b/bindings/python/chain.cpp	Tue Apr 14 14:38:08 2009 -0700
@@ -1,18 +1,15 @@
-#include <topology/chain.h>
-#include "static-persistence.h"
 #include <boost/python.hpp>
-
-using namespace boost::python;
+#include <boost/python/iterator.hpp>
 
-typedef     SPersistence::Chain                                 VChain;
-
+namespace bp = boost::python;
 
-VChain::const_iterator      begin(const VChain& c)              { return c.begin(); }
-VChain::const_iterator      end(const VChain& c)                { return c.end(); }
+#include "chain.h"
+
 
 void export_chain()
 {
-    class_<VChain>("Chain")
-        .def("__iter__",    range(&begin, &end))
+    bp::class_<VChain>("Chain")
+        .def("__iter__",    bp::iterator<VChain>())
+        .def("__len__",     &VChain::size)
     ;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/chain.h	Tue Apr 14 14:38:08 2009 -0700
@@ -0,0 +1,4 @@
+#include <topology/chain.h>
+#include "static-persistence.h"
+
+typedef     SPersistence::Chain                     VChain;
--- a/bindings/python/dionysus/__init__.py	Mon Apr 13 20:44:31 2009 -0700
+++ b/bindings/python/dionysus/__init__.py	Tue Apr 14 14:38:08 2009 -0700
@@ -10,7 +10,7 @@
 def repr_with_data(self):
     str = self._cpp_repr_()
     if hasattr(self, 'data'):
-        str += '%f' % self.data
+        str += ' %f' % self.data
     return str
 
 Simplex._cpp_init_ =    Simplex.__init__
--- a/bindings/python/filtration.cpp	Mon Apr 13 20:44:31 2009 -0700
+++ b/bindings/python/filtration.cpp	Tue Apr 14 14:38:08 2009 -0700
@@ -8,50 +8,7 @@
 
 
 #include "filtration.h"      // defines ListFiltration, ListTraits, ListRandomAccessIterator
-
-// Filtration python iterator interface    
-class FiltrationPythonIterator:
-    public boost::iterator_adaptor<FiltrationPythonIterator,        // Derived
-                                   ListFiltration::Index,           // Base
-                                   unsigned>                        // Value
-{
-    public:
-        typedef                 FiltrationPythonIterator                                        Self;
-        typedef                 boost::iterator_adaptor<FiltrationPythonIterator,           
-                                                        ListFiltration::Index,     
-                                                        unsigned>                               Parent;
-
-                                FiltrationPythonIterator(ListFiltration::Index i):
-                                    Parent(i)                                                   {}
-
-    private:
-        friend class boost::iterator_core_access;
-
-        Parent::reference dereference() const
-        {
-            // FIXME: I hate the const_cast here, how do I get rid of it?
-            return const_cast<unsigned&>(this->base()->base().base());
-        }
-};
-
-FiltrationPythonIterator
-py_begin(const ListFiltration& lf)
-{ return lf.begin(); }
-
-FiltrationPythonIterator
-py_end(const ListFiltration& lf)
-{ return lf.end(); }
-
-    
-struct PythonCmp
-{
-    template<class T>
-    bool            operator()(T x1, T x2) const        { return cmp_(x1, x2) < 0; }
-
-                    PythonCmp(object cmp): cmp_(cmp)    {}
-
-    object cmp_;
-};
+#include "utils.h"           // defines PythonCmp
 
 boost::shared_ptr<ListFiltration>  init_from_list(list lst, object cmp)
 {
@@ -61,13 +18,26 @@
     return p;
 }
 
+FiltrationPythonIterator
+lf_begin(const ListFiltration& lf)
+{ return lf.begin(); }
+
+FiltrationPythonIterator
+lf_end(const ListFiltration& lf)
+{ return lf.end(); }
+
+unsigned
+lf_getitem(const ListFiltration& lf, unsigned i)       
+{ return *(lf_begin(lf) + i); }
+
+
 void export_filtration()
 {
     class_<ListFiltration>("Filtration", no_init)
         .def("__init__",        make_constructor(&init_from_list))
-        //.def("simplex", )
 
-        .def("__iter__",        range(&py_begin, &py_end))
+        .def("__getitem__",     &lf_getitem)
+        .def("__iter__",        range(&lf_begin, &lf_end))
         .def("__len__",         &ListFiltration::size)
     ;
 }
--- a/bindings/python/filtration.h	Mon Apr 13 20:44:31 2009 -0700
+++ b/bindings/python/filtration.h	Tue Apr 14 14:38:08 2009 -0700
@@ -58,4 +58,30 @@
 
 typedef         Filtration<bp::list, unsigned, ListTraits>          ListFiltration;
 
+
+// Filtration python iterator interface    
+class FiltrationPythonIterator:
+    public boost::iterator_adaptor<FiltrationPythonIterator,    // Derived
+                                   ListFiltration::Index,       // Base
+                                   unsigned>                    // Value
+{
+    public:
+        typedef                 FiltrationPythonIterator                                        Self;
+        typedef                 boost::iterator_adaptor<Self,           
+                                                        ListFiltration::Index,
+                                                        unsigned>                               Parent;
+
+                                FiltrationPythonIterator(ListFiltration::Index i):
+                                    Parent(i)                                                   {}
+
+    private:
+        friend class boost::iterator_core_access;
+
+        Parent::reference dereference() const
+        {
+            // FIXME: I hate the const_cast here, how do I get rid of it?
+            return const_cast<unsigned&>(this->base()->base().base());
+        }
+};
+
 #endif
--- a/bindings/python/static-persistence.cpp	Mon Apr 13 20:44:31 2009 -0700
+++ b/bindings/python/static-persistence.cpp	Tue Apr 14 14:38:08 2009 -0700
@@ -1,12 +1,16 @@
 #include <topology/static-persistence.h>
 
 #include <boost/python.hpp>
+#include <boost/python/iterator.hpp>
+#include <boost/python/return_internal_reference.hpp>
 using namespace boost::python;
 
 #include "filtration.h"
 #include "static-persistence.h"
+#include "chain.h"
 
 
+/* SPersistence */
 boost::shared_ptr<SPersistence>     init_from_filtration(object f)
 {
     ListFiltration& lf = extract<ListFiltration&>(f);
@@ -14,18 +18,36 @@
     return p;
 }
 
+boost::counting_iterator<SPersistenceIndex>     py_sp_begin(SPersistence& sp)                   { return sp.begin(); }
+boost::counting_iterator<SPersistenceIndex>     py_sp_end(SPersistence& sp)                     { return sp.end(); }
+unsigned                                        distance(SPersistence& sp, 
+                                                         const SPersistenceIndex& i)            { return i - sp.begin(); }
+
+
+/* SPersistenceIndex */
+SPersistenceIndex                               pair(const SPersistenceIndex& i)                { return i->pair; }
+bool                                            sign(const SPersistenceIndex& i)                { return i->sign(); }
+const VChain&                                   cycle(const SPersistenceIndex& i)               { return i->cycle; }
+bool                                            index_eq(const SPersistenceIndex& i, 
+                                                         const SPersistenceIndex& j)            { return i == j; }
+
+
 void export_static_persistence()
 {
-    class_<SPersistenceNode>("StaticPersistenceNode")
-        .def_readonly("pair",   &SPersistenceNode::pair)
-        .def("sign",            &SPersistenceNode::sign)
-        .def_readonly("cycle",  &SPersistenceNode::cycle)
+    class_<SPersistenceIndex>("SPNode")
+        .add_property("pair",   &pair)
+        .def("sign",            &sign)
+        .def("cycle",           &cycle,         bp::return_internal_reference<1>())
+        .def("__eq__",          index_eq)
     ;
 
     class_<SPersistence>("StaticPersistence", no_init)
         .def("__init__",        make_constructor(&init_from_filtration))
+        
         .def("pair_simplices",  (void (SPersistence::*)())  &SPersistence::pair_simplices)
-        .def("__iter__",        range(&SPersistence::begin, &SPersistence::end))
+        .def("__call__",        &distance)
+
+        .def("__iter__",        range(&py_sp_begin, &py_sp_end))
         .def("__len__",         &SPersistence::size)
     ;
 }
--- a/bindings/python/static-persistence.h	Mon Apr 13 20:44:31 2009 -0700
+++ b/bindings/python/static-persistence.h	Tue Apr 14 14:38:08 2009 -0700
@@ -5,5 +5,6 @@
 
 typedef         StaticPersistence<>             SPersistence;
 typedef         SPersistence::OrderElement      SPersistenceNode;
+typedef         SPersistence::OrderIndex        SPersistenceIndex;
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/utils.h	Tue Apr 14 14:38:08 2009 -0700
@@ -0,0 +1,14 @@
+#ifndef __PYTHON_UTILS_H__
+#define __PYTHON_UTILS_H__
+
+struct PythonCmp
+{
+    template<class T>
+    bool            operator()(T x1, T x2) const        { return cmp_(x1, x2) < 0; }
+
+                    PythonCmp(object cmp): cmp_(cmp)    {}
+
+    object cmp_;
+};
+
+#endif
--- a/examples/triangle/triangle.py	Mon Apr 13 20:44:31 2009 -0700
+++ b/examples/triangle/triangle.py	Tue Apr 14 14:38:08 2009 -0700
@@ -1,6 +1,5 @@
 from dionysus import Simplex, Filtration, StaticPersistence, \
                      vertex_cmp, data_cmp, data_dim_cmp \
-#                    ,enable_log
 
 complex = [Simplex((0,),        0),                 # A
            Simplex((1,),        1),                 # B
@@ -15,15 +14,16 @@
 print "Data:   ", sorted(complex, data_cmp)
 print "DataDim:", sorted(complex, data_dim_cmp)
 
-complex.sort(vertex_cmp)
+complex.sort(vertex_cmp)        # put complex in the lexicographic order; required for persistence computation
 
 f = Filtration(complex, data_cmp)
-for i in f: print i,
-print
+print "Complex in the filtration order:", ', '.join((str(complex[i]) for i in f))
 
-#enable_log("topology/persistence")
 p = StaticPersistence(f)
 p.pair_simplices()
-for i in p: 
-    print i.sign()#, i.pair
-    #for ii in i.cycle: print ii
+for i in p:
+    print "%s (%d) - %s (%d)" % (complex[f[p(i)]], i.sign(), 
+                                 complex[f[p(i.pair)]], i.pair.sign())
+    print "Cycle (%d):" % len(i.cycle()), " + ".join((str(complex[f[p(ii)]]) for ii in i.cycle()))
+
+print "Number of unpaired simplices:", len([i for i in p if i == i.pair])