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
--- 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])