Merged in Python bindings for DynamicPersistenceChains dev
authorDmitriy Morozov <dmitriy@mrzv.org>
Tue, 14 Sep 2010 15:36:13 -0700
branchdev
changeset 234 7643a94222ae
parent 231 04a4629979da (current diff)
parent 233 ce6d679368c6 (diff)
child 235 07b3070cea74
Merged in Python bindings for DynamicPersistenceChains
--- a/bindings/python/CMakeLists.txt	Tue Sep 14 11:34:11 2010 -0700
+++ b/bindings/python/CMakeLists.txt	Tue Sep 14 15:36:13 2010 -0700
@@ -10,6 +10,7 @@
                                                 filtration.cpp
                                                 chain.cpp
                                                 static-persistence.cpp
+                                                dynamic-persistence.cpp
                                                 persistence-diagram.cpp
                                                 simplex.cpp
                                                 birthid.cpp
--- a/bindings/python/chain.cpp	Tue Sep 14 11:34:11 2010 -0700
+++ b/bindings/python/chain.cpp	Tue Sep 14 15:36:13 2010 -0700
@@ -9,13 +9,21 @@
 namespace dp = dionysus::python;
 
 
-boost::indirect_iterator<dp::VChain::const_iterator>    chain_begin(dp::VChain& c)                  { return boost::make_indirect_iterator(c.begin()); }
-boost::indirect_iterator<dp::VChain::const_iterator>    chain_end(dp::VChain& c)                    { return boost::make_indirect_iterator(c.end()); }
+template<class Chain>
+boost::indirect_iterator<typename Chain::const_iterator>    chain_begin(Chain& c)                  { return boost::make_indirect_iterator(c.begin()); }
+
+template<class Chain>
+boost::indirect_iterator<typename Chain::const_iterator>    chain_end(Chain& c)                    { return boost::make_indirect_iterator(c.end()); }
 
 void export_chain()
 {
-    bp::class_<dp::VChain>("Chain")
-        .def("__iter__",    bp::range<bp::return_internal_reference<1> >(&chain_begin, &chain_end))
-        .def("__len__",     &dp::VChain::size)
+    bp::class_<dp::VSPChain>("SPChain")
+        .def("__iter__",    bp::range<bp::return_internal_reference<1> >(&chain_begin<dp::VSPChain>, &chain_end<dp::VSPChain>))
+        .def("__len__",     &dp::VSPChain::size)
+    ;
+    
+    bp::class_<dp::VDPChain>("DPChain")
+        .def("__iter__",    bp::range<bp::return_internal_reference<1> >(&chain_begin<dp::VDPChain>, &chain_end<dp::VDPChain>))
+        .def("__len__",     &dp::VDPChain::size)
     ;
 }
--- a/bindings/python/chain.h	Tue Sep 14 11:34:11 2010 -0700
+++ b/bindings/python/chain.h	Tue Sep 14 15:36:13 2010 -0700
@@ -1,9 +1,11 @@
 #include <topology/chain.h>
 #include "static-persistence.h"
+#include "dynamic-persistence.h"
 
 namespace dionysus { 
 namespace python   {
 
-typedef     SPersistence::Chain                     VChain;
+typedef     SPersistence::Chain                     VSPChain;
+typedef     DPersistenceChains::Chain               VDPChain;
 
 } }     // namespace dionysus::python
--- a/bindings/python/dionysus.cpp	Tue Sep 14 11:34:11 2010 -0700
+++ b/bindings/python/dionysus.cpp	Tue Sep 14 15:36:13 2010 -0700
@@ -8,6 +8,7 @@
 void export_simplex();
 void export_filtration();
 void export_static_persistence();
+void export_dynamic_persistence_chains();
 void export_chain();
 void export_birthid();
 void export_zigzag_persistence();
@@ -37,6 +38,7 @@
     export_simplex();
     export_filtration();
     export_static_persistence();
+    export_dynamic_persistence_chains();
     export_chain();
     export_point();
     export_persistence_diagram();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dynamic-persistence.cpp	Tue Sep 14 15:36:13 2010 -0700
