--- a/bindings/python/CMakeLists.txt Wed Jan 28 14:57:17 2009 -0800
+++ b/bindings/python/CMakeLists.txt Thu Jan 29 10:16:56 2009 -0800
@@ -1,10 +1,19 @@
+find_package (PythonLibs)
+link_libraries (${PYTHON_LIBRARIES})
+include_directories (${PYTHON_INCLUDE_PATH})
link_libraries (${Boost_PYTHON_LIBRARY})
-include_directories ("/usr/include/python2.6")
-link_directories ("/usr/lib/python2.6")
+
+# currently can't build bindings with counters support, eventually FIXME
+remove_definitions (-DCOUNTERS)
add_library (_dionysus SHARED
dionysus.cpp
filtration.cpp
chain.cpp
static-persistence.cpp
- simplex.cpp)
-target_link_libraries (_dionysus ${libraries})
+ simplex.cpp
+ zigzag-persistence.cpp
+
+ test-optional.cpp
+ )
+
+target_link_libraries (_dionysus ${libraries})
--- a/bindings/python/dionysus.cpp Wed Jan 28 14:57:17 2009 -0800
+++ b/bindings/python/dionysus.cpp Thu Jan 29 10:16:56 2009 -0800
@@ -7,6 +7,7 @@
void export_filtration();
void export_static_persistence();
void export_chain();
+void export_zigzag_persistence();
#ifdef LOGGING
void enable_log(std::string s)
@@ -22,6 +23,8 @@
export_static_persistence();
export_chain();
+ export_zigzag_persistence();
+
#ifdef LOGGING
bp::def("enable_log", &enable_log);
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/__init__.py Thu Jan 29 10:16:56 2009 -0800
@@ -0,0 +1,18 @@
+from _dionysus import *
+
+
+#def init_with_data(s,v, d = None):
+# s._cpp_init_(v)
+# if d is not None:
+# s.data = d
+#
+#Simplex._cpp_init_ = Simplex.__init__
+#Simplex.__init__ = init_with_data
+#
+#def data_cmp(s1, s2):
+# return cmp(s1.data,s2.data)
+#
+#def data_dim_cmp(s1,s2):
+# dim_cmp = cmp(s1.dimension(), s2.dimension())
+# if dim_cmp: return dim_cmp
+# else: return data_cmp(s1,s2)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/python-optional.h Thu Jan 29 10:16:56 2009 -0800
@@ -0,0 +1,83 @@
+#ifndef __PYTHON_OPTIONAL_H__
+#define __PYTHON_OPTIONAL_H__
+
+#include <boost/python.hpp>
+
+// Taken from an email by John Wiegley;
+// http://mail.python.org/pipermail/cplusplus-sig/2007-May/012003.html
+
+template <typename T, typename TfromPy>
+struct object_from_python
+{
+ object_from_python()
+ {
+ boost::python::converter::registry::push_back(&TfromPy::convertible,
+ &TfromPy::construct,
+ boost::python::type_id<T>());
+ }
+};
+
+template <typename T, typename TtoPy, typename TfromPy>
+struct register_python_conversion
+{
+ register_python_conversion()
+ {
+ boost::python::to_python_converter<T, TtoPy>();
+ object_from_python<T, TfromPy>();
+ }
+};
+
+template <typename T>
+struct python_optional : public boost::noncopyable
+{
+ struct optional_to_python
+ {
+ static PyObject * convert(const boost::optional<T>& value)
+ {
+ return (value ? boost::python::to_python_value<T>()(*value) :
+ boost::python::detail::none());
+ }
+ };
+
+ struct optional_from_python
+ {
+ static void * convertible(PyObject * source)
+ {
+ using namespace boost::python::converter;
+
+ if (source == Py_None)
+ return source;
+
+ const registration& converters(registered<T>::converters);
+
+ if (implicit_rvalue_convertible_from_python(source, converters))
+ {
+ rvalue_from_python_stage1_data data = rvalue_from_python_stage1(source, converters);
+ return rvalue_from_python_stage2(source, data, converters);
+ }
+ return NULL;
+ }
+
+ static void construct(PyObject * source,
+ boost::python::converter::rvalue_from_python_stage1_data * data)
+ {
+ using namespace boost::python::converter;
+
+ void * const storage = ((rvalue_from_python_storage<T> *) data)->storage.bytes;
+
+ if (data->convertible == source) // == None
+ new (storage) boost::optional<T>(); // A Boost uninitialized value
+ else
+ new (storage) boost::optional<T>(*static_cast<T *>(data->convertible));
+
+ data->convertible = storage;
+ }
+ };
+
+ explicit python_optional()
+ {
+ register_python_conversion<boost::optional<T>, optional_to_python, optional_from_python>();
+ }
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/python-zigzag-persistence.h Thu Jan 29 10:16:56 2009 -0800
@@ -0,0 +1,15 @@
+#ifndef __PYTHON_ZIGZAG_PERSISTENCE_H__
+#define __PYTHON_ZIGZAG_PERSISTENCE_H__
+
+#include <topology/zigzag-persistence.h>
+#include <topology/image-zigzag-persistence.h>
+#include <boost/python.hpp>
+
+//typedef int BirthID;
+//typedef boost::python::long_ BirthID;
+typedef boost::python::object BirthID;
+
+typedef ZigzagPersistence<BirthID> ZZPersistence;
+typedef ImageZigzagPersistence<BirthID> IZZPersistence;
+
+#endif
--- a/bindings/python/simplex.cpp Wed Jan 28 14:57:17 2009 -0800
+++ b/bindings/python/simplex.cpp Thu Jan 29 10:16:56 2009 -0800
@@ -5,6 +5,7 @@
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/functional/hash.hpp>
using namespace boost::python;
/* Various wrappers for exposing Simplex to Python */
@@ -38,6 +39,20 @@
return p;
}
+// Simplex hash
+template<class V, class T>
+size_t hash_simplex(const Simplex<V,T>& s)
+{
+ return boost::hash_range(s.vertices().begin(), s.vertices().end());
+}
+
+template<class V, class T>
+size_t eq_simplex(const Simplex<V,T>& a, const Simplex<V,T>& b)
+{
+ return vertex_comparison(a,b) == 0;
+}
+
+
/* Comparisons */
// VertexComparison
template<class V, class T>
@@ -77,6 +92,9 @@
.add_property("vertices", range(&vertices_begin<Vertex,Data>, &vertices_end<Vertex,Data>))
.def(repr(self))
+
+ .def("__hash__", &hash_simplex<Vertex, Data>)
+ .def("__eq__", &eq_simplex<Vertex, Data>)
;
def("vertex_cmp", &vertex_comparison<Vertex, Data>);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/zigzag-persistence.cpp Thu Jan 29 10:16:56 2009 -0800
@@ -0,0 +1,86 @@
+#include <topology/zigzag-persistence.h>
+#include <topology/image-zigzag-persistence.h>
+
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+#include <boost/shared_ptr.hpp>
+namespace bp = boost::python;
+
+#include "python-zigzag-persistence.h" // defines ZZPersistence, IZZPersistence
+#include "python-optional.h"
+
+
+// ZigzagPersistence
+bp::tuple zzp_add(ZZPersistence& zzp, bp::object bdry, BirthID birth)
+{
+ // Make ZColumn
+ // NB: it's extremely weird that I have to do it this way,
+ // but for some reason I cannot just create boundary on the stack
+ boost::shared_ptr<ZZPersistence::ZColumn>
+ boundary(new ZZPersistence::ZColumn(bp::stl_input_iterator<ZZPersistence::SimplexIndex>(bdry),
+ bp::stl_input_iterator<ZZPersistence::SimplexIndex>()));
+ boundary->sort(zzp.cmp);
+
+ ZZPersistence::SimplexIndex i;
+ ZZPersistence::Death d;
+ boost::tie(i,d) = zzp.add(*boundary, birth);
+ return bp::make_tuple(i,d);
+}
+
+ZZPersistence::Death zzp_remove(ZZPersistence& zzp, ZZPersistence::SimplexIndex s, ZZPersistence::BirthID birth)
+{
+ return zzp.remove(s, birth);
+}
+
+
+// ImageZigzagPersistence
+bp::tuple izzp_add(IZZPersistence& izzp, bp::object bdry, bool subcomplex, BirthID birth)
+{
+ // Make ZColumn
+ // NB: it's extremely weird that I have to do it this way,
+ // but for some reason I cannot just create boundary on the stack
+ boost::shared_ptr<IZZPersistence::ZColumn>
+ boundary(new IZZPersistence::ZColumn(bp::stl_input_iterator<IZZPersistence::SimplexIndex>(bdry),
+ bp::stl_input_iterator<IZZPersistence::SimplexIndex>()));
+ boundary->sort(izzp.cmp);
+
+ IZZPersistence::SimplexIndex i;
+ IZZPersistence::Death d;
+ boost::tie(i,d) = izzp.add(*boundary, subcomplex, birth);
+ return bp::make_tuple(i,d);
+}
+
+IZZPersistence::Death izzp_remove(IZZPersistence& izzp, IZZPersistence::SimplexIndex s, IZZPersistence::BirthID birth)
+{
+ return izzp.remove(s, birth);
+}
+
+
+// SimplexIndex
+template<class T>
+unsigned si_order(T& si)
+{
+ return si->order;
+}
+
+
+void export_zigzag_persistence()
+{
+ python_optional<BirthID>();
+
+ bp::class_<ZZPersistence::SimplexIndex>("SimplexIndex")
+ .def("order", &si_order<ZZPersistence::SimplexIndex>);
+
+ bp::class_<IZZPersistence::SimplexIndex>("ISimplexIndex")
+ .def("order", &si_order<IZZPersistence::SimplexIndex>);
+
+ bp::class_<ZZPersistence>("ZigzagPersistence")
+ .def("add", &zzp_add)
+ .def("remove", &zzp_remove)
+ ;
+
+ bp::class_<IZZPersistence>("ImageZigzagPersistence")
+ .def("add", &izzp_add)
+ .def("remove", &izzp_remove)
+ ;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/triangle/triangle-zigzag.py Thu Jan 29 10:16:56 2009 -0800
@@ -0,0 +1,35 @@
+from dionysus import Simplex, ZigzagPersistence, \
+ vertex_cmp, data_cmp \
+# ,enable_log
+
+complex = {Simplex((0,), 0): None, # A
+ Simplex((1,), 1): None, # B
+ Simplex((2,), 2): None, # C
+ Simplex((0,1), 2.5): None, # AB
+ Simplex((1,2), 2.9): None, # BC
+ Simplex((0,2), 3.5): None, # CA
+ Simplex((0,1,2), 5): None} # ABC
+
+print "Complex:"
+for s in sorted(complex.keys()): print s
+print
+
+#enable_log("topology/persistence")
+zz = ZigzagPersistence()
+
+# Add all the simplices
+b = 1
+for s in sorted(complex.keys(), data_cmp):
+ print "%d: Adding %s" % (b, s)
+ i,d = zz.add([complex[ss] for ss in s.boundary], b)
+ complex[s] = i
+ if d: print "Interval (%d, %d)" % (d, b-1)
+ b += 1
+
+# Remove all the simplices
+for s in sorted(complex.keys(), reverse = True):
+ print "%d: Removing %s" % (b, s)
+ d = zz.remove(complex[s], b)
+ complex[s] = None
+ if d: print "Interval (%d, %d)" % (d, b-1)
+ b += 1
--- a/include/topology/zigzag-persistence.hpp Wed Jan 28 14:57:17 2009 -0800
+++ b/include/topology/zigzag-persistence.hpp Thu Jan 29 10:16:56 2009 -0800
@@ -1,5 +1,6 @@
#include <utilities/log.h>
#include <boost/utility.hpp>
+#include <boost/iterator/filter_iterator.hpp>
#include <algorithm>
#include <utilities/indirect.h>
#include <functional>