Initial commit of Python bindings dev
authorDmitriy Morozov <dmitriy@mrzv.org>
Thu, 25 Dec 2008 13:09:00 -0800
branchdev
changeset 104 2cc1db3b98c6
parent 103 2ac129839e02
child 105 051af83fba4c
Initial commit of Python bindings
CMakeLists.txt
bindings/CMakeLists.txt
bindings/python/CMakeLists.txt
bindings/python/chain.cpp
bindings/python/dionysus.cpp
bindings/python/filtration.cpp
bindings/python/python-filtration.h
bindings/python/python-simplex.h
bindings/python/python-static-persistence.h
bindings/python/simplex.cpp
bindings/python/static-persistence.cpp
examples/triangle/triangle.py
--- a/CMakeLists.txt	Thu Dec 25 13:08:41 2008 -0800
+++ b/CMakeLists.txt	Thu Dec 25 13:09:00 2008 -0800
@@ -9,7 +9,7 @@
 option						(use_synaps			"Build examples that use SYNAPS"		OFF)
 
 # Find everything that's always required
-find_package				(Boost REQUIRED COMPONENTS program_options serialization signals)
+find_package				(Boost REQUIRED COMPONENTS program_options python serialization signals)
 find_package				(Doxygen)
 if                          (use_dsrpdb)
     find_library			(dsrpdb_LIBRARY 			NAMES dsrpdb)
@@ -104,3 +104,4 @@
 # Process subdirectories
 add_subdirectory			(examples)
 add_subdirectory			(tests)