@@ -0,0 +1,41 @@
+#include <topology/dynamic-persistence.h>
+
+#include <boost/python.hpp>
+#include <boost/python/iterator.hpp>
+#include <boost/python/return_internal_reference.hpp>
+namespace bp = boost::python;
+
+#include "filtration.h"
+#include "dynamic-persistence.h"
+#include "chain.h"
+namespace dp = dionysus::python;
+
+
+dp::DPersistenceChains::iterator        dpc_begin(dp::DPersistenceChains& dpc)          { return dpc.begin(); }
+dp::DPersistenceChains::iterator        dpc_end(dp::DPersistenceChains& dpc)            { return dpc.end(); }
+
+void export_dynamic_persistence_chains()
+{
+    bp::class_<dp::DPersistenceChainsNode>("DPCNode", bp::no_init)
+        .def("pair",            &dp::pair<dp::DPersistenceChainsNode>,      bp::return_internal_reference<1>())
+        .add_property("cycle",  &dp::DPersistenceChainsNode::cycle)
+        .add_property("chain",  &dp::DPersistenceChainsNode::chain)
+        .def("sign",            &dp::DPersistenceChainsNode::sign)
+        .def("unpaired",        &dp::DPersistenceChainsNode::unpaired)
+    ;
+
+    bp::class_<dp::DPersistenceChains>("DynamicPersistenceChains", bp::no_init)
+        .def("__init__",        bp::make_constructor(&dp::init_from_filtration<dp::DPersistenceChains>))
+        
+        .def("pair_simplices",  &dp::DPersistenceChains::pair_simplices)
+        .def("__call__",        &dp::distance<dp::DPersistenceChains, dp::DPersistenceChainsIndex>)
+        .def("make_simplex_map",&dp::DPersistenceChains::make_simplex_map<dp::PythonFiltration>)
+
+        .def("__iter__",        bp::range<bp::return_internal_reference<1> >(dpc_begin, dpc_end))
+        .def("__len__",         &dp::DPersistenceChains::size)
+    ;
+
+    bp::class_<dp::DPersistenceChainsSimplexMap>("DPersistenceChainsSimplexMap", bp::no_init)
+        .def("__getitem__",     &dp::psmap_getitem<dp::DPersistenceChainsSimplexMap, dp::DPersistenceChainsIndex>,  bp::return_internal_reference<1>())
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dynamic-persistence.h	Tue Sep 14 15:36:13 2010 -0700
@@ -0,0 +1,17 @@
+#ifndef __PYTHON_DYNAMIC_PERSISTENCE_CHAINS_H__
+#define __PYTHON_DYNAMIC_PERSISTENCE_CHAINS_H__
+
+#include <topology/dynamic-persistence.h>
+#include "static-persistence.h"
+
+namespace dionysus {
+namespace python   {
+
+typedef         DynamicPersistenceChains<>          DPersistenceChains;
+typedef         DPersistenceChains::OrderElement    DPersistenceChainsNode;
+typedef         DPersistenceChains::OrderIndex      DPersistenceChainsIndex;
+typedef         DPersistenceChains::SimplexMap<PythonFiltration>        
+                                                    DPersistenceChainsSimplexMap;
+} } // namespace dionysus::python
+
+#endif
--- a/bindings/python/static-persistence.cpp	Tue Sep 14 11:34:11 2010 -0700
+++ b/bindings/python/static-persistence.cpp	Tue Sep 14 15:36:13 2010 -0700
@@ -11,47 +11,30 @@
 namespace dp = dionysus::python;
 
 
-/* SPersistence */
-boost::shared_ptr<dp::SPersistence>     init_from_filtration(bp::object f)
-{
-    dp::PythonFiltration& sf = bp::extract<dp::PythonFiltration&>(f);
-    boost::shared_ptr<dp::SPersistence> p(new dp::SPersistence(sf));
-    return p;
-}
-
 void                                    pair_simplices(dp::SPersistence& sp)                { sp.pair_simplices(false); }
 
-unsigned                                distance(dp::SPersistence& sp, 
-                                                 const dp::SPersistenceIndex& i)            { return sp.iterator_to(i) - sp.begin(); }
-
-/* SPNode */
-const dp::SPersistenceNode&             pair(const dp::SPersistenceNode& sn)                { return *sn.pair; }
-
-/* PersistenceSimplexMap */
-const dp::SimplexVD&                    psmap_getitem(const dp::PersistenceSimplexMap& psmap, 
-                                                      const dp::SPersistenceIndex& i)       { return psmap[i]; }
 
 void export_static_persistence()
 {
     bp::class_<dp::SPersistenceNode>("SPNode", bp::no_init)
-        .def("pair",            &pair,                      bp::return_internal_reference<1>())
+        .def("pair",            &dp::pair<dp::SPersistenceNode>,        bp::return_internal_reference<1>())
         .add_property("cycle",  &dp::SPersistenceNode::cycle)
         .def("sign",            &dp::SPersistenceNode::sign)
         .def("unpaired",        &dp::SPersistenceNode::unpaired)
     ;
 
     bp::class_<dp::SPersistence>("StaticPersistence", bp::no_init)
-        .def("__init__",        bp::make_constructor(&init_from_filtration))
+        .def("__init__",        bp::make_constructor(&dp::init_from_filtration<dp::SPersistence>))
         
         .def("pair_simplices",  &pair_simplices)
-        .def("__call__",        &distance)
+        .def("__call__",        &dp::distance<dp::SPersistence, dp::SPersistenceIndex>)
         .def("make_simplex_map",&dp::SPersistence::make_simplex_map<dp::PythonFiltration>)
 
         .def("__iter__",        bp::range<bp::return_internal_reference<1> >(&dp::SPersistence::begin, &dp::SPersistence::end))
         .def("__len__",         &dp::SPersistence::size)
     ;
 
-    bp::class_<dp::PersistenceSimplexMap>("PersistenceSimplexMap", bp::no_init)
-        .def("__getitem__",     &psmap_getitem,             bp::return_internal_reference<1>())
+    bp::class_<dp::SPersistenceSimplexMap>("SPersistenceSimplexMap", bp::no_init)
+        .def("__getitem__",     &dp::psmap_getitem<dp::SPersistenceSimplexMap, dp::SPersistenceIndex>,  bp::return_internal_reference<1>())
     ;
 }
--- a/bindings/python/static-persistence.h	Tue Sep 14 11:34:11 2010 -0700
+++ b/bindings/python/static-persistence.h	Tue Sep 14 15:36:13 2010 -0700
@@ -12,7 +12,32 @@
 typedef         SPersistence::OrderElement      SPersistenceNode;
 typedef         SPersistence::OrderIndex        SPersistenceIndex;
 typedef         SPersistence::SimplexMap<PythonFiltration>        
-                                                PersistenceSimplexMap;
+                                                SPersistenceSimplexMap;
+
+
+/* Persistence */
+template<class Persistence>
+boost::shared_ptr<Persistence>          init_from_filtration(bp::object f)
+{
+    PythonFiltration& sf = bp::extract<PythonFiltration&>(f);
+    boost::shared_ptr<Persistence> p(new Persistence(sf));
+    return p;
+}
+
+template<class Persistence, class PersistenceIndex>
+unsigned                                distance(Persistence& p, 
+                                                 const PersistenceIndex& i)             { return p.iterator_to(i) - p.begin(); }
+
+/* SPNode */
+template<class PNode>
+const PNode&                            pair(const PNode& n)                            { return *n.pair; }
+
+
+/* PersistenceSimplexMap */
+template<class PersistenceSimplexMap, class PersistenceIndex>
+const SimplexVD&                        psmap_getitem(const PersistenceSimplexMap& psmap, 
+                                                      const PersistenceIndex& i)        { return psmap[i]; }
+
 
 } } // namespace dionysus::python
 
