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