+add_subdirectory            (bindings)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/CMakeLists.txt	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,1 @@
+add_subdirectory			(python)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/CMakeLists.txt	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,10 @@
+link_libraries              (${Boost_PYTHON_LIBRARY})
+include_directories         ("/usr/include/python2.6")
+link_directories            ("/usr/lib/python2.6")
+add_library                 (_dionysus SHARED 
+                                                dionysus.cpp 
+                                                filtration.cpp
+                                                chain.cpp
+                                                static-persistence.cpp
+                                                simplex.cpp)
+target_link_libraries       (_dionysus ${libraries})                                            
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/chain.cpp	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,18 @@
+#include <topology/chain.h>
+#include "python-static-persistence.h"
+#include <boost/python.hpp>
+
+using namespace boost::python;
+
+typedef     SPersistence::OrderDescriptor::Chains::Chain        VChain;
+
+
+VChain::const_iterator      begin(const VChain& c)              { return c.begin(); }
+VChain::const_iterator      end(const VChain& c)                { return c.end(); }
+
+void export_chain()
+{
+    class_<VChain>("Chain")
+        .def("__iter__",    range(&begin, &end))
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus.cpp	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,28 @@
+#include <utilities/log.h>
+#include <boost/python.hpp>
+
+namespace bp = boost::python;
+
+void export_simplex();
+void export_filtration();
+void export_static_persistence();
+void export_chain();
+
+#ifdef LOGGING
+void            enable_log(std::string s)
+{
+    stdoutLog.subscribeTo(RLOG_CHANNEL(s.c_str()));
+}
+#endif
+
+BOOST_PYTHON_MODULE(_dionysus)
+{
+    export_simplex();
+    export_filtration();
+    export_static_persistence();
+    export_chain();
+
+#ifdef LOGGING
+    bp::def("enable_log",           &enable_log);
+#endif
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/filtration.cpp	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,73 @@
+#include <topology/filtration.h>
+#include <boost/iterator.hpp>
+#include "python-simplex.h"
+#include <iostream>
+
+#include <boost/python.hpp>
+using namespace boost::python;
+
+
+#include "python-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_;
+};
+
+boost::shared_ptr<ListFiltration>  init_from_list(list lst, object cmp)
+{
+    boost::shared_ptr<ListFiltration>  p(new ListFiltration(ListTraits::begin(lst),
+                                                            ListTraits::end(lst),
+                                                            PythonCmp(cmp)));
+    return p;
+}
+
+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("__len__",         &ListFiltration::size)
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/python-filtration.h	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,61 @@
+#ifndef __PYTHON_FILTRATION_H__
+#define __PYTHON_FILTRATION_H__
+
+#include <topology/filtration.h>
+#include <boost/python.hpp>
+#include "python-simplex.h"
+
+namespace bp = boost::python;
+
+// Random access iterator into python's list (using integer indices)
+class ListRandomAccessIterator:
+    public boost::iterator_adaptor<ListRandomAccessIterator,                // Derived
+                                   boost::counting_iterator<unsigned>,      // Base
+                                   SimplexVD>                               // Value
+{
+    public:
+        typedef                 ListRandomAccessIterator                                        Self;
+        typedef                 boost::iterator_adaptor<ListRandomAccessIterator,           
+                                                        boost::counting_iterator<unsigned>,     
+                                                        SimplexVD>                              Parent;
+                    
+                                ListRandomAccessIterator()                                      {}
+
+                                ListRandomAccessIterator(bp::list l, unsigned i):
+                                    Parent(i), l_(l)                                            {}
+
+    private:
+        friend class boost::iterator_core_access;
+        friend class FiltrationPythonIterator;
+
+        Parent::reference       dereference() const
+        {
+            const SimplexVD& s = bp::extract<const SimplexVD&>(l_[*(this->base())]);
+            return const_cast<SimplexVD&>(s);       // FIXME: get rid of const_cast
+        }
+
+        bp::list                l_;
+};
+
+// ComplexTraits describing complexes of type list
+struct ListTraits
+{
+    typedef     bp::list                                        Complex;
+    typedef     SimplexVD                                       Simplex;
+    typedef     ListRandomAccessIterator                        Index;
+    typedef     std::less<Index>                                IndexComparison;
+
+    typedef     BinarySearchMap<Simplex, Index,
+                                Simplex::VertexComparison>      SimplexIndexMap;
+
+    static SimplexIndexMap      simplex_index_map(const Complex& l)             { return SimplexIndexMap(begin(l), end(l)); }
+    static SimplexIndexMap      simplex_index_map(Index bg, Index end)          { return SimplexIndexMap(bg, end); }
+
+    static unsigned             size(const Complex& l)                          { return bp::extract<unsigned>(l.attr("__len__")()); }
+    static Index                begin(const Complex& l)                         { return Index(l, 0); }
+    static Index                end(const Complex& l)                           { return Index(l, size(l)); }
+};
+
+typedef         Filtration<bp::list, unsigned, ListTraits>          ListFiltration;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/python-simplex.h	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,11 @@
+#ifndef __PYTHON_SIMPLEX_H__
+#define __PYTHON_SIMPLEX_H__
+
+#include <topology/simplex.h>
+
+typedef                             int                                         Vertex;
+typedef                             double                                      Data;
+//typedef                             Empty<>                                     Data;
+typedef                             Simplex<Vertex, Data>                       SimplexVD;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/python-static-persistence.h	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,9 @@
+#ifndef __PYTHON_STATIC_PERSISTENCE_H__
+#define __PYTHON_STATIC_PERSISTENCE_H__
+
+#include <topology/static-persistence.h>
+
+typedef         StaticPersistence<>             SPersistence;
+typedef         SPersistence::OrderElement      SPersistenceNode;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/simplex.cpp	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,85 @@
+#include <topology/simplex.h>
+#include <utilities/indirect.h>
+#include <iostream>
+
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+#include <boost/shared_ptr.hpp>
+using namespace boost::python;
+
+/* Various wrappers for exposing Simplex to Python */
+// `data` property
+template<class V, class T>
+typename Simplex<V,T>::Data         get_data(const Simplex<V,T>& s)             { return s.data(); }
+template<class V, class T>
+void                                set_data(Simplex<V,T>& s, 
+                                             typename Simplex<V,T>::Data d)     { s.data() = d; }
+// `vertices` property
+template<class V, class T>
+typename Simplex<V,T>::VertexContainer::const_iterator
+                                    vertices_begin(const Simplex<V,T>& s)       { return s.vertices().begin(); }
+template<class V, class T>
+typename Simplex<V,T>::VertexContainer::const_iterator
+                                    vertices_end(const Simplex<V,T>& s)         { return s.vertices().end(); }
+
+// Constructor from iterator
+template<class V, class T>
+boost::shared_ptr<Simplex<V,T> >    init_from_iterator(object iter)                      
+{ 
+    boost::shared_ptr<Simplex<V,T> > p(new Simplex<V,T>(stl_input_iterator<V>(iter), stl_input_iterator<V>()));
+    return p;
+}
+
+// Constructor from iterator and data
+template<class V, class T>
+boost::shared_ptr<Simplex<V,T> >    init_from_iterator_data(object iter, T data)                      
+{ 
+    boost::shared_ptr<Simplex<V,T> > p(new Simplex<V,T>(stl_input_iterator<V>(iter), stl_input_iterator<V>(), data));
+    return p;
+}
+
+/* Comparisons */
+// VertexComparison
+template<class V, class T>
+int                                 vertex_comparison(const Simplex<V,T>& a, const Simplex<V,T>& b)
+{
+    return ThreeOutcomeCompare<typename Simplex<V,T>::VertexComparison>().compare(a,b);
+}
+
+// DataComparison
+template<class V, class T>
+int                                 data_comparison(const Simplex<V,T>& a, const Simplex<V,T>& b)
+{
+    return ThreeOutcomeCompare<typename Simplex<V,T>::DataComparison>().compare(a,b);
+}
+
+// DataDimensionComparison
+template<class V, class T>
+int                                 data_dimension_comparison(const Simplex<V,T>& a, const Simplex<V,T>& b)
+{
+    return ThreeOutcomeCompare<typename Simplex<V,T>::DataDimensionComparison>().compare(a,b);
+}
+
+#include "python-simplex.h"         // defines SimplexVD, Vertex, and Data
+
+void export_simplex()
+{
+    class_<SimplexVD>("Simplex")
+        .def("__init__",            make_constructor(&init_from_iterator<Vertex, Data>))
+        .def("__init__",            make_constructor(&init_from_iterator_data<Vertex, Data>))
+
+        .def("add",                 &SimplexVD::add)
+        .add_property("boundary",   range(&SimplexVD::boundary_begin, &SimplexVD::boundary_end))
+        .def("contains",            &SimplexVD::contains)
+        .def("join",                (void (SimplexVD::*)(const SimplexVD&)) &SimplexVD::join)
+        .def("dimension",           &SimplexVD::dimension)
+        .add_property("data",       &get_data<Vertex,Data>, &set_data<Vertex,Data>)
+        
+        .add_property("vertices",   range(&vertices_begin<Vertex,Data>, &vertices_end<Vertex,Data>))
+        .def(repr(self))
+    ;
+
+    def("vertex_cmp",               &vertex_comparison<Vertex, Data>);
+    def("data_cmp",                 &data_comparison<Vertex, Data>);
+    def("data_dim_cmp",             &data_dimension_comparison<Vertex, Data>);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/static-persistence.cpp	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,37 @@
+#include <topology/static-persistence.h>
+#include "python-filtration.h"
+
+#include <boost/python.hpp>
+using namespace boost::python;
+
+#include "python-static-persistence.h"
+
+boost::shared_ptr<SPersistence>     init_from_filtration(object f)
+{
+    ListFiltration& lf = extract<ListFiltration&>(f);
+    boost::shared_ptr<SPersistence> p(new SPersistence(lf));
+    return p;
+}
+
+void                                pair_simplices(SPersistence& p)
+{
+    p.pair_simplices(); 
+}
+
+void export_static_persistence()
+{
+    class_<SPersistenceNode>("StaticPersistenceNode")
+        .def_readonly("pair",   &SPersistenceNode::pair)
+        .def("sign",            &SPersistenceNode::sign)
+        .def_readonly("cycle",  &SPersistenceNode::cycle)
+    ;
+
+    class_<SPersistence>("StaticPersistence", no_init)
+        .def("__init__",        make_constructor(&init_from_filtration))
+
+        .def("pair_simplices",  &pair_simplices)
+
+        .def("__iter__",        range(&SPersistence::begin, &SPersistence::end))
+        .def("__len__",         &SPersistence::size)
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/triangle/triangle.py	Thu Dec 25 13:09:00 2008 -0800
@@ -0,0 +1,29 @@
+from dionysus import Simplex, Filtration, StaticPersistence, \
+                     vertex_cmp, data_cmp, data_dim_cmp \
+#                    ,enable_log
+
+complex = [Simplex((0,),        0),                 # A
+           Simplex((1,),        1),                 # B
+           Simplex((2,),        2),                 # C
+           Simplex((0,1),       2.5),               # AB
+           Simplex((1,2),       2.9),               # BC
+           Simplex((0,2),       3.5),               # CA
+           Simplex((0,1,2),     5)]                 # ABC
+
+print "Complex:", complex
+print "Vertex: ", sorted(complex, vertex_cmp)
+print "Data:   ", sorted(complex, data_cmp)
+print "DataDim:", sorted(complex, data_dim_cmp)
+
+complex.sort(vertex_cmp)
+
+f = Filtration(complex, data_cmp)
+for i in f: print i,
+print
+
+#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