--- a/doc/python/static-persistence.rst	Tue Sep 14 11:34:11 2010 -0700
+++ b/doc/python/static-persistence.rst	Tue Sep 14 15:36:13 2010 -0700
@@ -55,7 +55,7 @@
 
         Simplex's pair. The pair is set to self if the siplex is unpaired.
 
-    .. method:: cycle()
+    .. attribute:: cycle
 
         If the simplex is negative, its cycle (that it kills) is non-empty, and
         can be accessed using this method. The cycle itself is an iterable
@@ -70,9 +70,43 @@
 
         Indicates whether the simplex is unpaired.
 
-.. class:: PersistenceSimplexMap
+.. class:: SPersistenceSimplexMap
 
     .. method:: __getitem__(i)
 
         Given a persistence index, i.e. an :class:`SPNode`, returns the
         :class:`Simplex` it represents.
+
+
+:class:`DynamicPersistenceChains` class
+=======================================
+
+.. class:: DynamicPersistenceChains
+
+    This class works exactly like :class:`StaticPersistence`, providing all the
+    same methods. The only difference is that when iterating over it, the
+    elements are of type :class:`DPCNode`, described below. 
+
+.. class:: DPCNode
+
+    This class works just like :class:`SPNode`, except it has an additional
+    attribute :attr:`chain`. 
+
+    .. attribute:: chain
+    
+        It allows one to retrieve the "chain" associated with the simplex. 
+        (In terms of the :math:`R = DV` decomposition, it gives access to the
+        columns of the matrix :math:`V`.) In case of the positive simplex, this
+        is a cycle created by the addition of this simplex.  This access is
+        particularly useful for the unpaired positive simplices, allowing one to
+        recover the cycles they create. In case of the negative simplex, this chain's
+        boundary is exactly what's stored in the :attr:`~SPNode.cycle` attribute.
+    
+        For example, to print out all the essential cycles of the complex, one
+        can run the following loop::
+
+            smap = persistence.make_simplex_map(filtration)
+            for i in persistence:
+                if i.unpaired()
+                    for ii in i.chain: print smap[ii]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/triangle/triangle-chains.py	Tue Sep 14 15:36:13 2010 -0700
@@ -0,0 +1,33 @@
+from dionysus import Simplex, Filtration, DynamicPersistenceChains, \
+                     vertex_cmp, data_cmp, data_dim_cmp \
+
+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
+
+print "Complex:", complex
+print "Vertex: ", sorted(complex, vertex_cmp)
+print "Data:   ", sorted(complex, data_cmp)
+print "DataDim:", sorted(complex, data_dim_cmp)
+
+f = Filtration(complex, data_cmp)
+print "Complex in the filtration order:", ', '.join((str(s) for s in f))
+
+p = DynamicPersistenceChains(f)
+print "Persistence initialized"
+p.pair_simplices()
+print "Simplices paired"
+
+smap = p.make_simplex_map(f)
+for i in p:
+    print i.sign(), i.pair().sign()
+    print "%s (%d) - %s (%d)" % (smap[i], i.sign(), smap[i.pair()], i.pair().sign())
+    print "Cycle (%d):" % len(i.cycle), " + ".join((str(smap[ii]) for ii in i.cycle))
+    
+    if i.unpaired():
+        print "Chain (%d):" % len(i.chain), " + ".join((str(smap[ii]) for ii in i.chain))
+
+print "Number of unpaired simplices:", len([i for i in p if i.unpaired()])