Merge dev into default, to avoid the need for 'hg up tip' after clone
authorDmitriy Morozov <dmitriy@mrzv.org>
Tue, 27 Jun 2017 09:37:05 -0700
changeset 285 d9a79a28e3cc
parent 58 b3b810b64a79 (current diff)
parent 284 67644b9c7668 (diff)
child 286 0496c5f88b2a
Merge dev into default, to avoid the need for 'hg up tip' after clone
FindCGAL.Makefile
examples/grid/CMakeLists.txt
examples/grid/combustion-vineyard.cpp
examples/grid/grid2D.h
examples/grid/grid2D.hpp
examples/grid/grid2Dvineyard.h
examples/grid/grid2Dvineyard.hpp
examples/grid/pdbdistance-vineyard.cpp
examples/grid/pdbdistance.h
examples/grid/test-grid2D.cpp
include/topology/cycle.h
include/topology/cycle.hpp
include/topology/filtrationcontainer.h
include/topology/filtrationsimplex.h
include/topology/lowerstarfiltration.hpp
include/utilities/debug.h
include/utilities/sys.h
src/debug.cpp
--- a/.hgignore	Fri Aug 24 16:58:25 2007 -0400
+++ b/.hgignore	Tue Jun 27 09:37:05 2017 -0700
@@ -3,3 +3,4 @@
 docs
 aux
 build
+doc/.build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/.filters	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,11 @@
+[kinetic]
+category=kinetic
+
+[functionality]
+category=functionality
+
+[installation]
+category=installation
+
+[efficiency]
+category=efficiency
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/89ae955518665a61/new/1221008555.M726241P30017Q23.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,15 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Tue, 26 Feb 2008 18:22:06 -0500
+State: new
+Subject: Get rid of intostring() and .c_str()
+Message-Id: <89ae955518665a61-0-artemis@metatron>
+
+Get rid of the need for intostring() (in addition to tostring()), and having to
+place .c_str() after tostring() in rLog calls.
+
+The former is necessary because of some problem with disambiguating which
+operator<<(ostream,T) to use when Event is being output, so intostring() calls
+T.operator<<(ostream) explicitly. This problem seems to exist only for Events.
+
+It should be possible to solve the latter by returning char* from tostring()
+rather than std::string.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/8a14b4849071f910/new/1221008555.M667846P30017Q17.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Thu, 10 Jan 2008 04:36:03 -0500
+State: resolved
+Subject: Remove maintenance of "lazy decomposition"
+Message-Id: <8a14b4849071f910-0-artemis@metatron>
+resolution: fixed
+
+The maintenance of "lazy decomposition" (added in [a0736dd3c671]) is
+incorrect (due to original theoretical errors). Remove it completely.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/8a14b4849071f910/new/1229837212.M576947P31212Q2.rufus	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sat, 20 Dec 2008 21:26:52
+Subject: properties changes (state, resolution)
+Message-Id: <8a14b4849071f910-c82a77e7b320c7e8-artemis@rufus>
+References: <8a14b4849071f910-0-artemis@metatron>
+In-Reply-To: <8a14b4849071f910-0-artemis@metatron>
+
+state=resolved
+resolution=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/8aa25bcae639fc99/new/1221008555.M674695P30017Q18.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Fri, 04 Apr 2008 11:18:00
+State: fixed
+Subject: Switch in the pairing in Case 1.2
+Message-Id: <8aa25bcae639fc99-0-artemis@moscow>
+
+If simplex i is unpaired in Case 1.2, while i+1 is paired with l, and R[i,l]=1
+there is a switch in the pairing in Case 1.2.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/8aa25bcae639fc99/new/1221008555.M677989P30017Q19.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Fri, 04 Apr 2008 16:16:41
+Subject: Handled but mislabeled
+Message-Id: <8aa25bcae639fc99-bbca170318887f06-artemis@moscow>
+References: <8aa25bcae639fc99-0-artemis@moscow>
+In-Reply-To: <8aa25bcae639fc99-0-artemis@moscow>
+
+The situation is already handled in the code, but was mislabeled as Case 1.1.2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/8aa25bcae639fc99/new/1221008555.M679929P30017Q20.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Fri, 04 Apr 2008 16:17:10
+Subject: properties changes (state)
+Message-Id: <8aa25bcae639fc99-a4a82c4ab8c0f536-artemis@moscow>
+References: <8aa25bcae639fc99-0-artemis@moscow>
+In-Reply-To: <8aa25bcae639fc99-0-artemis@moscow>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/91986229a564f7e0/new/1221008555.M732706P30017Q24.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Thu, 21 Feb 2008 04:23:29 -0500
+State: fixed
+Subject: More elabroate domain in avida-landscape
+Message-Id: <91986229a564f7e0-0-artemis@metatron>
+
+Try minimum spanning tree (i.e., take only negative edges from avida-distance).
+Try a combination: all edges up to a certain (realtively small) length + MST.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/91986229a564f7e0/new/1221008555.M735706P30017Q25.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Mon, 25 Feb 2008 07:09:30 -0500
+Subject: properties changes (state)
+Message-Id: <91986229a564f7e0-9886ad2e18d12feb-artemis@metatron>
+References: <91986229a564f7e0-0-artemis@metatron>
+In-Reply-To: <91986229a564f7e0-0-artemis@metatron>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/957a589d7c6c3fa8/new/1230356422.M300560P11955Q1.rufus	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,11 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Fri, 26 Dec 2008 21:34:29
+State: new
+Subject: namespace dionysus
+Message-Id: <957a589d7c6c3fa8-0-artemis@rufus>
+category: installation
+
+Put everything in namespace dionysus. Besides making things more organized, it
+will also allow us to get rid of the problem of having to typedef Simplex<...>
+to Smplx. If it were in dionysus namespace, then 
+`typedef dionysus::Simplex<...> Simplex;` would work.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/957a589d7c6c3fa8/new/1239235561.M108369P10645Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Wed, 08 Apr 2009 17:06:01
+Subject: changed properties (category=installation)
+Message-Id: <957a589d7c6c3fa8-e9829eb7352224cf-artemis@cole>
+References: <957a589d7c6c3fa8-0-artemis@rufus>
+In-Reply-To: <957a589d7c6c3fa8-0-artemis@rufus>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/96b51b44f7764f5c/new/1221008595.M830007P30168Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Tue, 09 Sep 2008 18:03:00
+State: resolved
+Subject: Boost 1.36
+Message-Id: <96b51b44f7764f5c-0-artemis@cole>
+resolution: fixed
+
+Make the software compile with Boost 1.36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/96b51b44f7764f5c/new/1229837196.M796227P31208Q2.rufus	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sat, 20 Dec 2008 21:26:36
+Subject: properties changes (state, resolution)
+Message-Id: <96b51b44f7764f5c-85f856488e2d4827-artemis@rufus>
+References: <96b51b44f7764f5c-0-artemis@cole>
+In-Reply-To: <96b51b44f7764f5c-0-artemis@cole>
+
+state=resolved
+resolution=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/b5d8a8403ae3a0d2/new/1221008555.M687915P30017Q21.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Thu, 21 Feb 2008 04:54:00 -0500
+State: fixed
+Subject: Segfault in tests/geometry/test-kinetic-sort.cpp
+Message-Id: <b5d8a8403ae3a0d2-0-artemis@metatron>
+
+test-kinetic-sort segfaults when we subscribe to geometry/simulator RLog channel.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/b5d8a8403ae3a0d2/new/1221008555.M690386P30017Q22.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Fri, 22 Feb 2008 13:05:55 -0500
+Subject: properties changes (state)
+Message-Id: <b5d8a8403ae3a0d2-a0288cca74095157-artemis@metatron>
+References: <b5d8a8403ae3a0d2-0-artemis@metatron>
+In-Reply-To: <b5d8a8403ae3a0d2-0-artemis@metatron>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M610599P30017Q9.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Tue, 26 Feb 2008 05:22:56 -0500
+State: fixed
+Subject: Non-optimized CGAL runtime error
+Message-Id: <c420501cc5285bbc-0-artemis@metatron>
+
+If the code is compiled with optimizations off or with debug on, CGAL gives a
+runtime error.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M614720P30017Q10.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Tue, 26 Feb 2008 08:00:23 -0500
+Subject: properties changes (state)
+Message-Id: <c420501cc5285bbc-e983173b6cd399a6-artemis@metatron>
+References: <c420501cc5285bbc-0-artemis@metatron>
+In-Reply-To: <c420501cc5285bbc-0-artemis@metatron>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M618213P30017Q11.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,10 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Tue, 26 Feb 2008 08:00:50 -0500
+Subject: Fixed by adding CGAL_NO_ASSERTIONS
+Message-Id: <c420501cc5285bbc-d75d85d67d421f7e-artemis@metatron>
+References: <c420501cc5285bbc-0-artemis@metatron>
+In-Reply-To: <c420501cc5285bbc-0-artemis@metatron>
+
+I suspect the bug in CGAL (since everything works fine with CGAL_NO_ASSERTIONS
+set), so I disabled the offending assertion (and all the rest of them) by
+setting a CXX flag in CMakeLists.txt.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M619987P30017Q12.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 19 Mar 2008 12:47:24 -0400
+Subject: Fixed in 0a18d6902a55
+Message-Id: <c420501cc5285bbc-db67b15857938f7b-artemis@metatron>
+References: <c420501cc5285bbc-0-artemis@metatron>
+In-Reply-To: <c420501cc5285bbc-0-artemis@metatron>
+
+Fixed by dealing with infinite simplices in 0a18d6902a55
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M621758P30017Q13.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 19 Mar 2008 12:49:01 -0400
+Subject: Reopened for ar-vineyard
+Message-Id: <c420501cc5285bbc-8f74ccde6b3f0bea-artemis@metatron>
+References: <c420501cc5285bbc-0-artemis@metatron>
+In-Reply-To: <c420501cc5285bbc-0-artemis@metatron>
+
+Fix for ar-vineyard like for alphashapes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M623619P30017Q14.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 19 Mar 2008 12:49:47 -0400
+Subject: properties changes (state)
+Message-Id: <c420501cc5285bbc-ef5f506b45aba335-artemis@metatron>
+References: <c420501cc5285bbc-0-artemis@metatron>
+In-Reply-To: <c420501cc5285bbc-0-artemis@metatron>
+
+state=open
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c420501cc5285bbc/new/1221008555.M625407P30017Q15.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 19 Mar 2008 13:17:30 -0400
+Subject: Fixed for ar-vineyard
+Message-Id: <c420501cc5285bbc-feb676745fc16b8c-artemis@metatron>
+References: <c420501cc5285bbc-8f74ccde6b3f0bea-artemis@metatron>
+In-Reply-To: <c420501cc5285bbc-8f74ccde6b3f0bea-artemis@metatron>
+
+Fixed for ar-vineyard.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c664b2f69b5f6ea3/new/1221008555.M741909P30017Q26.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Thu, 28 Feb 2008 05:33:34 -0500
+State: fixed
+Subject: Two simulators
+Message-Id: <c664b2f69b5f6ea3-0-artemis@metatron>
+
+Consider using two simulators instead of one to make sure that trajectory
+changes are processed before simplex swaps.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c664b2f69b5f6ea3/new/1221008555.M745065P30017Q27.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Sat, 01 Mar 2008 04:45:05 -0500
+Subject: properties changes (state)
+Message-Id: <c664b2f69b5f6ea3-f8bf16bdff01098d-artemis@metatron>
+References: <c664b2f69b5f6ea3-0-artemis@metatron>
+In-Reply-To: <c664b2f69b5f6ea3-0-artemis@metatron>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/c664b2f69b5f6ea3/new/1221008555.M746854P30017Q28.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Sat, 01 Mar 2008 04:45:29 -0500
+Subject: Fixed in f236c7d659d0
+Message-Id: <c664b2f69b5f6ea3-a1742f0eb7b5e1c0-artemis@metatron>
+References: <c664b2f69b5f6ea3-0-artemis@metatron>
+In-Reply-To: <c664b2f69b5f6ea3-0-artemis@metatron>
+
+Fixed in f236c7d659d0.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/cd79223a108d3900/new/1221008555.M511949P30017Q2.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Fri, 22 Feb 2008 18:39:31 -0500
+State: new
+Subject: Incorrect sign_at() in UPolynomial<double>
+Message-Id: <cd79223a108d3900-0-artemis@metatron>
+category: kinetic
+
+UPolynomial<double>::sign_at() reports -1 as the sign of -2*x + 4 at x = 2. 
+Should be 0.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/cd79223a108d3900/new/1239235469.M178107P10641Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Wed, 08 Apr 2009 17:04:29
+Subject: changed properties (category=kinetic)
+Message-Id: <cd79223a108d3900-8e019293f49e27ce-artemis@cole>
+References: <cd79223a108d3900-0-artemis@metatron>
+In-Reply-To: <cd79223a108d3900-0-artemis@metatron>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/cff004eda75a26c2/new/1221008555.M586932P30017Q7.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Tue, 11 Mar 2008 04:05:25 -0400
+State: fixed
+Subject: Scale fitness
+Message-Id: <cff004eda75a26c2-0-artemis@metatron>
+
+When computing fitness persistence, divide all values by the maximum fitness.
+That way it's possible to compare persistence diagrams for runs in different
+environments.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/cff004eda75a26c2/new/1221008555.M591027P30017Q8.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Fri, 14 Mar 2008 18:34:41 -0400
+Subject: properties changes (state)
+Message-Id: <cff004eda75a26c2-ad10cae14deb092d-artemis@metatron>
+References: <cff004eda75a26c2-0-artemis@metatron>
+In-Reply-To: <cff004eda75a26c2-0-artemis@metatron>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/d2ab07329c3588ca/new/1221008555.M528839P30017Q3.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 27 Feb 2008 16:30:57 -0500
+State: fixed
+Subject: Segfault with topology/vineyard log enabled
+Message-Id: <d2ab07329c3588ca-0-artemis@metatron>
+
+The code segfaults in Vineyard::record_knee() if we subscribe to
+topology/vineyard log.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/d2ab07329c3588ca/new/1221008555.M531575P30017Q4.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Sat, 01 Mar 2008 04:46:46 -0500
+Subject: properties changes (state)
+Message-Id: <d2ab07329c3588ca-8c184b421f538482-artemis@metatron>
+References: <d2ab07329c3588ca-0-artemis@metatron>
+In-Reply-To: <d2ab07329c3588ca-0-artemis@metatron>
+
+state=fixed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/d2ab07329c3588ca/new/1221008555.M533535P30017Q5.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,8 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Sat, 01 Mar 2008 04:46:51 -0500
+Subject: Fixed in abba2950aced
+Message-Id: <d2ab07329c3588ca-fa65c35dfff6366f-artemis@metatron>
+References: <d2ab07329c3588ca-0-artemis@metatron>
+In-Reply-To: <d2ab07329c3588ca-0-artemis@metatron>
+
+Fixed in abba2950aced
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/de674a2ac5f6c18c/new/1229837097.M859247P31105Q1.rufus	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,11 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sat, 20 Dec 2008 21:21:53
+State: new
+Subject: Specialize ChainWrapper<C>::add() for linked lists
+Message-Id: <de674a2ac5f6c18c-0-artemis@rufus>
+category: functionality
+
+The current implementation of add() in ChainWrapper is container agnostic: it
+uses a temporary container, and then swaps it into place. There should be a
+specialized add() for linked lists (in particular, List from circular_list.h)
+since it is would likely be more efficient then the generic one.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/de674a2ac5f6c18c/new/1239235533.M711045P10644Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Wed, 08 Apr 2009 17:05:33
+Subject: changed properties (category=functionality)
+Message-Id: <de674a2ac5f6c18c-ba280aee1f76cd3f-artemis@cole>
+References: <de674a2ac5f6c18c-0-artemis@rufus>
+In-Reply-To: <de674a2ac5f6c18c-0-artemis@rufus>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/e6d9deee8fbd81a5/new/1221008555.M541088P30017Q6.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 06 Feb 2008 16:45:13 -0500
+State: new
+Subject: About section in README
+Message-Id: <e6d9deee8fbd81a5-0-artemis@metatron>
+
+Add "About" section to the README file.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/e6f52c44ef26f4a7/new/1239399291.M841173P26652Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,10 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Fri, 10 Apr 2009 14:33:18
+State: new
+Subject: Intrusive containers for ZigzagPersistence
+Message-Id: <e6f52c44ef26f4a7-0-artemis@cole>
+category: efficiency
+
+Use Boost's intrusive containers to store rows in ZigzagPersistence. This
+should get rid of the inefficiencies associated with the simplex removal
+(through ZigzagPersistence::remove()).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/e8659770a6824e01/new/1221008555.M475248P30017Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,10 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Wed, 09 Jan 2008 13:57:57 -0500
+State: new
+Subject: Change cout to rlog
+Message-Id: <e8659770a6824e01-0-artemis@metatron>
+
+In examples/grid/grid2Dvineyard.hpp (and in examples in general),
+change the use of std::cout for logging information to rlog.
+Naturally, create appropriate channels even if they are of only local
+use.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/ebda8db3f9908e33/new/1221008555.M637662P30017Q16.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <morozov@cs.duke.edu>
+Date: Mon, 25 Feb 2008 11:29:27 -0500
+State: resolved
+Subject: Efficient EventQueue
+Message-Id: <ebda8db3f9908e33-0-artemis@metatron>
+category: kinetic
+resolution: fixed
+
+Change EventQueue to an efficient implementation, e.g., using a Fibonacci heap.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/ebda8db3f9908e33/new/1239235517.M200551P10643Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Wed, 08 Apr 2009 17:05:17
+Subject: changed properties (category=kinetic)
+Message-Id: <ebda8db3f9908e33-f094f3f4c111054c-artemis@cole>
+References: <ebda8db3f9908e33-0-artemis@metatron>
+In-Reply-To: <ebda8db3f9908e33-0-artemis@metatron>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/ebda8db3f9908e33/new/1265568370.M269870P17954Q1.vine	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sun, 07 Feb 2010 10:45:04
+Subject: Switched to Boost's MultiIndex
+Message-Id: <ebda8db3f9908e33-e9c51216e26b5e19-artemis@vine>
+References: <ebda8db3f9908e33-0-artemis@metatron>
+In-Reply-To: <ebda8db3f9908e33-0-artemis@metatron>
+
+Switched EventQueue to Boost's MultiIndex with a sequence and ordered_non_unique
+indexing.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/ebda8db3f9908e33/new/1265605942.M759644P4728Q1.vine	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,9 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sun, 07 Feb 2010 21:11:12
+Subject: Binary heap
+Message-Id: <ebda8db3f9908e33-e780beb990f99293-artemis@vine>
+References: <ebda8db3f9908e33-0-artemis@metatron>
+In-Reply-To: <ebda8db3f9908e33-0-artemis@metatron>
+
+Changed EventQueue representation to a binary heap. Used code developed by Danny
+Tarlow and Yanbin Lu.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/f6496b3e37275888/new/1229837161.M623187P31203Q1.rufus	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,11 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Sat, 20 Dec 2008 21:24:59
+State: new
+Subject: Add field arithmetic
+Message-Id: <f6496b3e37275888-0-artemis@rufus>
+category: functionality
+
+Add support for field arithmetic (i.e., not only Z_2 field as it is now).
+However, make sure that there is a specialization of ChainWrapper<C>::add() for
+Z_2 field (since it can be made much more efficient both in terms of space and
+time).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.issues/f6496b3e37275888/new/1239235438.M855747P10635Q1.cole	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,7 @@
+From: Dmitriy Morozov <dmitriy@mrzv.org>
+Date: Wed, 08 Apr 2009 17:03:58
+Subject: changed properties (category=functionality)
+Message-Id: <f6496b3e37275888-937e7690680da5fe-artemis@cole>
+References: <f6496b3e37275888-0-artemis@rufus>
+In-Reply-To: <f6496b3e37275888-0-artemis@rufus>
+
--- a/CMakeLists.txt	Fri Aug 24 16:58:25 2007 -0400
+++ b/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -1,95 +1,88 @@
-project						(Dionysus)
+project                     (Dionysus)
+cmake_minimum_required      (VERSION 2.4)
 
-option						(debug				"Build Dionysus with debugging on" 		OFF)
-option						(counters			"Build Dionysus with counters on" 		OFF)
-option						(optimize			"Build Dionysus with optimization"		ON)
+option                      (logging            "Build Dionysus with logging on"        OFF)
+option                      (counters           "Build Dionysus with counters on"       OFF)
+option                      (debug              "Build Dionysus with debugging on"      OFF)
+option                      (optimize           "Build Dionysus with optimization"      ON)
+option                      (use_cgal           "Build examples and python bindings that use CGAL"       ON)
+option                      (use_dsrpdb         "Build examples that use DSR-PDB"       OFF)
+option                      (use_synaps         "Build examples that use SYNAPS"        OFF)
 
 # Find everything that's always required
-find_package				(Boost REQUIRED)
-find_package				(Doxygen)
-find_library				(dsrpdb_LIBRARY 			NAMES dsrpdb)
-find_path					(dsrpdb_INCLUDE_DIR 		dsrpdb/Protein.h)
-
-set							(libraries 					${libraries}
-														${dsrpdb_LIBRARY})
+find_package                (Boost REQUIRED COMPONENTS program_options python serialization signals)
+find_package                (Doxygen)
+if                          (use_dsrpdb)
+    find_library            (dsrpdb_LIBRARY             NAMES dsrpdb)
+    find_path               (dsrpdb_INCLUDE_DIR         dsrpdb/Protein.h)
+endif                       (use_dsrpdb)
 
-#CGAL
-execute_process				(COMMAND ${CMAKE_MAKE_PROGRAM} -f ${CMAKE_CURRENT_SOURCE_DIR}/FindCGAL.Makefile libpaths
-							 OUTPUT_VARIABLE cgal_libpaths)
-execute_process				(COMMAND ${CMAKE_MAKE_PROGRAM} -f ${CMAKE_CURRENT_SOURCE_DIR}/FindCGAL.Makefile ldflags
-							 OUTPUT_VARIABLE cgal_ldflags)
-execute_process				(COMMAND ${CMAKE_MAKE_PROGRAM} -f ${CMAKE_CURRENT_SOURCE_DIR}/FindCGAL.Makefile cxxflags
-							 OUTPUT_VARIABLE cgal_cxxflags)
-execute_process				(COMMAND ${CMAKE_MAKE_PROGRAM} -f ${CMAKE_CURRENT_SOURCE_DIR}/FindCGAL.Makefile libpath
-							 OUTPUT_VARIABLE cgal_libpath)
-#string						(REPLACE "\n" "" cgal_libpaths	${cgal_libpaths})
-#string						(REPLACE "\n" "" cgal_ldflags 	${cgal_ldflags})
-string						(REPLACE "\n" "" cgal_cxxflags 	${cgal_cxxflags})
-string						(REPLACE "\n" "" cgal_libpath 	${cgal_libpath})
-add_definitions				(${cgal_cxxflags})
-find_library				(cgal_LIBRARY				NAMES CGAL
-														PATHS ${cgal_libpath})
-find_library				(core_LIBRARY				NAMES CGALcore++
-														PATHS ${cgal_libpath})
-find_library				(mpfr_LIBRARY				NAMES mpfr)
-find_library				(gmp_LIBRARY				NAMES gmp)
-find_library				(gmpxx_LIBRARY				NAMES gmpxx)
-find_library				(m_LIBRARY					NAMES m)
-
-set							(cgal_libraries 			${cgal_LIBRARY} 
-														${core_LIBRARY}
-														${mpfr_LIBRARY} 
-														${gmp_LIBRARY} 
-														${gmpxx_LIBRARY} 
-														${m_LIBRARY})
+# CGAL
+if                          (use_cgal)
+    find_package            (CGAL QUIET)
+endif                       (use_cgal)
+#add_definitions             (-DCGAL_NO_ASSERTIONS -DCGAL_NO_PRECONDITIONS)
 
 # SYNAPS
-add_definitions				(-DBOOST_UBLAS_TYPE_CHECK=0)
-find_library				(synaps_LIBRARY				NAMES synaps)
-set							(synaps_libraries			${synaps_LIBRARY}
-														${gmp_LIBRARY}
-														${gmpxx_LIBRARY})
+if                          (use_synaps)
+    add_definitions         (-DBOOST_UBLAS_TYPE_CHECK=0)
+    find_library            (synaps_LIBRARY             NAMES synaps)
+    set                     (synaps_libraries           ${synaps_LIBRARY}
+                                                        ${gmp_LIBRARY}
+                                                        ${gmpxx_LIBRARY})
+endif                       (use_synaps)
 
 # Debugging
-if							(debug)
-	find_library			(cwd_LIBRARY				NAMES cwd)
-	find_path				(cwd_INCLUDE_DIR			libcwd/debug.h)
-	set 					(cwd_INCLUDE_DIR			${cwd_INCLUDE_DIR}/libcwd)
-	add_definitions			(-DCWDEBUG -g)
-	set						(external_sources			${CMAKE_CURRENT_SOURCE_DIR}/src/debug.cpp)
-	set						(libraries 					${libraries} ${cwd_LIBRARY})
-else						(debug)
-	add_definitions			(-DNDEBUG)
-endif						(debug)
+if                          (debug)
+    if                      (optimize)
+            set             (cxx_flags                  ${CMAKE_CXX_FLAGS_RELWITHDEBINFO})
+    else                    (optimize)
+            set             (cxx_flags                  ${CMAKE_CXX_FLAGS_DEBUG})
+    endif                   (optimize)
+else                        (debug)
+    if                      (optimize)
+            set             (cxx_flags                  ${CMAKE_CXX_FLAGS_RELEASE})
+    else                    (optimize)
+            set             (cxx_flags                  ${CMAKE_CXX_FLAGS})
+    endif                   (optimize)
+endif                       (debug)
+add_definitions             (${cxx_flags})
+
+# Fix the XCode bug
+add_definitions             (-ftemplate-depth=256)
+
+
+# Logging
+if                          (logging)
+    find_library            (rlog_LIBRARY               NAMES rlog)
+    find_path               (rlog_INCLUDE_DIR           rlog/rlog.h)
+    set                     (rlog_INCLUDE_DIR           ${rlog_INCLUDE_DIR})
+    add_definitions         (-DLOGGING -DRLOG_COMPONENT=dionysus)
+    set                     (libraries                  ${libraries} ${rlog_LIBRARY})
+endif                       (logging)
 
 # Counters
-if							(counters)
-	add_definitions			(-DCOUNTERS)
-endif						(counters)
-
-# Optimization
-if							(optimize GREATER 0)
-	add_definitions			(-O${optimize})
-elseif						(optimize)
-	add_definitions			(-O)
-endif						(optimize)
-endif						(optimize GREATER 0)
-
+if                          (counters)
+    add_definitions         (-DCOUNTERS)
+endif                       (counters)
 
 # Set includes
-include_directories			(${CMAKE_CURRENT_BINARY_DIR}
-							 ${CMAKE_CURRENT_SOURCE_DIR}/include
-							 ${Boost_INCLUDE_DIR}
-							 ${dsrpdb_INCLUDE_DIR}
-							 ${cwd_INCLUDE_DIR})
+include_directories         (${CMAKE_CURRENT_BINARY_DIR}
+                             ${CMAKE_CURRENT_SOURCE_DIR}/include
+                             ${Boost_INCLUDE_DIR}
+                             ${dsrpdb_INCLUDE_DIR}
+                             ${cwd_INCLUDE_DIR}
+                             ${rlog_INCLUDE_DIR})
 
 # Doxygen (FIXME)
-if							(DOXYGEN_FOUND)
-#	add_custom_target 		(docs ALL 
-#							${DOXYGEN_EXECUTABLE} Doxyfile
-#							DEPENDS Doxyfile)
-endif						(DOXYGEN_FOUND)
+if                          (DOXYGEN_FOUND)
+#   add_custom_target       (docs ALL
+#                           ${DOXYGEN_EXECUTABLE} Doxyfile
+#                           DEPENDS Doxyfile)
+endif                       (DOXYGEN_FOUND)
 
-# Set external sources
-add_subdirectory			(examples)
-add_subdirectory			(tests)
+# Process subdirectories
+add_subdirectory            (examples)
+add_subdirectory            (tests)
+add_subdirectory            (tools)
+add_subdirectory            (bindings)
--- a/FindCGAL.Makefile	Fri Aug 24 16:58:25 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-include $(CGAL_MAKEFILE)
-
-all: libpath libpaths ldflags cxxflags
-
-libpath:
-	@echo "$(CGAL_LIB_DIR)"
-
-libpaths:
-	@echo "$(CGAL_LIBPATHFLAGS)"
-
-ldflags:
-	@echo "$(CGAL_LDFLAGS)"
-
-cxxflags:
-	@echo "$(CGAL_CXXFLAGS)"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LEGAL	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,15 @@
+Copyright (C) 2006-2017  Dmitriy Morozov <dmitriy@mrzv.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,280 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
--- a/README	Fri Aug 24 16:58:25 2007 -0400
+++ b/README	Tue Jun 27 09:37:05 2017 -0700
@@ -1,28 +1,42 @@
-Dependencies
-  CGAL-3.3 -    for alpha-shapes and kinetic data structures
-  DSR-PDB -     for reading in PDB files
-  cmake -       for controlling the build process
-  boost -       great set of C++ libraries
-  Doxygen -     for building documentation
-  libcwd -      for debugging only (is not needed by default)
-  synaps -      for solving polynomial (for kinetic kernel), which in turn requires GMP
+% Dionysus README
+% Dmitriy Morozov
+
+## Dependencies
 
-Configuration
-  The path to CGAL's Makefile is expected to be set in $CGAL_MAKEFILE, the rest
-  is just usual CMake configuration
+  * [CGAL]-3.4 ---  for alpha-shapes and kinetic data structures
+  * [DSR-PDB] ---   for reading in PDB files (if use_dsrpdb is turned on in cmake)
+  * [CMake] ---     for controlling the build process
+  * [boost] ---     great set of C++ libraries
+  * [Doxygen] ---   for building documentation
+  * [rlog] ---      for logging only (is not needed by default)
+  * [SYNAPS] ---    for solving polynomials (for kinetic kernel), which in turn requires GMP
 
-Building
+[CGAL]:         http://www.cgal.org
+[DSR-PDB]:      http://www.salilab.org/~drussel/pdb/
+[CMake]:        http://www.cmake.org
+[boost]:        http://www.boost.org
+[Doxygen]:      http://www.stack.nl/~dimitri/doxygen/
+[rlog]:         http://www.arg0.net/rlog
+[SYNAPS]:       http://synaps.inria.fr/
+
+## Building
   To build examples, create a directory build (to keep everything in one place),
   go to that directory and run cmake and make:
-  mkdir build
-  cd build
-  cmake ..   (or "ccmake .." if you want a curses interface)
-  make
+
+    mkdir build
+    cd build
+    cmake ..   (or "ccmake .." if you want a curses interface)
+    make
   
-  In the cmake line you can provide -Ddebug:bool=on to turn on debugging,
-  -Dcounters:bool=on to turn on counters, -Doptimize:int=3 would set
-  optimization to -O3. All of this can be set using a text user interface by
-  running ccmake instead of cmake.
+  In the cmake line you can provide `-Ddebug:bool=on` to turn on debugging,
+  `-Dcounters:bool=on` to turn on counters, `-Doptimize:bool=on` to turn on
+  optimization, `-Duse_dsrpdb:bool=on` to turn on reading PDB files.  Depending on
+  the combination of debugging and optimization, a particular `CMAKE_CXX_FLAGS*`
+  is chosen.  All of this can be set using a text user interface by running
+  `ccmake` instead of `cmake`.
 
-Author
-  Dmitriy Morozov <morozov@cs.duke.edu>
+  When compiling on a 64 bit platform (with Boost 1.34) add
+  `-DBOOST_NO_INTRINSIC_INT64_T` to `CMAKE_CXX_FLAGS`.
+
+## Author
+  Dmitriy Morozov <dmitriy@mrzv.org>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,1 @@
+add_subdirectory			(python)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,53 @@
+find_package                (PythonLibs)
+link_libraries              (${PYTHON_LIBRARIES})
+include_directories         (${PYTHON_INCLUDE_PATH})
+link_libraries              (${Boost_PYTHON_LIBRARY})
+
+# currently can't build bindings with counters support, eventually FIXME
+remove_definitions          (-DCOUNTERS)
+set                         (sources
+                                                dionysus.cpp 
+                                                filtration.cpp
+                                                chain.cpp
+                                                static-persistence.cpp
+                                                dynamic-persistence.cpp
+                                                persistence-diagram.cpp
+                                                simplex.cpp
+                                                birthid.cpp
+                                                zigzag-persistence.cpp
+                                                cohomology-persistence.cpp
+                                                rips.cpp
+                                                distances.cpp
+                            )
+set                         (bindings_libraries ${libraries})
+
+if                          (CGAL_FOUND)
+    include                 (${CGAL_USE_FILE})
+
+    set                     (sources            ${sources}
+                                                alphashapes3d.cpp
+                                                alphashapes2d.cpp)
+    add_definitions         (${CGAL_CXX_FLAGS_INIT})
+    include_directories     (${CGAL_INCLUDE_DIRS})
+
+    link_libraries          (${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES})
+else                            (CGAL_FOUND)
+    message(STATUS "CGAL not found, alphashape bindings will not be built")
+    add_definitions         (-DNO_CGAL)
+endif                       (CGAL_FOUND)
+
+add_library                 (_dionysus SHARED   ${sources})
+target_link_libraries       (_dionysus          ${libraries})
+
+
+# Python files and the symlink
+add_custom_target           (dionysus ALL
+                             ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/dionysus ${CMAKE_CURRENT_BINARY_DIR}/dionysus
+                             DEPENDS            dionysus/__init__.py
+                                                dionysus/distances.py
+                            )
+
+get_target_property         (_dionysus_location _dionysus LOCATION)
+add_custom_target           (dionysus-link ALL 
+                             ${CMAKE_COMMAND} -E create_symlink ${_dionysus_location} ${CMAKE_CURRENT_BINARY_DIR}/dionysus/_dionysus.so
+                             DEPENDS _dionysus)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/alphashapes2d.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,44 @@
+// Wrap includes into namespaces to avoid nameclashes
+#include "../../examples/alphashapes/alphashapes2d.h" 
+
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+namespace bp = boost::python;
+
+#include "simplex.h"                // defines SimplexVD, Vertex, and Data
+namespace dp = dionysus::python;
+
+
+void fill_alpha2D_complex(bp::object points, bp::object complex)
+{
+    typedef     std::map<AlphaSimplex2D::Vertex, unsigned>      ASPointMap;
+
+    Delaunay2D  Dt;
+    ASPointMap  point_map;
+    unsigned i = 0;
+    for (bp::stl_input_iterator<bp::list> pt = points; pt != bp::stl_input_iterator<bp::list>(); ++pt)
+    {
+        double x = bp::extract<double>((*pt)[0]);
+        double y = bp::extract<double>((*pt)[1]);
+        point_map[Dt.insert(Point(x,y))] = i++;
+    }
+
+    AlphaSimplex2D::SimplexSet simplices;
+    fill_simplex_set(Dt, simplices);
+
+    for (AlphaSimplex2D::SimplexSet::const_iterator cur = simplices.begin(); cur != simplices.end(); ++cur)
+    {
+        dp::SimplexVD s;
+        for (AlphaSimplex2D::VertexContainer::const_iterator vcur  = cur->vertices().begin(); 
+                                                             vcur != cur->vertices().end(); ++vcur)
+            s.add(point_map[*vcur]);
+        
+        s.data() = bp::object(std::make_pair(cur->value(), !cur->attached()));      // regular/critical rather than attached
+        complex.attr("append")(s);
+    }
+}
+
+void export_alphashapes2d()
+{
+    bp::def("fill_alpha2D_complex",       &fill_alpha2D_complex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/alphashapes3d.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,48 @@
+// Wrap includes into namespaces to avoid nameclashes
+#include "../../examples/alphashapes/alphashapes3d.h" 
+
+#include <boost/shared_ptr.hpp>
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+namespace bp = boost::python;
+
+#include "utils.h"
+#include "simplex.h"                // defines SimplexVD, Vertex, and Data
+namespace dp = dionysus::python;
+
+
+void fill_alpha3D_complex(bp::object points, bp::object complex)
+{
+    typedef     std::map<AlphaSimplex3D::Vertex, unsigned>      ASPointMap;
+
+    Delaunay3D  Dt;
+    ASPointMap  point_map;
+    unsigned i = 0;
+    for (bp::stl_input_iterator<bp::list> pt = points; pt != bp::stl_input_iterator<bp::list>(); ++pt)
+    {
+        double x = bp::extract<double>((*pt)[0]);
+        double y = bp::extract<double>((*pt)[1]);
+        double z = bp::extract<double>((*pt)[2]);
+        point_map[Dt.insert(Point(x,y,z))] = i++;
+    }
+
+    AlphaSimplex3D::SimplexSet simplices;
+    fill_simplex_set(Dt, simplices);
+
+    for (AlphaSimplex3D::SimplexSet::const_iterator cur = simplices.begin(); cur != simplices.end(); ++cur)
+    {
+        
+        dp::SimplexVD s;
+        for (AlphaSimplex3D::VertexContainer::const_iterator vcur  = cur->vertices().begin(); 
+                                                             vcur != cur->vertices().end(); ++vcur)
+            s.add(point_map[*vcur]);
+        
+        s.data() = bp::object(std::make_pair(cur->value(), !cur->attached()));      // regular/critical rather than attached
+        complex.attr("append")(s);
+    }
+}
+
+void export_alphashapes3d()
+{
+    bp::def("fill_alpha3D_complex",       &fill_alpha3D_complex);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/birthid.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,10 @@
+#include "birthid.h"
+#include "optional.h"
+
+namespace dp = dionysus::python;
+
+void export_birthid()
+{
+    python_optional<dp::BirthID>();   
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/birthid.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,15 @@
+#ifndef __PYTHON_BIRTHID_H__
+#define __PYTHON_BIRTHID_H__
+
+#include <boost/python.hpp>
+
+namespace dionysus {
+namespace python   {
+
+//typedef         int                             BirthID;
+//typedef         boost::python::long_            BirthID;
+typedef         boost::python::object           BirthID;
+
+} } // namespace dionysus::python
+
+#endif // __PYTHON_BIRTHID_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/chain.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,29 @@
+#include <boost/iterator/indirect_iterator.hpp>
+
+#include <boost/python.hpp>
+#include <boost/python/iterator.hpp>
+#include <boost/python/return_internal_reference.hpp>
+namespace bp = boost::python;
+
+#include "chain.h"
+namespace dp = dionysus::python;
+
+
+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::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)
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/chain.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,11 @@
+#include <topology/chain.h>
+#include "static-persistence.h"
+#include "dynamic-persistence.h"
+
+namespace dionysus { 
+namespace python   {
+
+typedef     SPersistence::Chain                     VSPChain;
+typedef     DPersistenceChains::Chain               VDPChain;
+
+} }     // namespace dionysus::python
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/cohomology-persistence.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,112 @@
+#include <topology/cohomology-persistence.h>
+
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+#include <boost/python/overloads.hpp>
+#include <boost/shared_ptr.hpp>
+namespace bp = boost::python;
+
+#include "cohomology-persistence.h"             // defines CohomPersistence
+#include "optional.h"
+namespace dp = dionysus::python;
+
+
+// CohomPersistence
+boost::shared_ptr<dp::CohomPersistence>     init_from_prime(unsigned p)
+{
+    dp::CohomPersistence::Field field(p);       // Zp
+
+    boost::shared_ptr<dp::CohomPersistence> chp(new dp::CohomPersistence(field));
+    return chp;
+}
+
+boost::shared_ptr<dp::CohomPersistence>     init()
+{
+    return init_from_prime(11);
+}
+
+
+bp::tuple                                   chp_add(dp::CohomPersistence& chp,
+                                                    bp::object bdry,
+                                                    dp::BirthID birth,
+                                                    bool store,
+                                                    bool image,
+                                                    bp::object coefficients)
+{
+    dp::CohomPersistence::SimplexIndex      i;
+    dp::CohomPersistence::Death             d;
+    dp::CohomPersistence::CocyclePtr        ccl;
+
+    if (coefficients)
+    {
+        boost::tie(i,d,ccl)                         = chp.add(bp::stl_input_iterator<int>(coefficients),
+                                                              bp::stl_input_iterator<dp::CohomPersistence::SimplexIndex>(bdry),
+                                                              bp::stl_input_iterator<dp::CohomPersistence::SimplexIndex>(),
+                                                              birth, store, dp::CohomPersistence::SimplexData(), image);
+    } else
+    {
+        boost::tie(i,d,ccl)                         = chp.add(bp::stl_input_iterator<dp::CohomPersistence::SimplexIndex>(bdry),
+                                                              bp::stl_input_iterator<dp::CohomPersistence::SimplexIndex>(),
+                                                              birth, store, dp::CohomPersistence::SimplexData(), image);
+    }
+
+    return bp::make_tuple(i,d, ccl);
+}
+
+
+dp::CohomPersistence::ZColumn::const_iterator
+zcolumn_begin(dp::CohomPersistence::ZColumn& zcol)
+{ return zcol.begin(); }
+
+dp::CohomPersistence::ZColumn::const_iterator
+zcolumn_end(dp::CohomPersistence::ZColumn& zcol)
+{ return zcol.end(); }
+
+dp::CohomPersistence::ZColumn::const_iterator
+cocycle_zcolumn_begin(dp::CohomPersistence::Cocycle& ccl)
+{ return ccl.zcolumn.begin(); }
+
+dp::CohomPersistence::ZColumn::const_iterator
+cocycle_zcolumn_end(dp::CohomPersistence::Cocycle& ccl)
+{ return ccl.zcolumn.end(); }
+
+// SimplexIndex
+template<class T>
+unsigned                            si_order(T& si)
+{
+    return si->order;
+}
+
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(add_overloads, add, 2, 4)
+
+void export_cohomology_persistence()
+{
+    bp::class_<dp::CohomPersistence::SimplexIndex>("CHSimplexIndex")
+        .add_property("order",          &si_order<dp::CohomPersistence::SimplexIndex>)
+    ;
+
+    bp::class_<dp::CohomPersistence::SNode>("CHSNode", bp::no_init)
+        .add_property("coefficient",    &dp::CohomPersistence::SNode::coefficient)
+        .add_property("si",             &dp::CohomPersistence::SNode::si)
+    ;
+
+    bp::class_<dp::CohomPersistence>("CohomologyPersistence", bp::no_init)
+        .def("__init__",        bp::make_constructor(&init))
+        .def("__init__",        bp::make_constructor(&init_from_prime))
+        .def("add",             &chp_add, (bp::arg("bdry"), bp::arg("birth"), bp::arg("store")=true, bp::arg("image")=true, bp::arg("coefficients")=false))
+
+        .def("__iter__",        bp::range(&dp::CohomPersistence::begin, &dp::CohomPersistence::end))
+        .def("show_cocycles",   &dp::CohomPersistence::show_cocycles)
+    ;
+
+    bp::class_<dp::CohomPersistence::Cocycle>("Cocycle", bp::no_init)
+        .add_property("birth",  &dp::CohomPersistence::Cocycle::birth)
+        .def("__iter__",        bp::range(&cocycle_zcolumn_begin, &cocycle_zcolumn_end))
+    ;
+
+    bp::class_<dp::CohomPersistence::ZColumn,
+               boost::shared_ptr<dp::CohomPersistence::ZColumn> >("ZColumn", bp::no_init)
+        .def("__iter__",        bp::range(&zcolumn_begin, &zcolumn_end))
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/cohomology-persistence.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,16 @@
+#ifndef __PYTHON_ZIGZAG_PERSISTENCE_H__
+#define __PYTHON_ZIGZAG_PERSISTENCE_H__
+
+#include <topology/cohomology-persistence.h>
+#include <boost/python.hpp>
+
+#include "birthid.h"
+
+namespace dionysus {
+namespace python   {
+
+typedef         CohomologyPersistence<BirthID>  CohomPersistence;
+
+} } // namespace dionysus::python
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,61 @@
+#include <utilities/log.h>
+#include <boost/python.hpp>
+#include "utils.h"
+
+namespace bp = boost::python;
+namespace dp = dionysus::python;
+
+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();
+void export_cohomology_persistence();
+void export_point();
+void export_persistence_diagram();
+
+void export_rips();
+void export_pairwise_distances();
+
+#ifndef NO_CGAL
+void export_alphashapes2d();
+void export_alphashapes3d();
+#endif
+
+#ifdef LOGGING
+void            enable_log(std::string s)
+{
+    stdoutLog.subscribeTo(RLOG_CHANNEL(s.c_str()));
+}
+#endif
+
+BOOST_PYTHON_MODULE(_dionysus)
+{
+    bp::to_python_converter<std::pair<double, bool>, dp::PairToTupleConverter<double, bool> >();
+
+    export_simplex();
+    export_filtration();
+    export_static_persistence();
+    export_dynamic_persistence_chains();
+    export_chain();
+    export_point();
+    export_persistence_diagram();
+
+    export_birthid();
+    export_zigzag_persistence();
+    export_cohomology_persistence();
+
+    export_rips();
+    export_pairwise_distances();
+
+#ifndef NO_CGAL
+    export_alphashapes2d();
+    export_alphashapes3d();
+#endif
+
+#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	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,69 @@
+from    _dionysus   import *
+from    distances   import l2, ExplicitDistances, points_file
+from    zigzag      import *
+from    adaptor     import *
+import  circular
+
+def init_with_none(self, iter, data = None):        # convenience: data defaults to None
+    self._cpp_init_(iter, data)
+
+def repr_with_data(self):
+    str = self._cpp_repr_()
+    if type(self.data) == float:
+        str += ' %f' % self.data
+    return str
+
+Simplex._cpp_init_ =    Simplex.__init__
+Simplex.__init__   =    init_with_none
+Simplex._cpp_repr_ =    Simplex.__repr__
+Simplex.__repr__   =    repr_with_data
+
+def Simplex_getinitargs(self):
+    return ([v for v in self.vertices], self.data)
+
+Simplex.__getinitargs__ = Simplex_getinitargs
+
+def data_cmp(s1, s2):
+    return cmp(s1.data, s2.data)
+
+def data_dim_cmp(s1,s2):
+    return cmp(s1.dimension(), s2.dimension()) or data_cmp(s1,s2)
+
+def dim_data_cmp(s1,s2):
+    return data_cmp(s1,s2) or cmp(s1.dimension(), s2.dimension())
+
+def vertex_dim_cmp(s1, s2):
+    return cmp(s1.dimension(), s2.dimension()) or vertex_cmp(s1, s2)
+
+def dim_cmp(s1, s2):
+    return cmp(s1.dimension(), s2.dimension())
+
+def fill_alpha_complex(points, simplices):
+    if   len(points[0]) == 2:           # 2D
+        fill_alpha2D_complex(points, simplices)
+    elif len(points[0]) == 3:           # 3D
+        fill_alpha3D_complex(points, simplices)
+
+def closure(simplices, k):
+    """Compute the k-skeleton of the closure of the list of simplices."""
+
+    res = set()
+
+    from    itertools   import combinations
+    for s in simplices:
+        for kk in xrange(1, k+2):
+            for face in combinations(s.vertices, min(s.dimension() + 1, kk)):
+                res.add(Simplex(face, s.data))
+
+    return list(res)
+
+_init_diagrams = init_diagrams
+
+def init_diagrams(p, f, evaluator = None, data = None):
+    if isinstance(p, StaticCohomologyPersistence):
+        return init_diagrams_from_adaptor(p,f, evaluator, data)
+
+    return _init_diagrams(p,f, evaluator, data)
+
+def read_points(filename):
+    return [p for p in points_file(filename)]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/adaptor.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,114 @@
+from _dionysus import CohomologyPersistence, PersistenceDiagram, Cocycle
+
+class StaticCohomologyPersistence(object):
+    def __init__(self, filtration, prime = 2, subcomplex = lambda s: True):
+        self.filtration = filtration
+        self.prime = prime
+        self.subcomplex = subcomplex
+        self.persistence = CohomologyPersistence(prime)
+        self.pairs = []
+
+    def pair_simplices(self):
+        indices = []
+        for i,s in enumerate(self.filtration):
+            sc = self.subcomplex(s)
+            boundary = (indices[self.filtration(ss)] for ss in s.boundary)
+            idx,d,ccl = self.persistence.add(boundary, i, image = sc)
+            indices.append(idx)
+            self.pairs.append([i, sc, []])
+            if d:                           # Death
+                if self.pairs[d][1]:        # Birth was in the subcomplex
+                    self.pairs[i][0] = d    # i killed d
+                    self.pairs[d][0] = i    # d was killed by i
+                    self.pairs[d][2] = self._cocycle_list(ccl)  # record the cocycle at the time of death
+            else:
+                cocycle = self.persistence.__iter__().next()
+                self.pairs[-1][2] = cocycle
+
+        # Replace cocycles with lists
+        for i in xrange(len(self.pairs)):
+            ccl = self.pairs[i][2]
+            if isinstance(ccl, Cocycle):
+                self.pairs[i][2] = self._cocycle_list(ccl)
+
+    def _cocycle_list(self, ccl):
+        return [(n.coefficient if n.coefficient <= self.prime/2 else n.coefficient - self.prime, n.si.order) for n in ccl]
+
+    def __call__(self, n):
+        return n.i
+
+    def __len__(self):
+        return len(self.pairs)
+
+    def __iter__(self):
+        for i, (pair, subcomplex, cocycle) in enumerate(self.pairs):
+            if pair == i:       # unpaired
+                if subcomplex:
+                    yield APNode(i, self.pairs)
+            else:
+                if pair > i and subcomplex:
+                    yield APNode(i, self.pairs)
+                elif pair < i:
+                    pair_pair, pair_subcomplex, pair_cocycle = self.pairs[pair]
+                    if pair_subcomplex:
+                        yield APNode(i, self.pairs)
+
+    def make_simplex_map(self, filtration):
+        return APSimplexMap(filtration)
+
+class ImagePersistence(StaticCohomologyPersistence):
+    def __init__(self, filtration, subcomplex):
+        super(ImagePersistence, self).__init__(filtration, subcomplex = subcomplex)
+
+# Remaps APNodes into Simplices
+class APSimplexMap:
+    def __init__(self, filtration):
+        self.filtration = filtration
+
+    def __getitem__(self, n):
+        return self.filtration[n.i]
+
+class APNode:
+    def __init__(self, i, pairs):
+        self.i = i
+        self.pairs = pairs
+
+    def sign(self):
+        return self.unpaired() or self.i < self._pair()
+
+    def unpaired(self):
+        return self.i == self._pair()
+
+    def _pair(self):
+        return self.pairs[self.i][0]
+
+    def pair(self):
+        return APNode(self._pair(), self.pairs)
+
+    @property
+    def cocycle(self):
+        return self.pairs[self.i][2]
+
+def init_diagrams_from_adaptor(p, f, evaluator, data):
+    if not evaluator:
+        evaluator = lambda s: s.data
+
+    if not data:
+        data = lambda i: None
+
+    dgms = []
+    smap = p.make_simplex_map(f)
+    for n in p:
+        if not n.sign(): continue
+
+        dim = smap[n].dimension()
+        if dim + 1 > len(dgms):
+            dgms.append(PersistenceDiagram(dim))
+
+        b = evaluator(smap[n])
+        d = evaluator(smap[n.pair()]) if not n.unpaired() else float('inf')
+        if b == d: continue
+
+        dgms[dim].append((b,d, data(n)))
+
+    return dgms
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/circular/__init__.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,66 @@
+def smooth(filtration, cocycle):
+    from    cvxopt          import spmatrix, matrix
+    from    cvxopt.blas     import copy
+    from    lsqr            import lsqr
+
+    coefficient = []
+    coface_indices = []
+    face_indices = []
+    for i,s in enumerate(filtration):
+        if s.dimension() > 2: continue
+
+        c = 1
+        for sb in s.boundary:
+            j = filtration(sb)
+            coefficient.append(c)
+            coface_indices.append(i)
+            face_indices.append(j)
+            c *= -1
+
+    # Cocycle can be larger than D; we implicitly project it down
+    cocycle_max = max(zz[1] for zz in cocycle)
+
+    # D is a coboundary matrix
+    dimension = max(max(coface_indices), max(face_indices), cocycle_max) + 1
+    D = spmatrix(coefficient, coface_indices, face_indices, (dimension, dimension))
+
+    z = spmatrix([zz[0] for zz in cocycle],
+                 [zz[1] for zz in cocycle],
+                 [0     for zz in cocycle], (dimension, 1))
+
+    v1 = D * z
+    if bool(D*D):
+        raise Exception('D^2 is not 0')
+    if bool(v1):
+        raise Exception('Expected a cocycle as input')
+    z = matrix(z)
+
+    def Dfun(x,y,trans = 'N'):
+        if trans == 'N':
+            copy(D * x, y)
+        elif trans == 'T':
+            copy(D.T * x, y)
+        else:
+            assert False, "Unexpected trans parameter"
+
+    tol = 1e-10
+    show = False
+    maxit = None
+    solution = lsqr(Dfun, matrix(z), show = show, atol = tol, btol = tol, itnlim = maxit)
+
+    z_smooth = z - D*solution[0]
+
+    # print sum(z_smooth**2)
+    # assert sum((D*z_smooth)**2) < tol and sum((D.T*z_smooth)**2) < tol, "Expected a harmonic cocycle"
+    if not (sum((D*z_smooth)**2) < tol and sum((D.T*z_smooth)**2) < tol):
+        raise Exception("Expected a harmonic cocycle: %f %f" % (sum((D*z_smooth)**2), sum((D.T*z_smooth)**2)))
+
+    values = []
+    vertices = ((i,s) for (i,s) in enumerate(filtration) if s.dimension() == 0)
+    for i,s in vertices:
+        v = [v for v in s.vertices][0]
+        if v >= len(values):
+            values.extend((None for i in xrange(len(values), v+1)))
+        values[v] = solution[0][i]
+
+    return values
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/circular/lsqr.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,408 @@
+# LSQR solver from http://pages.cs.wisc.edu/~kline/cvxopt/
+
+from cvxopt import matrix
+from cvxopt.lapack import *
+from cvxopt.blas import *
+from math import sqrt
+
+"""
+a,b are scalars
+
+On exit, returns scalars c,s,r
+"""
+def SymOrtho(a,b):
+    aa=abs(a)
+    ab=abs(b)
+    if b==0.:
+        s=0.
+        r=aa
+        if aa==0.:
+            c=1.
+        else:
+            c=a/aa
+    elif a==0.:
+        c=0.
+        s=b/ab
+        r=ab
+    elif ab>=aa:
+        sb=1
+        if b<0: sb=-1
+        tau=a/b
+        s=sb*(1+tau**2)**-0.5
+        c=s*tau
+        r=b/s
+    elif aa>ab:
+        sa=1
+        if a<0: sa=-1
+        tau=b/a
+        c=sa*(1+tau**2)**-0.5
+        s=c*tau
+        r=a/c
+
+    return c,s,r
+
+"""
+
+It is usually recommended to use SYMMLQ for symmetric matrices
+
+Requires the syntax
+                   A(x,y)   == y:=[A]*x
+and
+           A(x,y,trans='T') == y:=[A.T]*x
+
+comments with '###' are followed by the intent of the original matlab
+code. This may be useful for debugging.
+
+"""
+
+def lsqr(  A, b, damp=0.0, atol=1e-8, btol=1e-8, conlim=1e8, itnlim=None, show=False, wantvar=False):
+    """
+
+    [ x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var ]...
+     = lsqr( m, n,  'aprod',  iw, rw, b, damp, atol, btol, conlim, itnlim, show );
+
+     LSQR solves  Ax = b  or  min ||b - Ax||_2  if damp = 0,
+     or   min || (b)  -  (  A   )x ||   otherwise.
+              || (0)     (damp I)  ||2
+     A  is an m by n matrix defined by  y = aprod( mode,m,n,x,iw,rw ),
+     where the parameter 'aprodname' refers to a function 'aprod' that
+     performs the matrix-vector operations.
+     If mode = 1,   aprod  must return  y = Ax   without altering x.
+     If mode = 2,   aprod  must return  y = A'x  without altering x.
+     WARNING:   The file containing the function 'aprod'
+                must not be called aprodname.m !!!!
+
+    -----------------------------------------------------------------------
+     LSQR uses an iterative (conjugate-gradient-like) method.
+     For further information, see
+     1. C. C. Paige and M. A. Saunders (1982a).
+        LSQR: An algorithm for sparse linear equations and sparse least squares,
+        ACM TOMS 8(1), 43-71.
+     2. C. C. Paige and M. A. Saunders (1982b).
+        Algorithm 583.  LSQR: Sparse linear equations and least squares problems,
+        ACM TOMS 8(2), 195-209.
+     3. M. A. Saunders (1995).  Solution of sparse rectangular systems using
+        LSQR and CRAIG, BIT 35, 588-604.
+
+     Input parameters:
+     iw, rw      are not used by lsqr, but are passed to aprod.
+     atol, btol  are stopping tolerances.  If both are 1.0e-9 (say),
+                 the final residual norm should be accurate to about 9 digits.
+                 (The final x will usually have fewer correct digits,
+                 depending on cond(A) and the size of damp.)
+     conlim      is also a stopping tolerance.  lsqr terminates if an estimate
+                 of cond(A) exceeds conlim.  For compatible systems Ax = b,
+                 conlim could be as large as 1.0e+12 (say).  For least-squares
+                 problems, conlim should be less than 1.0e+8.
+                 Maximum precision can be obtained by setting
+                 atol = btol = conlim = zero, but the number of iterations
+                 may then be excessive.
+     itnlim      is an explicit limit on iterations (for safety).
+     show = 1    gives an iteration log,
+     show = 0    suppresses output.
+
+     Output parameters:
+     x           is the final solution.
+     istop       gives the reason for termination.
+     istop       = 1 means x is an approximate solution to Ax = b.
+                 = 2 means x approximately solves the least-squares problem.
+     r1norm      = norm(r), where r = b - Ax.
+     r2norm      = sqrt( norm(r)^2  +  damp^2 * norm(x)^2 )
+                 = r1norm if damp = 0.
+     anorm       = estimate of Frobenius norm of Abar = [  A   ].
+                                                        [damp*I]
+     acond       = estimate of cond(Abar).
+     arnorm      = estimate of norm(A'*r - damp^2*x).
+     xnorm       = norm(x).
+     var         (if present) estimates all diagonals of (A'A)^{-1} (if damp=0)
+                 or more generally (A'A + damp^2*I)^{-1}.
+                 This is well defined if A has full column rank or damp > 0.
+                 (Not sure what var means if rank(A) < n and damp = 0.)
+
+
+            1990: Derived from Fortran 77 version of LSQR.
+     22 May 1992: bbnorm was used incorrectly.  Replaced by anorm.
+     26 Oct 1992: More input and output parameters added.
+     01 Sep 1994: Matrix-vector routine is now a parameter 'aprodname'.
+                  Print log reformatted.
+     14 Jun 1997: show  added to allow printing or not.
+     30 Jun 1997: var   added as an optional output parameter.
+     07 Aug 2002: Output parameter rnorm replaced by r1norm and r2norm.
+                  Michael Saunders, Systems Optimization Laboratory,
+                  Dept of MS&E, Stanford University.
+    -----------------------------------------------------------------------
+    """
+    """
+         Initialize.
+    """
+    n=len(b)
+    m=n
+    if itnlim is None: itnlim=2*n
+
+    msg=('The exact solution is  x = 0                              ',
+         'Ax - b is small enough, given atol, btol                  ',
+         'The least-squares solution is good enough, given atol     ',
+         'The estimate of cond(Abar) has exceeded conlim            ',
+         'Ax - b is small enough for this machine                   ',
+         'The least-squares solution is good enough for this machine',
+         'Cond(Abar) seems to be too large for this machine         ',
+         'The iteration limit has been reached                      ');
+
+    var = matrix(0.,(n,1));
+
+    if show:
+        print ' '
+        print 'LSQR            Least-squares solution of  Ax = b'
+        str1 = 'The matrix A has %8g rows  and %8g cols' % (m, n)
+        str2 = 'damp = %20.14e    wantvar = %8g' %( damp,wantvar)
+        str3 = 'atol = %8.2e                 conlim = %8.2e'%( atol, conlim)
+        str4 = 'btol = %8.2e                 itnlim = %8g'  %( btol, itnlim)
+        print str1
+        print str2
+        print str3
+        print str4
+
+    itn    = 0;		istop  = 0;		nstop  = 0;
+    ctol   = 0;
+    if conlim > 0: ctol = 1/conlim
+    anorm  = 0;		acond  = 0;
+    dampsq = damp**2;	ddnorm = 0;		res2   = 0;
+    xnorm  = 0;		xxnorm = 0;		z      = 0;
+    cs2    = -1;		sn2    = 0;
+
+    """
+    Set up the first vectors u and v for the bidiagonalization.
+     These satisfy  beta*u = b,  alfa*v = A'u.
+    """
+    __x    = matrix(0., (n,1)) # a matrix for temporary holding
+    v      = matrix(0., (n,1))
+    u      = +b;
+    x      = matrix(0., (n,1))
+    alfa   = 0;
+    beta = nrm2( u );
+    w      = matrix(0., (n,1))
+
+    if beta > 0:
+        ### u = (1/beta) * u;
+        ### v = feval( aprodname, 2, m, n, u, iw, rw );
+        scal(1/beta,u)
+	A(u,v,trans='T'); #v = feval( aprodname, 2, m, n, u, iw, rw );
+        alfa = nrm2( v );
+
+    if alfa > 0:
+        ### v = (1/alfa) * v;
+        scal(1/alfa,v)
+        copy(v,w)
+
+
+    rhobar = alfa;		phibar = beta;		bnorm  = beta;
+    rnorm  = beta;
+    r1norm = rnorm;
+    r2norm = rnorm;
+
+    # reverse the order here from the original matlab code because
+    # there was an error on return when arnorm==0
+    arnorm = alfa * beta;
+    if arnorm == 0:
+        print msg[0];
+        return x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var
+
+    head1  = '   Itn      x[0]       r1norm     r2norm ';
+    head2  = ' Compatible   LS      Norm A   Cond A';
+
+    if show:
+        print ' '
+        print head1, head2
+        test1  = 1;		test2  = alfa / beta;
+        str1   = '%6g %12.5e'    %(    itn,   x[0] );
+        str2   = ' %10.3e %10.3e'%( r1norm, r2norm );
+        str3   = '  %8.1e %8.1e' %(  test1,  test2 );
+        print str1, str2, str3
+
+    """
+    %------------------------------------------------------------------
+    %     Main iteration loop.
+    %------------------------------------------------------------------
+    """
+    while itn < itnlim:
+        itn = itn + 1;
+        """
+        %     Perform the next step of the bidiagonalization to obtain the
+        %     next  beta, u, alfa, v.  These satisfy the relations
+        %                beta*u  =  a*v   -  alfa*u,
+        %                alfa*v  =  A'*u  -  beta*v.
+        """
+        ### u    = feval( aprodname, 1, m, n, v, iw, rw )  -  alfa*u;
+        copy(u, __x)
+        A(v,u)
+        axpy(__x,u,-alfa)
+
+        beta = nrm2( u );
+        if beta > 0:
+            ### u     = (1/beta) * u;
+            scal(1/beta,u)
+            anorm = sqrt(anorm**2 + alfa**2 + beta**2 + damp**2);
+            ### v     = feval( aprodname, 2, m, n, u, iw, rw )  -  beta*v;
+            copy(v,__x)
+            A(u,v,trans='T')
+            axpy(__x,v,-beta)
+
+            alfa  = nrm2( v );
+            if alfa > 0:
+                ### v = (1/alfa) * v;
+                scal(1/alfa, v)
+
+        """
+        %     Use a plane rotation to eliminate the damping parameter.
+        %     This alters the diagonal (rhobar) of the lower-bidiagonal matrix.
+        """
+
+        rhobar1 = sqrt(rhobar**2 + damp**2);
+        cs1     = rhobar / rhobar1;
+        sn1     = damp   / rhobar1;
+        psi     = sn1 * phibar;
+        phibar  = cs1 * phibar;
+        """
+        %     Use a plane rotation to eliminate the subdiagonal element (beta)
+        %     of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix.
+        """
+
+
+        ###cs      =   rhobar1/ rho;
+        ###sn      =   beta   / rho;
+        cs,sn,rho = SymOrtho(rhobar1,beta)
+
+        theta   =   sn * alfa;
+        rhobar  = - cs * alfa;
+        phi     =   cs * phibar;
+        phibar  =   sn * phibar;
+        tau     =   sn * phi;
+        """
+        %     Update x and w.
+        """
+        t1      =   phi  /rho;
+        t2      = - theta/rho;
+        dk      =   (1/rho)*w;
+
+        ### x       = x      +  t1*w;
+        axpy(w,x,t1)
+        ### w       = v      +  t2*w;
+        scal(t2,w)
+        axpy(v,w)
+        ddnorm  = ddnorm +  nrm2(dk)**2;
+        if wantvar:
+            ### var = var  +  dk.*dk;
+            axpy(dk**2, var)
+        """
+        %     Use a plane rotation on the right to eliminate the
+        %     super-diagonal element (theta) of the upper-bidiagonal matrix.
+        %     Then use the result to estimate  norm(x).
+        """
+
+        delta   =   sn2 * rho;
+        gambar  = - cs2 * rho;
+        rhs     =   phi  -  delta * z;
+        zbar    =   rhs / gambar;
+        xnorm   =   sqrt(xxnorm + zbar**2);
+        gamma   =   sqrt(gambar**2 +theta**2);
+        cs2     =   gambar / gamma;
+        sn2     =   theta  / gamma;
+        z       =   rhs    / gamma;
+        xxnorm  =   xxnorm  +  z**2;
+        """
+        %     Test for convergence.
+        %     First, estimate the condition of the matrix  Abar,
+        %     and the norms of  rbar  and  Abar'rbar.
+        """
+        acond   =   anorm * sqrt(ddnorm);
+        res1    =   phibar**2;
+        res2    =   res2  +  psi**2;
+        rnorm   =   sqrt( res1 + res2 );
+        arnorm  =   alfa * abs( tau );
+        """
+        %     07 Aug 2002:
+        %     Distinguish between
+        %        r1norm = ||b - Ax|| and
+        %        r2norm = rnorm in current code
+        %               = sqrt(r1norm^2 + damp^2*||x||^2).
+        %        Estimate r1norm from
+        %        r1norm = sqrt(r2norm^2 - damp^2*||x||^2).
+        %     Although there is cancellation, it might be accurate enough.
+        """
+        r1sq    =   rnorm**2  -  dampsq * xxnorm;
+        r1norm  =   sqrt( abs(r1sq) );
+        if r1sq < 0: r1norm = - r1norm;
+        r2norm  =   rnorm;
+        """
+        %     Now use these norms to estimate certain other quantities,
+        %     some of which will be small near a solution.
+        """
+        test1   =   rnorm / bnorm;
+        test2   =   arnorm/( anorm * rnorm );
+        test3   =       1 / acond;
+        t1      =   test1 / (1    +  anorm * xnorm / bnorm);
+        rtol    =   btol  +  atol *  anorm * xnorm / bnorm;
+        """
+        %     The following tests guard against extremely small values of
+        %     atol, btol  or  ctol.  (The user may have set any or all of
+        %     the parameters  atol, btol, conlim  to 0.)
+        %     The effect is equivalent to the normal tests using
+        %     atol = eps,  btol = eps,  conlim = 1/eps.
+        """
+        if itn >= itnlim  : istop = 7;
+        if 1 + test3  <= 1: istop = 6;
+        if 1 + test2  <= 1: istop = 5;
+        if 1 + t1     <= 1: istop = 4;
+        """
+        %     Allow for tolerances set by the user.
+        """
+        if  test3 <= ctol:  istop = 3;
+        if  test2 <= atol:  istop = 2;
+        if  test1 <= rtol:  istop = 1;
+        """
+        %     See if it is time to print something.
+        """
+        prnt = False;
+        if n     <= 40       : prnt = True;
+        if itn   <= 10       : prnt = True;
+        if itn   >= itnlim-10: prnt = True;
+        # if itn%10 == 0       : prnt = True;
+        if test3 <=  2*ctol  : prnt = True;
+        if test2 <= 10*atol  : prnt = True;
+        if test1 <= 10*rtol  : prnt = True;
+        if istop !=  0       : prnt = True;
+
+        if prnt:
+            if show:
+                str1 = '%6g %12.5e'%        (itn,   x[0] );
+                str2 = ' %10.3e %10.3e'% (r1norm, r2norm );
+                str3 = '  %8.1e %8.1e'%  ( test1,  test2 );
+                str4 = ' %8.1e %8.1e'%   ( anorm,  acond );
+                print str1, str2, str3, str4
+
+        if istop != 0: break
+
+    """
+    %     End of iteration loop.
+    %     Print the stopping condition.
+    """
+    if show:
+        print ' '
+        print 'LSQR finished'
+        print msg[istop]
+        print ' '
+        str1 = 'istop =%8g   r1norm =%8.1e'%  ( istop, r1norm );
+        str2 = 'anorm =%8.1e   arnorm =%8.1e'%( anorm, arnorm );
+        str3 = 'itn   =%8g   r2norm =%8.1e'%  (   itn, r2norm );
+        str4 = 'acond =%8.1e   xnorm  =%8.1e'%( acond, xnorm  );
+        print str1+ '   ' +str2
+        print str3+ '   ' +str4
+        print ' '
+
+    return x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var
+
+    """
+    %-----------------------------------------------------------------------
+    % End of lsqr.m
+    %-----------------------------------------------------------------------
+    """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/distances.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,40 @@
+from    math        import sqrt
+
+def l2(p):
+    return sqrt(sum((x**2 for x in p)))
+
+# Pairwise distances between the elements of `points` with respect to some `norm`
+class PairwiseDistances:
+    def __init__(self, points, norm = l2):
+        self.points = points
+        self.norm = norm
+
+    def __len__(self):
+        return len(self.points)
+
+    def __call__(self, p1, p2):
+        return self.norm((x - y for (x,y) in zip(self.points[p1], self.points[p2])))
+
+# Caches all distances specified by `distances`
+class ExplicitDistances:
+    def __init__(self, distances):
+        self.len = len(distances)
+        self.distances = []
+        for i in xrange(self.len): 
+            self.distances.append([])
+            for j in xrange(self.len):
+                self.distances[-1].append(distances(i,j))
+
+    def __len__(self):
+        return self.len
+
+    def __call__(self, p1, p2):
+        return self.distances[p1][p2]
+
+# Generator of all points in a file `filename` with one point per line
+def points_file(filename):
+    fd = open(filename)
+    for line in fd.xreadlines():
+        if line.startswith('#'): continue
+        yield map(float, line.strip().split())
+    fd.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/viewer/PyGLWidget.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,309 @@
+# -*- coding: utf-8 -*-
+#===============================================================================
+#
+# PyGLWidget.py
+#
+# A simple GL Viewer.
+#
+# Copyright (c) 2011, Arne Schmitz <arne.schmitz@gmx.net>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the <organization> nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#===============================================================================
+
+from PyQt4 import QtCore, QtGui, QtOpenGL
+import math
+import numpy
+import numpy.linalg as linalg
+import OpenGL
+OpenGL.ERROR_CHECKING = False
+from OpenGL.GL import *
+from OpenGL.GLU import *
+
+class PyGLWidget(QtOpenGL.QGLWidget):
+
+    # Qt signals
+    signalGLMatrixChanged = QtCore.pyqtSignal()
+    rotationBeginEvent = QtCore.pyqtSignal()
+    rotationEndEvent = QtCore.pyqtSignal()
+
+    def __init__(self, parent = None):
+        format = QtOpenGL.QGLFormat()
+        format.setSampleBuffers(True)
+        QtOpenGL.QGLWidget.__init__(self, format, parent)
+        self.setCursor(QtCore.Qt.OpenHandCursor)
+        self.setMouseTracking(True)
+
+        self.modelview_matrix_  = []
+        self.translate_vector_  = [0.0, 0.0, 0.0]
+        self.viewport_matrix_   = []
+        self.projection_matrix_ = []
+        self.near_   = 0.1
+        self.far_    = 100.0
+        self.fovy_   = 45.0
+        self.radius_ = 5.0
+        self.last_point_2D_ = QtCore.QPoint()
+        self.last_point_ok_ = False
+        self.last_point_3D_ = [1.0, 0.0, 0.0]
+        self.isInRotation_  = False
+
+        # connections
+        #self.signalGLMatrixChanged.connect(self.printModelViewMatrix)
+
+    @QtCore.pyqtSlot()
+    def printModelViewMatrix(self):
+        print self.modelview_matrix_
+
+    def initializeGL(self):
+        # OpenGL state
+        glClearColor(1.0, 1.0, 1.0, 0.0)
+        glEnable(GL_DEPTH_TEST)
+        self.reset_view()
+
+    def resizeGL(self, width, height):
+        glViewport( 0, 0, width, height );
+        self.set_projection( self.near_, self.far_, self.fovy_ );
+        self.updateGL()
+
+    def paintGL(self):
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+
+        glMatrixMode(GL_MODELVIEW)
+        glLoadMatrixd(self.modelview_matrix_)
+
+    def set_projection(self, _near, _far, _fovy):
+        self.near_ = _near
+        self.far_ = _far
+        self.fovy_ = _fovy
+        self.makeCurrent()
+        glMatrixMode( GL_PROJECTION )
+        glLoadIdentity()
+        gluPerspective( self.fovy_, float(self.width()) / float(self.height()),
+                        self.near_, self.far_ )
+        self.updateGL()
+
+    def set_center(self, _cog):
+        self.center_ = _cog
+        self.view_all()
+
+    def set_radius(self, _radius):
+        self.radius_ = _radius
+        self.set_projection(_radius / 100.0, _radius * 100.0, self.fovy_)
+        self.reset_view()
+        self.translate([0, 0, -_radius * 2.0])
+        self.view_all()
+        self.updateGL()
+
+    def reset_view(self):
+        # scene pos and size
+        glMatrixMode( GL_MODELVIEW )
+        glLoadIdentity();
+        self.modelview_matrix_ = glGetDoublev( GL_MODELVIEW_MATRIX )
+        self.set_center([0.0, 0.0, 0.0])
+
+    def reset_rotation(self):
+        self.modelview_matrix_[0] = [1.0, 0.0, 0.0, 0.0]
+        self.modelview_matrix_[1] = [0.0, 1.0, 0.0, 0.0]
+        self.modelview_matrix_[2] = [0.0, 0.0, 1.0, 0.0]
+        glMatrixMode(GL_MODELVIEW)
+        glLoadMatrixd(self.modelview_matrix_)
+        self.updateGL()
+
+    def translate(self, _trans):
+        # Translate the object by _trans
+        # Update modelview_matrix_
+        self.makeCurrent()
+        glMatrixMode(GL_MODELVIEW)
+        glLoadIdentity()
+        glTranslated(_trans[0], _trans[1], _trans[2])
+        glMultMatrixd(self.modelview_matrix_)
+        self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
+        self.translate_vector_[0] = self.modelview_matrix_[3][0]
+        self.translate_vector_[1] = self.modelview_matrix_[3][1]
+        self.translate_vector_[2] = self.modelview_matrix_[3][2]
+        self.signalGLMatrixChanged.emit()
+
+    def rotate(self, _axis, _angle):
+        t = [self.modelview_matrix_[0][0] * self.center_[0] +
+             self.modelview_matrix_[1][0] * self.center_[1] +
+             self.modelview_matrix_[2][0] * self.center_[2] +
+             self.modelview_matrix_[3][0],
+             self.modelview_matrix_[0][1] * self.center_[0] +
+             self.modelview_matrix_[1][1] * self.center_[1] +
+             self.modelview_matrix_[2][1] * self.center_[2] +
+             self.modelview_matrix_[3][1],
+             self.modelview_matrix_[0][2] * self.center_[0] +
+             self.modelview_matrix_[1][2] * self.center_[1] +
+             self.modelview_matrix_[2][2] * self.center_[2] +
+             self.modelview_matrix_[3][2]]
+
+        self.makeCurrent()
+        glLoadIdentity()
+        glTranslatef(t[0], t[1], t[2])
+        glRotated(_angle, _axis[0], _axis[1], _axis[2])
+        glTranslatef(-t[0], -t[1], -t[2])
+        glMultMatrixd(self.modelview_matrix_)
+        self.modelview_matrix_ = glGetDoublev(GL_MODELVIEW_MATRIX)
+        self.signalGLMatrixChanged.emit()
+
+    def view_all(self):
+        self.translate( [ -( self.modelview_matrix_[0][0] * self.center_[0] +
+                             self.modelview_matrix_[0][1] * self.center_[1] +
+                             self.modelview_matrix_[0][2] * self.center_[2] +
+                             self.modelview_matrix_[0][3]),
+                           -( self.modelview_matrix_[1][0] * self.center_[0] +
+                              self.modelview_matrix_[1][1] * self.center_[1] +
+                              self.modelview_matrix_[1][2] * self.center_[2] +
+                              self.modelview_matrix_[1][3]),
+                           -( self.modelview_matrix_[2][0] * self.center_[0] +
+                              self.modelview_matrix_[2][1] * self.center_[1] +
+                              self.modelview_matrix_[2][2] * self.center_[2] +
+                              self.modelview_matrix_[2][3] +
+                              self.radius_ / 2.0 )])
+
+    def map_to_sphere(self, _v2D):
+        _v3D = [0.0, 0.0, 0.0]
+        # inside Widget?
+        if (( _v2D.x() >= 0 ) and ( _v2D.x() <= self.width() ) and
+            ( _v2D.y() >= 0 ) and ( _v2D.y() <= self.height() ) ):
+            # map Qt Coordinates to the centered unit square [-0.5..0.5]x[-0.5..0.5]
+            x  = float( _v2D.x() - 0.5 * self.width())  / self.width()
+            y  = float( 0.5 * self.height() - _v2D.y()) / self.height()
+
+            _v3D[0] = x;
+            _v3D[1] = y;
+            # use Pythagoras to comp z-coord (the sphere has radius sqrt(2.0*0.5*0.5))
+            z2 = 2.0*0.5*0.5-x*x-y*y;
+            # numerical robust sqrt
+            _v3D[2] = math.sqrt(max( z2, 0.0 ))
+
+            # normalize direction to unit sphere
+            n = linalg.norm(_v3D)
+            _v3D = numpy.array(_v3D) / n
+
+            return True, _v3D
+        else:
+            return False, _v3D
+
+    def wheelEvent(self, _event):
+        # Use the mouse wheel to zoom in/out
+
+        d = - float(_event.delta()) / 200.0 * self.radius_
+        self.translate([0.0, 0.0, d])
+        self.updateGL()
+        _event.accept()
+
+    def mousePressEvent(self, _event):
+        self.last_point_2D_ = _event.pos()
+        self.last_point_ok_, self.last_point_3D_ = self.map_to_sphere(self.last_point_2D_)
+
+    def mouseMoveEvent(self, _event):
+        newPoint2D = _event.pos()
+
+        if ((newPoint2D.x() < 0) or (newPoint2D.x() > self.width()) or
+            (newPoint2D.y() < 0) or (newPoint2D.y() > self.height())):
+            return
+
+        # Left button: rotate around center_
+        # Middle button: translate object
+        # Left & middle button: zoom in/out
+
+        value_y = 0
+        newPoint_hitSphere, newPoint3D = self.map_to_sphere(newPoint2D)
+
+        dx = float(newPoint2D.x() - self.last_point_2D_.x())
+        dy = float(newPoint2D.y() - self.last_point_2D_.y())
+
+        w  = float(self.width())
+        h  = float(self.height())
+
+        # enable GL context
+        self.makeCurrent()
+
+        # move in z direction
+        if (((_event.buttons() & QtCore.Qt.LeftButton) and (_event.buttons() & QtCore.Qt.MidButton))
+            or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ControlModifier)):
+            value_y = self.radius_ * dy * 2.0 / h;
+            self.translate([0.0, 0.0, value_y])
+        # move in x,y direction
+        elif (_event.buttons() & QtCore.Qt.MidButton
+              or (_event.buttons() & QtCore.Qt.LeftButton and _event.modifiers() & QtCore.Qt.ShiftModifier)):
+            z = - (self.modelview_matrix_[0][2] * self.center_[0] +
+                   self.modelview_matrix_[1][2] * self.center_[1] +
+                   self.modelview_matrix_[2][2] * self.center_[2] +
+                   self.modelview_matrix_[3][2]) / (self.modelview_matrix_[0][3] * self.center_[0] +
+                                                    self.modelview_matrix_[1][3] * self.center_[1] +
+                                                    self.modelview_matrix_[2][3] * self.center_[2] +
+                                                    self.modelview_matrix_[3][3])
+
+            fovy   = 45.0
+            aspect = w / h
+            n      = 0.01 * self.radius_
+            up     = math.tan(fovy / 2.0 * math.pi / 180.0) * n
+            right  = aspect * up
+
+            self.translate( [2.0 * dx / w * right / n * z,
+                             -2.0 * dy / h * up / n * z,
+                             0.0] )
+
+
+        # rotate
+        elif (_event.buttons() & QtCore.Qt.LeftButton):
+            if (not self.isInRotation_):
+                self.isInRotation_ = True
+                self.rotationBeginEvent.emit()
+
+            axis = [0.0, 0.0, 0.0]
+            angle = 0.0
+
+            if (self.last_point_ok_ and newPoint_hitSphere):
+                axis = numpy.cross(self.last_point_3D_, newPoint3D)
+                cos_angle = numpy.dot(self.last_point_3D_, newPoint3D)
+                if (abs(cos_angle) < 1.0):
+                    angle = math.acos(cos_angle) * 180.0 / math.pi
+                    angle *= 2.0
+                self.rotate(axis, angle)
+
+        # remember this point
+        self.last_point_2D_ = newPoint2D
+        self.last_point_3D_ = newPoint3D
+        self.last_point_ok_ = newPoint_hitSphere
+
+        # trigger redraw
+        self.updateGL()
+
+        def mouseReleaseEvent(self, _event):
+            if (isInRotation_):
+                isInRotation_ = false
+                self.rotationEndEvent.emit()
+            last_point_ok_ = False
+
+#===============================================================================
+#
+# Local Variables:
+# mode: Python
+# indent-tabs-mode: nil
+# End:
+#
+#===============================================================================
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/viewer/__init__.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,16 @@
+from    diagram     import show_diagram as _show_diagram
+from    complex2d   import show_complex_2D as _show_complex_2D
+from    complex3d   import show_complex_3D as _show_complex_3D
+
+from    PyQt4       import QtGui
+
+_app = QtGui.QApplication([])
+
+def show_complex(points, complex = None, values = None, subcomplex = None, **kwargs):
+    if len(points[0]) == 2:
+        _show_complex_2D(points, complex, values, subcomplex, app = _app, **kwargs)
+    if len(points[0]) == 3:
+        _show_complex_3D(points, complex, values, subcomplex, app = _app, **kwargs)
+
+def show_diagram(dgm, noise = 0):
+    return _show_diagram(dgm, noise, _app)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/viewer/complex2d.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,117 @@
+from    PyQt4       import QtGui, QtCore
+from    dionysus    import Simplex
+
+class ComplexViewer2D(QtGui.QGraphicsView):
+    def __init__(self, points, complex = None, values = None, subcomplex = None):
+        super(QtGui.QGraphicsView, self).__init__()
+        self._pan = False
+
+        self.points = points
+        if complex:
+            complex = [s for s in complex]
+        else:
+            # Create vertex simplices if no complex provided
+            complex = [Simplex([i]) for i in xrange(len(self.points))]
+
+        if not subcomplex:
+            subcomplex = []
+
+        if not values:
+            values = [0]*len(self.points)
+        self.values = values
+        self.maxval, self.minval = max(values), min(values)
+
+        self.setRenderHint(QtGui.QPainter.Antialiasing)
+        self.scene = QtGui.QGraphicsScene(self)
+        self.setScene(self.scene)
+
+        minx = min(p[0] for p in points)
+        miny = min(p[1] for p in points)
+        maxx = max(p[0] for p in points)
+        maxy = max(p[1] for p in points)
+
+        radius = min(maxx - minx, maxy - miny)/100
+        self.scene.setSceneRect(minx - 10*radius, miny - 10*radius, (maxx - minx) + 20*radius, (maxy - miny) + 20*radius)
+
+        self.draw_complex(complex, radius, colormap = self.colormap)
+        self.draw_complex(subcomplex, 3*radius, colormap = lambda v: QtCore.Qt.green, line_color = QtCore.Qt.green)
+
+        # Flip y-axis
+        self.scale(1,-1)
+
+        # Set the correct view
+        rect = self.scene.itemsBoundingRect()
+        self.fitInView(rect, QtCore.Qt.KeepAspectRatio)
+
+    def draw_complex(self, complex, radius, colormap, line_color = QtCore.Qt.black):
+        complex.sort(lambda s1, s2: -cmp(s1.dimension(), s2.dimension()))
+        for s in complex:
+            vertices = [v for v in s.vertices]
+            if s.dimension() == 0:              # point
+                p = self.points[vertices[0]]
+                v = self.values[vertices[0]]
+                item = QtGui.QGraphicsEllipseItem(p[0] - radius/2,p[1] - radius/2,radius,radius)
+                color = colormap(v)
+                item.setBrush(QtGui.QBrush(color))
+                item.setPen(QtGui.QPen(color))
+            elif s.dimension() == 1:            # edge
+                p0 = self.points[vertices[0]]
+                p1 = self.points[vertices[1]]
+                item = QtGui.QGraphicsLineItem(p0[0], p0[1], p1[0], p1[1])
+                item.setPen(QtGui.QPen(line_color))
+            else:                               # higher-d simplex
+                pts = [QtCore.QPointF(self.points[v][0], self.points[v][1]) for v in vertices]
+                item = QtGui.QGraphicsPolygonItem(QtGui.QPolygonF(pts))
+                item.setBrush(QtCore.Qt.blue)
+
+            self.scene.addItem(item)
+
+    def colormap(self, v):
+        if self.maxval <= self.minval:
+            t = 0
+        else:
+            t = (v - self.minval)/(self.maxval - self.minval)
+        c = QtGui.QColor()
+        c.setHsv(int(t*255), 255, 255)
+        return c
+
+    def wheelEvent(self, event):
+        delta = 1 + float(event.delta())/100
+        if delta < 0:
+            event.ignore()
+            return
+        self.scale(delta, delta)
+        event.accept()
+
+    def mousePressEvent(self, event):
+        if event.button() == QtCore.Qt.RightButton:
+            self._pan = True
+            self._panStartX = event.x()
+            self._panStartY = event.y()
+            self.setCursor(QtCore.Qt.ClosedHandCursor)
+            event.accept()
+
+    def mouseReleaseEvent(self, event):
+        if event.button() == QtCore.Qt.RightButton:
+            self._pan = False
+            self.setCursor(QtCore.Qt.ArrowCursor)
+            event.accept()
+            return
+        event.ignore()
+
+    def mouseMoveEvent(self, event):
+        if self._pan:
+            self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - (event.x() - self._panStartX))
+            self.verticalScrollBar().setValue(self.verticalScrollBar().value() - (event.y() - self._panStartY))
+            self._panStartX = event.x()
+            self._panStartY = event.y()
+            event.accept()
+            return
+        event.ignore()
+
+def show_complex_2D(points, complex = None, values = None, subcomplex = None, app = None):
+    #app = QtGui.QApplication([])
+    view = ComplexViewer2D(points, complex, values, subcomplex)
+    view.show()
+    view.raise_()
+    app.exec_()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/viewer/complex3d.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,118 @@
+from    PyQt4       import QtGui, QtCore
+from    PyGLWidget  import PyGLWidget
+from    OpenGL.GL   import *
+from    dionysus    import Simplex
+from    math        import sqrt
+
+class ComplexViewer3D(PyGLWidget):
+    def __init__(self, points, complex = None, values = None, subcomplex = None, point_size = 3.):
+        self.display_list = None
+        PyGLWidget.__init__(self)
+
+        #glEnable( GL_BLEND )
+        #glEnable( GL_LINE_SMOOTH )
+        #glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+
+        self.point_size = point_size
+        self.points = points
+        if complex:
+            self.complex = [s for s in complex]
+        else:
+            # Create vertex simplices if no complex provided
+            self.complex = [Simplex([i]) for i in xrange(len(self.points))]
+
+        if subcomplex:
+            self.subcomplex = subcomplex
+        else:
+            self.subcomplex = []
+
+        self.values = values
+        if not values:
+            self.values = [0]*len(self.points)
+        self.maxval, self.minval = max(self.values), min(self.values)
+
+        center, radius = self.center_radius()
+        self.set_radius(radius)
+        self.set_center(center)
+
+        self.make_display_list()
+
+    def center_radius(self):
+        c = [0,0,0]
+        for p in self.points:
+            for i in xrange(3): c[i] += p[i]
+        for i in xrange(3): c[i] /= len(self.points)
+
+        r = 0
+        for p in self.points:
+            d = sqrt((p[0] - c[0])**2 + (p[1] - c[1])**2 + (p[2] - c[2])**2)
+            if d > r: r = d
+        return c,r
+
+    def paintGL(self):
+        PyGLWidget.paintGL(self)
+        if self.display_list:
+            glCallList(self.display_list)
+
+    def make_display_list(self):
+        self.display_list = glGenLists(1)
+        glNewList(self.display_list, GL_COMPILE)
+        self.draw_complex(self.complex,    self.point_size,   2., self.colormap)
+        self.draw_complex(self.subcomplex, 2*self.point_size, 4., colormap = lambda v: (0,1.,0), line_color = (0,1.,0))
+        glEndList()
+
+
+    def draw_complex(self, complex, point_size, line_size, colormap, line_color = (0,0,1.)):
+        glPointSize(point_size)
+        glLineWidth(line_size)
+        complex.sort(lambda s1, s2: -cmp(s1.dimension(), s2.dimension()))
+        for s in complex:
+            vertices = [v for v in s.vertices]
+            if s.dimension() == 0:              # point
+                p = self.points[vertices[0]]
+                v = self.values[vertices[0]]
+
+                c = self.colormap(v)
+                glColor3f(*c)
+                glBegin(GL_POINTS)
+                glVertex3f(p[0],p[1],p[2])
+                glEnd()
+            if s.dimension() == 1:            # edge
+                p0 = self.points[vertices[0]]
+                p1 = self.points[vertices[1]]
+
+                glColor3f(*line_color)
+                glBegin(GL_LINES)
+                glVertex3f(p0[0],p0[1],p0[2])
+                glVertex3f(p1[0],p1[1],p1[2])
+                glEnd()
+            elif s.dimension() == 2:
+                p0 = self.points[vertices[0]]
+                p1 = self.points[vertices[1]]
+                p2 = self.points[vertices[2]]
+
+                glColor3f(1,1,0)
+                glBegin(GL_TRIANGLES)
+                glVertex3f(p0[0],p0[1],p0[2])
+                glVertex3f(p1[0],p1[1],p1[2])
+                glVertex3f(p2[0],p2[1],p2[2])
+                glEnd()
+
+    def colormap(self, v):
+        if self.maxval <= self.minval:
+            t = 0
+        else:
+            t = (v - self.minval)/(self.maxval - self.minval)
+        c = QtGui.QColor()
+        c.setHsv(int(t*255), 255, 255)
+        cr = float(c.red())/255
+        cg = float(c.green())/255
+        cb = float(c.blue())/255
+        return (cr,cg,cb)
+
+def show_complex_3D(points, complex = None, values = None, subcomplex = None, app = None, point_size = 3.):
+    #app = QtGui.QApplication([])
+    view = ComplexViewer3D(points, complex, values, subcomplex, point_size)
+    view.show()
+    view.raise_()
+    app.exec_()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/viewer/diagram.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,156 @@
+from    PyQt4       import QtGui, QtCore
+from    math        import fabs
+
+class DiagramPoint(QtGui.QGraphicsEllipseItem):
+    def __init__(self,x,y, p, infty = False, color = 0):
+        super(QtGui.QGraphicsEllipseItem, self).__init__()
+        c = self.color(color)
+        self.setBrush(QtGui.QBrush(c[0]))
+        self.setPen(QtGui.QPen(c[1]))
+        self.radius = .075
+        if infty:
+            self.radius *= 2
+        self.x, self.y = x,y
+        self.scale(1)
+        self.p = p
+
+    def scale(self, delta):
+        self.radius *= delta
+        self.setRect(self.x - self.radius, self.y - self.radius, 2*self.radius, 2*self.radius)
+
+    def color(self, i):
+        return self._colors[i % len(self._colors)]
+
+    # (fill, border) pairs
+    _colors = [(QtCore.Qt.red,   QtGui.QColor(225, 0, 0)),
+               (QtCore.Qt.blue,  QtGui.QColor(0, 0, 225)),
+               (QtCore.Qt.green, QtGui.QColor(0, 225, 0)),
+              ]
+
+class DiagramViewer(QtGui.QGraphicsView):
+    def __init__(self, dgm, noise):
+        super(QtGui.QGraphicsView, self).__init__()
+
+        self.selection = None
+        self._pan = False
+
+        self.setRenderHint(QtGui.QPainter.Antialiasing)
+        self.scene = QtGui.QGraphicsScene(self)
+        self.setScene(self.scene)
+
+        if not isinstance(dgm, list):
+            # Assume it's just a single diagram
+            dgms = [dgm]
+        else:
+            dgms = dgm
+
+        inf = float('inf')
+        xs = [p[0] for d in dgms for p in d]
+        ys = [p[1] for d in dgms for p in d]
+        minx = min(0, min(xs) if xs else 0)
+        miny = min(0, min(ys) if ys else 0)
+        xs = [x for x in xs if x != inf]
+        ys = [y for y in ys if y != inf]
+        maxx = max(0, max(xs) if xs else 0)
+        maxy = max(0, max(ys) if ys else 0)
+
+        self.draw_axes(minx,miny,maxx,maxy)
+
+        for i, dgm in enumerate(dgms):
+            for p in dgm:
+                x,y = p[0],p[1]
+                if fabs(y - x) < noise:
+                    continue
+                if fabs(x) == inf or fabs(y) == inf:
+                    if x == inf: x = maxx + 2
+                    if y == inf: y = maxy + 2
+                    if x == -inf: x = minx - 2
+                    if y == -inf: y = miny - 2
+                    item = DiagramPoint(x,y,p, infty = True, color = i)
+                else:
+                    item = DiagramPoint(x,y,p, color = i)
+                self.scene.addItem(item)
+
+        # Flip y-axis
+        self.scale(1, -1)
+
+        # Set the correct view
+        rect = self.scene.itemsBoundingRect()
+        self.fitInView(rect, QtCore.Qt.KeepAspectRatio)
+
+    def mousePressEvent(self, event):
+        if event.button() == QtCore.Qt.RightButton:
+            self._pan = True
+            self._panStartX = event.x()
+            self._panStartY = event.y()
+            self.setCursor(QtCore.Qt.ClosedHandCursor)
+            event.accept()
+        else:
+            p = self.mapToScene(event.pos())
+            item = self.scene.itemAt(p)
+            if isinstance(item, DiagramPoint):
+                self.selection = item.p
+                self.close()
+
+    def mouseReleaseEvent(self, event):
+        if event.button() == QtCore.Qt.RightButton:
+            self._pan = False
+            self.setCursor(QtCore.Qt.ArrowCursor)
+            event.accept()
+            return
+        event.ignore()
+
+    def mouseMoveEvent(self, event):
+        if self._pan:
+            self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - (event.x() - self._panStartX))
+            self.verticalScrollBar().setValue(self.verticalScrollBar().value() - (event.y() - self._panStartY))
+            self._panStartX = event.x()
+            self._panStartY = event.y()
+            event.accept()
+            return
+        event.ignore()
+
+    def wheelEvent(self, event):
+        delta = 1 + float(event.delta())/100
+        if delta < 0:
+            event.ignore()
+            return
+        self.scale(delta, delta)
+        for item in self.scene.items():
+            if isinstance(item, DiagramPoint):
+                item.scale(1/delta)
+        event.accept()
+
+    def draw_axes(self, minx, miny, maxx, maxy):
+        # Draw axes and diagonal
+        if maxx > 0:
+            self.scene.addItem(QtGui.QGraphicsLineItem(0,0, maxx, 0))
+        if minx < 0:
+            self.scene.addItem(QtGui.QGraphicsLineItem(minx,0, 0, 0))
+        if maxy > 0:
+            self.scene.addItem(QtGui.QGraphicsLineItem(0,0, 0, maxy))
+        if miny < 0:
+            self.scene.addItem(QtGui.QGraphicsLineItem(0,miny, 0, 0))
+        self.scene.addItem(QtGui.QGraphicsLineItem(0,0, min(maxx, maxy), min(maxx, maxy)))
+        self.scene.addItem(QtGui.QGraphicsLineItem(max(minx,miny), max(minx,miny), 0,0))
+
+        # Dashed, gray integer lattice
+        pen = QtGui.QPen(QtCore.Qt.DashLine)
+        pen.setColor(QtCore.Qt.gray)
+        for i in xrange(min(0, int(minx)) + 1, max(0,int(maxx)) + 1):
+            line = QtGui.QGraphicsLineItem(i,0, i, maxy)
+            line.setPen(pen)
+            self.scene.addItem(line)
+        for i in xrange(min(0, int(miny)) + 1, max(0, int(maxy)) + 1):
+            line = QtGui.QGraphicsLineItem(0,i, maxx, i)
+            line.setPen(pen)
+            self.scene.addItem(line)
+
+
+def show_diagram(dgm, noise, app):
+    #app = QtGui.QApplication([])
+    view = DiagramViewer(dgm, noise)
+    view.show()
+    view.raise_()
+    app.exec_()
+    return view.selection
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dionysus/zigzag.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,20 @@
+def add_simplices(zz, simplices, complex, birth, report_local = False):
+    deaths = []
+    for s in simplices:
+        i,d = zz.add([complex[sb] for sb in s.boundary], (s.dimension(), birth))
+        complex[s] = i
+        if d is not None:
+            if report_local or not d[1] == birth:
+                deaths.append(d)
+    return deaths
+            
+
+def remove_simplices(zz, simplices, complex, birth, report_local = False):
+    deaths = []
+    for s in simplices:
+        d = zz.remove(complex[s], (s.dimension() - 1, birth))
+        complex[s] = None
+        if d is not None:
+            if report_local or not d[1] == birth:
+                deaths.append(d)
+    return deaths
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/distances.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,21 @@
+#include <boost/python.hpp>
+namespace bp = boost::python;
+
+#include "distances.h"
+namespace dp = dionysus::python;
+
+boost::shared_ptr<dp::ListPointPairwiseDistances>       init_from_list(bp::list lst)
+{
+    boost::shared_ptr<dp::ListPointPairwiseDistances>   p(new dp::ListPointPairwiseDistances(lst));
+    return p;
+}
+
+void export_pairwise_distances()
+{
+    bp::class_<dp::ListPointPairwiseDistances>("PairwiseDistances", bp::no_init)
+        .def("__init__",        bp::make_constructor(&init_from_list))
+        .def("__len__",         &dp::ListPointPairwiseDistances::size)
+        .def("__call__",        &dp::ListPointPairwiseDistances::operator())
+    ;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/distances.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,54 @@
+#include <utilities/log.h>
+
+#include <boost/python.hpp>
+namespace bp = boost::python;
+
+namespace dionysus { 
+namespace python   {
+
+typedef     bp::list            ListPoint;
+
+struct ListPointL2Distance:
+    public std::binary_function<bp::object, bp::object, double>
+{
+    result_type     operator()(bp::object p1, bp::object p2) const
+    {
+        ListPoint lp1 = bp::extract<ListPoint>(p1), lp2 = bp::extract<ListPoint>(p2);
+
+        AssertMsg(bp::len(lp1) == bp::len(lp2), "Points must be in the same dimension (in L2Distance): dim1=%d, dim2=%d", bp::len(lp1), bp::len(lp2));
+        result_type sum = 0;
+        for (size_t i = 0; i < bp::len(lp1); ++i)
+        {
+            double diff = bp::extract<double>(lp1[i]) - bp::extract<double>(lp2[i]);
+            sum += diff*diff;
+        }
+
+        return sqrt(sum);
+    }
+};
+
+class ListPointPairwiseDistances
+{
+    public:
+        typedef             bp::list                                        Container;
+        typedef             ListPointL2Distance                             Distance;
+        typedef             unsigned                                        IndexType;
+        typedef             Distance::result_type                           DistanceType;
+
+
+                            ListPointPairwiseDistances(Container container): 
+                                container_(container)                       {}
+
+        DistanceType        operator()(IndexType a, IndexType b) const      { return distance_(container_[a], container_[b]); }
+
+        size_t              size() const                                    { return bp::len(container_); }
+        IndexType           begin() const                                   { return 0; }
+        IndexType           end() const                                     { return size(); }
+
+    private:
+        Container           container_;
+        Distance            distance_;
+};
+
+} }     // namespace dionysus::python
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/dynamic-persistence.cpp	Tue Jun 27 09:37:05 2017 -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 Jun 27 09:37:05 2017 -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/filtration.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,60 @@
+#include <topology/filtration.h>
+
+#include <boost/python.hpp>
+#include <boost/iterator.hpp>
+#include <boost/python/return_internal_reference.hpp>
+namespace bp = boost::python;
+
+
+#include "simplex.h"
+#include "filtration.h"      // defines PythonFiltration
+#include "utils.h"           // defines PythonCmp
+namespace dp = dionysus::python;
+
+boost::shared_ptr<dp::PythonFiltration>     init_from_iterator(bp::object iter)
+{
+    typedef     dp::PythonFiltration::Simplex   Smplx;
+    boost::shared_ptr<dp::PythonFiltration>     p(new dp::PythonFiltration(bp::stl_input_iterator<Smplx>(iter), 
+                                                                           bp::stl_input_iterator<Smplx>()));
+    return p;
+}
+
+boost::shared_ptr<dp::PythonFiltration>     init_from_iterator_cmp(bp::object iter, bp::object cmp)
+{
+    typedef     dp::PythonFiltration::Simplex   Smplx;
+    boost::shared_ptr<dp::PythonFiltration>     p(new dp::PythonFiltration(bp::stl_input_iterator<Smplx>(iter), 
+                                                                           bp::stl_input_iterator<Smplx>(),
+                                                                           dp::PythonCmp(cmp)));
+    return p;
+}
+
+void                                        filtration_sort(dp::PythonFiltration& f, bp::object cmp)
+{ f.sort(dp::PythonCmp(cmp)); }
+
+const dp::PythonFiltration::Simplex&        f_getitem(const dp::PythonFiltration& f, int i)
+{ 
+    if (i >= 0)
+        return f.simplex(f.begin() + i); 
+    else
+        return f.simplex(f.end() + i);
+}
+
+unsigned                                    f_call(const dp::PythonFiltration& f, const dp::PythonFiltration::Simplex& s)
+{ return f.find(s) - f.begin(); }
+
+
+void export_filtration()
+{
+    bp::class_<dp::PythonFiltration>("Filtration")
+        .def("__init__",        bp::make_constructor(&init_from_iterator))
+        .def("__init__",        bp::make_constructor(&init_from_iterator_cmp))
+
+        .def("append",          &dp::PythonFiltration::push_back)
+        .def("sort",            &filtration_sort)
+
+        .def("__getitem__",     &f_getitem,      bp::return_internal_reference<1>())
+        .def("__call__",        &f_call)
+        .def("__iter__",        bp::range<bp::return_internal_reference<1> >(&dp::PythonFiltration::begin, &dp::PythonFiltration::end))
+        .def("__len__",         &dp::PythonFiltration::size)
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/filtration.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,18 @@
+#ifndef __PYTHON_FILTRATION_H__
+#define __PYTHON_FILTRATION_H__
+
+#include <topology/filtration.h>
+#include <boost/python.hpp>
+#include "simplex.h"
+#include "utils.h"                      // for ListRandomAccessIterator
+
+namespace bp = boost::python;
+
+namespace dionysus {
+namespace python   {
+
+typedef         Filtration<SimplexVD>                       PythonFiltration;
+
+} } // namespace dionysus::python
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/optional.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,85 @@
+#ifndef __PYTHON_OPTIONAL_H__
+#define __PYTHON_OPTIONAL_H__
+
+#include <boost/python.hpp>
+#include <boost/optional.hpp>
+#include <boost/utility.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/persistence-diagram.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,229 @@
+#include<topology/persistence-diagram.h>
+#include<utilities/types.h>
+
+#include "filtration.h"
+#include "simplex.h"
+#include "static-persistence.h"
+#include "dynamic-persistence.h"
+
+#include <boost/foreach.hpp>
+
+#include<boost/python.hpp>
+#include<boost/python/init.hpp>
+#include<boost/shared_ptr.hpp>
+#include<boost/python/stl_iterator.hpp>
+#include<boost/python/def.hpp>
+#include<boost/python/register_ptr_to_python.hpp>
+namespace bp = boost::python;
+
+
+namespace dionysus{
+namespace python{
+
+typedef     bp::object                  Data;
+typedef     PersistenceDiagram<Data>    PersistenceDiagramD;
+typedef     PersistenceDiagramD::Point  PointD;
+typedef     boost::shared_ptr<PersistenceDiagramD>  PDgmPtr;
+
+} } //namespace dionysus::python
+
+namespace dp = dionysus::python;
+
+struct PointFromTupleConverter
+{
+    PointFromTupleConverter()
+    {
+        boost::python::converter::registry::push_back(&convertible,
+                                                      &construct,
+                                                      boost::python::type_id<dp::PointD>());
+    }
+
+    static void* convertible(PyObject* obj_ptr)
+    {
+        if (!PyTuple_Check(obj_ptr)) return 0;
+        if (PyTuple_Size(obj_ptr) < 2) return 0;
+        return obj_ptr;
+    }
+
+    static void construct(PyObject* obj_ptr,
+                          boost::python::converter::rvalue_from_python_stage1_data* data)
+    {
+        //const char* value = PyString_AsString(obj_ptr);
+        //if (value == 0) boost::python::throw_error_already_set();
+
+        // Grab pointer to memory into which to construct the new T
+        void* storage = ( (boost::python::converter::rvalue_from_python_storage<dp::PointD>*) data)->storage.bytes;
+
+        RealType x = bp::extract<RealType>(PyTuple_GetItem(obj_ptr, 0));
+        RealType y = bp::extract<RealType>(PyTuple_GetItem(obj_ptr, 1));
+
+        // in-place construct the new T using the character data extraced from the python object
+        dp::PointD* p = new (storage) dp::PointD(x,y);
+
+        if (PyTuple_Size(obj_ptr) > 2)
+            p->data() = bp::extract<bp::object>(PyTuple_GetItem(obj_ptr, 2));
+
+        // Stash the memory chunk pointer for later use by boost.python
+        data->convertible = storage;
+    }
+};
+
+struct PointToTupleConverter
+{
+    static PyObject* convert(const dp::PointD& p)
+    {
+        if (p.data().ptr() == bp::object().ptr())
+            return bp::incref(bp::make_tuple(p.x(), p.y()).ptr());
+        else
+            return bp::incref(bp::make_tuple(p.x(), p.y(), p.data()).ptr());
+    }
+};
+
+
+void export_point( )
+{
+    PointFromTupleConverter();
+    bp::to_python_converter<dp::PointD, PointToTupleConverter>();
+}
+
+
+boost::shared_ptr<dp::PersistenceDiagramD>      init_from_points_sequence(Dimension dimension, bp::object point_sequence)
+{
+    typedef     bp::stl_input_iterator<dp::PointD>  PointIterator;
+
+    PointIterator beg = PointIterator(point_sequence), end = PointIterator();
+    boost::shared_ptr<dp::PersistenceDiagramD> p(new dp::PersistenceDiagramD(dimension));
+
+    for(PointIterator cur = beg; cur != end; cur++)
+        (*p).push_back(*cur);
+    return p;
+
+}
+
+RealType    bottleneck_distance_adapter(const dp::PersistenceDiagramD& dgm1, const dp::PersistenceDiagramD& dgm2)
+{
+    return bottleneck_distance(dgm1, dgm2);
+}
+
+
+template<class Persistence>
+struct InitDiagrams
+{
+    typedef             std::map<int, dp::PDgmPtr>                                          DiagramMap;
+    typedef             typename Persistence::template SimplexMap<dp::PythonFiltration>     SMap;
+
+    struct DataEvaluator
+    {
+                            DataEvaluator(const SMap& smap_):
+                                smap(smap_)                         {}
+
+        template<class Key>
+        RealType            operator()(Key k) const                 { return bp::extract<RealType>(smap[k].data()); }
+
+        const SMap& smap;
+    };
+
+    struct PythonEvaluator
+    {
+                            PythonEvaluator(const SMap& smap_, bp::object eval_):
+                                smap(smap_), eval(eval_)            {}
+
+        template<class Key>
+        RealType            operator()(Key k) const                 { return bp::extract<RealType>(eval(smap[k])); }
+
+        const SMap& smap;
+        bp::object  eval;
+    };
+
+    // A hack
+    struct DiagramMapOwner: public DiagramMap
+    {
+        typedef             dp::PersistenceDiagramD                 mapped_type;
+
+        mapped_type&        operator[](Dimension d)
+        {
+            if (this->find(d) == this->end())
+                this->insert(std::make_pair(d, dp::PDgmPtr(new dp::PersistenceDiagramD(d))));
+            return *DiagramMap::operator[](d);
+        }
+    };
+
+    static
+    bp::list    extract_list(const DiagramMapOwner& dgms)
+    {
+        bp::list result;
+        size_t dim = 0;
+        typedef         typename DiagramMapOwner::value_type         ValType;
+        BOOST_FOREACH(const ValType& dim_dgm, dgms)
+        {
+            while (dim_dgm.first > dim)
+            {
+                result.append(dp::PDgmPtr(new dp::PersistenceDiagramD));
+                ++dim;
+            }
+
+            // dim_dgm.first == dim
+            result.append(dim_dgm.second);
+            dim++;
+        }
+
+        return result;
+    }
+
+    struct PointDataVisitor
+    {
+                PointDataVisitor(bp::object data_): data(data_)                                 {}
+        void    point(const typename Persistence::iterator& i, dp::PointD& p) const             { p.data() = data(*i); }
+        bp::object data;
+    };
+
+    static
+    bp::list    init(const Persistence& p, const dp::PythonFiltration& f, bp::object eval, bp::object data)
+    {
+
+        DiagramMapOwner dgms;
+        SMap            smap = p.make_simplex_map(f);
+        if (eval == bp::object())
+            init_diagrams(dgms, p.begin(), p.end(),
+                          DataEvaluator(smap),
+                          evaluate_through_map(smap, dp::SimplexVD::DimensionExtractor()));
+        else if (data == bp::object())
+            init_diagrams(dgms, p.begin(), p.end(),
+                          PythonEvaluator(smap, eval),
+                          evaluate_through_map(smap, dp::SimplexVD::DimensionExtractor()));
+        else
+            init_diagrams(dgms, p.begin(), p.end(),
+                          PythonEvaluator(smap, eval),
+                          evaluate_through_map(smap, dp::SimplexVD::DimensionExtractor()),
+                          PointDataVisitor(data));
+        return extract_list(dgms);
+    }
+};
+
+void export_persistence_diagram()
+{
+    bp::class_<dp::PersistenceDiagramD, dp::PDgmPtr>("PersistenceDiagram")
+        .def("__init__",            bp::make_constructor(&init_from_points_sequence))
+        .def(                       bp::init<Dimension>())
+        .def("append",              &dp::PersistenceDiagramD::push_back)
+        .add_property("dimension",  &dp::PersistenceDiagramD::dimension)
+        .def(                       repr(bp::self))
+        .def("__iter__",            bp::range(&dp::PersistenceDiagramD::begin, &dp::PersistenceDiagramD::end))
+        .def("__len__",             &dp::PersistenceDiagramD::size)
+    ;
+    bp::register_ptr_to_python<dp::PDgmPtr>();
+
+    bp::def("init_diagrams",        &InitDiagrams<dp::SPersistence>::init,
+                                     (bp::arg("persistence"),
+                                      bp::arg("filtration"),
+                                      bp::arg("eval")=bp::object(),
+                                      bp::arg("data")=bp::object()));
+    bp::def("init_diagrams",        &InitDiagrams<dp::DPersistenceChains>::init,
+                                     (bp::arg("persistence"),
+                                      bp::arg("filtration"),
+                                      bp::arg("eval")=bp::object(),
+                                      bp::arg("data")=bp::object()));
+
+    bp::def("bottleneck_distance",  &bottleneck_distance_adapter);
+    bp::def("wasserstein_distance", &wasserstein_distance<dp::PersistenceDiagramD>);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/rips.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,35 @@
+#include <topology/rips.h>
+#include <boost/python.hpp>
+namespace bp = boost::python;
+
+#include "rips.h"                   // defines RipsWithDistances
+namespace dp = dionysus::python;
+
+#include <iostream>
+
+
+/* Various wrappers for exposing Rips to Python */
+// Constructor from distances
+boost::shared_ptr<dp::RipsWithDistances>        init_from_distances(bp::object distances)
+{ 
+    boost::shared_ptr<dp::RipsWithDistances>    p(new dp::RipsWithDistances(distances));
+    return p;
+}
+
+void export_rips()
+{
+    bp::class_<dp::RipsWithDistances>("Rips", bp::no_init)
+        .def("__init__",            bp::make_constructor(&init_from_distances))
+        .def("generate",            &dp::RipsWithDistances::generate)
+        .def("generate",            &dp::RipsWithDistances::generate_candidates)
+        .def("vertex_cofaces",      &dp::RipsWithDistances::vertex_cofaces)
+        .def("vertex_cofaces",      &dp::RipsWithDistances::vertex_cofaces_candidate)
+        .def("edge_cofaces",        &dp::RipsWithDistances::edge_cofaces)
+        .def("edge_cofaces",        &dp::RipsWithDistances::edge_cofaces_candidates)
+
+        .def("cmp",                 &dp::RipsWithDistances::cmp)
+        .def("cmp",                 &dp::RipsWithDistances::cmp_native)
+        .def("eval",                &dp::RipsWithDistances::eval)
+        .def("eval",                &dp::RipsWithDistances::eval_native)
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/rips.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,112 @@
+#ifndef __PYTHON_RIPS_H__
+#define __PYTHON_RIPS_H__
+
+#include <topology/rips.h>
+#include <utilities/indirect.h>
+
+#include "simplex.h"
+
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+
+
+namespace bp = boost::python;
+
+
+namespace dionysus { 
+namespace python   {
+
+// This strange wrapper is necessary because Rips<...> stores only a const reference to the distances. 
+// Something on the C++ side of things must store the actual DistancesWrapper object, and that's the 
+// purpose of this class.
+class RipsWithDistances
+{
+    public:
+        class DistancesWrapper
+        {
+            public:
+                typedef             unsigned                                        IndexType;
+                typedef             double                                          DistanceType;
+        
+                                    DistancesWrapper(bp::object distances):
+                                        distances_(distances)                       {}
+        
+                DistanceType        operator()(IndexType a, IndexType b) const      { return bp::extract<DistanceType>(distances_(a, b)); }
+        
+                IndexType           size() const                                    { return bp::len(distances_); }
+                IndexType           begin() const                                   { return 0; }
+                IndexType           end() const                                     { return size(); }
+        
+            private:
+                bp::object          distances_;
+        };
+
+        typedef             DistancesWrapper::IndexType                             IndexType;
+        typedef             DistancesWrapper::DistanceType                          DistanceType;
+
+        typedef             Rips<DistancesWrapper, SimplexVD>                       RipsDS;
+        typedef             RipsDS::Comparison                                      Comparison;
+        typedef             RipsDS::Evaluator                                       Evaluator;
+
+        class FunctorWrapper
+        {
+            public:
+                                    FunctorWrapper(bp::object functor):
+                                        functor_(functor)                           {}
+        
+                void                operator()(const RipsDS::Simplex& s) const      { functor_(s); }
+        
+            private:
+                bp::object          functor_;
+        };
+
+
+                            RipsWithDistances(bp::object distances):
+                                distances_(distances), rips_(distances_),
+                                cmp_(Comparison(distances_)), eval_(distances_)     {}
+
+        void                generate(Dimension k, DistanceType max, bp::object functor) const
+        { rips_.generate(k, max, FunctorWrapper(functor)); }
+
+        void                vertex_cofaces(IndexType v, Dimension k, DistanceType max, bp::object functor) const
+        { rips_.vertex_cofaces(v, k, max, FunctorWrapper(functor)); }
+        
+        void                edge_cofaces(IndexType u, IndexType v, Dimension k, DistanceType max, bp::object functor) const
+        { rips_.edge_cofaces(u, v, k, max, FunctorWrapper(functor)); }
+
+        void                generate_candidates(Dimension k, DistanceType max, bp::object functor, bp::object seq) const
+        { 
+            rips_.generate(k, max, FunctorWrapper(functor), 
+                           bp::stl_input_iterator<IndexType>(seq), bp::stl_input_iterator<IndexType>());
+        }
+        
+        void                vertex_cofaces_candidate(IndexType v, Dimension k, DistanceType max, 
+                                                     bp::object functor, bp::object seq) const
+        { 
+            rips_.vertex_cofaces(v, k, max, FunctorWrapper(functor), 
+                                 bp::stl_input_iterator<IndexType>(seq), bp::stl_input_iterator<IndexType>());
+        }
+        
+        void                edge_cofaces_candidates(IndexType u, IndexType v, Dimension k, DistanceType max, 
+                                                    bp::object functor, bp::object seq) const
+        { 
+            rips_.edge_cofaces(u, v, k, max, FunctorWrapper(functor), 
+                               bp::stl_input_iterator<IndexType>(seq), bp::stl_input_iterator<IndexType>());
+        }
+
+        int                 cmp(const SimplexObject& s1, const SimplexObject& s2) const                     { return cmp_native(s1, s2); }
+        int                 cmp_native(const SimplexVD& s1, const SimplexVD& s2) const                      { return cmp_.compare(s1, s2); }
+        
+        DistanceType        eval(const SimplexObject& s) const                                              { return eval_native(s); }
+        DistanceType        eval_native(const SimplexVD& s) const                                           { return eval_(s); }
+        
+    private:
+        DistancesWrapper                            distances_;
+        RipsDS                                      rips_;
+        ThreeOutcomeCompare<Comparison>             cmp_;           // in Python, cmp is a three outcome comparison
+        Evaluator                                   eval_;
+};
+
+} } // namespace dionysus::python
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/simplex.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,98 @@
+#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>
+#include <boost/functional/hash.hpp>
+namespace bp = boost::python;
+
+#include "simplex.h"                // defines SimplexVD, Vertex, and Data
+namespace dp = dionysus::python;
+
+
+/* Various wrappers for exposing Simplex to Python */
+// `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        TODO: the default argument is not working yet
+template<class V, class T>
+boost::shared_ptr<Simplex<V,T> >    init_from_iterator(bp::object iter, bp::object d)
+{ 
+    boost::shared_ptr<Simplex<V,T> > p(new Simplex<V,T>(bp::stl_input_iterator<V>(iter), bp::stl_input_iterator<V>(), d));
+    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;
+}
+
+template<class S>
+bool                                contains(const S& s, const S& other)
+{ 
+    return s.contains(other);
+}
+
+template<class S>
+dp::Data                            get_data(const S& s)
+{
+    return s.data();
+}
+
+template<class S>
+void                                set_data(S& s, dp::Data d)
+{
+    s.data() = d;
+}
+
+/* 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);
+}
+
+
+void export_simplex()
+{
+    bp::class_<dp::SimplexVD>("Simplex")
+        .def("__init__",            bp::make_constructor(&init_from_iterator<dp::Vertex, dp::Data>))
+
+        .def("add",                 &dp::SimplexVD::add)
+        .add_property("boundary",   bp::range(&dp::SimplexVD::boundary_begin, &dp::SimplexVD::boundary_end))
+        .def("contains",            &contains<dp::SimplexVD>)
+        .def("join",                (void (dp::SimplexVD::*)(const dp::SimplexVD&)) &dp::SimplexVD::join)
+        .def("dimension",           &dp::SimplexVD::dimension)
+        .add_property("data",       &get_data<dp::SimplexVD>, &set_data<dp::SimplexVD>)
+        
+        .add_property("vertices",   bp::range(&vertices_begin<dp::Vertex, dp::Data>, &vertices_end<dp::Vertex, dp::Data>))
+        .def(repr(bp::self))
+
+        .def("__hash__",            &hash_simplex<dp::Vertex, dp::Data>)
+        .def("__eq__",              &eq_simplex<dp::Vertex, dp::Data>)
+        .enable_pickling()
+    ;
+
+    bp::class_<dp::SimplexObject>("SimplexObject")
+        .def("__getattribute__",    &dp::SimplexObject::getattribute)
+    ;
+
+    bp::def("vertex_cmp",           &vertex_comparison<dp::Vertex, dp::Data>);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/simplex.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,65 @@
+#ifndef __PYTHON_SIMPLEX_H__
+#define __PYTHON_SIMPLEX_H__
+
+#include <topology/simplex.h>
+
+#include <boost/python.hpp>
+#include <boost/python/stl_iterator.hpp>
+namespace bp = boost::python;
+
+
+namespace dionysus {
+namespace python   {
+
+/**
+ * SimplexVD is a base class for Python simplices (it's exposed to python as Simplex)
+ *
+ * SimplexObject is the representation of Python simplices in C++; i.e. it wraps bp::object and exposes a simplex-like interface.
+ */
+typedef                             int                                         Vertex;
+typedef                             bp::object                                  Data;
+typedef                             Simplex<Vertex, Data>                       SimplexVD;
+
+
+// Wrapper around bp::object that acts like a simplex
+class SimplexObject: public bp::object
+{
+    public:
+        typedef                 SimplexObject                                   Self;
+        typedef                 bp::object                                      Parent;
+        typedef                 bp::stl_input_iterator<Self>                    BoundaryIterator;
+
+
+                                SimplexObject(Parent o = Parent()): Parent(o)   {}
+
+        BoundaryIterator        boundary_begin() const                          { return bp::stl_input_iterator<Self>(this->attr("boundary")); }
+        BoundaryIterator        boundary_end() const                            { return bp::stl_input_iterator<Self>(); }
+
+                                operator SimplexVD() const                      { return bp::extract<const SimplexVD&>(*this); }
+                                operator bp::object() const                     { return *this; }
+
+        bp::object              getattribute(const char* name) const            { return this->attr(name); }
+
+        class                   VertexComparison: public SimplexVD::VertexComparison
+        {
+            public:
+                typedef         Self                                            first_argument_type;
+                typedef         Self                                            second_argument_type;
+                typedef         bool                                            result_type;
+
+                bool            operator()(const SimplexObject& s1, const SimplexObject& s2) const  
+                { return SimplexVD::VertexComparison::operator()(bp::extract<const SimplexVD&>(s1), bp::extract<const SimplexVD&>(s2)); }
+        };
+};
+
+struct SimplexObjectToSimplexVD
+{
+    static PyObject* convert (const SimplexObject& so)
+    {
+        return (PyObject*) &so;
+    }
+};
+
+} } // namespace dionysus::python
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/static-persistence.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,44 @@
+#include <topology/static-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 "static-persistence.h"
+#include "chain.h"
+namespace dp = dionysus::python;
+
+
+void            pair_simplices(dp::SPersistence& sp, bool store_negative)
+{
+    dp::SPersistence::PairVisitorNoProgress visitor;
+    sp.pair_simplices(sp.begin(), sp.end(), store_negative, visitor);
+}
+
+
+void export_static_persistence()
+{
+    bp::class_<dp::SPersistenceNode>("SPNode", bp::no_init)
+        .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(&dp::init_from_filtration<dp::SPersistence>))
+
+        .def("pair_simplices",  &pair_simplices, (bp::args("store_negative")=false))
+        .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::SPersistenceSimplexMap>("SPersistenceSimplexMap", bp::no_init)
+        .def("__getitem__",     &dp::psmap_getitem<dp::SPersistenceSimplexMap, dp::SPersistenceIndex>,  bp::return_internal_reference<1>())
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/static-persistence.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,44 @@
+#ifndef __PYTHON_STATIC_PERSISTENCE_H__
+#define __PYTHON_STATIC_PERSISTENCE_H__
+
+#include <topology/static-persistence.h>
+
+#include "filtration.h"
+
+namespace dionysus {
+namespace python   {
+
+typedef         StaticPersistence<>             SPersistence;
+typedef         SPersistence::OrderElement      SPersistenceNode;
+typedef         SPersistence::OrderIndex        SPersistenceIndex;
+typedef         SPersistence::SimplexMap<PythonFiltration>        
+                                                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
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/utils.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,62 @@
+#ifndef __PYTHON_UTILS_H__
+#define __PYTHON_UTILS_H__
+
+#include <boost/python.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+namespace bp = boost::python;
+
+namespace dionysus {
+namespace python   {
+
+// Random access iterator into python's list (using integer indices)
+template<class Value>
+class ListRandomAccessIterator:
+    public boost::iterator_adaptor<ListRandomAccessIterator<Value>,         // Derived
+                                   boost::counting_iterator<unsigned>,      // Base
+                                   Value,                                   // Value
+                                   boost::use_default,
+                                   Value>
+{
+    public:
+        typedef                 ListRandomAccessIterator                                        Self;
+        typedef                 boost::iterator_adaptor<ListRandomAccessIterator,           
+                                                        boost::counting_iterator<unsigned>,     
+                                                        Value,
+                                                        boost::use_default,
+                                                        Value>                                  Parent;
+                    
+                                ListRandomAccessIterator()                                      {}
+
+                                ListRandomAccessIterator(bp::list l, unsigned i):
+                                    Parent(i), l_(l)                                            {}
+
+    private:
+        friend class boost::iterator_core_access;
+        friend class FiltrationPythonIterator;
+
+        typename Parent::reference       
+                                dereference() const                                             { return bp::object(l_[*(this->base())]); }
+
+        bp::list                l_;
+};
+
+// Adaptor of a Pyhon object to act as a C++-style comparison functor
+struct PythonCmp
+{
+    template<class T>
+    bool            operator()(T x1, T x2) const            { return cmp_(x1, x2) < 0; }
+
+                    PythonCmp(bp::object cmp): cmp_(cmp)    {}
+
+    bp::object      cmp_;
+};
+
+template<class T1, class T2>
+struct PairToTupleConverter 
+{
+    static PyObject* convert(const std::pair<T1, T2>& pair) { return bp::incref(bp::make_tuple(pair.first, pair.second).ptr()); }
+};
+
+} } // namespace dionysus::python
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/zigzag-persistence.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,128 @@
+#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 "zigzag-persistence.h"             // defines ZZPersistence, IZZPersistence
+#include "optional.h"
+namespace dp = dionysus::python;
+
+#include <sstream>
+#include <string>
+
+
+// ZigzagPersistence
+bp::tuple                           zzp_add(dp::ZZPersistence& zzp, bp::object bdry, dp::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<dp::ZZPersistence::ZColumn>
+                                            boundary(new dp::ZZPersistence::ZColumn(bp::stl_input_iterator<dp::ZZPersistence::SimplexIndex>(bdry),
+                                                                                    bp::stl_input_iterator<dp::ZZPersistence::SimplexIndex>()));
+    boundary->sort(zzp.cmp);
+
+    dp::ZZPersistence::SimplexIndex         i;
+    dp::ZZPersistence::Death                d;
+    boost::tie(i,d)                                 = zzp.add(*boundary, birth);
+    return bp::make_tuple(i,d);
+}
+
+dp::ZZPersistence::Death            zzp_remove(dp::ZZPersistence& zzp, dp::ZZPersistence::SimplexIndex s, dp::ZZPersistence::BirthID birth)
+{
+    return zzp.remove(s, birth);
+}
+
+bool                                zzp_is_alive(dp::ZZPersistence& zzp, const dp::ZZPersistence::ZNode& zn)
+{
+    return zzp.is_alive(zn);
+}
+
+// ImageZigzagPersistence
+bp::tuple                           izzp_add(dp::IZZPersistence& izzp, bp::object bdry, bool subcomplex, dp::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<dp::IZZPersistence::ZColumn>
+                                            boundary(new dp::IZZPersistence::ZColumn(bp::stl_input_iterator<dp::IZZPersistence::SimplexIndex>(bdry),
+                                                                                     bp::stl_input_iterator<dp::IZZPersistence::SimplexIndex>()));
+    boundary->sort(izzp.cmp);
+
+    dp::IZZPersistence::SimplexIndex            i;
+    dp::IZZPersistence::Death                   d;
+    boost::tie(i,d)                                 = izzp.add(*boundary, subcomplex, birth);
+    return bp::make_tuple(i,d);
+}
+
+dp::IZZPersistence::Death           izzp_remove(dp::IZZPersistence& izzp, dp::IZZPersistence::SimplexIndex s, dp::IZZPersistence::BirthID birth)
+{
+    return izzp.remove(s, birth);
+}
+
+
+// SimplexIndex
+template<class T>
+unsigned                            si_order(T& si)
+{
+    return si->order;
+}
+
+template<class T>
+std::string                         si_repr(T& si)
+{
+    std::ostringstream out; out << "SimplexIndex <" << si->order << ">";
+    return out.str();
+}
+
+// ZNode
+template<class Persistence>
+typename Persistence::ZColumn::const_iterator
+znode_zcolumn_begin(typename Persistence::ZNode& zn)
+{ return zn.z_column.begin(); }
+
+template<class Persistence>
+typename Persistence::ZColumn::const_iterator
+znode_zcolumn_end(typename Persistence::ZNode& zn)
+{ return zn.z_column.end(); }
+
+
+
+void export_zigzag_persistence()
+{
+    bp::class_<dp::ZZPersistence::SimplexIndex>("ZZSimplexIndex")
+        .def("order",           &si_order<dp::ZZPersistence::SimplexIndex>)
+        .def("__repr__",        &si_repr<dp::ZZPersistence::SimplexIndex>)
+    ;
+
+    bp::class_<dp::IZZPersistence::SimplexIndex>("IZZSimplexIndex")
+        .def("order",           &si_order<dp::IZZPersistence::SimplexIndex>)
+        .def("__repr__",        &si_repr<dp::IZZPersistence::SimplexIndex>)
+    ;
+
+    bp::class_<dp::ZZPersistence>("ZigzagPersistence")
+        .def("add",             &zzp_add)
+        .def("remove",          &zzp_remove)
+        .def("is_alive",        &zzp_is_alive)
+        .def("__iter__",        bp::range(&dp::ZZPersistence::begin, &dp::ZZPersistence::end))
+    ;
+
+    bp::class_<dp::IZZPersistence>("ImageZigzagPersistence")
+        .def("add",             &izzp_add)
+        .def("remove",          &izzp_remove)
+        .def("__iter__",        bp::range(&dp::IZZPersistence::image_begin, &dp::IZZPersistence::image_end))
+    ;
+
+    bp::class_<dp::ZZPersistence::ZNode>("ZNode", bp::no_init)
+        .add_property("birth",  &dp::ZZPersistence::ZNode::birth)
+        .def("__iter__",        bp::range(&znode_zcolumn_begin<dp::ZZPersistence>, &znode_zcolumn_end<dp::ZZPersistence>))
+    ;
+
+    bp::class_<dp::IZZPersistence::ZNode>("IZNode", bp::no_init)
+        .add_property("birth",  &dp::IZZPersistence::ZNode::birth)
+        .def("__iter__",        bp::range(&znode_zcolumn_begin<dp::IZZPersistence>, &znode_zcolumn_end<dp::IZZPersistence>))
+    ;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/python/zigzag-persistence.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,18 @@
+#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>
+
+#include "birthid.h"
+
+namespace dionysus {
+namespace python   {
+
+typedef         ZigzagPersistence<BirthID>      ZZPersistence;
+typedef         ImageZigzagPersistence<BirthID> IZZPersistence;
+
+} } // namespace dionysus::python
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/Makefile	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,75 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d .build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html      to make standalone HTML files"
+	@echo "  pickle    to make pickle files"
+	@echo "  json      to make JSON files"
+	@echo "  htmlhelp  to make HTML files and a HTML help project"
+	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  changes   to make an overview over all changed/added/deprecated items"
+	@echo "  linkcheck to check all external links for integrity"
+
+clean:
+	-rm -rf .build/*
+
+html:
+	mkdir -p .build/html .build/doctrees
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) .build/html
+	@echo
+	@echo "Build finished. The HTML pages are in .build/html."
+
+pickle:
+	mkdir -p .build/pickle .build/doctrees
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) .build/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+web: pickle
+
+json:
+	mkdir -p .build/json .build/doctrees
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) .build/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	mkdir -p .build/htmlhelp .build/doctrees
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) .build/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in .build/htmlhelp."
+
+latex:
+	mkdir -p .build/latex .build/doctrees
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) .build/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in .build/latex."
+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+	      "run these through (pdf)latex."
+
+changes:
+	mkdir -p .build/changes .build/doctrees
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) .build/changes
+	@echo
+	@echo "The overview file is in .build/changes."
+
+linkcheck:
+	mkdir -p .build/linkcheck .build/doctrees
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) .build/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in .build/linkcheck/output.txt."
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/bibliography.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,34 @@
+Bibliography
+============
+
+.. |edels|      replace:: Herbert Edelsbrunner
+.. .. _edels:      http://www.cs.duke.edu/~edels/
+.. |david|      replace:: David Cohen-Steiner
+.. .. _david:      http://www-sop.inria.fr/geometrica/team/David.Cohen-Steiner/
+.. |morozov|    replace:: Dmitriy Morozov
+.. .. _morozov:    http://www.mrzv.org/
+.. |afra|       replace:: Afra Zomorodian
+.. .. _afra:       http://www.cs.dartmouth.edu/~afra/
+.. |letscher|   replace:: David Letscher
+.. |gunnar|     replace:: Gunnar Carlsson
+.. .. _gunnar:     http://math.stanford.edu/~gunnar/
+.. |vin|        replace:: Vin de Silva
+.. .. _vin:        http://pages.pomona.edu/~vds04747/
+.. |mikael|     replace:: Mikael Vejdemo Johansson 
+
+.. [CdSM09] |gunnar|, |vin|, and |morozov|.
+            `Zigzag Persistent Homology and Real-valued Functions
+            <http://www.mrzv.org/publications/zigzags/>`__.
+
+.. [CEM06] |david|, |edels|, and |morozov|. 
+           `Vines and Vineyards by Updating Persistence in Linear Time 
+           <http://www.mrzv.org/publications/vineyards/>`__.
+
+.. [dSVJ09] |vin|, |mikael|.
+            Persistent Cohomology and Circular Coordinates.
+
+.. [ELZ02] |edels|, |letscher|, and |afra|. 
+           Topological Persistence and Simplification.
+
+.. [ZC05]  |afra| and |gunnar|.
+           Computing Persistent Homology.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/conf.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,205 @@
+# -*- coding: utf-8 -*-
+#
+# Dionysus documentation build configuration file, created by
+# sphinx-quickstart on Tue Dec  9 10:21:40 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+sys.path.append('.')
+
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 
+              #'sphinx.ext.jsmath',  'ext.sprite_jsmath', 
+              'sphinx.ext.pngmath',
+              'ext.sfile']
+todo_include_todos = True
+
+jsmath_path = 'jsMath/easy/load.js'
+
+# Base URI for sfile extension
+sfile_base_uri = 'http://hg.mrzv.org/Dionysus/file/tip/'
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['.templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Dionysus'
+copyright = u'2005--2009, Dmitriy Morozov'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '3'
+# The full version, including alpha/beta/rc tags.
+release = '3'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['.build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The theme to use for HTML and HTML Help pages.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = 'Dionysus'
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Dionysusdoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+  ('index', 'Dionysus.tex', ur'Dionysus Documentation',
+   ur'Dmitriy Morozov', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/alphashape.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,36 @@
+.. _alpha-shape-example:
+
+Alpha shape example
+===================
+
+The example given in :sfile:`examples/alphashapes/alphashapes.py` takes a
+filename containing points in 2D or 3D on the command line. It generates the
+alpha shape filtration of those points, and computes its persistence. It then
+outputs the persistence diagram in the format of a point (dimension, birth,
+death) per line.
+
+.. literalinclude:: ../../examples/alphashapes/alphashapes.py
+   :language: python
+
+After the points are read into the list ``points``, the functions
+:ref:`fill_alpha*_complex <alphashapes>` fill the :class:`Filtration` with the
+simplices of the Delaunay triangulation. Each one has its :attr:`~Simplex.data`
+attribute set to the tuple consisting of its alpha shape value (the minimum value of the squared
+distance function on its dual Voronoi cell) and whether the simplex is regular
+or critical.
+
+The filtration then sorts the simplices with
+respect to their data and dimension (via :func:`data_dim_cmp`)::
+
+    f = Filtration()
+    fill_alpha*_complex(points, f)
+    f.sort(data_dim_cmp)
+
+We initialize :class:`StaticPersistence`, and pair the simplices::
+
+    p = StaticPersistence(f)
+    p.pair_simplices()
+    
+Iterating over the :class:`StaticPersistence`, we output the points of the
+persistence diagram (dimension, birth, death) in the last for loop. If the
+simplex is unpaired (``i.unpaired()``), the class it creates survives till infinity.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/cohomology.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,129 @@
+.. _cohomology-parametrization:
+
+Parametrizing a point set using circle valued functions
+=======================================================
+
+The procedure described below is explained in detail in [dSVJ09]_.
+
+.. program:: rips-pairwise-cohomology
+
+One can use :sfile:`examples/cohomology/rips-pairwise-cohomology.cpp` to compute
+persistent pairing of the Rips filtration using the persistent cohomology
+algorithm. It takes as input a file containing a point set in Euclidean space
+(one per line) as well as the following command-line flags:
+
+.. cmdoption:: -p, --prime
+
+    The prime to use in the computation (defaults to 11).
+
+.. cmdoption:: -m, --max-distance
+
+    Maximum cutoff parameter up to which to compute the complex.
+
+.. cmdoption:: -s, --skeleton-dimension
+
+    Skeleton to compute; persistent pairs output will be this number minus 1
+    (defaults to 2).
+
+.. cmdoption:: -b, --boundary
+
+    Filename where to output the boundary matrix.
+
+.. cmdoption:: -c, --cocycle
+
+    Prefix of the filenames where to output the 1-dimensional cocycles.
+
+.. cmdoption:: -v, --vertices
+
+    Filename where to output the simplex vertex mapping.
+
+.. cmdoption:: -d, --diagram
+
+    Filename where to output the persistence diagram.
+
+
+For example::
+
+    rips-pairwise-cohomology points.txt -m 1 -b points.bdry -c points -v points.vrt -d points.dgm
+
+Assuming that at the threshold value of 1 (``-m 1`` above) Rips complex contains
+1-dimensional cocycles, they will be output into filenames of the form
+``points-0.ccl``, ``points-1.ccl``, etc.
+
+Subsequently one can use :sfile:`examples/cohomology/cocycle.py` to assign to
+each vertex of the input point set a circle-valued function. It takes the
+boundary matrix, cocycle, and simplex-vertex map as an input (all produced at
+the previous step)::
+
+    cocycle.py points.bdry points-0.ccl points.vrt
+
+The above command outputs a file ``points-0.val`` which contains values assigned
+to the input points (the lines match the lines of the input file
+``points.txt``, but also contains the indices).
+
+
+Plotting
+--------
+
+Two auxilliary tools allow one to visualize the values assigned to the points
+(using Matplotlib_): :sfile:`tools/plot-values/plot.py` and
+:sfile:`tools/plot-values/scatter.py`::
+    
+    plot.py points-0.val points.txt scatter.py points-0.val points-1.val
+
+.. _Matplotlib:                             http://matplotlib.sourceforge.net/    
+
+
+Dependency
+----------
+
+The Python `LSQR code`_ (ported from the `Stanford MATLAB implementation`_ to
+Python by `Jeffery Kline`_) included with Dionysus, and used in
+:sfile:`examples/cohomology/cocycle.py`, requires CVXOPT_.
+
+.. _`LSQR code`:                            http://pages.cs.wisc.edu/~kline/cvxopt/
+.. _CVXOPT:                                 http://abel.ee.ucla.edu/cvxopt/
+.. _`Stanford MATLAB implementation`:       http://www.stanford.edu/group/SOL/software/lsqr.html
+.. _`Jeffery Kline`:                        http://pages.cs.wisc.edu/~kline/
+
+
+.. _rips-pairwise-cohomology:
+
+Python cohomology computation
+-----------------------------
+
+:sfile:`examples/cohomology/rips-pairwise-cohomology.py` gives an example of the
+same computation performed in Python (but with the output in a different format).
+
+After the simplicial complex is computed in a list `simplices`, and the list is
+sorted with respect to the Rips filtration order, the simplices are inserted
+into the :class:`CohomologyPersistence` one by one::
+
+    # list simplices is created
+
+    ch = CohomologyPersistence(prime)
+    complex = {}
+
+    for s in simplices:
+        i,d = ch.add([complex[sb] for sb in s.boundary], (s.dimension(), s.data))
+        complex[s] = i
+        if d: 
+            dimension, birth = d
+            print dimension, birth, s.data
+        # else birth
+
+Above dictionary `complex` maintains the map of simplices to indices returned by
+:meth:`CohomologyPersistence.add`.  The pair `(dimension, data)` is used as the
+birth value. Here `data` is the value associated with the simplex in the Rips
+filtration. The pair is returned back if a death occurs, and is printed on the
+standard output. After the for loop finishes, one may output infinite
+persistence classes with the following for loop::
+
+    for ccl in ch:
+        dimension, birth = ccl.birth
+        if dimension >= skeleton: continue
+        print dimension, birth, 'inf'         # dimension, simplex data = birth
+    
+Naturally one may iterate over `ccl` which is of type :class:`Cocycle` and
+extract more information. For example, this is necessary to get the coefficients
+that serve as the input for :sfile:`examples/cohomology/cocycle.py`.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/index.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,55 @@
+.. _examples:
+
+Examples
+========
+
+The most basic example and therefore a good place to start getting acquainted
+with the library is the :ref:`triangle-example`. It adds simplices of a triangle
+one by one, and then (in case of a :ref:`triangle-zigzag-example`), removes them
+one by one.
+
+.. toctree::
+    
+    triangle
+    triangle-zigzag
+    
+The simplest example that instead of specifying the complex explicitly,
+constructs it from the input point set is the :ref:`alpha-shape-example`. The
+example reads points from a file, determines their dimension dynamically (based
+on the number of coordinates in the first line of the file), and then constructs
+an alpha shape and outputs its persistence diagram.
+
+.. toctree::
+
+    alphashape
+
+Another example that follows a similar strategy is the computation of the
+Vietoris-Rips complex. Since only pairwise distances are required it works with
+points in arbitrary dimension. (Of course, in dimensions 2 and 3 the complexes
+are much larger than those for the :ref:`alpha-shape-example`).
+
+.. toctree::
+    :maxdepth: 1
+
+    rips
+
+One may use persistent cohomology algorithm to extract persistent cocycles,
+turn them into harmonic cocycles, and use them to parametrize the input point
+set; for details see [dSVJ09]_. The explanation of how to use Dionysus to
+achieve this is available.
+
+.. toctree::
+    :maxdepth: 1
+
+    cohomology
+
+A simple example of computing persistence of a lower-star filtration is in
+:sfile:`examples/pl-functions/lsfiltration.py`.
+
+A C++-only, but useful example is computation of a vineyard of piecewise
+straight-line homotopy of piecewise-linear functions.
+
+.. toctree::
+    :maxdepth: 1
+
+    pl-vineyard
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/pl-vineyard.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,72 @@
+.. _pl-vineyard:
+
+Piecewise-Linear Vineyard
+=========================
+
+Given a simplicial complex :math:`K`, and a sequence of values on each one of
+its vertices, one may construct a homotopy of PL functions on the complex that
+interpolates linearly between the values. For any given time in the homotopy, we
+get a function from the simplicial complex to the real line, and we can compute
+its persistence diagram. Stacking all such diagrams together we get a
+persistence vineyard [CEM06]_. An example that computes such a vineyard is in 
+:sfile:`examples/pl-functions/pl-vineyard.cpp`. 
+
+.. program:: pl-vineyard
+
+Once compiled, it takes three files as the input::
+    
+    pl-vineyard complex values output-prefix
+
+``complex`` lists the simplices of the simplicial complex :math:`K`, one
+per-line::
+
+    0
+    1
+    0 1
+    2
+    0 2
+    ...
+
+``values`` lists the vertex values of the consequtive "frames" of the homotopy.
+Each line is a sequence of as many numbers as there are vertices in the complex.
+It describes a single frame. :program:`pl-vineayrd` constructs the homotopy over
+the interval :math:`[0,k-1]`, where :math:`k` is the number of frames. As an
+example of ``values`` input::
+
+    3.3   6    2
+    1.2   3    10
+    7.5   2.1  0
+
+This input means: :math:`f_0(0) = 3.3, f_1(0) = 1.2, f_2(0) = 7.5`. Similarly, 
+:math:`f_0(1) = 6, f_1(1) = 3, f_2(1) = 2.1`; 
+:math:`f_0(2) = 2, f_1(2) = 10, f_2(2) = 0`.
+
+The vineyard is saved to the files prefixed with ``output-prefix``, followed by
+the dimension and extension, e.g. ``myfunction1.vin`` or ``myfunction1.edg``,
+depending on the format. The two formats are vines and edges. The former saves
+one vine per line, listed as a stream of triplets BIRTH DEATH TIME::
+
+    4 5 0 3.4 5.6 0.4 3 6 1 ...
+
+The edge format represents the vine as a sequence of edges, each given as a
+start and end point. So the above vine would appear as::
+
+    4 5 0
+    3.4 5.6 0.4
+    3.4 5.6 0.4
+    3 6 1
+    ...
+
+:program:`pl-vineyard` takes additional options:
+
+.. cmdoption:: -s, --skip-infinite
+
+    Do not output infinite vines.
+
+.. cmdoption:: -v, --save-vines
+
+    Output vines, instead of the default edge format.
+
+.. cmdoption:: -e, --explicit-events
+
+    Go through the events one by one (useful for the debugging).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/rips.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,71 @@
+.. _rips-example:
+
+Rips complex example
+====================
+
+.. todo::
+   Explain `Vietoris-Rips complex`_.
+
+There is an elementary example in :sfile:`examples/rips/rips.py` that computes a
+Rips complex of a few points with integer coordinates on a line. It illustrates
+the use of Rips complexes and in particular of defining your own notion of a
+:ref:`Distance <Distances>` based on which the Rips complex is constructed.
+
+A more useful example is given in :sfile:`examples/rips/rips-pairwise.py` (and
+its C++ counterpart in :sfile:`examples/rips/rips-pairwise.cpp`). The example
+takes on the command line the filename of a file with points in Euclidean space
+(one point per line), and a cut off parameters for the skeleton and the
+:math:`\epsilon` parameter for the Rips complex construction. It then constructs
+the Rips complex up to these cutoff parameters, computes its persistence, and
+outputs the persistence diagram (one point per line).
+
+.. literalinclude:: ../../examples/rips/rips-pairwise.py
+
+The bit that sets up the Rips complex is::
+
+    distances = PairwiseDistances(points)
+    rips = Rips(distances)
+    simplices = Filtration()
+    rips.generate(skeleton, max, simplices.append)
+
+The computation of persistence and output of the persistence diagram are the
+same as in the :ref:`alpha-shape-example`. The example also incorporates 
+the :ref:`speed-up-suggestions` given in the :ref:`tutorial`.
+
+
+
+C++ sketch
+----------
+.. highlight:: cpp
+
+.. warning:: This section is not finished.
+
+The example given in :sfile:`examples/rips/rips.cpp` illustrates how one can use
+the library to compute persistence of a `Vietoris-Rips complex`_ for a given set of
+distances. At the top of the file a `struct Distances` is defined. The
+particular distances in the example are trivial (they are points with integer
+coordinates on a real line), however, the `struct` illustrates the basic
+requirements of any such class to be passed to the `Rips<Distances>` class.
+
+.. _`Vietoris-Rips complex`:        http://en.wikipedia.org/wiki/Vietoris-Rips_complex
+
+The Rips complex itself is generated in the line::
+
+    rips.generate(2, 50, make_push_back_functor(complex));
+
+which tells it to generate a 2-skeleton of the Rips complex up to 
+distance value of 50, and insert the simplices into the previously defined
+vector `complex`. 
+
+Subsequent sort is unnecessary since Bron-Kerbosch algorithm that generates the
+complex will actually generate the simplices in lexicographic order; it's there
+for illustration purposes only (the simplices must be sorted
+lexicographically). 
+
+The following "paragraph" sets up the filtration with respect to simplex sizes
+(specified by `Generator::Comparison(distances)`), and computes its persistence::
+
+    // Generate filtration with respect to distance and compute its persistence
+    Fltr f(complex.begin(), complex.end(), Generator::Comparison(distances));
+    Persistence p(f);
+    p.pair_simplices();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/triangle-zigzag.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,38 @@
+.. _triangle-zigzag-example:
+
+Triangle zigzag example
+=======================
+
+Simple example of a filtered triangle where simplices are first inserted in a
+given order, and then removed in the reverse order is in
+:sfile:`examples/triangle/triangle-zigzag.cpp`. Its Python equivalent
+(:sfile:`examples/triangle/triangle-zigzag.py`) is described next.
+
+.. literalinclude:: ../../examples/triangle/triangle-zigzag.py
+   :language: python
+
+Unlike the :ref:`triangle-example`, here we use :class:`ZigzagPersistence` to
+compute the pairings, and therefore need to store the internal representations
+of the simplicies used by the class. These representation are stored in the
+dictionary ``complex``, which maps the simplices to their representations for
+:class:`ZigzagPersistence`.
+
+The first for loop processes the simplices sorted with respect to
+:func:`data_cmp`. :meth:`ZigzagPersistence.add` invoked within the loop accepts
+the boundary of the newly added cell in its internal representation, which is
+computed by looking up each simplex in the dictionary ``complex``:
+``[complex[ss] for ss in s.boundary]``. If there is a birth, the value to be
+associated with the newly created class is ``b`` (which in this case is simply a
+counter).  :meth:`~ZigzagPersistence.add` returns a pair ``(i,d)``. The former
+is an internal representation of the newly added cell, which we immediately
+record with ``complex[s] = i``. The latter is an indicator of whether a death
+has occurred, which happens iff ``d is not None``, in which case ``d`` is the
+birth value passed to :meth:`~ZigzagPersistence.add` whenever the class that
+just died was born. If the death occurred, then we outut the interval ``(d,
+b-1)``.
+
+The second for loop removes simplices in the reverse order of their insertion.
+:meth:`~ZigzagPersistence.remove` takes the index of the cells to be removed
+(looked up in the ``complex`` dictionary: ``complex[s]``), and takes a birth
+value in case a class is born. It return only a death indicator (which again is
+``None`` if no death occurred).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/examples/triangle.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,37 @@
+.. _triangle-example:
+
+Triangle example
+================
+
+Simple example of a filtered triangle is given in
+:sfile:`examples/triangle/triangle.cpp`. Its equivalent in Python appears in
+:sfile:`examples/triangle/triangle.py`, and we describe it next.
+
+.. literalinclude:: ../../examples/triangle/triangle.py
+   :language: python
+
+After the necessary imports, the ``complex`` is setup explicitly as a list of
+simplices. Each :class:`Simplex` constructor takes an iterable sequence of
+vertices, and optionally a data value.
+
+A filtration ``f`` is initialized using the :class:`Filtration` class, which
+takes a list of simplices (or anything iterable) and a comparison that defines
+in what order the simplices should come in the filtration. In this case we use
+:func:`data_cmp`, which simply compares simplices' :attr:`~Simplex.data`
+attributes.
+
+:class:`StaticPersistence` is initialized with the filtration, and its method
+:meth:`~StaticPersistence.pair_simplices` pairs the simplices of the
+filtration::
+
+    p = StaticPersistence(f)
+    p.pair_simplices()
+
+Subsequently, we iterate over ``p`` to access a representation of each simplex
+in the filtration order. We output each simplex, its sign, and its pair. The auxilliary 
+``smap = p.make_simplex_map(f)`` remaps the indices of :class:`StaticPersistence` into 
+the simplices in the filtration.
+Naturally, one could use this to access the
+:attr:`~Simplex.data` attribute of the simplices to output the actual
+persistence diagram, as is done in the :ref:`alpha-shape-example` and the
+:ref:`rips-example`.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/ext/cppdocs.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,202 @@
+from docutils               import nodes, utils
+from docutils.parsers.rst   import directives
+from sphinx                 import addnodes
+from sphinx.util.compat     import Directive
+
+from sphinx.directives.desc import CDesc
+
+############
+# CppClass #
+############
+class CppClass(nodes.Part, nodes.Element):
+    @staticmethod
+    def html_visit(visitor, node):
+        visitor.body.append('<dl class="class">')
+        visitor.body.append(visitor.starttag(node, 'dt'))
+        if node['tparams']:
+            visitor.body.append('<em class="property">template</em> &lt;')
+            tparam_names = ['class ' + tp[0] for tp in node['tparams']]
+            visitor.body.append(', '.join(tparam_names))
+            visitor.body.append('&gt;<br/>')
+            
+        visitor.body.append('<em class="property">class</em> ')
+        visitor.body.append('<tt class="descname">' + node['name'] + '</tt>')
+        visitor.body.append(u'<a class="headerlink" href="#%s" title="%s">\u00B6</a>' % 
+                              ('cppclass-'+node['name'], _('Permalink to this class')))
+        visitor.body.append('</dt>')
+        visitor.body.append('<dd>')
+
+        if node['derives']:
+            visitor.body.append('<p>Derives from ')
+            for d in node['derives'].split(','):
+                dnode ={ 'type': 'cppclass', 'target': d.strip() } 
+                Ref.html_visit(visitor, dnode)
+                visitor.body.append(d)
+                Ref.html_depart(visitor, dnode)
+            visitor.body.append('.</p>')
+
+        visitor.body.append('<p>')
+        for name, desc in node['tparams']:
+            visitor.body.append(name + ' &mdash; ' + desc + '<br/>')
+        visitor.body.append('</p>')
+
+
+    @staticmethod
+    def html_depart(visitor, node):
+        visitor.body.append('</dd></dl>')
+
+
+class CppClassDirective(Directive):
+    has_content = True
+    required_arguments = 1
+    final_argument_whitespace = True
+    option_spec = { 'derives': directives.unchanged,
+                    'tparam':  directives.unchanged }
+
+    def run(self):
+        env = self.state.document.settings.env
+
+        cppclass = CppClass()
+        cppclass['name'] = self.arguments[0]
+        cppclass['derives'] = self.options.get('derives')
+
+        targetname = '%s-%s' % ('cppclass', cppclass['name'])
+        targetnode = nodes.target('', '', ids=[targetname])
+        self.state.document.note_explicit_target(targetnode)
+
+        indextext = _('%s (C++ class)') % cppclass['name']
+        inode = addnodes.index(entries = [('single', indextext, 
+                                           'cppclass-' + cppclass['name'], 
+                                           cppclass['name'])])
+
+        self.state.nested_parse(self.content, self.content_offset, cppclass)
+
+        return [inode, targetnode, cppclass]
+
+class TParam(nodes.Element):
+    pass
+
+class TParamDirective(Directive):
+    required_arguments = 1
+    optional_arguments = 1
+    final_argument_whitespace = True
+
+    def run(self):
+        tparam = TParam()
+
+        tparam['name'] = self.arguments[0]
+        if len(self.arguments) > 1:
+            tparam['description'] = self.arguments[1]
+
+        return [tparam]
+
+
+#############
+# CppMethod #
+#############
+class CppMethod(nodes.Part, nodes.Element):
+    @staticmethod
+    def html_visit(visitor, node):
+        visitor.body.append(visitor.starttag(node, 'dt'))
+        visitor.body.append(node['name'])
+        visitor.body.append(u'<a class="headerlink" href="#%s" title="%s">\u00B6</a>' % 
+                             ('cppmethod-' + node['classname'] + '::' + node['name'], _('Permalink to this class')))
+        visitor.body.append('</dt>')
+        visitor.body.append('<dd>')
+
+    @staticmethod
+    def html_depart(visitor, node):
+        visitor.body.append('</dd></dl>')
+
+
+class CppMethodDirective(Directive):
+    has_content = True
+    required_arguments = 1
+    final_argument_whitespace = True
+
+    def run(self):
+        env = self.state.document.settings.env
+
+        cppmethod = CppMethod()
+        cppmethod['name'] = self.arguments[0]            # TODO: parse name
+
+        targetname = '%s-%s' % ('cppmethod', cppmethod['name'])
+        targetnode = nodes.target('', '', ids=[targetname])
+        self.state.document.note_explicit_target(targetnode)
+
+        indextext = _('%s (C++ method)') % cppmethod['name']
+        inode = addnodes.index(entries = [('single', indextext, 
+                                           'cppmethod-' + cppmethod['name'], 
+                                           cppmethod['name'])])
+
+        self.state.nested_parse(self.content, self.content_offset, cppmethod)
+
+        return [inode, targetnode, cppmethod]
+
+
+class Ref(nodes.Inline, nodes.TextElement):
+    @staticmethod
+    def html_visit(visitor, node):
+        if node['type'] == 'cppclass':
+            visitor.body.append('<a href="#%s-%s">' % (node['type'], node['target']))
+        elif node['type'] == 'cppmethod':
+            # TODO: check if the name is not fully qualified, and has a parent CppClass node, 
+            #       in that case, prepend the name, otherwise
+            visitor.body.append('<a href="#%s-%s::%s">' % (node['type'], node['classname'], node['target']))
+
+
+    @staticmethod
+    def html_depart(visitor, node):
+        visitor.body.append('</a>')
+
+def cppclass_role(role, rawtext ,text, lineno, inliner, options={}, content=[]):
+    text = utils.unescape(text)
+    node = Ref(text, text, target=text, type='cppclass')
+    node['docname'] = inliner.document.settings.env.docname
+    return [node], []
+
+def cppmethod_role(role, rawtext ,text, lineno, inliner, options={}, content=[]):
+    text = utils.unescape(text)
+    node = Ref(text, text, target=text, type='cppmethod')
+    node['docname'] = inliner.document.settings.env.docname
+    return [node], []
+
+
+def process_classnames(app, doctree, fromdocname):
+    for node in doctree.traverse(CppClass):
+        for method in node.traverse(CppMethod):
+            method['classname'] = node['name']
+        for ref in node.traverse(Ref):
+            if ref['type'] == 'cppmethod':
+                ref['classname'] = node['name']
+
+def process_tparams(app, doctree, fromdocname):
+    for node in doctree.traverse(CppClass):
+        node['tparams'] = []
+        for tparam in node.traverse(TParam):
+            node['tparams'].append((tparam['name'], tparam['description']))
+
+
+def process_cfunction_scope(app, doctree, fromdocname):
+    for node in doctree.traverse():
+        if 'ctype' in node: print node
+        if 'cfunction' in node: print node
+        
+def setup(app):
+    app.add_node(Ref,               html=(Ref.html_visit, Ref.html_depart))
+
+    app.add_directive('cppclass',   CppClassDirective)
+    app.add_node(CppClass,          html=(CppClass.html_visit, CppClass.html_depart))
+    app.add_role('cppclass',        cppclass_role)
+    
+    app.add_directive('tparam',     TParamDirective)
+    app.add_node(TParam,            html=(lambda v,n: '', lambda v,n: ''))
+    
+    app.add_directive('cppmethod',  CppMethodDirective)
+    app.add_node(CppMethod,         html=(CppMethod.html_visit, CppMethod.html_depart))
+    app.add_role('cppmethod',       cppmethod_role)
+
+    app.connect('doctree-resolved', process_classnames)
+    app.connect('doctree-resolved', process_tparams)
+    
+    app.connect('doctree-resolved', process_cfunction_scope)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/ext/sfile.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,14 @@
+from docutils import nodes, utils
+import posixpath
+
+def sfile_role(typ, rawtext, etext, lineno, inliner, options={}, content=[]):
+    env = inliner.document.settings.env
+    baseuri = env.config.sfile_base_uri
+    text = utils.unescape(etext)
+    refnode = nodes.reference('', '', refuri=posixpath.join(baseuri, text))
+    refnode += nodes.literal(text, text)
+    return [refnode], []
+
+def setup(app):
+    app.add_role('sfile', sfile_role)
+    app.add_config_value('sfile_base_uri', 'http://example.com/source', True) 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/ext/sprite_jsmath.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,2 @@
+def setup(app):
+    app.add_javascript('jsMath/plugins/spriteImageFonts.js')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/get-build-install.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,135 @@
+.. _download:
+
+Get, Build, Install
+===================
+
+The most up to date code is available from
+`my Mercurial repository`_.
+If you have Mercurial_, the easiest way to obtain the code is by cloning it:
+
+.. parsed-literal::
+
+  hg clone |dionysus-url|
+  cd Dionysus
+  hg up tip
+
+If you don't have time or desire to deal with Mercurial, you can download the
+`tarball of the entire repository`_. The advantage of using Mercurial is that it
+makes it very easy to keep up with the updates that are periodically committed
+to the repository::
+
+  hg pull -u
+
+
+.. |dionysus-url|   replace:: http://hg.mrzv.org/Dionysus/
+
+.. _Mercurial:      http://www.selenic.com/mercurial/
+
+.. _`tarball of the entire repository`:     http://hg.mrzv.org/Dionysus/archive/tip.tar.gz
+.. _`my Mercurial repository`:              http://hg.mrzv.org/Dionysus/
+
+
+Dependencies
+------------
+Dionysus requires the following software:
+
+  :CMake_:              for building (version :math:`\geq` 2.6)
+  :Boost_:              C++ utilities (version :math:`\geq` 1.36; including Boost.Python used to create
+                        Python bindings)
+
+Optional dependencies:
+
+  :CGAL_:               for alpha shapes   (version :math:`\geq` 3.4)
+  :CVXOPT_:             for :ref:`circle-valued parametrization <cohomology-parametrization>` using LSQR
+  :PyQt4_:              for :mod:`viewer` module
+  :PyOpenGL_, NumPy_:   for 3D visualization in :mod:`viewer` module
+  :PyX_:                :sfile:`tools/draw-diagram/draw.py` uses `PyX`_ to
+                        produce a PDF of the diagram
+  :rlog_:               used for logging only (not needed by default)
+
+..  :dsrpdb_:             for reading PDB files
+    :SYNAPS_:             for solving polynomials (for kinetic kernel), which in
+                        turn requires GMP_
+
+.. _CMake:          http://www.cmake.org
+.. _Boost:          http://www.boost.org
+.. _CGAL:           http://www.cgal.org
+.. _CVXOPT:         http://abel.ee.ucla.edu/cvxopt/
+.. _PyQt4:          http://www.riverbankcomputing.co.uk/software/pyqt/intro
+.. _PyOpenGL:       http://pyopengl.sourceforge.net/
+.. _NumPy:          http://numpy.scipy.org/
+.. _PyX:            http://pyx.sourceforge.net/
+.. _rlog:           http://www.arg0.net/rlog
+.. _dsrpdb:         http://www.salilab.org/~drussel/pdb/
+.. _SYNAPS:         http://www-sop.inria.fr/galaad/synaps/
+.. _GMP:            http://gmplib.org/
+
+
+Building
+--------
+To build the examples as well as the :ref:`Python bindings <python-bindings>`,
+create a directory ``build``. Inside that directory run ``cmake`` and ``make``::
+
+  mkdir build
+  cd build
+  cmake ..
+  make
+
+.. tip::
+
+   To use GCC 4.2 on a Mac one can try ``CXX=g++-4.2 cmake ..`` instead of
+   ``cmake ..``.
+
+Instead of ``cmake``, one can run ``ccmake`` for a curses interface. The
+following configuration options are available. One can set them either through
+the curses interface or by passing a flag of the form ``-Doptimize:bool=on`` to
+``cmake``.
+
+  :debug:         Turns on debugging compilation
+  :optimize:      Turns on compiler optimizations (`on` by default)
+  :logging:       Turns on logging facilities
+  :counters:      Turns on various built-in counters
+
+Depending on the combination of debugging and optimization, a particular
+``CMAKE_CXX_FLAGS*`` is chosen.
+
+.. tip::    The default settings work fine unless you want to dive into the
+            library's internals with logging or study the performance of various
+            algorithms with counters.
+
+.. todo::       Write sections on logging and counters.
+
+Some parts of Dionysus understand the ``DEBUG_CONTAINERS`` definition which can
+be appended to ``CMAKE_CXX_FLAGS``. If set, the library will use GCC STL's
+debugging containers (from the ``std::__debug`` namespace defined in ``debug/*``
+header files). These containers return safe iterators (the kind that check
+whether they are singular when compared, or additionally whether they are out of
+bounds when dereferenced).
+
+.. todo:: ``ZIGZAG_CONSISTENCY`` definition
+
+
+Install
+-------
+
+At the moment there are no installation procedures. To run the Python code you
+need to have ``.../build/bindings/python`` somewhere in your ``PYTHONPATH``.
+I.e. add::
+
+    export PYTHONPATH=.../build/bindings/python
+
+to your ``~/.bashrc`` (assuming you are using Bash_). Alternatively, run the
+python examples from within ``.../build/bindings/python``::
+
+    python .../Dionysus/examples/triangle/triangle.py
+
+The C++ examples can be run from anywhere. The C++ library consists only of
+header files (no library actually needs to be built), so to compile against it,
+it suffices to add ``-I .../Dionysus/include`` to your ``g++`` flags::
+
+    g++ your-code.cpp -o your-code -I .../Dionysus/include
+
+Proper installation procedures (with ``make install``) will be added in the
+future.
+
+.. _Bash:       http://www.gnu.org/software/bash/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/index.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,60 @@
+Welcome to Dionysus' documentation!
+===================================
+
+Dionysus is a C++ library for computing persistent homology. It provides
+implementations of the following algorithms:
+
+.. sidebar:: Contents
+   
+   .. toctree::
+      :maxdepth: 1
+   
+      get-build-install
+      tutorial
+      examples/index
+      python/overview
+      bibliography
+
+* Persistent homology computation [ELZ02]_ [ZC05]_
+* Vineyards [CEM06]_    |cpp-only|
+* Persistent cohomology computation (described in [dSVJ09]_)
+* Zigzag persistent homology [CdSM09]_
+* :ref:`examples` provide useful functionality in and of themselves:
+  
+  * :ref:`Alpha shape construction <alpha-shape-example>` in 2D and 3D
+  * :ref:`Rips complex construction <rips-example>`
+  * Cech complex construction       |cpp-only|
+  * :ref:`Circle-valued parametrization <cohomology-parametrization>`
+  * :ref:`Piecewise-linear vineyards <pl-vineyard>`
+
+.. todo:: 
+   Document more examples.
+
+The C++ API is currently very poorly documented. One's best source for its
+documentation is its usage in various :ref:`examples` (located in
+:sfile:`examples/`).
+
+The :ref:`Python bindings <python-bindings>` provide both a simple interface to
+the low-level C++ functionality as well as high-level auxilliary routines. Their
+"thinness" is meant to provide the efficiency benefits of C++ together with the
+simplicity, elegance, and interactivity of Python. Since they mimick the C++
+functionality, their documentation may be a helpful resource for the latter.
+
+:ref:`Download <download>` the software, or read a :ref:`tutorial` to
+get acquainted with its structure.
+
+The library is distributed under the GPL_ license.
+
+.. _GPL: http://www.gnu.org/licenses/gpl.html
+
+.. include::    substitutions.aux
+
+
+..
+    Indices and tables
+    ==================
+
+    * :ref:`genindex`
+    * :ref:`modindex`
+    * :ref:`search`
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/alphashapes.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,47 @@
+.. _alphashapes:
+
+Alpha shapes
+============
+
+There are two functions provided to compute alpha shapes. One in 2D and one in
+3D. Both take a list of points (each a list of coordinates) as input, and fill a
+list with the simplices of the `Delaunay triangulation`_. Each such simplex is
+said to be *attached* (or *regular*) if its dual Voronoi cell does not contain a
+critical point of the distance function to the point set. The smallest value of
+the squared distance function on the dual Voronoi cell of the Delaunay simplex
+is the alpha shape value assigned to it. This value is stored in the simplex's
+`data` attribute; whether it is attached is stored in the `attached` attribute.
+
+.. _`Delaunay triangulation`:   http://en.wikipedia.org/wiki/Delaunay_triangulation
+
+
+.. function:: fill_alpha_complex(points, complex)
+
+    Based on the dimension of the first point, decides which of the two functions
+    below to call.
+
+.. function:: fill_alpha2D_complex(points, complex)
+
+    Appends to the `complex` the simplices of the 2D Delaunay triangulation
+    on the `points`.
+
+.. function:: fill_alpha3D_complex(points, complex)
+
+    Appends to the `complex` the simplices of the 3D Delaunay triangulation
+    on the `points`.
+
+
+Example
+-------
+
+The following example generates 10 points on a circle, and computes their
+Delaunay triangulation with corresponding alpha shape values::
+
+    from math import sin, cos, pi
+    points = [[cos(2*pi*t/10), sin(2*pi*t/10)] for t in xrange(10)]
+    complex = Filtration()
+    fill_alpha2D_complex(points, complex)
+
+One can extract any given alpha shape with the usual Python list notation::
+
+    alphashape = [s for s in complex if s.data[0] <= .5]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/cohomology-persistence.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,175 @@
+:class:`CohomologyPersistence` class
+====================================
+
+The :ref:`rips-pairwise-cohomology` illustrates the use of :class:`CohomologyPersistence`.
+
+.. class:: CohomologyPersistence
+
+    .. method:: __init__(prime = 11)
+
+        Initializes :class:`CohomologyPersistence` with the given `prime`; from
+        this point on all the computation will be performed with coefficients
+        in :math:`\mathbb{Z}/prime \mathbb{Z}`.
+
+    .. method:: add(boundary, birth, [store = True], [image = True], [coefficients = []])
+
+        Adds a simplex with the given `boundary` to the complex, i.e.
+        :math:`K_{i+1} = K_i \cup \sigma` and `boundary` = :math:`\partial \sigma`.
+        If a new class is born as a result of the addition, `birth` is stored with
+        it for future reference.
+
+        If `store` is ``False`` and a class is born, it will not be stored in
+        :class:`CohomologyPersistence`. This avoids wasting space on the
+        classes of the dimension equal to the maximum-dimensional simplices of
+        the complex since such classes will never die.
+
+        The `image` parameter allows one to work with a case of a space
+        :math:`L \subseteq K` where the filtration of :math:`K` induces a
+        filtration of :math:`L`. In this case, one may want to compute **image
+        persistence** (i.e. the persistence of the sequences of the images given
+        by the inclusion of :math:`L` in :math:`K`). `image` indicates whether
+        the simplex added belongs to :math:`L` or not.
+
+        If given, `coefficients` is a list parallel to `boundary` that provides
+        coefficients for the corresponding boundary elements. If empty, it is
+        assumed to be :math:`(-1)^i`.
+
+        :returns: a triple (`i`, `d`, `ccl`). The first element is the index `i`.
+                  It is the internal representation of the newly added simplex,
+                  and should be used later when constructing the
+                  boundaries of its cofaces. In other words, `boundary` must
+                  consist of these indices.  The second element `d` is the death
+                  element. It is `None` if a birth occurred, otherwise it
+                  contains the value passed as `birth` to
+                  :meth:`~CohomologyPersistence.add` when the class that just
+                  died was born.
+                  The third element `ccl` returns the dying cocycle
+                  (iterable over instances of :class:`CHSNode`), in case of a death.
+                  It's empty if a birth occurs.
+
+    .. method:: __iter__()
+
+        Iterator over the live cocycles stored in
+        :class:`CohomologyPersistence`. The returned elements are of the type
+        :class:`Cocycle` below.
+
+
+.. class:: Cocycle
+
+    .. attribute:: birth
+
+        The birth value associated with the cocycle. It is passed to
+        :class:`CohomologyPersistence` in method
+        :meth:`~CohomologyPersistence.add`.
+
+    .. method:: __iter__()
+
+        Iterator over the individual nodes (simplices) of the cocycle, each of type
+        :class:`CHSNode`.
+
+.. class:: CHSNode
+
+    .. attribute:: si
+
+        The index of the simplex, of type :class:`CHSimplexIndex`.
+
+    .. attribute:: coefficient
+
+        Coefficient in :math:`\mathbb{Z}/prime \mathbb{Z}` associated with the
+        simplex.
+
+
+.. class:: CHSimplexIndex
+
+    .. attribute:: order
+
+        The count associated with the simplex when it is inserted into
+        :class:`CohomologyPersistence`.
+
+
+Adaptor
+-------
+
+:class:`StaticCohomologyPersistence` provides a wrapper around
+class :class:`CohomologyPersistence` that's compatible with :class:`StaticPersistence`.
+See the documentation of the latter class for details.
+
+
+.. class:: StaticCohomologyPersistence
+
+   .. method:: __init__(filtration, prime = 2)
+
+        Initializes :class:`StaticCohomologyPersistence` with the given
+        :class:`Filtration`. `prime` is passed straight to the wrapped
+        :class:`CohomologyPersistence` class.
+
+   .. method:: pair_simplices()
+
+        Pairs simplices using :class:`CohomologyPersistence` class.
+
+   .. method:: __call__(i)
+
+        Given a node in the internal representation, the method returns its
+        integer offset from the beginning of the filtration.
+
+   .. method:: make_simplex_map(filtration)
+
+        Creates an auxilliary map from the nodes to the simplices::
+
+            smap = persistence.make_simplex_map(filtration)
+            for i in persistence:
+                if i.unpaired(): print smap[i]
+
+   .. method:: __iter__()
+
+        Iterator over the nodes (representing individual simplices). See
+        :class:`APNode`.
+
+   .. method:: __len__()
+
+        Returns the number of nodes (i.e. the number of simplices).
+
+.. class:: APNode
+
+    The following methods behave the same way as they do in :class:`SPNode`.
+
+    .. method:: sign()
+
+    .. method:: pair()
+
+    .. method:: unpaired()
+
+    The only crucial distinction in the behavior comes with the attribute
+    :attr:`cocycle`.
+
+    .. attribute:: cocycle
+
+        If the simplex is positive, this attribute stores a cocycle it created (recorded at the time of its death).
+        The 1-dimensional cocycles can be used with the :func:`circular.smooth` function to turn
+        them into circle-valued maps.
+        ::
+
+            for i in persistence:
+                if i.sign(): print i.cocycle
+
+
+.. class:: ImagePersistence
+
+    This class is another wrapper around :class:`CohomologyPersistence` that can
+    compute image persistence induced by inclusion of a subcomplex. Its
+    interface is the same as :class:`StaticCohomologyPersistence` above, except
+    for the constructor:
+
+    .. method:: __init__(filtration, subcomplex)
+
+       `subcomplex` is a function called with every simplex. It should return
+       ``True`` if the simplex belong to the subcomplex; ``False`` otherwise.
+
+
+Circular coordinates
+--------------------
+
+.. function:: circular.smooth(filtration, cocycle)
+
+   Returns a map from the vertices of the simplicial complex `filtration` to a circle :math:`[-.5, .5]`,
+   where the opposite ends of the interval are identified.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/filtration.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,43 @@
+:class:`Filtration` class
+=========================
+
+.. class:: Filtration
+    
+    This class serves as a representation of the simplicial complex. It knows both 
+    how to perform a fast lookup of a given simplex, as well as how to 
+    iterate over the simplices in a sorted order.
+
+    .. method:: __init__()
+    .. method:: __init__(simplices, cmp)
+    
+        Initializes :class:`Filtration` by internally storing the elements of the sequence
+        `simplices`, and  in the order sorted with respect to `cmp`.
+
+    .. method:: append(s)
+        
+        Appends the given simplex `s` to the filtration.
+
+    .. method:: sort(cmp)
+
+        Sorts the filtration with respect to the comparison `cmp`.
+
+    .. method:: __getitem__(i)
+
+        Random access to the elements of the filtration.
+
+    .. method:: __call__(s)
+        
+        Finds the integer index of the given simplex in the sorted order of the filtration.
+
+    .. method:: __iter__()
+ 
+        Iterator over the elements of the filtration sorted with respect
+        to the comparison `cmp`. E.g.::
+
+            simplices = [Simplex([0], 2), ..., Simplex([3,4,5], 3.5)]
+            f = Filtration(simplices, data_dim_cmp)
+            for s in f: print s
+
+    .. method:: __len__()
+
+        Size of the filtration.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/overview.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,24 @@
+.. _python-bindings:
+
+Python bindings: module :mod:`dionysus`
+=======================================
+
+.. module::         dionysus
+.. moduleauthor::   Dmitriy Morozov <dmitriy@mrzv.org>
+
+The :ref:`tutorial` describes how to use the bindings. The pages in this section
+document the API of various classes and functions.
+
+The following classes are available in the module:
+
+.. toctree::
+    :maxdepth: 1
+
+    simplex.rst
+    filtration.rst
+    static-persistence.rst
+    cohomology-persistence.rst
+    alphashapes.rst
+    rips.rst
+    zigzag-persistence.rst
+    persistence-diagram.rst
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/persistence-diagram.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,67 @@
+:class:`PersistenceDiagram` class
+==================================
+
+.. class:: PersistenceDiagram
+
+    .. method:: __init__( dimension )
+
+        Initializes : an empty( no points ) :class:`PersistenceDiagram` object and sets
+        the :attr:`~PersistenceDiagram.dimension` attribute( must be integer ) e.g.::
+
+            dia = PersistenceDiagram( 1 )
+
+    .. method:: __init__( dimension, point_seq )
+
+        Initializes :class:`PersistenceDiagram` of specified dimension from the given sequence `seq` of tuples, e.g.::
+
+            dia = PersistenceDiagram( 1, (1,2) )
+
+        The tuples must have at least 2 elements ``(birth, death)``.
+        If there is a third element, it is stored as extra data associated to
+        a point.
+
+    .. method:: append( p )
+
+        Adds point `p` to the persistence diagram.
+
+    .. attribute:: dimension
+
+        Dimension of the persistence diagram. Must be an integer. Must be set at initialization.
+
+    .. method:: __iter__( )
+
+        Iterator over the points in the persistence diagram,
+        e.g.::
+
+            for p in dia: print p
+
+    .. method:: __len__( )
+
+        :returns: The number of points in the diagram.
+
+
+
+Utility functions for persistence diagrams
+--------------------------------------------
+
+.. function:: init_diagrams(persistence, filtration[, eval = lambda s: s.data[, data = lambda i: None]])
+
+    Initializes a collection of :class:`PersistenceDiagram` instances from `persistence`
+    and `filtration`. Optional `eval` can determine how to extract birth and
+    death values from a simplex. For example, if `filtration` was filled using
+    :func:`fill_alpha_complex()`, the :attr:`~Simplex.data` contains a pair ``(value, critical)``.
+    We can extract the ``value`` from the tuple::
+
+        init_diagrams(persistence, filtration, lambda s: s.data[0])
+
+    Optional `data` argument can return arbitrary data to associate with each point,
+    given an node of `persistence`.
+
+.. function:: bottleneck_distance(dia1, dia2)
+
+    Calculates the bottleneck distance between the two persistence diagrams.
+
+.. function:: wasserstein_distance(dia1, dia2, p)
+
+    Calculates the `p`-th Wasserstein distance between the two persistence diagrams.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/rips.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,114 @@
+:class:`Rips` class
+======================
+
+.. class:: Rips
+
+    .. method:: __init__(distances)
+    
+        Initializes :class:`Rips` with the given `distances` whose main purpose
+        is to return the distance of two points given their indices. See
+        Distances_ below.
+
+    .. method:: generate(k, max, functor[, seq])
+     
+        Calls `functor` with every simplex in the `k`-skeleton of the Rips
+        complex :math:`VR` (`max`). If `seq` is provided, then the complex is
+        restricted to the vertex indices in the sequence.
+
+    .. method:: vertex_cofaces(v, k, max, functor[, seq])
+     
+        Calls `functor` with every coface of the vertex `v` in the `k`-skeleton
+        of the Rips complex :math:`VR` (`max`). If `seq` is provided, then the
+        complex is restricted to the vertex indices in the sequence.
+
+    .. method:: edge_cofaces(u, v, k, max, functor[, seq])
+     
+        Calls `functor` with every coface of the edge (`u`, `v`) in the
+        `k`-skeleton of the Rips complex :math:`VR` (`max`). If `seq` is
+        provided, then the complex is restricted to the vertex indices in the
+        sequence.
+
+    .. method:: cmp(s1, s2)
+
+        Compares simplices `s1` and `s2` with respect to their ordering in the
+        Rips complex.  Note that like Python's built in `cmp` this is a three
+        possible outsome comparison (-1,0,1) for (:math:`\leq, =, \geq`,
+        respectively).
+
+    .. method:: eval(s)
+
+        Returns the size of simplex `s`, i.e. the length of its longest edge.
+
+
+.. _distances:
+
+Distances
+---------
+
+An instance of `distances` passed to the constructor of :class:`Rips` should
+know its length and the distances between the points. The length should be
+retrievable via ``len(distance)`` and it determines how many points the complex
+is built on. The distances between the points are inferred by the class
+:class:`Rips` by calling `distances` with a pair of vertices as arguments.
+
+For example, the following class represents 10 points on an integer lattice::
+
+    class Distances:
+        def __len__(self): 
+            return 10
+
+        def __call__(self, x, y):
+            return math.fabs(y-x)
+
+The bindings expose a C++ class as a Python class :class:`PairwiseDistances` to deal with
+explicit points in a Euclidean space. In pure Python it could be defined as
+follows (in fact it used to be a pure Python class, and one may still find it in 
+:sfile:`bindings/python/dionysus/distances.py`; its performance is much slower
+than its pure C++ analog)::
+
+    class PairwiseDistances:
+        def __init__(self, points, norm = l2):
+            self.points = points
+            self.norm = norm
+
+        def __len__(self):
+            return len(self.points)
+
+        def __call__(self, p1, p2):
+            return self.norm([x - y for (x,y) in zip(self.points[p1], self.points[p2])])
+
+Another distances class is available that speeds up the computation of the Rips
+complex at the expense of the memory usage: :class:`ExplicitDistances`. It is
+initialized with an instance of any class that behaves like a distances class,
+and it stores all of its distances explicitly to not have to recompute them in
+the future::
+
+    distances = PairwiseDistances(points)
+    distances = ExplicitDistances(distances)
+
+With :class:`PairwiseDistances` being a C++ class, and
+:class:`ExplicitDistances` being pure Python, the speed-up seems minor.
+
+
+Example
+-------
+
+The following example reads in points from a file, and fills the list
+`simplices` with the simplices of the 2-skeleton of the Rips complex built on
+those vertices with distance cutoff parameter 50. Subsequently it computes the
+persistence of the resulting filtration (defined by ``rips.cmp``)::
+
+    points = [for p in points_file('...')]
+    distances = PairwiseDistances(points)
+    rips = Rips(distances)
+    simplices = Filtration()
+    rips.generate(2, 50, simplices.append)
+    
+    simplices.sort(rips.cmp)
+    p = StaticPersistence(simplices)
+    p.pair_simplices()
+
+Essentially the same example is implemented in
+:sfile:`examples/rips/rips-pairwise.py`, although it reads the `k` and `max`
+parameters for the Rips complex on the command line, and uses a trick to speed
+up the computation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/simplex.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,84 @@
+:class:`Simplex` class
+======================
+
+.. class:: Simplex
+
+    .. method:: __init__(seq[, data])
+    
+        Initializes :class:`Simplex` from the given sequence `seq` and
+        optionally real value `data`, e.g.::
+    
+            s = Simplex([1,2,3], 7.8)
+
+    .. method:: add(v)
+        
+        Adds vertex `v` to the simplex, increasing its dimension by 1.
+
+        .. seealso:: :meth:`~Simplex.join`
+
+    .. attribute:: boundary
+
+        Iterator over the boundary :math:`\partial \sigma` of the simplex,
+        e.g.::
+            
+            for sb in s.boundary: print sb
+
+    .. method:: contains(v)
+
+        :returns: `True` iff the simplex contains vertex `v`.
+
+    .. method:: dimension()
+
+        :returns: the dimension of the simplex (one less than its number of
+                  vertices).
+
+    .. method:: join(other)
+        
+        Joins the current simplex with the `other` simplex. The method copies over 
+        the vertices from the `other` simplex.
+
+    .. attribute:: data
+        
+        Real value stored in the simplex.
+
+    .. attribute:: vertices
+
+        (Sorted) vertices of the simplex accessible as a sequence, e.g.::
+        
+            for v in s.vertices: print v,
+
+    .. method:: __hash__()
+    .. method:: __eq__(other)
+
+        Simplices are hashable, and equality comparable, and therefore can be
+        stored in a dictionary.  Simplices are equal if their
+        :attr:`~Simplex.vertices` are the same.
+
+
+Utility functions for manipulating simplices
+--------------------------------------------
+
+The first function :func:`vertex_cmp` is a Python interface to a C++ function.
+The rest are pure Python functions defined in
+:sfile:`bindings/python/dionysus/__init__.py`.
+
+.. function:: vertex_cmp(s1, s2)
+    
+    Compares the two simplices with respect to the lexicographic order of their vertices.
+
+.. function:: vertex_dim_cmp(s1, s2)
+    
+    Compares the two simplices with respect to their dimension, and lexicographically 
+    within the same dimension.
+
+.. function:: data_cmp(s1, s2)
+    
+    Compares the two simplices with respect to the data (real values) they
+    store.
+
+.. function:: data_dim_cmp(s1, s2)
+    
+    Compares the two simplices with respect to their dimension and within the same 
+    dimension with respect to their data.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/python/static-persistence.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,113 @@
+:class:`StaticPersistence` class
+================================
+
+.. class:: StaticPersistence
+
+    .. method:: __init__(filtration)
+
+        Initializes :class:`StaticPersistence` with the given
+        :class:`Filtration`. This operation effectively computes the boundary
+        matrix of the complex captured by the filtration with rows and columns
+        sorted with respect to the filtration ordering.
+
+    .. method:: pair_simplices(store_negative = False)
+
+        Pairs simplices using the [ELZ02]_ algorithm. `store_negative` indicates
+        whether to store the negative simplices in the cycles.
+
+    .. method:: __call__(i)
+
+        Given an SPNode in the internal representation, the method returns its
+        integer offset from the beginning of the filtration. This is useful to
+        lookup the actual name of the simplex in the complex.
+
+    .. method:: make_simplex_map(filtration)
+
+        Creates an auxilliary :class:`PersistenceSimplexMap` used to lookup the actual
+        simplices from the persistence indices. For example, the following
+        snippet prints out all the unpaired simplices::
+
+            smap = persistence.make_simplex_map(filtration)
+            for i in persistence:
+                if i.unpaired(): print smap[i]
+
+    .. method:: __iter__()
+
+        Iterator over the nodes (representing individual simplices). See
+        :class:`SPNode`.
+
+    .. method:: __len__()
+
+        Returns the number of nodes (i.e. the number of simplices).
+
+
+.. class:: SPNode
+
+    The class represents nodes stored in :class:`StaticPersistence`. These nodes
+    are aware of their :meth:`sign` and :attr:`pair` (and :meth:`cycle` if
+    negative after :meth:`StaticPersistence.pair_simplices` has run).
+
+    .. method:: sign()
+
+        Returns the sign of the simplex: `True` for positive, `False` for
+        negative.
+
+    .. method:: pair()
+
+        Simplex's pair. The pair is set to self if the siplex is unpaired.
+
+    .. 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
+        container of :class:`SPNode`. For example, one can print the basis for
+        the (bounding) cycles::
+
+            smap = persistence.make_simplex_map(filtration)
+            for i in persistence:
+                for ii in i.cycle: print smap[ii]
+
+    .. method:: unpaired()
+
+        Indicates whether the simplex is unpaired.
+
+.. 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/doc/python/zigzag-persistence.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,115 @@
+:class:`ZigzagPersistence` class
+================================
+
+The class deals with the setting :math:`K_1 \rightarrow K_2 \leftarrow K_3 \rightarrow \dots`.
+The :ref:`triangle-zigzag-example` illustrates the use of :class:`ZigzagPersistence`.
+
+.. class:: ZigzagPersistence
+
+    .. method:: add(boundary, birth)
+        
+        Adds a simplex with the given `boundary` to the complex, i.e. 
+        :math:`K_{i+1} = K_i \cup \sigma` and `boundary` = :math:`\partial \sigma`.
+        If a new class is born as a result of the addition, `birth` is stored with 
+        it for future reference.
+
+        :returns: a pair (`i`, `d`). The first element is the index `i`. 
+                  It is the internal representation of the newly added simplex,
+                  and should be used later for removal or when constructing the
+                  boundaries of its cofaces. In other words, `boundary` must
+                  consist of these indices.  The second element `d` is the death
+                  element. It is `None` if a birth occurred, otherwise it
+                  contains the value passed as `birth` to
+                  :meth:`~ZigzagPersistence.add` or
+                  :meth:`~ZigzagPersistence.remove` when the class that just
+                  died was born.
+
+    .. method:: remove(index, birth)
+      
+        Removes the simplex identified by the given `index` from the complex. If
+        a new class is born as a result of the removal, `birth` is stored with
+        it for future reference.
+        
+        :returns: `None` if a birth has occurred, otherwise it contains the value 
+                  passed as `birth` to :meth:`~ZigzagPersistence.add` or
+                  :meth:`~ZigzagPersistence.remove` when the class that just
+                  died was born.
+
+    .. method:: is_alive(z)
+
+        Determines whether a given cycle is alive. The input should be an
+        instance of :class:`ZNode`.
+
+    .. method:: __iter__()
+
+        Iterator over elements of type :class:`ZNode`, i.e. the cycles stored in the structure.
+
+.. class:: ZNode
+
+    .. attribute:: birth
+
+        The birth value associated with the cycle. It is passed to
+        :class:`ZigzagPersistence` in method
+        :meth:`~ZigzagPersistence.add`.
+
+    .. method:: __iter__()
+
+        Iterator over the individual nodes (simplices) of the cycle (same
+        indices that are passed to and returned by
+        :meth:`~ZigzagPersistence.add`.
+
+
+Auxilliary functions
+--------------------
+
+A pair of auxilliary functions is provided to help add and remove entire
+collections of simplices. Both are pure Python functions defined in
+:sfile:`bindings/python/dionysus/zigzag.py`.
+
+    .. function:: add_simplices(zigzag, simplices, complex, birth, report_local = False)
+
+        Adds each simplex in `simplices` to the `zigzag`. `complex` is a
+        dictionary mapping simplices to their indices (in `zigzag`'s internal
+        representation). All the newly born classes are given the value of
+        `birth`.
+
+        :returns: list of deaths that occur as a result of `simplices`' removal. 
+                  Each death is a pair of the dimension of the class and the
+                  `birth` value passed when the class was born.  By default the
+                  deaths equal to `birth` are not reported unless `report_local`
+                  is set to `True`.
+
+    .. function:: remove_simplices(zigzag, simplices, complex, birth, report_local = False)
+
+        Same parameters and return as in :func:`add_simplices` except that
+        `simplices` are removed from the `zigzag` and the `complex`.
+
+
+
+:class:`ImageZigzagPersistence` class
+=====================================
+
+The class deals with the setting 
+
+.. math::
+    \begin{array}{ccccccc}
+        K_1         & \rightarrow   & K_2       &   \leftarrow      & K_3       & \rightarrow   & \dots \\
+        \uparrow    &               & \uparrow  &                   & \uparrow  & \\
+        L_1         & \rightarrow   & L_2       &   \leftarrow      & L_3       & \rightarrow   & \dots
+    \end{array}
+
+where the vertical maps are inclusions, i.e. :math:`L_i \subseteq K_i`.
+
+.. class:: ImageZigzagPersistence
+
+    .. method:: add(boundary, subcomplex, birth)
+ 
+        Interface is the same as in :meth:`ZigzagPersistence.add`. The
+        additional parameter `subcomplex` controls whether the simplex is added
+        to :math:`L` or not. We always have :math:`K_{i+1} = K_i \cup \sigma`.
+        If `subcomplex` is true, then :math:`L_{i+1} = L_i \cup \sigma`,
+        otherwise :math:`L_{i+1} = L_i`.
+
+    .. method:: remove(index, birth)
+      
+        Interface is exactly the same as in :meth:`ZigzagPersistence.remove`.        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/substitutions.aux	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,2 @@
+.. |cpp-only|   replace:: :sup:`(C++ only)`
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial.rst	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,203 @@
+.. _tutorial:
+
+Brief Tutorial
+==============
+
+It suffices to import only the necessary commands from module :mod:`dionysus`,
+but for the purposes of the tutorial, we import everything::
+
+    from dionysus import *
+
+Read in a points file (for :func:`points_file` the points should appear one per
+line with coordinates separated with spaces; of course, one can read in the
+points however one wants)::
+
+    points = [p for p in points_file('points_filename')]
+    print "Number of points:", len(points)
+
+
+Complexes
+---------
+
+If the points are in :math:`\mathbb{R}^2` or :math:`\mathbb{R}^3`, one can
+construct an alphashape filtration::
+
+    simplices = Filtration()
+    fill_alpha2D_complex(points, simplices)     # for 2D, or
+    fill_alpha3D_complex(points, simplices)     # for 3D
+
+
+Functions :ref:`fill_alpha*_complex <alphashapes>` fill the ``simplices``
+with all the :class:`simplices <Simplex>` of the Delaunay triangulation. 
+Each one has its attribute ``data`` set to a pair: the
+smallest value of the squared distance function on the dual Voronoi cell and
+whether the simplex is critical or not (i.e. whether its dual cell does or
+does not contain a critical point of the distance function).
+See :ref:`alphashapes` for more details, and :ref:`alpha-shape-example` for a
+full example.
+
+As a result, if one wanted only those simplices whose alpha shape value did not
+exceed 10, one could obtain them as follows::
+
+    simplices10 = [s for s in simplices if s.data[0] <= 10]
+
+If the point set lies in higher dimensions, one may construct a Rips complex on
+it. This complex requires only pairwise distances, which makes it very
+versatile. One must first construct an instance of a class providing such
+distances (e.g. :class:`PairwiseDistances` for explicit points, see
+:ref:`distances` for more details), and then pass it to the :class:`Rips`
+complex class::
+
+    distances = PairwiseDistances(points)
+    rips = Rips(distances)
+
+Usually, because of space restrictions, generation of a Rips complex has to be
+restricted to a :math:`k`-skeleton of the complex and some maximal parameter
+:math:`max`. In the following example :math:`k = 3` and :math:`max = 50`::
+
+    simplices = Filtration()
+    rips.generate(3, 50, simplices.append)
+
+:meth:`Rips.generate` takes a skeleton and a maximum distance cutoffs, and a
+function which is called with each of the simplices in the complex (in this
+case, Python list `simplices`' ``append`` method).
+    
+
+Persistence
+-----------
+
+There are two ways of computing persistence in Dionysus. The first *offline*
+way, required by :class:`StaticPersistence` (and its derivatives), is to set up
+the entire filtration at once, compute its persistence in one operation, and
+then examine the pairings. The second way is to feed simplices one by one in an
+*online* manner and manually keep track of the pairs that are created.
+:class:`ZigzagPersistence` and :class:`CohomologyPersistence` accept their
+input this way,
+
+
+Offline
+^^^^^^^
+
+For the first approach, i.e. to use :class:`StaticPersistence`, one must put the
+sort the filtration with respect to some ordering
+(for example, :func:`data_dim_cmp` for alpha shapes or :meth:`Rips.cmp` for the
+Rips complex)::
+
+    simplices.sort(data_dim_cmp)     # for the alpha shapes
+    simplices.sort(rips.cmp)         # for the rips complex
+
+Creating an instance of :class:`StaticPersistence` initialized with the
+filtration really initializes a boundary matrix. The subsequent call to
+:meth:`~StaticPersistence.pair_simplices` reduces the matrix to compute the
+persistence of the filtration::
+
+    p = StaticPersistence(simplices)
+    p.pair_simplices()
+
+Once the simplices are paired, one may examine the pairings by iterating over
+the instance of :class:`StaticPersistence`. We can use an auxilliary map ``smap`` 
+to remap the persistence indices into the actual simplices::
+
+    smap = p.make_simplex_map(simplices)
+    for i in p:
+        if i.sign():
+            birth = smap[i]
+            if i.unpaired():
+                print birth.dimension(), birth.data, "inf"
+                continue
+            
+            death = smap[i.pair()]
+            print birth.dimension(), birth.data, death.data
+
+The iterator ``i`` over the instance ``p`` of :class:`StaticPersistence` is of type
+:class:`SPNode`, and represents individual simplices taken in the filtration
+order. It knows about its own :meth:`~SPNode.sign` and :meth:`~SPNode.pair` as well as
+whether it is :math:`~SPNode.unpaired`. :meth:`StaticPersistence.make_simplex_map` creates 
+a map that we use to get the actual simplices: ``smap[i]`` and ``smap[i.pair()]``.
+The previous code snippet prints out the persistence diagrams of the given
+filtration.
+
+
+Online
+^^^^^^
+
+Class :class:`ZigzagPersistence` accepts additions and removals of the simplices
+one by one, and returns an internal representation of the simplices.
+(:class:`CohomologyPersistence` works in the same way, but accepts only
+additions of the simplices.) 
+When one
+adds a simplex via :meth:`ZigzagPersistence.add`, one must provide its boundary
+in this internal representation together with a *birth value* which
+:class:`ZigzagPersistence` will store in case a class is born as a result of the
+addition. :meth:`~ZigzagPersistence.add` returns a pair ``(i,d)``. ``i`` is the
+internal representation of the newly added simplex, which one must record for
+future use in the boundaries of its cofaces (below it is recorded in the
+dictionary ``complex``). ``d`` is `None` in case of the birth, otherwise, it is the
+previously recorded birth value of the class that dies as a result of the
+addition. The following code adds all the ``simplices`` to a zigzag::
+
+    simplices.sort(data_dim_cmp)
+    complex = {}
+    zz = ZigzagPersistence()
+    for s in simplices:
+        i,d = zz.add([complex[sb] for sb in s.boundary], (s.dimension(), s.data))
+        complex[s] = i
+        if d is not None:                   # we have a death
+            dimension, birth = d            # we previously stored the (dimension, data) pair
+            print dimension, birth, s.data       
+
+Similarly, one can remove simplices by calling :meth:`ZigzagPersistence.remove`
+with the internal index previously returned by :meth:`~ZigzagPersistence.add`::
+
+    for s in reversed(simplices):
+        d = zz.remove(complex[s], (s.dimension() - 1, s.data))
+        del complex[s]
+        if d is not None:
+            dimension, birth = d
+            print dimension, birth, s.data
+
+Naturally, :meth:`~ZigzagPersistence.remove` returns only `d`. 
+
+If one wants to add or remove an entire set of simplices "at once" (i.e.  with
+all births being assigned the same value), there are two helper functions:
+:func:`add_simplices` and :func:`remove_simplices`.
+
+See the :ref:`bindings reference <python-bindings>` for more details, and
+:ref:`triangle-zigzag-example` for an example of :class:`ZigzagPersistence`.
+See :ref:`rips-pairwise-cohomology` for an example of
+:class:`CohomologyPersistence`.
+
+
+.. _speed-up-suggestions:
+
+Speed-up suggestions
+--------------------
+
+Currently, when the choice comes between efficiency and flexibility, the Python
+bindings err on the side of flexibility. There is hope that in the future the
+choice won't really be necessary. Meanwhile, one can use a few techniques that
+speed up computation at the expense of memory. Note, however, that since the
+recent switch of :class:`PairwiseDistances` to C++ rather than pure Python, it
+is not clear whether these deliver a substantial speed-up:
+
+* To avoid (possibly expensive) computation of distances during Rips complex
+  generation, store :class:`ExplicitDistances` (see :ref:`distances`)::
+
+        distances = PairwiseDistances(points)
+        distances = ExplicitDistances(distances)
+
+* To avoid the computation of simplex sizes in the Rips complex during the
+  initialization of a :class:`Filtration`, store them explicitly in
+  :attr:`Simplex.data` attribute (this is not done by default to save memory);
+  then use :func:`data_dim_cmp` when sorting the
+  :class:`Filtration`::
+
+        rips = Rips(distances)
+        simplices = Filtration()
+        rips.generate(..., simplices.append)
+        for s in simplices: s.data = rips.eval(s)
+        simplices.sort(data_dim_cmp)
+
+
+
+.. include::    substitutions.aux
--- a/examples/CMakeLists.txt	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -1,5 +1,15 @@
-add_subdirectory			(alphashapes)
-add_subdirectory			(ar-vineyard)
-add_subdirectory			(cech-complex)
-add_subdirectory			(grid)
-add_subdirectory			(triangle)
+add_executable                  (bottleneck-distance bottleneck-distance.cpp)
+target_link_libraries           (bottleneck-distance ${libraries} ${Boost_PROGRAM_OPTIONS_LIBRARY})
+
+add_subdirectory            (alphashapes)
+#add_subdirectory           (ar-vineyard)
+add_subdirectory            (cech-complex)
+add_subdirectory            (consistency)
+add_subdirectory            (cohomology)
+add_subdirectory            (fitness)
+add_subdirectory            (pl-functions)
+add_subdirectory            (triangle)
+add_subdirectory            (poincare)
+add_subdirectory            (rips)
+add_subdirectory            (filtration)
+add_subdirectory            (homology-zigzags)
--- a/examples/alphashapes/CMakeLists.txt	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/alphashapes/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -1,8 +1,27 @@
-set							(targets						
-							 alphashapes3d
-							 alpharadius)
-							 
-foreach 					(t ${targets})
-	add_executable			(${t} ${t}.cpp ${external_sources})
-	target_link_libraries	(${t} ${libraries} ${cgal_libraries})
-endforeach 					(t ${targets})
+set                             (libraries                      ${libraries} 
+                                                                ${Boost_SERIALIZATION_LIBRARY}
+                                                                ${Boost_PROGRAM_OPTIONS_LIBRARY})
+
+# Build compare-diagrams
+add_executable                  (compare-diagrams               compare-diagrams.cpp)
+target_link_libraries           (compare-diagrams               ${libraries})
+
+# Add targets that depend on CGAL
+if                              (CGAL_FOUND)
+    include                     (${CGAL_USE_FILE})
+
+    set                         (targets                        alphashapes3d
+                                                                alphashapes2d
+                                                                alphashapes3d-cohomology
+                                                                #alpharadius
+                                )
+    add_definitions             (${CGAL_CXX_FLAGS_INIT})
+    include_directories         (${CGAL_INCLUDE_DIRS})
+
+    foreach                     (t ${targets})
+        add_executable          (${t} ${t}.cpp)
+        target_link_libraries   (${t} ${libraries} ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES})
+    endforeach                  (t ${targets})
+else                            (CGAL_FOUND)
+    message(STATUS "CGAL not found, therefore alphashapes will not be built.")
+endif                           (CGAL_FOUND)
--- a/examples/alphashapes/alpharadius.cpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/alphashapes/alpharadius.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,5 +1,4 @@
-#include <utilities/sys.h>
-#include <utilities/debug.h>
+#include <utilities/log.h>
 
 #include "alphashapes3d.h"
 #include <topology/filtration.h>
@@ -48,11 +47,13 @@
 
 int main(int argc, char** argv) 
 {
-#ifdef CWDEBUG
-	Debug(dc::filtration.on());
-	//Debug(dc::cycle.on());
+#ifdef LOGGING
+	rlog::RLogInit(argc, argv);
 
-	dionysus::debug::init();
+	stdoutLog.subscribeTo( RLOG_CHANNEL("info") );
+	stdoutLog.subscribeTo( RLOG_CHANNEL("error") );
+	stdoutLog.subscribeTo( RLOG_CHANNEL("topology/filtration") );
+	//stdoutLog.subscribeTo( RLOG_CHANNEL("topology/cycle") );
 #endif
 
 	std::istream& in = std::cin;
@@ -66,7 +67,7 @@
 		Point p(x,y,z);
 		Dt.insert(p);
 	}
-	std::cout << "Delaunay triangulation computed" << std::endl;
+	rInfo("Delaunay triangulation computed");
  
 	AlphaSimplex3DVector alpha_ordering;
 	fill_alpha_order(Dt, alpha_ordering);
@@ -83,17 +84,17 @@
 			continue;
 		
 		double current_alpha = CGAL::to_double(cur->value());
-		std::cout << "Current alpha: " << current_alpha << std::endl;
+		rInfo("Current alpha: %f", current_alpha);
 		std::sort(radius_ordering.begin(), radius_ordering.end(), ro);
-		std::cout << "Radius ordering size: " << radius_ordering.size() << std::endl;
+		rInfo("Radius ordering size: %i", radius_ordering.size());
 
 		RadiusFiltration rf;
 		for (SimplexVector::const_iterator cur = radius_ordering.begin(); cur != radius_ordering.end(); ++cur)
 			rf.append(*cur);
 		rf.fill_simplex_index_map();
-		std::cout << "Simplex index map filled" << std::endl;
+		rInfo("Simplex index map filled");
 		rf.pair_simplices(rf.begin(), rf.end());
-		std::cout << "Pairing computed" << std::endl;
+		rInfo("Pairing computed");
 	
 		for (RadiusFiltration::const_Index cur = rf.begin(); cur != rf.end(); ++cur)
 		{
@@ -101,7 +102,7 @@
 	
 			RealValue d1 = cur->distance;
 			//if (cur == cur->pair())
-			//	std::cout << "Unpaired " << cur->dimension() << ' ' << CGAL::to_double(d1) << std::endl;
+			//	rInfo("Unpaired %d %f", cur->dimension(), CGAL::to_double(d1));
 			
 			RealValue d2 = cur->pair()->distance;
 			if (d1 == d2)	continue;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,42 @@
+# Computes the persistence diagram of the alpha shapes in both 2D and 3D 
+# (decided dynamically based on the input file)
+
+from    dionysus        import Filtration, StaticPersistence, data_dim_cmp, vertex_cmp, \
+                               fill_alpha3D_complex, fill_alpha2D_complex, points_file
+from    sys             import argv, exit
+from    math            import sqrt
+
+
+if len(argv) < 2:
+    print "Usage: %s POINTS" % argv[0]
+    exit()
+
+points = [p for p in points_file(argv[1])]
+f = Filtration()
+if   len(points[0]) == 2:           # 2D
+    fill_alpha2D_complex(points, f)
+elif len(points[1]) == 3:           # 3D
+    fill_alpha3D_complex(points, f)
+
+print "Total number of simplices:", len(f)
+
+f.sort(data_dim_cmp)
+print "Filtration initialized"
+
+p = StaticPersistence(f)
+print "StaticPersistence initialized" 
+
+p.pair_simplices()
+print "Simplices paired"
+
+print "Outputting persistence diagram"
+smap = p.make_simplex_map(f)
+for i in p:
+    if i.sign():
+        b = smap[i]
+        if i.unpaired():
+            print b.dimension(), sqrt(b.data[0]), "inf"
+            continue
+
+        d = smap[i.pair()]
+        print b.dimension(), sqrt(b.data[0]), sqrt(d.data[0])
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes2d.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,69 @@
+#include <utilities/log.h>
+
+#include "alphashapes2d.h"
+#include <topology/filtration.h>
+#include <topology/static-persistence.h>
+#include <topology/persistence-diagram.h>
+#include <iostream>
+
+#include <fstream>
+
+
+typedef Filtration<AlphaSimplex2D>              AlphaFiltration;
+typedef StaticPersistence<>                     Persistence;
+typedef PersistenceDiagram<>                    PDgm;
+
+
+int main(int argc, char** argv) 
+{
+#ifdef LOGGING
+    rlog::RLogInit(argc, argv);
+
+    stdoutLog.subscribeTo( RLOG_CHANNEL("error") );
+    stdoutLog.subscribeTo( RLOG_CHANNEL("info") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/filtration") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/cycle") );
+#endif
+
+    SetFrequency(GetCounter("filtration/pair"), 10000);
+    SetTrigger(GetCounter("filtration/pair"), GetCounter(""));
+
+    // Read in the point set and compute its Delaunay triangulation
+    std::istream& in = std::cin;
+    double x,y;
+    Delaunay2D Dt;
+    while(in)
+    {
+        in >> x >> y;
+        if (!in) break;
+        Point p(x,y);
+        Dt.insert(p);
+    }
+    rInfo("Delaunay triangulation computed");
+   
+    AlphaFiltration af;
+    fill_complex(Dt, af);
+    rInfo("Simplices: %i", af.size());
+
+    // Create the alpha-shape filtration
+    af.sort(AlphaSimplex2D::AlphaOrder());
+    rInfo("Filtration initialized");
+
+    Persistence p(af);
+    rInfo("Persistence initializaed");
+
+    p.pair_simplices();
+    rInfo("Simplices paired");
+
+    Persistence::SimplexMap<AlphaFiltration>    m       = p.make_simplex_map(af);
+    std::map<Dimension, PDgm>                   dgms;
+    init_diagrams(dgms, p.begin(), p.end(), 
+                  evaluate_through_map(m, AlphaSimplex2D::AlphaValueEvaluator()),
+                  evaluate_through_map(m, AlphaSimplex2D::DimensionExtractor()));
+
+#if 1
+    std::cout << 0 << std::endl << dgms[0] << std::endl;
+    std::cout << 1 << std::endl << dgms[1] << std::endl;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes2d.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,84 @@
+/**
+ * Author: Dmitriy Morozov
+ * Department of Computer Science, Duke University, 2007
+ */
+
+#ifndef __ALPHASHAPES2D_H__
+#define __ALPHASHAPES2D_H__
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Delaunay_triangulation_2.h>
+
+#include <topology/simplex.h>
+#include <utilities/types.h>
+
+#include <vector>
+#include <set>
+#include <iostream>
+
+struct K: CGAL::Exact_predicates_exact_constructions_kernel {};
+
+typedef CGAL::Delaunay_triangulation_2<K>           Delaunay2D;
+typedef Delaunay2D::Point                           Point;
+typedef Delaunay2D::Vertex_handle                   Vertex_handle;
+typedef Delaunay2D::Face_handle                     Face_handle;
+typedef K::FT                                       RealValue;
+
+typedef Delaunay2D::Finite_vertices_iterator        Vertex_iterator;
+typedef Delaunay2D::Finite_edges_iterator           Edge_iterator;
+typedef Delaunay2D::Finite_faces_iterator           Face_iterator;
+
+
+class AlphaSimplex2D: public Simplex<Vertex_handle>
+{
+    public:
+        typedef     Simplex<Vertex_handle>                              Parent;
+        typedef     std::set<AlphaSimplex2D, Parent::VertexComparison>  SimplexSet;
+        typedef     Parent::VertexContainer                             VertexSet;
+
+    public:
+                                    AlphaSimplex2D()                    {}
+                                    AlphaSimplex2D(const Parent& p): 
+                                            Parent(p)                   {}
+                                    AlphaSimplex2D(const AlphaSimplex2D& s): 
+                                            Parent(s)                   { attached_ = s.attached_; alpha_ = s.alpha_; }
+                                    AlphaSimplex2D(const Delaunay2D::Vertex& v);
+        
+                                    AlphaSimplex2D(const Delaunay2D::Edge& e);
+                                    AlphaSimplex2D(const Delaunay2D::Edge& e, const SimplexSet& simplices, const Delaunay2D& Dt);
+        
+                                    AlphaSimplex2D(const Delaunay2D::Face& c);
+        
+        RealType                    value() const                       { return CGAL::to_double(alpha_); }
+        RealValue                   alpha() const                       { return alpha_; }
+        bool                        attached() const                    { return attached_; }
+
+        // Ordering
+        struct AlphaOrder
+        { bool operator()(const AlphaSimplex2D& first, const AlphaSimplex2D& second) const; };
+        
+        struct AlphaValueEvaluator
+        { 
+            typedef                 AlphaSimplex2D                                  first_argument_type;
+            typedef                 RealType                                        result_type;
+
+            RealType                operator()(const AlphaSimplex2D& s) const       { return s.value(); }
+        };
+
+        std::ostream&               operator<<(std::ostream& out) const;
+        
+    private:
+        RealValue                   alpha_;
+        bool                        attached_;
+};
+
+typedef             std::vector<AlphaSimplex2D>                             AlphaSimplex2DVector;
+void                fill_simplex_set(const Delaunay2D& Dt, AlphaSimplex2D::SimplexSet& simplices);
+template<class Filtration>
+void                fill_complex(const Delaunay2D& Dt,     Filtration& filtration);
+
+std::ostream&       operator<<(std::ostream& out, const AlphaSimplex2D& s)  { return s.operator<<(out); }
+
+#include "alphashapes2d.hpp"
+
+#endif // __ALPHASHAPES2D_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes2d.hpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,123 @@
+#include <utilities/log.h>
+#include <boost/foreach.hpp>
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Vertex& v): alpha_(0), attached_(false)
+{
+    for (int i = 0; i < 3; ++i)
+        if (v.face()->vertex(i) != Vertex_handle() && v.face()->vertex(i)->point() == v.point())
+            Parent::add(v.face()->vertex(i));
+}
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Edge& e): attached_(false)
+{
+    Face_handle f = e.first;
+    for (int i = 0; i < 3; ++i)
+        if (i != e.second)
+            Parent::add(f->vertex(i));
+}
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Edge& e, const SimplexSet& simplices, const Delaunay2D& Dt): attached_(false)
+{
+    Face_handle f = e.first;
+    for (int i = 0; i < 3; ++i)
+        if (i != e.second)
+            Parent::add(f->vertex(i));
+
+    VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin();
+    const Point& p1 = (*v++)->point();
+    const Point& p2 = (*v)->point();
+
+    Face_handle o = f->neighbor(e.second);
+    if (o == Face_handle())
+    {
+        alpha_ = CGAL::squared_radius(p1, p2);
+        return;
+    }
+    int oi = o->index(f);
+
+    attached_ = false;
+    if (!Dt.is_infinite(f->vertex(e.second)) &&
+        CGAL::side_of_bounded_circle(p1, p2,
+                                     f->vertex(e.second)->point()) == CGAL::ON_BOUNDED_SIDE)
+        attached_ = true;
+    else if (!Dt.is_infinite(o->vertex(oi)) &&
+             CGAL::side_of_bounded_circle(p1, p2,
+                                          o->vertex(oi)->point()) == CGAL::ON_BOUNDED_SIDE)
+        attached_ = true;
+    else
+        alpha_ = CGAL::squared_radius(p1, p2);
+
+    if (attached_)
+    {
+        if (Dt.is_infinite(f))
+            alpha_ = simplices.find(AlphaSimplex2D(*o))->alpha();
+        else if (Dt.is_infinite(o))
+            alpha_ = simplices.find(AlphaSimplex2D(*f))->alpha();
+        else
+            alpha_ = std::min(simplices.find(AlphaSimplex2D(*f))->alpha(),
+                              simplices.find(AlphaSimplex2D(*o))->alpha());
+    }
+}
+
+AlphaSimplex2D::
+AlphaSimplex2D(const Delaunay2D::Face& f): attached_(false)
+{
+    for (int i = 0; i < 3; ++i)
+        Parent::add(f.vertex(i));
+    VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin();
+    Point p1 = (*v++)->point();
+    Point p2 = (*v++)->point();
+    Point p3 = (*v)->point();
+    alpha_ = CGAL::squared_radius(p1, p2, p3);
+}
+
+
+bool
+AlphaSimplex2D::AlphaOrder::
+operator()(const AlphaSimplex2D& first, const AlphaSimplex2D& second) const
+{
+    if (first.alpha() == second.alpha())
+        return (first.dimension() < second.dimension());
+    else
+        return (first.alpha() < second.alpha());
+}
+
+std::ostream&
+AlphaSimplex2D::
+operator<<(std::ostream& out) const
+{
+    for (VertexSet::const_iterator cur = Parent::vertices().begin();
+                                   cur != Parent::vertices().end(); ++cur)
+        out << **cur << ", ";
+    out << "value = " << value();
+
+    return out;
+}
+
+void fill_simplex_set(const Delaunay2D& Dt, AlphaSimplex2D::SimplexSet& simplices)
+{
+    for(Face_iterator cur = Dt.finite_faces_begin(); cur != Dt.finite_faces_end(); ++cur)
+        simplices.insert(AlphaSimplex2D(*cur));
+    rInfo("Faces inserted");
+    for(Edge_iterator cur = Dt.finite_edges_begin(); cur != Dt.finite_edges_end(); ++cur)
+        simplices.insert(AlphaSimplex2D(*cur, simplices, Dt));
+    rInfo("Edges inserted");
+    for(Vertex_iterator cur = Dt.finite_vertices_begin(); cur != Dt.finite_vertices_end(); ++cur)
+        simplices.insert(AlphaSimplex2D(*cur));
+    rInfo("Vertices inserted");
+}
+
+template<class Filtration>
+void fill_complex(const Delaunay2D& Dt, Filtration& filtration)
+{
+    // Compute all simplices with their alpha values and attachment information
+    // TODO: this can be optimized; the new Filtration can act as a SimplexSet
+    AlphaSimplex2D::SimplexSet simplices;
+    fill_simplex_set(Dt, simplices);
+    BOOST_FOREACH(const AlphaSimplex2D& s, simplices)
+        filtration.push_back(s);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/alphashapes3d-cohomology.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,132 @@
+#include "alphashapes3d.h"
+#include "../cohomology/wrappers.h"
+
+#include <topology/cohomology-persistence.h>
+
+#include <utilities/log.h>
+#include <utilities/timer.h>
+
+#include <iostream>
+#include <fstream>
+
+#include <boost/program_options.hpp>
+#include <boost/progress.hpp>
+#include <boost/foreach.hpp>
+
+
+typedef     boost::tuple<Dimension, RealType>                       BirthInfo;
+typedef     CohomologyPersistence<BirthInfo>                        Persistence;
+
+typedef     Persistence::SimplexIndex                               Index;
+typedef     Persistence::Death                                      Death;
+typedef     Persistence::CocyclePtr                                 CocyclePtr;
+
+namespace po = boost::program_options;
+
+int main(int argc, char** argv) 
+{
+#ifdef LOGGING
+    rlog::RLogInit(argc, argv);
+
+    stdoutLog.subscribeTo( RLOG_CHANNEL("info") );
+    stdoutLog.subscribeTo( RLOG_CHANNEL("error") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/persistence") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/chain") );
+#endif
+
+    std::string     infilename, outfilename;
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+        ("input-file",   po::value<std::string>(&infilename),     "Point set whose alpha shape filtration and persistence we want to compute")
+        ("output-file",  po::value<std::string>(&outfilename),    "Where to write the collection of persistence diagrams");
+
+    po::positional_options_description pos;
+    pos.add("input-file", 1);
+    pos.add("output-file", 2);
+    
+    po::options_description all; all.add(hidden);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(argc, argv).
+                  options(all).positional(pos).run(), vm);
+    po::notify(vm);
+
+    if (!vm.count("input-file") || !vm.count("output-file"))
+    { 
+        std::cout << "Usage: " << argv[0] << " input-file output-file" << std::endl;
+        // std::cout << hidden << std::endl; 
+        return 1; 
+    }
+
+    std::ofstream   diagram_out(outfilename.c_str());
+
+    Timer total_timer; total_timer.start();
+
+    // Read in the point set and compute its Delaunay triangulation
+    std::ifstream in(infilename.c_str());
+    double x,y,z;
+    Delaunay3D Dt;
+    while(in)
+    {
+        in >> x >> y >> z;
+        Point p(x,y,z);
+        Dt.insert(p);
+    }
+    rInfo("Delaunay triangulation computed");
+ 
+    // Set up the alpha shape filtration
+    typedef     std::vector<AlphaSimplex3D>     AlphaSimplex3DVector;
+    AlphaSimplex3DVector complex;
+    fill_complex(Dt, complex);
+    rInfo("Simplices: %d", complex.size());
+    std::sort(complex.begin(), complex.end(), AlphaSimplex3D::AlphaOrder());
+ 
+    Timer persistence_timer; persistence_timer.start();
+    std::map<AlphaSimplex3D, Index, AlphaSimplex3D::VertexComparison>       complex_map;
+    Persistence             p;
+    boost::progress_display show_progress(complex.size());
+
+    #ifdef COUNTERS
+    Counter::CounterType    max_element_count = 0;
+    #endif
+    
+    for(AlphaSimplex3DVector::const_iterator cur = complex.begin(); cur != complex.end(); ++cur)
+    {
+        const AlphaSimplex3D& s = *cur;
+        std::vector<Index>      boundary;
+        for (AlphaSimplex3D::BoundaryIterator bcur  = s.boundary_begin(); bcur != s.boundary_end(); ++bcur)
+            boundary.push_back(complex_map[*bcur]);
+        
+        Index idx; Death d; CocyclePtr ccl;
+        bool store = s.dimension() < 3;
+        boost::tie(idx, d, ccl)     = p.add(boundary.begin(), boundary.end(), boost::make_tuple(s.dimension(), s.value()), store);
+        
+        // c[*cur] = idx;
+        if (store)
+            complex_map[s] = idx;
+
+        if (d && (s.value() - d->get<1>()) > 0)
+        {
+            AssertMsg(d->get<0>() == s.dimension() - 1, "Dimensions must match");
+            diagram_out << (s.dimension() - 1) << " " << d->get<1>() << " " << s.value() << std::endl;
+        }
+        ++show_progress;
+        
+        #ifdef COUNTERS
+        max_element_count = std::max(max_element_count, cCohomologyElementCount->count);
+        #endif
+    }
+    // output infinte persistence pairs 
+    for (Persistence::CocycleIndex cur = p.begin(); cur != p.end(); ++cur)
+        diagram_out << cur->birth.get<0>() << " " << cur->birth.get<1>() << " inf" << std::endl;
+    persistence_timer.stop();
+    
+    total_timer.stop();
+    persistence_timer.check("Persistence timer");
+    total_timer.check("Total timer");
+
+    #ifdef COUNTERS
+    std::cout << "Max element count: " << max_element_count << std::endl;
+    #endif
+}
--- a/examples/alphashapes/alphashapes3d.cpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/alphashapes/alphashapes3d.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,38 +1,106 @@
-#include <utilities/sys.h>
-#include <utilities/debug.h>
+#include <utilities/log.h>
+#include <utilities/timer.h>
 
 #include "alphashapes3d.h"
 #include <topology/filtration.h>
+#include <topology/static-persistence.h>
+#include <topology/persistence-diagram.h>
 #include <iostream>
+
 #include <fstream>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/serialization/map.hpp>
+
+#include <boost/program_options.hpp>
 
 
-typedef Filtration<AlphaSimplex3D>				AlphaFiltration;
+typedef Filtration<AlphaSimplex3D>              AlphaFiltration;
+typedef StaticPersistence<>                     Persistence;
+typedef PersistenceDiagram<>                    PDgm;
+
+namespace po = boost::program_options;
 
 int main(int argc, char** argv) 
 {
-	// Read in the point set and compute its Delaunay triangulation
-	std::istream& in = std::cin;
-	double x,y,z;
-	Delaunay Dt;
-	while(in)
-	{
-		in >> x >> y >> z;
-		Point p(x,y,z);
-		Dt.insert(p);
-	}
-	std::cout << "Delaunay triangulation computed" << std::endl;
+#ifdef LOGGING
+    rlog::RLogInit(argc, argv);
+
+    stdoutLog.subscribeTo( RLOG_CHANNEL("info") );
+    stdoutLog.subscribeTo( RLOG_CHANNEL("error") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/persistence") );
+    //stdoutLog.subscribeTo( RLOG_CHANNEL("topology/chain") );
+#endif
+
+    // SetFrequency(GetCounter("persistence/pair"), 10000);
+    // SetTrigger(GetCounter("persistence/pair"), GetCounter(""));
+
+    std::string     infilename, outfilename;
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+        ("input-file",   po::value<std::string>(&infilename),     "Point set whose alpha shape filtration and persistence we want to compute")
+        ("output-file",  po::value<std::string>(&outfilename),    "Where to write the collection of persistence diagrams");
+
+    po::positional_options_description pos;
+    pos.add("input-file", 1);
+    pos.add("output-file", 2);
+    
+    po::options_description all; all.add(hidden);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(argc, argv).
+                  options(all).positional(pos).run(), vm);
+    po::notify(vm);
+
+    if (!vm.count("input-file") || !vm.count("output-file"))
+    { 
+        std::cout << "Usage: " << argv[0] << " input-file output-file" << std::endl;
+        std::cout << hidden << std::endl; 
+        return 1; 
+    }
+
+
+    // Read in the point set and compute its Delaunay triangulation
+    std::ifstream in(infilename.c_str());
+    double x,y,z;
+    Delaunay3D Dt;
+    while(in)
+    {
+        in >> x >> y >> z;
+        Point p(x,y,z);
+        Dt.insert(p);
+    }
+    rInfo("Delaunay triangulation computed");
    
-	AlphaSimplex3DVector alpha_ordering;
-	fill_alpha_order(Dt, alpha_ordering);
-	std::cout << "Simplices: " << alpha_ordering.size() << std::endl;
+    AlphaFiltration  af;
+    fill_complex(Dt, af);
+    rInfo("Simplices: %d", af.size());
+
+    // Create the alpha-shape filtration
+    af.sort(AlphaSimplex3D::AlphaOrder());
+    rInfo("Filtration initialized");
+    
+    Persistence p(af);
+    rInfo("Persistence initializaed");
 
-	// Create the alpha-shape filtration
-	AlphaFiltration af;
-	for (AlphaSimplex3DVector::const_iterator cur = alpha_ordering.begin(); cur != alpha_ordering.end(); ++cur)
-		af.append(*cur);
-	af.fill_simplex_index_map();
-	af.pair_simplices(af.begin(), af.end());
-	std::cout << "Simplices paired" << std::endl;
+    Timer persistence_timer; persistence_timer.start();
+    p.pair_simplices();
+    persistence_timer.stop();
+    rInfo("Simplices paired");
+    persistence_timer.check("Persistence timer");
+
+    Persistence::SimplexMap<AlphaFiltration>    m       = p.make_simplex_map(af);
+    std::map<Dimension, PDgm> dgms;
+    init_diagrams(dgms, p.begin(), p.end(), 
+                  evaluate_through_map(m, AlphaSimplex3D::AlphaValueEvaluator()), 
+                  evaluate_through_map(m, AlphaSimplex3D::DimensionExtractor()));
+#if 0
+    std::cout << 0 << std::endl << dgms[0] << std::endl;
+    std::cout << 1 << std::endl << dgms[1] << std::endl;
+    std::cout << 2 << std::endl << dgms[2] << std::endl;
+#endif
+
+    std::ofstream ofs(outfilename.c_str());
+    boost::archive::binary_oarchive oa(ofs);
+    oa << dgms;
 }
-
--- a/examples/alphashapes/alphashapes3d.h	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/alphashapes/alphashapes3d.h	Tue Jun 27 09:37:05 2017 -0700
@@ -18,30 +18,25 @@
 
 struct K: CGAL::Exact_predicates_exact_constructions_kernel {};
 
-typedef CGAL::Delaunay_triangulation_3<K>    		Delaunay;
-typedef Delaunay::Point                				Point;
-typedef Delaunay::Vertex            				Vertex;
-typedef Delaunay::Vertex_handle            			Vertex_handle;
-typedef Delaunay::Edge								Edge;
-typedef Delaunay::Facet								Facet;
-typedef Delaunay::Cell								Cell;
-typedef Delaunay::Cell_handle						Cell_handle;
-typedef K::FT										RealValue;
+typedef CGAL::Delaunay_triangulation_3<K>           Delaunay3D;
+typedef Delaunay3D::Point                           Point;
+typedef Delaunay3D::Vertex_handle                   Vertex_handle;
+typedef Delaunay3D::Cell_handle                     Cell_handle;
+typedef K::FT                                       RealValue;
 
-typedef Delaunay::Finite_vertices_iterator    		Vertex_iterator;
-typedef Delaunay::Finite_edges_iterator        		Edge_iterator;
-typedef Delaunay::Finite_facets_iterator        	Facet_iterator;
-typedef Delaunay::Finite_cells_iterator        		Cell_iterator;
-typedef Delaunay::Facet_circulator					Facet_circulator;
+typedef Delaunay3D::Finite_vertices_iterator        Vertex_iterator;
+typedef Delaunay3D::Finite_edges_iterator           Edge_iterator;
+typedef Delaunay3D::Finite_facets_iterator          Facet_iterator;
+typedef Delaunay3D::Finite_cells_iterator           Cell_iterator;
+typedef Delaunay3D::Facet_circulator                Facet_circulator;
 
 
-class AlphaSimplex3D: public SimplexWithVertices<Vertex_handle>
+class AlphaSimplex3D: public Simplex<Vertex_handle>
 {
 	public:
-		typedef 	std::set<AlphaSimplex3D>							SimplexSet;
-		typedef		SimplexWithVertices<Vertex_handle>					Parent;
+		typedef		Simplex<Vertex_handle>					            Parent;
+		typedef 	std::set<AlphaSimplex3D, Parent::VertexComparison>  SimplexSet;
 		typedef		Parent::VertexContainer								VertexSet;
-		typedef		std::list<AlphaSimplex3D>							Cycle;
 
     public:
 									AlphaSimplex3D()					{}
@@ -49,25 +44,32 @@
 											Parent(p) 					{}
 									AlphaSimplex3D(const AlphaSimplex3D& s): 
 											Parent(s) 					{ attached_ = s.attached_; alpha_ = s.alpha_; }
-	    							AlphaSimplex3D(const ::Vertex& v);
+	    							AlphaSimplex3D(const Delaunay3D::Vertex& v);
 		
-								    AlphaSimplex3D(const Edge& e);
-								    AlphaSimplex3D(const Edge& e, const SimplexSet& simplices, Facet_circulator facet_bg);
+								    AlphaSimplex3D(const Delaunay3D::Edge& e);
+								    AlphaSimplex3D(const Delaunay3D::Edge& e, const SimplexSet& simplices, const Delaunay3D& Dt, Facet_circulator facet_bg);
 		
-								    AlphaSimplex3D(const Facet& f);
-								    AlphaSimplex3D(const Facet& f, const SimplexSet& simplices);
+								    AlphaSimplex3D(const Delaunay3D::Facet& f);
+								    AlphaSimplex3D(const Delaunay3D::Facet& f, const SimplexSet& simplices, const Delaunay3D& Dt);
 	    
-									AlphaSimplex3D(const Cell& c);
+									AlphaSimplex3D(const Delaunay3D::Cell& c);
 	    
 		RealType					value() const						{ return CGAL::to_double(alpha_); }
 		RealValue					alpha() const						{ return alpha_; }
 		bool						attached() const					{ return attached_; }
-		Cycle						boundary() const;
 
 		// Ordering
 		struct AlphaOrder
 		{ bool operator()(const AlphaSimplex3D& first, const AlphaSimplex3D& second) const; };
-		
+	
+        struct AlphaValueEvaluator
+        { 
+            typedef                 AlphaSimplex3D                                  first_argument_type;
+            typedef                 RealType                                        result_type;
+
+            RealType                operator()(const AlphaSimplex3D& s) const       { return s.value(); }
+        };
+
 		std::ostream& 				operator<<(std::ostream& out) const;
 		
 	private:
@@ -75,9 +77,9 @@
 		bool 						attached_;
 };
 
-typedef 			std::vector<AlphaSimplex3D>								AlphaSimplex3DVector;
-void 				fill_alpha_order(const Delaunay& Dt, 
-									 AlphaSimplex3DVector& alpha_order);
+void 				fill_simplex_set(const Delaunay3D& Dt, AlphaSimplex3D::SimplexSet& simplices);
+template<class Filtration>
+void 				fill_complex(const Delaunay3D& Dt,     Filtration& filtration);
 
 std::ostream& 		operator<<(std::ostream& out, const AlphaSimplex3D& s)	{ return s.operator<<(out); }
 
--- a/examples/alphashapes/alphashapes3d.hpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/alphashapes/alphashapes3d.hpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,182 +1,171 @@
-AlphaSimplex3D::	    
-AlphaSimplex3D(const ::Vertex& v): alpha_(0), attached_(false)
+#include <utilities/log.h>
+#include <boost/foreach.hpp>
+
+AlphaSimplex3D::
+AlphaSimplex3D(const Delaunay3D::Vertex& v): alpha_(0), attached_(false)
 {
-	for (int i = 0; i < 4; ++i)
-		if (v.cell()->vertex(i)->point() == v.point())
-			Parent::add(v.cell()->vertex(i));
+    for (int i = 0; i < 4; ++i)
+        if (v.cell()->vertex(i)->point() == v.point())
+            Parent::add(v.cell()->vertex(i));
 }
 
-AlphaSimplex3D::	    
-AlphaSimplex3D(const Edge& e)
+AlphaSimplex3D::
+AlphaSimplex3D(const Delaunay3D::Edge& e)
 {
     Cell_handle c = e.first;
-	Parent::add(c->vertex(e.second));
-	Parent::add(c->vertex(e.third));
+    Parent::add(c->vertex(e.second));
+    Parent::add(c->vertex(e.third));
 }
 
-AlphaSimplex3D::	    
-AlphaSimplex3D(const Edge& e, const SimplexSet& simplices, Facet_circulator facet_bg)
+AlphaSimplex3D::
+AlphaSimplex3D(const Delaunay3D::Edge& e, const SimplexSet& simplices, const Delaunay3D& Dt, Facet_circulator facet_bg)
 {
     Cell_handle c = e.first;
-	Parent::add(c->vertex(e.second));
-	Parent::add(c->vertex(e.third));
+    Parent::add(c->vertex(e.second));
+    Parent::add(c->vertex(e.third));
 
-	Facet_circulator cur = facet_bg;
-	SimplexSet::const_iterator cur_iter = simplices.find(AlphaSimplex3D(*cur));
-	while (cur_iter == simplices.end())
-	{
-		++cur; 
-		cur_iter = simplices.find(AlphaSimplex3D(*cur));
-	}
-	RealValue min = cur_iter->alpha();
-	
-	VertexSet::const_iterator v = Parent::vertices().begin();
-	const Point& p1 = (*v++)->point();
-	const Point& p2 = (*v)->point();
-	attached_ = false;
+    Facet_circulator cur = facet_bg;
+    while (Dt.is_infinite(*cur))    ++cur;
+    SimplexSet::const_iterator cur_iter = simplices.find(AlphaSimplex3D(*cur));
+    RealValue min = cur_iter->alpha();
+
+    const VertexSet& vertices = static_cast<const Parent*>(this)->vertices();
+    VertexSet::const_iterator v = vertices.begin();
+    const Point& p1 = (*v++)->point();
+    const Point& p2 = (*v)->point();
+    attached_ = false;
 
-	if (facet_bg != 0) do
-	{
-		VertexSet::const_iterator v = Parent::vertices().begin();
-		int i0 = (*cur).first->index(*v++);
-		int i1 = (*cur).first->index(*v);
-		int i = 6 - i0 - i1 - (*cur).second;
-		Point p3 = (*cur).first->vertex(i)->point();
+    if (facet_bg != 0) do
+    {
+        VertexSet::const_iterator v = vertices.begin();
+        int i0 = (*cur).first->index(*v++);
+        int i1 = (*cur).first->index(*v);
+        int i = 6 - i0 - i1 - (*cur).second;
+        if (Dt.is_infinite(cur->first->vertex(i))) { ++cur; continue; }
+        Point p3 = (*cur).first->vertex(i)->point();
 
-		cur_iter = simplices.find(AlphaSimplex3D(*cur));
-		if (cur_iter == simplices.end())			// cur is infinite
-		{
-			++cur; continue;
-		}
-		
-		if (CGAL::side_of_bounded_sphere(p1, p2, p3) == CGAL::ON_BOUNDED_SIDE)
-			attached_ = true;
-		RealValue val = cur_iter->alpha();
-		if (val < min)
-			min = val;
-		++cur;
-	} while (cur != facet_bg);
+        cur_iter = simplices.find(AlphaSimplex3D(*cur));
+        if (CGAL::side_of_bounded_sphere(p1, p2, p3) == CGAL::ON_BOUNDED_SIDE)
+            attached_ = true;
+        RealValue val = cur_iter->alpha();
+        if (val < min)
+            min = val;
+        ++cur;
+    } while (cur != facet_bg);
 
-	if (attached_)
-		alpha_ = min;
-	else
-		alpha_ = CGAL::squared_radius(p1, p2);
+    if (attached_)
+        alpha_ = min;
+    else
+        alpha_ = CGAL::squared_radius(p1, p2);
 }
 
-AlphaSimplex3D::	    
-AlphaSimplex3D(const Facet& f)
+AlphaSimplex3D::
+AlphaSimplex3D(const Delaunay3D::Facet& f)
 {
     Cell_handle c = f.first;
-	for (int i = 0; i < 4; ++i)
-		if (i != f.second)
-			Parent::add(c->vertex(i));
+    for (int i = 0; i < 4; ++i)
+        if (i != f.second)
+            Parent::add(c->vertex(i));
 }
 
-AlphaSimplex3D::	    
-AlphaSimplex3D(const Facet& f, const SimplexSet& simplices)
+AlphaSimplex3D::
+AlphaSimplex3D(const Delaunay3D::Facet& f, const SimplexSet& simplices, const Delaunay3D& Dt)
 {
     Cell_handle c = f.first;
-	for (int i = 0; i < 4; ++i)
-		if (i != f.second)
-			Parent::add(c->vertex(i));
+    for (int i = 0; i < 4; ++i)
+        if (i != f.second)
+            Parent::add(c->vertex(i));
 
-	Cell_handle o = c->neighbor(f.second);
-	int oi = o->index(c);
+    Cell_handle o = c->neighbor(f.second);
+    int oi = o->index(c);
+
+    VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin();
+    const Point& p1 = (*v++)->point();
+    const Point& p2 = (*v++)->point();
+    const Point& p3 = (*v)->point();
 
-	VertexSet::const_iterator v = Parent::vertices().begin();
-	const Point& p1 = (*v++)->point();
-	const Point& p2 = (*v++)->point();
-	const Point& p3 = (*v)->point();
-	
-	attached_ = false;
-	if (CGAL::side_of_bounded_sphere(p1, p2, p3,
-									 c->vertex(f.second)->point()) == CGAL::ON_BOUNDED_SIDE)
-		attached_ = true;
-	else if (CGAL::side_of_bounded_sphere(p1, p2, p3,
-										  o->vertex(oi)->point()) == CGAL::ON_BOUNDED_SIDE)
-		attached_ = true;
-	else
-		alpha_ = squared_radius(p1, p2, p3);
-	
-	if (attached_)
-	{
-		SimplexSet::const_iterator c_iter = simplices.find(AlphaSimplex3D(*c));
-		SimplexSet::const_iterator o_iter = simplices.find(AlphaSimplex3D(*o));
-		if (c_iter == simplices.end())			// c is infinite
-			alpha_ = o_iter->alpha();
-		else if (o_iter == simplices.end())		// o is infinite
-			alpha_ = c_iter->alpha();
-		else
-			alpha_ = std::min(c_iter->alpha(), o_iter->alpha());
-	}
+    attached_ = false;
+    if (!Dt.is_infinite(c->vertex(f.second)) &&
+        CGAL::side_of_bounded_sphere(p1, p2, p3,
+                                     c->vertex(f.second)->point()) == CGAL::ON_BOUNDED_SIDE)
+        attached_ = true;
+    else if (!Dt.is_infinite(o->vertex(oi)) &&
+             CGAL::side_of_bounded_sphere(p1, p2, p3,
+                                          o->vertex(oi)->point()) == CGAL::ON_BOUNDED_SIDE)
+        attached_ = true;
+    else
+        alpha_ = CGAL::squared_radius(p1, p2, p3);
+
+    if (attached_)
+    {
+        if (Dt.is_infinite(c))
+            alpha_ = simplices.find(AlphaSimplex3D(*o))->alpha();
+        else if (Dt.is_infinite(o))
+            alpha_ = simplices.find(AlphaSimplex3D(*c))->alpha();
+        else
+            alpha_ = std::min(simplices.find(AlphaSimplex3D(*c))->alpha(),
+                              simplices.find(AlphaSimplex3D(*o))->alpha());
+    }
 }
 
-AlphaSimplex3D::	    
-AlphaSimplex3D(const Cell& c): attached_(false)
+AlphaSimplex3D::
+AlphaSimplex3D(const Delaunay3D::Cell& c): attached_(false)
 {
-	for (int i = 0; i < 4; ++i)
-		Parent::add(c.vertex(i));
-	VertexSet::const_iterator v = Parent::vertices().begin();
-	Point p1 = (*v++)->point();
-	Point p2 = (*v++)->point();
-	Point p3 = (*v++)->point();
-	Point p4 = (*v)->point();
-	alpha_ = CGAL::squared_radius(p1, p2, p3, p4);
-}
-
-AlphaSimplex3D::Cycle
-AlphaSimplex3D::boundary() const
-{
-	Cycle bdry;
-	Parent::Cycle pbdry = Parent::boundary();
-	for (Parent::Cycle::const_iterator cur = pbdry.begin(); cur != pbdry.end(); ++cur)
-		bdry.push_back(*cur);
-	return bdry;
+    for (int i = 0; i < 4; ++i)
+        Parent::add(c.vertex(i));
+    VertexSet::const_iterator v = static_cast<const Parent*>(this)->vertices().begin();
+    Point p1 = (*v++)->point();
+    Point p2 = (*v++)->point();
+    Point p3 = (*v++)->point();
+    Point p4 = (*v)->point();
+    alpha_ = CGAL::squared_radius(p1, p2, p3, p4);
 }
 
 
-bool 
+bool
 AlphaSimplex3D::AlphaOrder::
 operator()(const AlphaSimplex3D& first, const AlphaSimplex3D& second) const
 {
-	if (first.alpha() == second.alpha())
-		return (first.dimension() < second.dimension());
-	else
-		return (first.alpha() < second.alpha()); 
+    if (first.alpha() == second.alpha())
+        return (first.dimension() < second.dimension());
+    else
+        return (first.alpha() < second.alpha());
 }
 
-std::ostream& 
+std::ostream&
 AlphaSimplex3D::
 operator<<(std::ostream& out) const
 {
-	for (VertexSet::const_iterator cur = Parent::vertices().begin(); cur != Parent::vertices().end(); ++cur)
-		out << **cur << ", ";
-	out << "value = " << value();
+    for (VertexSet::const_iterator cur = Parent::vertices().begin(); cur != Parent::vertices().end(); ++cur)
+        out << **cur << ", ";
+    out << "value = " << value();
 
-	return out;
+    return out;
 }
 
-
-void fill_alpha_order(const Delaunay& Dt, AlphaSimplex3DVector& alpha_order)
+void fill_simplex_set(const Delaunay3D& Dt, AlphaSimplex3D::SimplexSet& simplices)
 {
-	// Compute all simplices with their alpha values and attachment information
-	AlphaSimplex3D::SimplexSet simplices;
-	for(Cell_iterator cur = Dt.finite_cells_begin(); cur != Dt.finite_cells_end(); ++cur)
-		simplices.insert(AlphaSimplex3D(*cur));
-	std::cout << "Cells inserted" << std::endl;
-	for(Facet_iterator cur = Dt.finite_facets_begin(); cur != Dt.finite_facets_end(); ++cur)
-		simplices.insert(AlphaSimplex3D(*cur, simplices));
-	std::cout << "Facets inserted" << std::endl;
-	for(Edge_iterator cur = Dt.finite_edges_begin(); cur != Dt.finite_edges_end(); ++cur)
-		simplices.insert(AlphaSimplex3D(*cur, simplices, Dt.incident_facets(*cur)));
-	std::cout << "Edges inserted" << std::endl;
-	for(Vertex_iterator cur = Dt.finite_vertices_begin(); cur != Dt.finite_vertices_end(); ++cur)
-		simplices.insert(AlphaSimplex3D(*cur));
-	std::cout << "Vertices inserted" << std::endl;
-    
-	// Sort simplices by their alpha values
-	alpha_order.resize(simplices.size());
-	std::copy(simplices.begin(), simplices.end(), alpha_order.begin());
-	std::sort(alpha_order.begin(), alpha_order.end(), AlphaSimplex3D::AlphaOrder());
+    // Compute all simplices with their alpha values and attachment information
+    for(Cell_iterator cur = Dt.finite_cells_begin(); cur != Dt.finite_cells_end(); ++cur)
+        simplices.insert(AlphaSimplex3D(*cur));
+    rInfo("Cells inserted");
+    for(Facet_iterator cur = Dt.finite_facets_begin(); cur != Dt.finite_facets_end(); ++cur)
+        simplices.insert(AlphaSimplex3D(*cur, simplices, Dt));
+    rInfo("Facets inserted");
+    for(Edge_iterator cur = Dt.finite_edges_begin(); cur != Dt.finite_edges_end(); ++cur)
+        simplices.insert(AlphaSimplex3D(*cur, simplices, Dt, Dt.incident_facets(*cur)));
+    rInfo("Edges inserted");
+    for(Vertex_iterator cur = Dt.finite_vertices_begin(); cur != Dt.finite_vertices_end(); ++cur)
+        simplices.insert(AlphaSimplex3D(*cur));
+    rInfo("Vertices inserted");
 }
 
+template<class Filtration>
+void fill_complex(const Delaunay3D& Dt, Filtration& filtration)
+{
+    AlphaSimplex3D::SimplexSet simplices;
+    fill_simplex_set(Dt, simplices);
+    BOOST_FOREACH(const AlphaSimplex3D& s, simplices)
+        filtration.push_back(s);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/alphashapes/compare-diagrams.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,56 @@
+#include <utilities/types.h>
+#include <topology/persistence-diagram.h>
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/map.hpp>
+
+#include <boost/program_options.hpp>
+
+
+typedef PersistenceDiagram<>                    PDgm;
+
+namespace po = boost::program_options;
+
+
+int main(int argc, char* argv[])
+{
+    std::string     filename1, filename2;
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+        ("input-file1",  po::value<std::string>(&filename1), "The first collection of persistence diagrams")
+        ("input-file2",  po::value<std::string>(&filename2), "The second collection of persistence diagrams");
+
+    po::positional_options_description p;
+    p.add("input-file1", 1);
+    p.add("input-file2", 2);
+    
+    po::options_description all; all.add(hidden);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(argc, argv).
+                  options(all).positional(p).run(), vm);
+    po::notify(vm);
+
+    if (!vm.count("input-file1") || !vm.count("input-file2"))
+    { 
+        std::cout << "Usage: " << argv[0] << " input-file1 input-file2" << std::endl;
+        std::cout << hidden << std::endl; 
+        return 1; 
+    }
+
+    std::ifstream ifs1(filename1.c_str()), ifs2(filename2.c_str());
+    boost::archive::binary_iarchive ia1(ifs1), ia2(ifs2);
+
+    std::map<Dimension, PDgm>       dgms1, dgms2;
+
+    ia1 >> dgms1;
+    ia2 >> dgms2;
+
+    std::cout << "Distance between dimension 0: " << bottleneck_distance(dgms1[0], dgms2[0]) << std::endl;
+    std::cout << "Distance between dimension 1: " << bottleneck_distance(dgms1[1], dgms2[1]) << std::endl;
+    std::cout << "Distance between dimension 2: " << bottleneck_distance(dgms1[2], dgms2[2]) << std::endl;
+}
--- a/examples/ar-vineyard/CMakeLists.txt	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/ar-vineyard/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -1,7 +1,10 @@
 set							(targets						
 							 ar-vineyard)
-							 
+	
+add_definitions				(${cgal_cxxflags})
 foreach 					(t ${targets})
 	add_executable			(${t} ${t}.cpp ${external_sources})
-	target_link_libraries	(${t} ${libraries} ${cgal_libraries} ${synaps_libraries})
+	target_link_libraries	(${t}   ${libraries} ${cgal_library} ${CGAL_3RD_PARTY_LIBRARIES} 
+                                    ${Boost_SIGNALS_LIBRARY} 
+                                    ${Boost_PROGRAM_OPTIONS_LIBRARY})
 endforeach 					(t)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/ar-vineyard/ar-function-kernel.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,80 @@
+#ifndef __AR_FUNCTION_KERNEL_H__
+#define __AR_FUNCTION_KERNEL_H__
+
+
+#include <stack>
+#include <iostream>
+#include "ar-simplex3d.h"
+
+
+
+/**
+ * Represents function suitable for the FunctionKernel. Albeit very restrictive 
+ * (it only supports subtraction), although that should suffice for KineticSort.
+ */
+class ARFunction
+{
+    public:
+        /// Represents the three forms of the involved functions. See Appendix B of LHI paper.
+        enum                        FunctionForm                                        { none, rho, lambda, phi };
+
+    public:
+                                    ARFunction(FunctionForm f, ARSimplex3D* s): 
+                                        form_(f), form2_(none),
+                                        simplex_(s), simplex2_(0)                       {}
+                                    ARFunction(const ARFunction& other):
+                                        form_(other.form_), form2_(other.form2_),
+                                        simplex_(other.simplex_), 
+                                        simplex2_(other.simplex2_)                      {}
+
+        ARFunction&                 operator-=(const ARFunction& other)                 { form2_ = other.form_; simplex2_ = other.simplex_; return *this; }
+        ARFunction                  operator-(const ARFunction& other)                  { return (ARFunction(*this) -= other); }
+
+        FunctionForm                form() const                                        { return form_; }
+        FunctionForm                form2() const                                       { return form2_; }
+        ARSimplex3D*                simplex() const                                     { return simplex_; }
+        ARSimplex3D*                simplex2() const                                    { return simplex2_; }
+
+        std::ostream&               operator<<(std::ostream& out) const                 { return (out << "(" << form_ << ", " << simplex_ << "), (" 
+                                                                                                             << form2_ << ", " << simplex2_ << ")"); }
+
+    private:
+        FunctionForm                form_, form2_;      // the function is form_ - form2_
+        ARSimplex3D                 *simplex_, *simplex2_;
+};
+
+std::ostream&
+operator<<(std::ostream& out, const ARFunction& f)
+{ return f.operator<<(out); }
+
+/**
+ * Function kernel specialized at solving the kinds of functions involved in 
+ * ARVineyard construction. We cannot use a polynomial kernel (which includes 
+ * rational functions) that we already have because not all involved functions
+ * are rational.
+ */
+class ARFunctionKernel
+{
+    public:
+        typedef                     double                                              FieldType;
+        typedef                     FieldType                                           RootType;
+        typedef                     std::stack<RootType>                                RootStack;
+        typedef                     ARSimplex3D::RealValue                              SimplexFieldType;
+
+        typedef                     ARFunction                                          Function;
+        typedef                     Function::FunctionForm                              FunctionForm;
+    
+    public:
+        static void                 solve(const Function& f, RootStack& stack);
+        static RootType             root(RootType r)                                    { return r; }
+        static RootType             root(SimplexFieldType r)                            { return CGAL::to_double(r); }
+        static int                  sign_at(const Function& f, RootType r);
+        static RootType             between(RootType r1, RootType r2)                   { return (r1 + r2)/2; }
+        static int                  sign_at_negative_infinity(const Function& f);
+
+        static FieldType            value_at(const Function& f, RootType v);
+};
+
+#include "ar-function-kernel.hpp"
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/ar-vineyard/ar-function-kernel.hpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,144 @@
+#include <utilities/log.h>
+#include <cmath>
+
+#if LOGGING
+static rlog::RLogChannel* rlARFunctionKernel =                      DEF_CHANNEL("ar/function-kernel", rlog::Log_Debug);
+static rlog::RLogChannel* rlARFunctionKernelValue =                 DEF_CHANNEL("ar/function-kernel/value", rlog::Log_Debug);
+#endif
+
+
+/* For now only rho and phi are implemented */
+void
+ARFunctionKernel::
+solve(const Function& f, RootStack& stack)
+{
+    AssertMsg(stack.empty(), "Stack must be empty before solving");
+    AssertMsg((f.form() != Function::none) && (f.form2() != Function::none), "Solving possible only for differences");
+
+    FunctionForm f1 = f.form(), f2 = f.form2();
+    const ARSimplex3D   *s1 = f.simplex(), 
+                        *s2 = f.simplex2();
+    if (f1 < f2)    { std::swap(f1,f2); std::swap(s1,s2); }         // for simplicity enforce function order 
+                                                                    // to handle fewer cases explicitly
+    AssertMsg(f1 != Function::lambda && f2 != Function::lambda, "Lambda not implemented yet");
+
+    rLog(rlARFunctionKernel,    "Solve: function1 = (%i, %p), function2 = (%i, %p)",
+                                f1, s1, f2, s2);
+    
+    //if (f1 == Function::phi && f2 == Function::phi)         return;
+    //if (f1 == Function::rho && f2 == Function::rho)         return;
+
+    if (f1 == Function::phi && f2 == Function::rho)
+    {
+        SimplexFieldType r = s2->alpha() - s1->phi_const();
+        rLog(rlARFunctionKernel, "  phi = rho => r^2 = %s (%lf)", tostring(r).c_str(), root(r));
+        stack.push(root(r));
+    }
+
+    if (f1 == Function::phi && f2 == Function::lambda)
+    {
+        rLog(rlARFunctionKernel, "  phi = lambda");
+        SimplexFieldType r2 = (s2->rho() + s2->v() - s2->s() - s1->phi_const());
+        r2 *= r2;
+        r2 /= 4*s2->v();
+        r2 += s2->s();
+        if (r2 >= s2->s() + s2->v())
+            stack.push(root(r2));
+
+        SimplexFieldType r1 = s2->rho() - s1->phi_const();
+        if (r1 <= s2->s() + s2->v())
+            stack.push(root(r1));
+    }
+    
+    // FIXME: this is far from complete!
+    if (f1 == Function::lambda && f2 == Function::lambda)
+    {
+        rLog(rlARFunctionKernel, "  lambda = lambda");
+        if ((s1->s() + s1->v() < s2->s() + s2->v()))                // let f1 be the function with larger break point
+        {   std::swap(f1,f2); std::swap(s1,s2); }
+
+        if (s1->rho() > s2->rho())
+        {
+            RootType r = root(s2->s() + s2->v() + s1->rho() - s2->rho()) + 2*sqrt(root(s2->v()*(s1->rho() - s2->rho())));
+            if (r < root(s1->s() + s1->v()) && r > root(s2->s() + s2->v()))
+                stack.push(r);
+        }
+    }
+
+    if (f1 == Function::lambda && f2 == Function::rho)
+    {
+        rLog(rlARFunctionKernel, "  lambda = rho");
+        // perhaps no solutions instead of an assertion is the right way to deal with this
+        AssertMsg(s2->alpha() > s1->rho(), "Rho_0^2 must be greater than Rho^2");
+
+        RootType r = sqrt(root(s2->v()*(s2->alpha() - s1->rho())));         // damn square roots
+        r *= 2;
+        r += root(s1->s() + s1->v() + s2->alpha() - s1->rho());
+    }
+    rLog(rlARFunctionKernel, "  Stack size: %i", stack.size());
+    if (stack.size() > 0) rLog(rlARFunctionKernel, "  Top: %lf", stack.top());
+}
+
+int
+ARFunctionKernel::
+sign_at(const Function& f, RootType r)
+{
+    FieldType v = value_at(f,r);
+    if (v > 0)  return true;
+    else        return false;
+}
+
+int
+ARFunctionKernel::
+sign_at_negative_infinity(const Function& f)
+{
+    FunctionForm f1 = f.form(), f2 = f.form2();
+    const ARSimplex3D   *s1 = f.simplex(), 
+                        *s2 = f.simplex2();
+    int multiplier = 1;
+    if (f1 < f2) { std::swap(f1, f2); std::swap(s1, s2); multiplier = -1; }
+    
+    AssertMsg(f1 != Function::lambda && f2 != Function::lambda, "Lambda not implemented yet");
+
+    if (f1 == Function::phi && f2 == Function::phi)
+    {
+        if (s1->phi_const() == s2->phi_const()) return  0;
+        if (s1->phi_const() > s2->phi_const())  return  1;        // multiplier must be 1
+        else                                    return -1;
+    }
+    
+    if (f1 == Function::phi && f2 == Function::rho)
+        return -multiplier;
+
+    if (f1 == Function::rho && f2 == Function::rho)
+    {
+        if (s1->alpha() == s2->alpha())         return  0;
+        if (s1->alpha() > s2->alpha())          return  1;        // multiplier must be 1
+        else                                    return -1;
+    }
+
+    AssertMsg(false, "The case analysis should be exhaustive in sign at -infinity");
+    return false;
+}
+        
+ARFunctionKernel::FieldType            
+ARFunctionKernel::
+value_at(const Function& f, RootType v)
+{
+    FunctionForm f1 = f.form(), f2 = f.form2();
+    ARSimplex3D     *s1 = f.simplex(), 
+                    *s2 = f.simplex2();
+
+    AssertMsg(f2 == Function::none && s2 == 0, "Value_at knows only about functions themselves, not their differences");
+    AssertMsg(f1 != Function::lambda, "Lambda not implemented yet");
+    rLog(rlARFunctionKernelValue,    "Value_at: function = (%i, %p)", f1, s1);
+
+    if (f1 == Function::phi)
+        return v + root(s1->phi_const());
+
+    if (f1 == Function::rho)
+        return root(s1->alpha());
+    
+    AssertMsg(false, "The case analysis should be exhaustive in value_at");
+    return 0;
+}
--- a/examples/ar-vineyard/ar-simplex3d.h	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/ar-vineyard/ar-simplex3d.h	Tue Jun 27 09:37:05 2017 -0700
@@ -28,7 +28,6 @@
 typedef Delaunay::Facet								Facet;
 typedef Delaunay::Cell								Cell;
 typedef Delaunay::Cell_handle						Cell_handle;
-typedef K::FT										RealValue;
 
 typedef Delaunay::Finite_vertices_iterator    		Vertex_iterator;
 typedef Delaunay::Finite_edges_iterator        		Edge_iterator;
@@ -40,6 +39,7 @@
 class ARSimplex3D: public SimplexWithVertices<Vertex_handle>
 {
 	public:
+        typedef     K::FT										        RealValue;
 		typedef 	std::map<ARSimplex3D, RealValue>					SimplexPhiMap;
 		typedef		SimplexWithVertices<Vertex_handle>					Parent;
 		typedef		Parent::VertexContainer								VertexSet;
@@ -56,10 +56,11 @@
 		
 								    ARSimplex3D(const Edge& e);
 								    ARSimplex3D(const Edge& e, const Point& z, SimplexPhiMap& simplices, 
-												Facet_circulator facet_bg);
+                                                const Delaunay& Dt, Facet_circulator facet_bg);
 		
 								    ARSimplex3D(const Facet& f);
-								    ARSimplex3D(const Facet& f, const Point& z, const SimplexPhiMap& simplices);
+								    ARSimplex3D(const Facet& f, const Point& z, const SimplexPhiMap& simplices,
+                                                const Delaunay& Dt);
 	    
 									ARSimplex3D(const Cell& c, const Point& z);
 	    
@@ -89,6 +90,8 @@
 		RealValue					phi_const_;	// see LHI paper, Appendices A and B
 		bool 						attached_;
 
+        // in paper's notation: s_ = v^2; v_ = d^2
+
 };
 
 typedef 			std::vector<ARSimplex3D>								ARSimplex3DVector;
--- a/examples/ar-vineyard/ar-simplex3d.hpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/ar-vineyard/ar-simplex3d.hpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,3 +1,9 @@
+#include <utilities/log.h>
+
+#if LOGGING
+static rlog::RLogChannel* rlARSimplex3D =                       DEF_CHANNEL("ar/simplex3d", rlog::Log_Debug);
+#endif
+
 ARSimplex3D::	    
 ARSimplex3D(const ARSimplex3D& s): Parent(s)
 { 
@@ -35,19 +41,15 @@
 }
 
 ARSimplex3D::	    
-ARSimplex3D(const Edge& e, const Point& z, SimplexPhiMap& simplices, Facet_circulator facet_bg)
+ARSimplex3D(const Edge& e, const Point& z, SimplexPhiMap& simplices, const Delaunay& Dt, Facet_circulator facet_bg)
 {
     Cell_handle c = e.first;
 	Parent::add(c->vertex(e.second));
 	Parent::add(c->vertex(e.third));
 
 	Facet_circulator cur = facet_bg;
+	while (Dt.is_infinite(*cur))    ++cur; 
 	SimplexPhiMap::const_iterator cur_iter = simplices.find(ARSimplex3D(*cur));
-	while (cur_iter == simplices.end())
-	{
-		++cur; 
-		cur_iter = simplices.find(ARSimplex3D(*cur));
-	}
 	RealValue min = cur_iter->first.alpha();
 	RealValue phi_const_min = cur_iter->first.phi_const();
 	
@@ -63,10 +65,8 @@
 		int i0 = (*cur).first->index(*v1);
 		int i1 = (*cur).first->index(*v2);
 		int i = 6 - i0 - i1 - (*cur).second;
-		Point p3 = (*cur).first->vertex(i)->point();
 
-		cur_iter = simplices.find(ARSimplex3D(*cur));
-		if (cur_iter == simplices.end())			// cur is infinite
+		if (Dt.is_infinite(cur->first->vertex(i)))
 		{
 			++cur; continue;
 			// FIXME: what do we do with infinite cofaces (i.e., what
@@ -74,9 +74,11 @@
 			// infinite?
 		}
 		
+		Point p3 = (*cur).first->vertex(i)->point();
 		if (CGAL::side_of_bounded_sphere(p1, p2, p3) == CGAL::ON_BOUNDED_SIDE)
 			attached_ = true;
 		
+	    SimplexPhiMap::const_iterator cur_iter = simplices.find(ARSimplex3D(*cur));
 		RealValue 								val 				= cur_iter->first.alpha();
 		if (val < min) 							min 				= val;
 		RealValue 								phi_const_val 		= cur_iter->first.phi_const();
@@ -99,7 +101,7 @@
 
 	
 	s_ = CGAL::squared_distance(z, K::Segment_3(p1,p2).supporting_line());
-	Point origin;
+	Point origin(0,0,0);
 	Point cc = origin + ((p1 - origin) + (p2 - origin))/2;		// CGAL is funny
 	v_ = CGAL::squared_distance(z, cc) - s_;
 }
@@ -114,7 +116,7 @@
 }
 
 ARSimplex3D::	    
-ARSimplex3D(const Facet& f, const Point& z, const SimplexPhiMap& simplices)
+ARSimplex3D(const Facet& f, const Point& z, const SimplexPhiMap& simplices, const Delaunay& Dt)
 {
     Cell_handle c = f.first;
 	for (int i = 0; i < 4; ++i)
@@ -133,29 +135,33 @@
 	rho_ = squared_radius(p1, p2, p3);
 	
 	attached_ = false;
-	if (CGAL::side_of_bounded_sphere(p1, p2, p3,
+	if (!Dt.is_infinite(c->vertex(f.second)) &&
+        CGAL::side_of_bounded_sphere(p1, p2, p3,
 									 c->vertex(f.second)->point()) == CGAL::ON_BOUNDED_SIDE)
 		attached_ = true;
-	else if (CGAL::side_of_bounded_sphere(p1, p2, p3,
+	else if (!Dt.is_infinite(o->vertex(oi)) &&
+             CGAL::side_of_bounded_sphere(p1, p2, p3,
 										  o->vertex(oi)->point()) == CGAL::ON_BOUNDED_SIDE)
 		attached_ = true;
 	else
 		alpha_ = rho_;
 	
-	SimplexPhiMap::const_iterator c_iter = simplices.find(ARSimplex3D(*c,z));
-	SimplexPhiMap::const_iterator o_iter = simplices.find(ARSimplex3D(*o,z));
-	if (c_iter == simplices.end())			// c is infinite
+	if (Dt.is_infinite(c))
 	{
+	    SimplexPhiMap::const_iterator o_iter = simplices.find(ARSimplex3D(*o,z));
 		if (attached_) alpha_ = o_iter->first.alpha();
 		phi_const_ = o_iter->first.phi_const();					// FIXME: it's probably the other way around
 	}
-	else if (o_iter == simplices.end())		// o is infinite
+	else if (Dt.is_infinite(o))
 	{
+	    SimplexPhiMap::const_iterator c_iter = simplices.find(ARSimplex3D(*c,z));
 		if (attached_) alpha_ = c_iter->first.alpha();
 		phi_const_ = c_iter->first.phi_const();					// FIXME: it's probably the other way around
 	}
 	else
 	{
+	    SimplexPhiMap::const_iterator o_iter = simplices.find(ARSimplex3D(*o,z));
+	    SimplexPhiMap::const_iterator c_iter = simplices.find(ARSimplex3D(*c,z));
 		if (attached_) alpha_ = std::min(c_iter->first.alpha(), o_iter->first.alpha());
 		phi_const_ = std::min(c_iter->first.phi_const(), o_iter->first.phi_const());
 	}
@@ -208,8 +214,9 @@
 ARSimplex3D::
 operator<<(std::ostream& out) const
 {
+    out << this << ": ";
 	for (VertexSet::const_iterator cur = Parent::vertices().begin(); cur != Parent::vertices().end(); ++cur)
-		out << **cur << ", ";
+		out << &(**cur) << ", ";
 	out << "value = " << value();
 
 	return out;
@@ -226,19 +233,19 @@
 	ARSimplex3D::SimplexPhiMap simplices;
 	for(Cell_iterator cur = Dt.finite_cells_begin(); cur != Dt.finite_cells_end(); ++cur)
 		update_simplex_phi_map(ARSimplex3D(*cur, z), simplices);
-	std::cout << "Cells inserted" << std::endl;
+	rLog(rlARSimplex3D, "Cells inserted");
 	for(Vertex_iterator cur = Dt.finite_vertices_begin(); cur != Dt.finite_vertices_end(); ++cur)
 		simplices[ARSimplex3D(*cur, z)] = 0;			// only one tetrahedron can have non-negative phi_const value 
 														// (namely the one containing z); all other simplices will have a 
 														// negative phi_const value, so 0 is safe
-	std::cout << "Vertices inserted" << std::endl;
+	rLog(rlARSimplex3D, "Vertices inserted");
 
 	for(Facet_iterator cur = Dt.finite_facets_begin(); cur != Dt.finite_facets_end(); ++cur)
-		update_simplex_phi_map(ARSimplex3D(*cur, z, simplices), simplices);
-	std::cout << "Facets inserted" << std::endl;
+		update_simplex_phi_map(ARSimplex3D(*cur, z, simplices, Dt), simplices);
+	rLog(rlARSimplex3D, "Facets inserted");
 	for(Edge_iterator cur = Dt.finite_edges_begin(); cur != Dt.finite_edges_end(); ++cur)
-		update_simplex_phi_map(ARSimplex3D(*cur, z, simplices, Dt.incident_facets(*cur)), simplices);
-	std::cout << "Edges inserted" << std::endl;
+		update_simplex_phi_map(ARSimplex3D(*cur, z, simplices, Dt, Dt.incident_facets(*cur)), simplices);
+	rLog(rlARSimplex3D, "Edges inserted");
     
 	// Sort simplices by their alpha values
 	alpha_order.resize(simplices.size()); ARSimplex3DVector::iterator out = alpha_order.begin();
--- a/examples/ar-vineyard/ar-vineyard.cpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/ar-vineyard/ar-vineyard.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,40 +1,80 @@
-#include <utilities/sys.h>
-#include <utilities/debug.h>
+#include <utilities/log.h>
 
 #include "ar-vineyard.h"
 
 #include <iostream>
 #include <fstream>
+#include <string>
+#include <vector>
+
+#include <boost/program_options.hpp>
+namespace po = boost::program_options;
 
 
 int main(int argc, char** argv) 
 {
-#ifdef CWDEBUG
-	Debug(dc::filtration.off());
-	Debug(dc::cycle.off());
-	Debug(dc::vineyard.off());
-	Debug(dc::transpositions.off());
-	Debug(dc::lsfiltration.off());
+#ifdef LOGGING
+	rlog::RLogInit(argc, argv);
+	stderrLog.subscribeTo( RLOG_CHANNEL("error") );
+#endif
+
+	std::string infilename;
+	double zx,zy,zz,r;
+	std::string outfilename;
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+        ("input-file",  po::value<std::string>(&infilename), "Points file")
+        ("x",  po::value<double>(&zx), "x")
+        ("y",  po::value<double>(&zy), "y")
+        ("z",  po::value<double>(&zz), "z")
+        ("r",  po::value<double>(&r), "r")
+        ("output-file",  po::value<std::string>(&outfilename), "Vineyard edges output");
 
-	dionysus::debug::init();
+    std::vector<std::string> log_channels;
+    po::options_description visible("Allowed options");
+    visible.add_options()
+        ("help,h",      "produce help message");
+#if LOGGING
+    visible.add_options()
+        ("log,l",       po::value< std::vector<std::string> >(&log_channels),
+                        "log channels to turn on");
+#endif
+    
+    po::positional_options_description p;
+    p.add("input-file", 1).add("x", 1).add("y", 1).add("z", 1).add("r", 1).add("output-file", 1);
+    
+    po::options_description all; all.add(visible).add(hidden);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(argc, argv).
+                  options(all).positional(p).run(), vm);
+    po::notify(vm);
+
+#if LOGGING
+    for (std::vector<std::string>::const_iterator cur = log_channels.begin(); cur != log_channels.end(); ++cur)
+        stdoutLog.subscribeTo( RLOG_CHANNEL(cur->c_str()) );
+    /* Interesting channels
+     * "ar/vineyard", "ar/function-kernel/value", "geometry/simulator",
+     * "topology/filtration", "topology/cycle", "topology/vineyard",
+     * "topology/filtration/transpositions", "topology/lowerstar"
+     */
 #endif
 
 	// Read command-line arguments
-	if (argc < 6)
+	if (vm.count("help") || !vm.count("input-file") || !vm.count("output-file") 
+                         || !vm.count("x") || !vm.count("y") || !vm.count("z") || !vm.count("r"))
 	{
-		std::cout << "Usage: ar-vineyard POINTS X Y Z OUTFILENAME" << std::endl;
+		std::cout << "Usage: ar-vineyard [OPTIONS] POINTS X Y Z R OUTFILENAME" << std::endl;
 		std::cout << "  POINTS       - filename containing points" << std::endl;
 		std::cout << "  X,Y,Z        - center-point z at which to compute the vineyard" << std::endl;
+		std::cout << "  R            - maximum radius" << std::endl;
 		std::cout << "  OUTFILENAME  - filename for the resulting vineyard" << std::endl;
+        std::cout << visible << std::endl;
 		std::cout << std::endl;
 		std::cout << "Computes an (alpha,r)-vineyard of the given pointset around the given point." << std::endl;
-		exit(0);
+		return 1;
 	}
-	std::string infilename = argv[1];
-	double zx,zy,zz; std::istringstream(argv[2]) >> zx;
-	std::istringstream(argv[3]) >> zy; std::istringstream(argv[4]) >> zz;
-	std::string outfilename = argv[5];
-	
 	
 	// Read in the point set and compute its Delaunay triangulation
 	std::ifstream in(infilename.c_str());
@@ -52,7 +92,7 @@
 	arv.compute_pairing();
 
 	// Compute vineyard
-	arv.compute_vineyard(true);
+	arv.compute_vineyard(r);
 	std::cout << "Vineyard computed" << std::endl;
 	arv.vineyard()->save_edges(outfilename);
 }
--- a/examples/ar-vineyard/ar-vineyard.h	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/ar-vineyard/ar-vineyard.h	Tue Jun 27 09:37:05 2017 -0700
@@ -6,84 +6,108 @@
 #ifndef __AR_VINEYARD_H__
 #define __AR_VINEYARD_H__
 
-#include "utilities/sys.h"
-#include "utilities/debug.h"
+#include <boost/signals.hpp>
+#include <boost/bind.hpp>
+#include <list>
+#include <vector>
 
 #include "topology/conesimplex.h"
 #include "topology/filtration.h"
 #include "geometry/kinetic-sort.h"
+#include "geometry/simulator.h"
 
-#include <list>
 #include "ar-simplex3d.h"
+#include "ar-function-kernel.h"
 
 
-class ARConeSimplex: public ConeSimplex<ARSimplex3D>
+template <class Simulator_>
+class ARConeSimplex3D: public ConeSimplex<ARSimplex3D>
 {
 	public:
 		typedef						ConeSimplex<ARSimplex3D>									Parent;
 		typedef						ARSimplex3D													ARSimplex3D;
-		typedef						Filtration<ARConeSimplex>									Filtration;
 		
-		/// \name Polynomial Kernel types
+		/// \name Simulator types
 		/// @{
-		typedef						double														FieldType;
-		typedef						UPolynomial<FieldType>										PolyKernel;
-		typedef						PolyKernel::Polynomial										Polynomial;
-		typedef						Simulator<PolyKernel>										Simulator;
+        typedef                     Simulator_                                                  Simulator;
+        typedef                     typename Simulator::FunctionKernel                          FunctionKernel;
+        typedef                     typename FunctionKernel::Function                           Function;
+        /// @}
 		
-		typedef						KineticSort<ARFiltration, SimplexTrajectoryExtractor, Simulator>
-																								SimplexSort;
-		typedef						SimplexSort::iterator										SimplexSortIterator;
-		typedef						SimplexSortIterator											Key;
+		/// \name ThresholdSort types
+		/// @{
+		typedef 					std::list<Function>										    ThresholdList;
+        typedef                     typename ThresholdList::iterator                            ThresholdListIterator;
+
+		struct 						ThresholdTrajectoryExtractor
+		{	Function                operator()(ThresholdListIterator i) const		            { return *i; } };
+
+		typedef						KineticSort<ThresholdListIterator, 
+                                                ThresholdTrajectoryExtractor, Simulator>		ThresholdSort;
 		/// @}
 
-		/// \name Kinetic Sort types
-		/// @{
-		typedef 					std::list<Polynomial>										ThresholdList;
-
-		struct 						ThresholdTrajectoryExtractor
-		{	Polynomial				operator()(ThresholdList::iterator i) const				{ return *i; } }
-		struct 						SimplexTrajectoryExtractor
-		{	Polynomial				operator()(ARFiltration::iterator i) const					{ i->thresholds().front(); }
+        typedef                     boost::signal<void (Simulator*)>                            NewMaxSignal;
+    
+    public:
+									ARConeSimplex3D(const ARSimplex3D& s, bool coned = false);
+									ARConeSimplex3D(const Parent& p): Parent(p)                 {}      // crucial for boundary() to work correctly
+									ARConeSimplex3D(const ARConeSimplex3D& other):              // need explicit copy-constructor because of the signal
+                                        Parent(other, other.coned()), 
+                                        thresholds_(other.thresholds_)                          {}
 
-		typedef						KineticSort<ThresholdList, ThresholdTrajectoryExtractor, Simulator>	
-																								ThresholdSort;
-		/// @}
+		const ThresholdList&        thresholds() const											{ return thresholds_; }
 
-									ARConeSimplex(const ARSimplex3D& s, bool coned = false): 
-										Parent(s, coned), 
-										thresholds_sort_(&thresholds_)							{}
+        NewMaxSignal&               new_max_signal()                                            { return new_max_signal_; }
+        const Function&             max_threshold() const                                       { return thresholds_.back(); }
+		void						schedule_thresholds(Simulator* simulator);
 
-		Key							kinetic_key() const											{ return key_; }
-		void						set_kinetic_key(Key k)										{ key_ = k; }
-		const ThresholdList&		thresholds() const											{ return thresholds_; }
-
-		void						schedule_thresholds(Simulator* simulator);
+        // need explicit operator= because of the signal
+        ARConeSimplex3D&            operator=(const ARConeSimplex3D& other)                     { Parent::operator=(other); thresholds_ = other.thresholds_; return *this; }
 
 								
 	private:
-		Key							key_;
 		ThresholdList				thresholds_;
 		ThresholdSort				thresholds_sort_;
+        NewMaxSignal                new_max_signal_;
 
-		void						swap_thresholds(ThresholdList* tl, typename ThresholdList::iterator i);
+		void						swap_thresholds(ThresholdListIterator i, Simulator* simulator);
 };
 
-
+/**
+ * Encapsulated filtration, and provides compute_vineyard() functionality.
+ */
 class ARVineyard
 {
 	public:
 		typedef						ARVineyard													Self;
+	
+        /// \name FunctionKernel and Simulator types
+        /// @{
+        typedef                     ARFunctionKernel                                            FunctionKernel;
+        typedef                     FunctionKernel::Function                                    Function;
+        typedef                     Simulator<FunctionKernel>                                   SimulatorAR;
+        /// @}
+
+        /// \name Filtration types
+        /// @{    
+        typedef                     ARConeSimplex3D<SimulatorAR>                                ConeSimplex3D;
+		typedef						Filtration<ConeSimplex3D>									FiltrationAR;
+		typedef						FiltrationAR::Simplex										Simplex;
+		typedef						FiltrationAR::Index											Index;
+		typedef						FiltrationAR::Vineyard										Vineyard;
+		typedef						Vineyard::Evaluator											Evaluator;
+        /// @}
 		
-		typedef						ARConeSimplex::Filtration									ARFiltration;	
-		typedef						ARFiltration::Simplex										Simplex;
-		typedef						ARFiltration::Index											Index;
-		typedef						ARFiltration::Vineyard										Vineyard;
-		typedef						Vineyard::Evaluator											Evaluator;
+        /// \name SimplexSort types
+        /// @{
+        struct 						SimplexTrajectoryExtractor
+		{	Function				operator()(Index i) const									{ return i->max_threshold(); } };
+
+		typedef						KineticSort<Index, SimplexTrajectoryExtractor, SimulatorAR> SimplexSort;
+		typedef						SimplexSort::iterator										SimplexSortIterator;
 		
-		typedef						ARConeSimplex::Simulator									Simulator;	
-		typedef						ARConeSimplex::SimplexSort									SimplexSort;	
-
+        class                       ThresholdChangeSlot;              // used to notify of change in max threshold
+		/// @}
 
 		typedef						std::list<Point>											PointList;
 
@@ -95,21 +119,20 @@
 									~ARVineyard();
 
 		void						compute_pairing();
-		void						compute_vineyard(bool explicit_events = false);
+		void						compute_vineyard(double max_radius);
 		
-		const ARFiltration*			filtration() const											{ return filtration_; }
+		const FiltrationAR*			filtration() const											{ return filtration_; }
 		const Vineyard*				vineyard() const											{ return vineyard_; }
 
 	public:
-		// For Kinetic Sort
-		static void 				swap(ARFiltration* filtration, Index i);
+		void 						swap(Index i, SimulatorAR* simulator);						///< For kinetic sort
 	
 	private:
 		void 						add_simplices();
 		void						change_evaluator(Evaluator* eval);
 
 	private:
-		ARFiltration*				filtration_;
+		FiltrationAR*				filtration_;
 		Vineyard*					vineyard_;
 		Evaluator*					evaluator_;
 
@@ -133,35 +156,58 @@
 
 //BOOST_CLASS_EXPORT(ARVineyard)
 
+#ifdef COUNTERS
+static Counter*  cARVineyardTrajectoryKnee =		 GetCounter("ar/vineyard/trajectoryknee");
+#endif
+
+class ARVineyard::ThresholdChangeSlot
+{   
+    public:
+                                ThresholdChangeSlot(SimplexSortIterator iter, SimplexSort* sort, 
+                                                    Vineyard* vineyard, SimulatorAR* sort_simulator):
+                                    iter_(iter), sort_(sort), vineyard_(vineyard), sort_simulator_(sort_simulator)      { iter_->element->new_max_signal().connect(*this); }
+        void                    operator()(SimulatorAR* simulator)                                
+        { 
+            Count(cARVineyardTrajectoryKnee); 
+            sort_->update_trajectory(iter_, sort_simulator_); 
+            if (iter_->element->sign()) 
+                vineyard_->record_knee(iter_->element);
+            else
+                vineyard_->record_knee(iter_->element->pair());
+        }
+    
+    private:
+        SimplexSortIterator     iter_;
+        SimplexSort*            sort_;              // could make both of these static
+        Vineyard*               vineyard_;          // currently inefficient since there is
+                                                    // only one SimplexSort and one Vineyard, 
+                                                    // but each is stored in every slot
+        SimulatorAR*              sort_simulator_;
+};
 
 class ARVineyard::StaticEvaluator: public Evaluator
 {
 	public:
-									StaticEvaluator(RealType t): time_(t)						{}
+									StaticEvaluator()                   						{}
 
-		virtual RealType			time() const												{ return time_; }
+		virtual RealType			time() const												{ return 0; }
 		virtual RealType			value(const Simplex& s) const								{ return s.value(); }
-
-	private:
-		RealType					time_;
 };
 
 class ARVineyard::KineticEvaluator: public Evaluator
 {
 	public:
-									KineticEvaluator(Simulator::Handle sp, 
-													 ActivePointsTable::Handle apt, 
-													 RealType time_offset): 
-										sp_(sp), apt_(apt)										{}
+									KineticEvaluator(SimulatorAR* simplex_sort_simulator,
+                                                     SimulatorAR* trajectory_sort_simulator): 
+                                        simplex_sort_simulator_(simplex_sort_simulator),
+                                        trajectory_sort_simulator_(trajectory_sort_simulator)   {}
 
-		virtual RealType			time() const												{ return CGAL::to_double(get_time()); }
-		virtual RealType			value(const Simplex& s)	const								{ return CGAL::to_double(apt_->at(s.kinetic_key()).x()(get_time())); }
+		virtual RealType			time() const												{ return std::max(simplex_sort_simulator_->current_time(), trajectory_sort_simulator_->current_time()); }
+		virtual RealType			value(const Simplex& s)	const								{ return FunctionKernel::value_at(s.max_threshold(), time()); }
 
 	private:
-		Simulator::Time				get_time() const											{ return sp_->current_time(); }
-		
-		Simulator::Handle			sp_;
-		ActivePointsTable::Handle 	apt_;
+		SimulatorAR*                simplex_sort_simulator_;
+        SimulatorAR*                trajectory_sort_simulator_;
 };
 
 
--- a/examples/ar-vineyard/ar-vineyard.hpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/ar-vineyard/ar-vineyard.hpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,44 +1,68 @@
+#include <utilities/log.h>
+
 /* Implementation */
+
+#ifdef LOGGING
+static rlog::RLogChannel* rlARVineyard =                        DEF_CHANNEL("ar/vineyard", rlog::Log_Debug);
+static rlog::RLogChannel* rlARVineyardComputing =               DEF_CHANNEL("ar/vineyard/computing", rlog::Log_Debug);
+static rlog::RLogChannel* rlARVineyardSwap =                    DEF_CHANNEL("ar/vineyard/swap", rlog::Log_Debug);
+static rlog::RLogChannel* rlARVineyardThresholdSwap =           DEF_CHANNEL("ar/vineyard/threshold/swap", rlog::Log_Debug);
+#endif
+
+
+template <class Simulator_>
+ARConeSimplex3D<Simulator_>::
+ARConeSimplex3D(const ARSimplex3D& s, bool coned): Parent(s, coned)
+{}
 	
+template <class Simulator_>
 void
-ARConeSimplex::
-swap_thresholds(ThresholdList* tl, typename ThresholdList::iterator i)
+ARConeSimplex3D<Simulator_>::
+swap_thresholds(ThresholdListIterator i, Simulator* simulator)
 {
-	AssertMsg(tl == &thresholds_, "Swap in the wrong list");		// might as well take advantage of the redundancy
-
+    rLog(rlARVineyardThresholdSwap, "Transposing %s and %s", tostring(*i).c_str(),
+                                                             tostring(*boost::next(i)).c_str());
 	typename ThresholdList::iterator n = boost::next(i);
-	tl->splice(i, *tl, n);
-	if (n == tl->begin())
-
+	thresholds_.splice(i, thresholds_, n);
+	if (boost::next(i) == thresholds_.end())
+        new_max_signal_(simulator);
 }
 
+template <class Simulator_>
 void
-ARConeSimplex::
+ARConeSimplex3D<Simulator_>::
 schedule_thresholds(Simulator* simulator)
 {
-	thresholds_sort_.insert(thresholds_sort_.end(), thresholds_.begin(), thresholds_.end(), simulator);
+    if (!coned()) thresholds_.push_back(Function(Function::rho, this));
+    else        
+    { 
+        thresholds_.push_back(Function(Function::phi, this)); 
+        thresholds_.push_back(Function(Function::rho, this)); 
+	    thresholds_sort_.initialize(thresholds_.begin(), thresholds_.end(), 
+		    						boost::bind(&ARConeSimplex3D::swap_thresholds, this, _1, _2), simulator);
+    }
 }
 
 
 ARVineyard::
-ARVineyard(const PointList& points, const Point& z): simplex_sort_(0), z_(z)
+ARVineyard(const PointList& points, const Point& z): z_(z)
 {
 	for (PointList::const_iterator cur = points.begin(); cur != points.end(); ++cur)
 		dt_.insert(*cur);
-	std::cout << "Delaunay triangulation computed" << std::endl;
+	rLog(rlARVineyard, "Delaunay triangulation computed");
 
 	ARSimplex3DVector alpha_ordering;
 	fill_alpha_order(dt_, z_, alpha_ordering);
-	std::cout << "Delaunay simplices: " << alpha_ordering.size() << std::endl;
+	rLog(rlARVineyard, "Delaunay simplices: %i", alpha_ordering.size());
 		
-	evaluator_ = new StaticEvaluator(0);
+	evaluator_ = new StaticEvaluator;
 	vineyard_ = new Vineyard(evaluator_);
 
-	filtration_ = new ARFiltration(vineyard_);
+	filtration_ = new FiltrationAR(vineyard_);
 	for (ARSimplex3DVector::const_iterator cur = alpha_ordering.begin(); cur != alpha_ordering.end(); ++cur)
 	{
-		filtration_->append(ARConeSimplex(*cur));						// Delaunay simplex
-		filtration_->append(ARConeSimplex(*cur, true));	// Coned off delaunay simplex
+		filtration_->append(ConeSimplex3D(*cur));         // Delaunay simplex
+		filtration_->append(ConeSimplex3D(*cur, true));   // Coned off delaunay simplex
 	}
 }
 
@@ -57,111 +81,64 @@
 	filtration_->fill_simplex_index_map();
 	filtration_->pair_simplices(filtration_->begin(), filtration_->end());
 	vineyard_->start_vines(filtration_->begin(), filtration_->end());
-	std::cout << "Simplices paired" << std::endl;
+	rLog(rlARVineyard, "Simplices paired");
 }
 
 void					
 ARVineyard::
-compute_vineyard(bool explicit_events)
+compute_vineyard(double max_radius)
 {
 	AssertMsg(filtration_->is_paired(), "Simplices must be paired for a vineyard to be computed");
 	
-	Simulator simulator;
-	SimplexSort	simplex_sort(filtration_, swap);
-
-
-
-
-
-
-
-	simplex_sort.initialize(&simulator);
-
-
-
-	typedef Traits::Kinetic_kernel::Point_1 								Point_1;
-	typedef Simulator::Time													Time;
+	SimulatorAR simplex_sort_simulator, trajectory_sort_simulator;
+	SimplexSort	simplex_sort;
 	
-	Traits tr(0,1);
-	Simulator::Handle sp = tr.simulator_handle();
-	ActivePointsTable::Handle apt = tr.active_points_1_table_handle();
-	Sort sort(tr, SortVisitor(this));
-	
-	// Setup the kinetic sort and membership changes
-	std::cout << "Setting up the kinetic sort and membership events" << std::endl;
-	CF cf; 
-	kinetic_map_.clear();
+	// Schedule thresholds
 	for (Index cur = filtration_->begin(); cur != filtration_->end(); ++cur)
-	{
-		F x = cf(F::NT(CGAL::to_double(cur->alpha())));
-		Point_1 p(x);
-		cur->set_kinetic_key(apt->insert(p));
-		kinetic_map_[cur->kinetic_key()] = cur;
-			
-		if (!cur->coned()) continue;						// non-coned simplices stay put, so we are done
+        cur->schedule_thresholds(&trajectory_sort_simulator);
 
-		Time lambda_alpha = CGAL::to_double((cur->alpha() - cur->rho()));	// when lambda becomes greater than alpha
-		lambda_alpha += 2*CGAL::sqrt(CGAL::to_double(cur->s()*lambda_alpha));
-		lambda_alpha += CGAL::to_double(cur->s() + cur->v());
-
-		Time phi_alpha = CGAL::to_double(cur->alpha() - cur->phi_const());
+	// Once thresholds are scheduled, we can initialize the simplex_sort
+	simplex_sort.initialize(filtration_->begin(), filtration_->end(), 
+							boost::bind(&ARVineyard::swap, this, _1, _2), &simplex_sort_simulator);
+    rLog(rlARVineyardComputing, "SimplexSort initialized");
 
-		Time phi_lambda = CGAL::to_double(cur->rho() + cur->s() - cur->v() - cur->phi_const());
-		phi_lambda *= phi_lambda;
-		phi_lambda /= CGAL::to_double(4*cur->s());
-		phi_lambda += CGAL::to_double(cur->v());
-
-		Time sv = CGAL::to_double(cur->s() + cur->v());
-		
-		if (true || phi_lambda < sv || phi_lambda < phi_alpha)		// FIXME: remove true
-		{
-			sp->new_event(Time(phi_alpha), 
-						  MembershipFunctionChangeEvent(cur->kinetic_key(),
-														cf(F::NT(CGAL::to_double(cur->phi_const())), 1),
-														apt));		// \phi^2 = r^2 + \phi_c^2
-			std::cout << "Scheduled" << std::endl;
-		} else
-			std::cout << "Not scheduled" << std::endl;
-		
-
-		//sp->new_event(Time(...), MembershipFunctionChangeEvent(cur->kinetic_key()));
-		
-		std::cout << *cur << std::endl;
-		std::cout << "lambda_alpha: " 		<< lambda_alpha << std::endl;
-		std::cout << "phi_alpha: " 			<< phi_alpha << std::endl;
-		std::cout << "phi_lambda: " 		<< phi_lambda << std::endl;
-		std::cout << "s^2 + v^2: " 			<< sv << std::endl;
-		std::cout << std::endl;
-	}
+    // Connect signals and slots
+    std::vector<ThresholdChangeSlot> slots; 
+    slots.reserve(filtration_->size());
+    for (SimplexSortIterator cur = simplex_sort.begin(); cur != simplex_sort.end(); ++cur)
+        slots.push_back(ThresholdChangeSlot(cur, &simplex_sort, vineyard_, &simplex_sort_simulator));
+    rLog(rlARVineyardComputing, "Signals and slots connected");
+    rLog(rlARVineyardComputing, "SimplexSort size: %i", simplex_sort_simulator.size());
+    rLog(rlARVineyardComputing, "TrajectorySort size: %i", trajectory_sort_simulator.size());
 	
-	// Process all the events (compute the vineyard in the process)
-	// FIXME: the time should not be 1, but something like twice the radius of
-	// the pointset as seen from z
-	change_evaluator(new KineticEvaluator(sp, apt, 0));
-	if (explicit_events)
-	{
-		while (sp->next_event_time() < 1)
-		{
-			std::cout << "Next event time: " << sp->next_event_time() << std::endl;
-			sp->set_current_event_number(sp->current_event_number() + 1);
-			std::cout << "Processed event" << std::endl;
-		}
-	} else
-		sp->set_current_time(1.0);
-	std::cout << "Processed " << sp->current_event_number() << " events" << std::endl;
+    // Simulate
+	change_evaluator(new KineticEvaluator(&simplex_sort_simulator, &trajectory_sort_simulator));
+    while ((simplex_sort_simulator.current_time() < max_radius || trajectory_sort_simulator.current_time() < max_radius) && !(simplex_sort_simulator.reached_infinity() && trajectory_sort_simulator.reached_infinity()))
+    {
+        if (*(simplex_sort_simulator.top()) < *(trajectory_sort_simulator.top()))
+        {
+            rLog(rlARVineyardComputing, "Current time before: %lf (simplex sort)", simplex_sort_simulator.current_time());
+            rLog(rlARVineyardComputing, "Top event: %s (simplex sort)", intostring(*(simplex_sort_simulator.top())).c_str());
+            simplex_sort_simulator.process();
+        } else
+        {
+            rLog(rlARVineyardComputing, "Current time before: %lf (trajectory sort)", trajectory_sort_simulator.current_time());
+            rLog(rlARVineyardComputing, "Top event: %s (trajectory sort)", intostring(*(trajectory_sort_simulator.top())).c_str());
+            trajectory_sort_simulator.process();
+        }
+    }
 	
-	//change_evaluator(new StaticEvaluator(1));
 	vineyard_->record_diagram(filtration_->begin(), filtration_->end());
 }
 		
 void 					
 ARVineyard::
-swap(Key a, Key b)
+swap(Index i, SimulatorAR* simulator)
 {
-	Index ao = kinetic_map_[a], bo = kinetic_map_[b];
-	AssertMsg(filtration_->get_trails_cmp()(ao, bo), "In swap(a,b), a must precede b");
-	filtration_->transpose(ao);
-	AssertMsg(filtration_->get_trails_cmp()(bo, ao), "In swap(a,b), b must precede a after the transposition");
+    rLog(rlARVineyardSwap, "Transposing %p and %p:", &(*i), &(*boost::next(i)));
+    rLog(rlARVineyardSwap, "  %s and", tostring(*i).c_str());
+    rLog(rlARVineyardSwap, "  %s", tostring(*boost::next(i)).c_str());
+	filtration_->transpose(i);
 }
 
 void
@@ -174,30 +151,3 @@
 	evaluator_ = eval;
 	vineyard_->set_evaluator(evaluator_);
 }
-
-void 
-ARVineyardBase::MembershipFunctionChangeEvent::
-process() const
-{
-	apt_->set(key_, function_);
-	std::cout << "Updated for phi's dominance" << std::endl;
-}
-
-
-template<class Vertex_handle>
-void
-ARVineyardBase::SortVisitor::
-before_swap(Vertex_handle a, Vertex_handle b) const
-{ 
-	std::cout << "Swapping elements" << *a << " and " << *b << std::endl;
-	arv_->swap(*a,*b); 
-}
-
-
-std::ostream&
-ARVineyardBase::MembershipFunctionChangeEvent::
-operator<<(std::ostream& out) const
-{
-	return out << "Membership change" << std::endl;
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/bottleneck-distance.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,68 @@
+#include <utilities/types.h>
+#include <topology/persistence-diagram.h>
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/map.hpp>
+
+#include <boost/program_options.hpp>
+
+
+typedef PersistenceDiagram<>                    PDgm;
+
+namespace po = boost::program_options;
+
+
+void read_diagram(PDgm& dgm, const std::string& filename)
+{
+    std::ifstream in(filename.c_str());
+    std::string line;
+    std::getline(in, line);
+    while (in)
+    {
+        std::istringstream sin(line);
+        double x,y;
+        sin >> x >> y;
+        dgm.push_back(PDgm::Point(x,y));
+        std::getline(in, line);
+    }
+}
+
+int main(int argc, char* argv[])
+{
+    std::string     filename1, filename2;
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+        ("input-file1",  po::value<std::string>(&filename1), "The first collection of persistence diagrams")
+        ("input-file2",  po::value<std::string>(&filename2), "The second collection of persistence diagrams");
+
+    po::positional_options_description p;
+    p.add("input-file1", 1);
+    p.add("input-file2", 2);
+
+    po::options_description all; all.add(hidden);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(argc, argv).
+                  options(all).positional(p).run(), vm);
+    po::notify(vm);
+
+    if (!vm.count("input-file1") || !vm.count("input-file2"))
+    {
+        std::cout << "Usage: " << argv[0] << " input-file1 input-file2" << std::endl;
+        return 1;
+    }
+
+    PDgm dgm1, dgm2;
+    read_diagram(dgm1, filename1);
+    read_diagram(dgm2, filename2);
+    //std::cout << "Size dgm1: " << dgm1.size() << std::endl;
+    //std::cout << "Size dgm2: " << dgm2.size() << std::endl;
+
+    //std::cout << "Distance: " << bottleneck_distance(dgm1, dgm2) << std::endl;
+    std::cout << "L2-Distance: " << wasserstein_distance(dgm1, dgm2, 2) << std::endl;
+}
--- a/examples/cech-complex/CMakeLists.txt	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/cech-complex/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -1,7 +1,7 @@
-set							(targets						
-							 cech-complex)
-							 
-foreach 					(t ${targets})
-	add_executable			(${t} ${t}.cpp ${external_sources})
-	target_link_libraries	(${t} ${libraries} ${cgal_libraries})
-endforeach 					(t ${targets})
+set                         (targets                        
+                             cech-complex)
+                             
+foreach                     (t ${targets})
+    add_executable          (${t} ${t}.cpp)
+    target_link_libraries   (${t} ${libraries})
+endforeach                  (t ${targets})
--- a/examples/cech-complex/cech-complex.cpp	Fri Aug 24 16:58:25 2007 -0400
+++ b/examples/cech-complex/cech-complex.cpp	Tue Jun 27 09:37:05 2017 -0700
@@ -1,8 +1,10 @@
-#include <utilities/sys.h>
-#include <utilities/debug.h>
+#include <utilities/log.h>
 
 #include <topology/simplex.h>
 #include <topology/filtration.h>
+#include <topology/static-persistence.h>
+//#include <topology/dynamic-persistence.h>
+#include <topology/persistence-diagram.h>
 #include "Miniball_dynamic_d.h"
 #include <algorithm>
 
@@ -10,120 +12,119 @@
 #include <fstream>
 
 
-typedef 		std::vector<Point>										PointContainer;
-typedef			unsigned int 											PointIndex;
-typedef			SimplexWithValue<PointIndex>							Simplex;
-typedef 		std::vector<Simplex> 									SimplexVector;
-typedef 		Filtration<Simplex>										CechFiltration;
-
-class DimensionValueComparison
-{
-	public:
-		bool	operator()(const Simplex& s1, const Simplex& s2) const
-		{
-			if (s1.dimension() == s2.dimension())
-				return s1.get_value() < s2.get_value();
-			else
-				return s1.dimension() < s2.dimension();
-		}
-};
+typedef         std::vector<Point>                                      PointContainer;
+typedef         unsigned int                                            PointIndex;
+typedef         Simplex<PointIndex, double>                             Smplx;
+typedef         Filtration<Smplx>                                       CechFiltration;
+typedef         StaticPersistence<>                                     Persistence;
+//typedef         DynamicPersistenceTrails<>                              Persistence;
+typedef         PersistenceDiagram<>            PDgm;
 
 int choose(int n, int k)
 {
-	if (k > n/2) k = n-k;
-	int numerator = 1, denominator = 1;
-	for (int i = 0; i < k; ++i)
-	{ numerator *= (n-i); denominator *= (i+1); }
-	return numerator/denominator;
+    if (k > n/2) k = n-k;
+    int numerator = 1, denominator = 1;
+    for (int i = 0; i < k; ++i)
+    { numerator *= (n-i); denominator *= (i+1); }
+    return numerator/denominator;
 }
 
-void add_simplices(SimplexVector& sv, int d, const PointContainer& points)
+void add_simplices(CechFiltration& sv, int d, const PointContainer& points)
 {
-	PointIndex indices[d+1];
-	for (int i = 0; i < d+1; ++i) 
-		indices[i] = d - i;
+    PointIndex indices[d+1];
+    for (int i = 0; i < d+1; ++i) 
+        indices[i] = d - i;
 
-	while(indices[d] < points.size() - d)
-	{
-		// Add simplex
-		Miniball mb(points[indices[0]].dim());
-		Simplex s;
-		for (int i = 0; i < d+1; ++i)
-		{
-			s.add(indices[i]);
-			mb.check_in(points[indices[i]]);
-		}
-		mb.build();
-		s.set_value(mb.squared_radius());
-		sv.push_back(s);
+    while(indices[d] < points.size() - d)
+    {
+        // Add simplex
+        Miniball mb(points[indices[0]].dim());
+        Smplx s;
+        for (int i = 0; i < d+1; ++i)
+        {
+            s.add(indices[i]);
+            mb.check_in(points[indices[i]]);
+        }
+        mb.build();
+        s.data() = mb.squared_radius();
+        sv.push_back(s);
 
-		
-		// Advance indices
-		for (int i = 0; i < d+1; ++i)
-		{
-			++indices[i];
-			if (indices[i] < points.size() - i)
-			{
-				for (int j = i-1; j >= 0; --j)
-					indices[j] = indices[j+1] + 1;
-				break;
-			}
-		}
-	}
+        
+        // Advance indices
+        for (int i = 0; i < d+1; ++i)
+        {
+            ++indices[i];
+            if (indices[i] < points.size() - i)
+            {
+                for (int j = i-1; j >= 0; --j)
+                    indices[j] = indices[j+1] + 1;
+                break;
+            }
+        }
+    }
 }
 
 int main(int argc, char** argv) 
 {
-	// Read in the point set and compute its Delaunay triangulation
-	std::istream& in = std::cin;
-	int ambient_d, homology_d;	
-	in >> ambient_d >> homology_d;
-	
-	std::cout << "Ambient dimension: " << ambient_d << std::endl;
-	std::cout << "Will compute PD up to dimension: " << homology_d << std::endl;
-	
-	// Read points
-	PointContainer points;
-	while(in)
-	{
-		Point p(ambient_d);
-		for (int i = 0; i < ambient_d; ++i)
-			in >> p[i];
-		points.push_back(p);
-	}
-	std::cout << "Points read: " << points.size() << std::endl;
+#ifdef LOGGING
+    rlog::RLogInit(argc, argv);
+
+    stdoutLog.subscribeTo( RLOG_CHANNEL("info") );
+    stdoutLog.subscribeTo( RLOG_CHANNEL("error") );
+#endif
+
+    SetFrequency(GetCounter("persistence/pair"), 10000);
+    SetTrigger(GetCounter("persistence/pair"), GetCounter(""));
+
+    // Read in the point set and compute its Delaunay triangulation
+    std::istream& in = std::cin;
+    int ambient_d, homology_d;
+    in >> ambient_d >> homology_d;
+    
+    rInfo("Ambient dimension: %d", ambient_d);
+    rInfo("Will compute PD up to dimension: %d", homology_d);
+    
+    // Read points
+    PointContainer points;
+    while(in)
+    {
+        Point p(ambient_d);
+        for (int i = 0; i < ambient_d; ++i)
+            in >> p[i];
+        points.push_back(p);
+    }
+    rInfo("Points read: %d", points.size());
    
-	// Compute Cech values
-	CechFiltration cf;
-	{										// resource acquisition is initialization
-		SimplexVector	sv;
-		int num_simplices = 0;
-		for (int i = 0; i <= homology_d + 1; ++i)
-			num_simplices += choose(points.size(), i+1);
-		sv.reserve(num_simplices);
-		std::cout << "Reserved SimplexVector of size: " << num_simplices << std::endl;
+    // Compute simplices with their Cech values
+    int num_simplices = 0;
+    for (int i = 0; i <= homology_d + 1; ++i)
+        num_simplices += choose(points.size(), i+1);
+    rInfo("Reserved SimplexVector of size: %d", num_simplices);
+
+    CechFiltration cf;
+    for (int i = 0; i <= homology_d + 1; ++i)
+        add_simplices(cf, i, points);
+    rInfo("Size of SimplexVector: %d", cf.size());
+
+    // Sort the filtration
+    cf.sort(DataDimensionComparison<Smplx>());
+    rInfo("Filtration initialized");
 
-		for (int i = 0; i <= homology_d + 1; ++i)
-			add_simplices(sv, i, points);
-		std::cout << "Size of SimplexVector: " << sv.size() << std::endl;
-			
-		std::sort(sv.begin(), sv.end(), DimensionValueComparison());
-		
-		for (SimplexVector::const_iterator cur = sv.begin(); cur != sv.end(); ++cur)
-			cf.append(*cur);
-	}
+    // Compute persistence
+    Persistence p(cf);
+    rInfo("Persistence initialized");
+    p.pair_simplices();
+    rInfo("Simplices paired");
 
-	// Compute persistence
-	cf.fill_simplex_index_map();
-	cf.pair_simplices(cf.begin(), cf.end());
-	std::cout << "Simplices paired" << std::endl;
+    Persistence::SimplexMap<CechFiltration>     m = p.make_simplex_map(cf);
+    std::map<Dimension, PDgm> dgms;
+    init_diagrams(dgms, p.begin(), p.end(), 
+                  evaluate_through_map(m, Smplx::DataEvaluator()), 
+                  evaluate_through_map(m,  Smplx::DimensionExtractor()));
 
-	for (CechFiltration::Index i = cf.begin(); i != cf.end(); ++i)
-		if (i->is_paired())
-		{
-			if (i->sign())
-				std::cout << i->dimension() << " " << i->get_value() << " " << i->pair()->get_value() << std::endl;
-		} //else std::cout << i->value() << std::endl;
-
+    for (int i = 0; i <= homology_d; ++i)
+    {
+        std::cout << i << std::endl << dgms[i] << std::endl;
+    }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/cohomology/CMakeLists.txt	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,12 @@
+set                         (targets                        
+                             rips-cohomology
+                             rips-pairwise-cohomology
+                             rips-explicit-cohomology
+                             rips-weighted-cohomology
+                             triangle-cohomology
+                            )
+                             
+foreach                     (t ${targets})
+    add_executable          (${t} ${t}.cpp)
+    target_link_libraries   (${t} ${libraries} ${Boost_PROGRAM_OPTIONS_LIBRARY})
+endforeach                  (t ${targets})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/cohomology/cocycle.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+from    cvxopt          import spmatrix, matrix
+from    cvxopt.blas     import copy
+from    lsqr            import lsqr
+from    sys             import argv, exit
+import  os.path
+
+def smooth(boundary_list, cocycle_list):
+    dimension = max((max(d[1], d[2]) for d in boundary_list))
+    dimension += 1
+
+    # NB: D is a coboundary matrix; 1 and 2 below are transposed
+    D = spmatrix([d[0] for d in boundary_list],
+                 [d[2] for d in boundary_list],
+                 [d[1] for d in boundary_list], (dimension, dimension))
+
+           
+    z = spmatrix([zz[0] for zz in cocycle_list],
+                 [zz[1] for zz in cocycle_list],
+                 [0     for zz in cocycle_list], (dimension, 1))
+
+    v1 = D * z
+    # print "D^2 is zero:", not bool(D*D)
+    # print "D*z is zero:", not bool(v1)
+    z = matrix(z)
+
+    def Dfun(x,y,trans = 'N'):
+        if trans == 'N':
+            copy(D * x, y)
+        elif trans == 'T':
+            copy(D.T * x, y)
+        else:
+            assert False, "Unexpected trans parameter"
+
+    tol = 1e-10
+    show = False
+    maxit = None
+    solution = lsqr(Dfun, matrix(z), show = show, atol = tol, btol = tol, itnlim = maxit)
+    
+    v = z - D*solution[0]
+
+    # print sum(v**2)
+    # assert sum((D*v)**2) < tol and sum((D.T*v)**2) < tol, "Expected a harmonic cocycle"
+    if not (sum((D*v)**2) < tol and sum((D.T*v)**2) < tol):
+        print "Expected a harmonic cocycle:", sum((D*v)**2), sum((D.T*v)**2) 
+
+    return solution[0], v
+
+
+def vertex_values(solution, vertices):
+    values = [None]*len(vertices)
+    for i,v in vertices:
+        values[v] = solution[i]
+    return values
+    
+
+def read_list_file(filename):
+    list = []
+    with open(filename) as fp:
+        for line in fp.xreadlines():
+            if line.startswith('#'): continue
+            list.append(map(int, line.split()))
+    return list
+
+
+if __name__ == '__main__':
+    if len(argv) < 4:
+        print "Usage: %s BOUNDARY COCYCLE VERTEXMAP" % argv[0]
+        exit()
+
+    boundary_filename = argv[1]
+    cocycle_filename = argv[2]
+    vertexmap_filename = argv[3]
+
+    boundary_list = read_list_file(boundary_filename)
+    cocycle_list = read_list_file(cocycle_filename)
+    vertexmap_list = read_list_file(vertexmap_filename)
+
+    solution, v = smooth(boundary_list, cocycle_list)
+    values = vertex_values(solution, vertexmap_list)
+
+    outfn = os.path.splitext(cocycle_filename)[0] + '.val'
+    with open(outfn, 'w') as f:
+        for i,v in enumerate(values):
+            f.write('%d %f\n' % (i,v))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/cohomology/lsqr.py	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,408 @@
+# LSQR solver from http://pages.cs.wisc.edu/~kline/cvxopt/
+
+from cvxopt import matrix
+from cvxopt.lapack import *
+from cvxopt.blas import *
+from math import sqrt
+
+"""
+a,b are scalars
+
+On exit, returns scalars c,s,r
+"""
+def SymOrtho(a,b):
+    aa=abs(a)
+    ab=abs(b)
+    if b==0.:
+        s=0.
+        r=aa
+        if aa==0.:
+            c=1.
+        else:
+            c=a/aa
+    elif a==0.:
+        c=0.
+        s=b/ab
+        r=ab
+    elif ab>=aa:
+        sb=1
+        if b<0: sb=-1
+        tau=a/b
+        s=sb*(1+tau**2)**-0.5
+        c=s*tau
+        r=b/s
+    elif aa>ab:
+        sa=1
+        if a<0: sa=-1
+        tau=b/a
+        c=sa*(1+tau**2)**-0.5
+        s=c*tau
+        r=a/c
+        
+    return c,s,r
+
+"""
+
+It is usually recommended to use SYMMLQ for symmetric matrices
+
+Requires the syntax
+                   A(x,y)   == y:=[A]*x
+and
+           A(x,y,trans='T') == y:=[A.T]*x
+
+comments with '###' are followed by the intent of the original matlab
+code. This may be useful for debugging.
+
+"""
+
+def lsqr(  A, b, damp=0.0, atol=1e-8, btol=1e-8, conlim=1e8, itnlim=None, show=False, wantvar=False):
+    """
+    
+    [ x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var ]...
+     = lsqr( m, n,  'aprod',  iw, rw, b, damp, atol, btol, conlim, itnlim, show );
+    
+     LSQR solves  Ax = b  or  min ||b - Ax||_2  if damp = 0,
+     or   min || (b)  -  (  A   )x ||   otherwise.
+              || (0)     (damp I)  ||2
+     A  is an m by n matrix defined by  y = aprod( mode,m,n,x,iw,rw ),
+     where the parameter 'aprodname' refers to a function 'aprod' that
+     performs the matrix-vector operations.
+     If mode = 1,   aprod  must return  y = Ax   without altering x.
+     If mode = 2,   aprod  must return  y = A'x  without altering x.
+     WARNING:   The file containing the function 'aprod'
+                must not be called aprodname.m !!!!
+
+    -----------------------------------------------------------------------
+     LSQR uses an iterative (conjugate-gradient-like) method.
+     For further information, see 
+     1. C. C. Paige and M. A. Saunders (1982a).
+        LSQR: An algorithm for sparse linear equations and sparse least squares,
+        ACM TOMS 8(1), 43-71.
+     2. C. C. Paige and M. A. Saunders (1982b).
+        Algorithm 583.  LSQR: Sparse linear equations and least squares problems,
+        ACM TOMS 8(2), 195-209.
+     3. M. A. Saunders (1995).  Solution of sparse rectangular systems using
+        LSQR and CRAIG, BIT 35, 588-604.
+    
+     Input parameters:
+     iw, rw      are not used by lsqr, but are passed to aprod.
+     atol, btol  are stopping tolerances.  If both are 1.0e-9 (say),
+                 the final residual norm should be accurate to about 9 digits.
+                 (The final x will usually have fewer correct digits,
+                 depending on cond(A) and the size of damp.)
+     conlim      is also a stopping tolerance.  lsqr terminates if an estimate
+                 of cond(A) exceeds conlim.  For compatible systems Ax = b,
+                 conlim could be as large as 1.0e+12 (say).  For least-squares
+                 problems, conlim should be less than 1.0e+8.
+                 Maximum precision can be obtained by setting
+                 atol = btol = conlim = zero, but the number of iterations
+                 may then be excessive.
+     itnlim      is an explicit limit on iterations (for safety).
+     show = 1    gives an iteration log,
+     show = 0    suppresses output.
+    
+     Output parameters:
+     x           is the final solution.
+     istop       gives the reason for termination.
+     istop       = 1 means x is an approximate solution to Ax = b.
+                 = 2 means x approximately solves the least-squares problem.
+     r1norm      = norm(r), where r = b - Ax.
+     r2norm      = sqrt( norm(r)^2  +  damp^2 * norm(x)^2 )
+                 = r1norm if damp = 0.
+     anorm       = estimate of Frobenius norm of Abar = [  A   ].
+                                                        [damp*I]
+     acond       = estimate of cond(Abar).
+     arnorm      = estimate of norm(A'*r - damp^2*x).
+     xnorm       = norm(x).
+     var         (if present) estimates all diagonals of (A'A)^{-1} (if damp=0)
+                 or more generally (A'A + damp^2*I)^{-1}.
+                 This is well defined if A has full column rank or damp > 0.
+                 (Not sure what var means if rank(A) < n and damp = 0.)
+                 
+    
+            1990: Derived from Fortran 77 version of LSQR.
+     22 May 1992: bbnorm was used incorrectly.  Replaced by anorm.
+     26 Oct 1992: More input and output parameters added.
+     01 Sep 1994: Matrix-vector routine is now a parameter 'aprodname'.
+                  Print log reformatted.
+     14 Jun 1997: show  added to allow printing or not.
+     30 Jun 1997: var   added as an optional output parameter.
+     07 Aug 2002: Output parameter rnorm replaced by r1norm and r2norm.
+                  Michael Saunders, Systems Optimization Laboratory,
+                  Dept of MS&E, Stanford University.
+    -----------------------------------------------------------------------
+    """
+    """
+         Initialize.
+    """
+    n=len(b)
+    m=n
+    if itnlim is None: itnlim=2*n    
+
+    msg=('The exact solution is  x = 0                              ',
+         'Ax - b is small enough, given atol, btol                  ',
+         'The least-squares solution is good enough, given atol     ',
+         'The estimate of cond(Abar) has exceeded conlim            ',
+         'Ax - b is small enough for this machine                   ',
+         'The least-squares solution is good enough for this machine',
+         'Cond(Abar) seems to be too large for this machine         ',
+         'The iteration limit has been reached                      ');
+
+    var = matrix(0.,(n,1));
+
+    if show:
+        print ' '
+        print 'LSQR            Least-squares solution of  Ax = b'
+        str1 = 'The matrix A has %8g rows  and %8g cols' % (m, n)
+        str2 = 'damp = %20.14e    wantvar = %8g' %( damp,wantvar)
+        str3 = 'atol = %8.2e                 conlim = %8.2e'%( atol, conlim)
+        str4 = 'btol = %8.2e                 itnlim = %8g'  %( btol, itnlim)
+        print str1
+        print str2
+        print str3
+        print str4
+
+    itn    = 0;		istop  = 0;		nstop  = 0;
+    ctol   = 0;
+    if conlim > 0: ctol = 1/conlim
+    anorm  = 0;		acond  = 0;
+    dampsq = damp**2;	ddnorm = 0;		res2   = 0;
+    xnorm  = 0;		xxnorm = 0;		z      = 0;
+    cs2    = -1;		sn2    = 0;
+    
+    """
+    Set up the first vectors u and v for the bidiagonalization.
+     These satisfy  beta*u = b,  alfa*v = A'u.
+    """
+    __x    = matrix(0., (n,1)) # a matrix for temporary holding
+    v      = matrix(0., (n,1))
+    u      = +b;	
+    x      = matrix(0., (n,1))
+    alfa   = 0;
+    beta = nrm2( u );
+    w      = matrix(0., (n,1))
+    
+    if beta > 0:
+        ### u = (1/beta) * u;
+        ### v = feval( aprodname, 2, m, n, u, iw, rw );
+        scal(1/beta,u)
+	A(u,v,trans='T'); #v = feval( aprodname, 2, m, n, u, iw, rw );
+        alfa = nrm2( v );
+
+    if alfa > 0:
+        ### v = (1/alfa) * v;
+        scal(1/alfa,v)
+        copy(v,w)
+
+
+    rhobar = alfa;		phibar = beta;		bnorm  = beta;
+    rnorm  = beta;
+    r1norm = rnorm;
+    r2norm = rnorm;
+
+    # reverse the order here from the original matlab code because
+    # there was an error on return when arnorm==0
+    arnorm = alfa * beta;
+    if arnorm == 0:
+        print msg[0];
+        return x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var 
+
+    head1  = '   Itn      x[0]       r1norm     r2norm ';
+    head2  = ' Compatible   LS      Norm A   Cond A';
+    
+    if show:
+        print ' '
+        print head1, head2
+        test1  = 1;		test2  = alfa / beta;
+        str1   = '%6g %12.5e'    %(    itn,   x[0] );
+        str2   = ' %10.3e %10.3e'%( r1norm, r2norm );
+        str3   = '  %8.1e %8.1e' %(  test1,  test2 );
+        print str1, str2, str3
+        
+    """
+    %------------------------------------------------------------------
+    %     Main iteration loop.
+    %------------------------------------------------------------------
+    """
+    while itn < itnlim:
+        itn = itn + 1;
+        """
+        %     Perform the next step of the bidiagonalization to obtain the
+        %     next  beta, u, alfa, v.  These satisfy the relations
+        %                beta*u  =  a*v   -  alfa*u,
+        %                alfa*v  =  A'*u  -  beta*v.
+        """
+        ### u    = feval( aprodname, 1, m, n, v, iw, rw )  -  alfa*u;
+        copy(u, __x)
+        A(v,u)
+        axpy(__x,u,-alfa)
+
+        beta = nrm2( u );
+        if beta > 0:
+            ### u     = (1/beta) * u;
+            scal(1/beta,u)
+            anorm = sqrt(anorm**2 + alfa**2 + beta**2 + damp**2);
+            ### v     = feval( aprodname, 2, m, n, u, iw, rw )  -  beta*v;
+            copy(v,__x)
+            A(u,v,trans='T')
+            axpy(__x,v,-beta)
+
+            alfa  = nrm2( v );
+            if alfa > 0:
+                ### v = (1/alfa) * v;
+                scal(1/alfa, v)
+
+        """
+        %     Use a plane rotation to eliminate the damping parameter.
+        %     This alters the diagonal (rhobar) of the lower-bidiagonal matrix.
+        """
+
+        rhobar1 = sqrt(rhobar**2 + damp**2);
+        cs1     = rhobar / rhobar1;
+        sn1     = damp   / rhobar1;
+        psi     = sn1 * phibar;
+        phibar  = cs1 * phibar;
+        """
+        %     Use a plane rotation to eliminate the subdiagonal element (beta)
+        %     of the lower-bidiagonal matrix, giving an upper-bidiagonal matrix.
+        """
+
+
+        ###cs      =   rhobar1/ rho;
+        ###sn      =   beta   / rho;
+        cs,sn,rho = SymOrtho(rhobar1,beta)
+        
+        theta   =   sn * alfa;
+        rhobar  = - cs * alfa;
+        phi     =   cs * phibar;
+        phibar  =   sn * phibar;
+        tau     =   sn * phi;
+        """
+        %     Update x and w.
+        """
+        t1      =   phi  /rho;
+        t2      = - theta/rho;
+        dk      =   (1/rho)*w;
+
+        ### x       = x      +  t1*w;
+        axpy(w,x,t1)
+        ### w       = v      +  t2*w;
+        scal(t2,w)
+        axpy(v,w)
+        ddnorm  = ddnorm +  nrm2(dk)**2;
+        if wantvar:
+            ### var = var  +  dk.*dk; 
+            axpy(dk**2, var)
+        """
+        %     Use a plane rotation on the right to eliminate the
+        %     super-diagonal element (theta) of the upper-bidiagonal matrix.
+        %     Then use the result to estimate  norm(x).
+        """
+
+        delta   =   sn2 * rho;
+        gambar  = - cs2 * rho;
+        rhs     =   phi  -  delta * z;
+        zbar    =   rhs / gambar;
+        xnorm   =   sqrt(xxnorm + zbar**2);
+        gamma   =   sqrt(gambar**2 +theta**2);
+        cs2     =   gambar / gamma;
+        sn2     =   theta  / gamma;
+        z       =   rhs    / gamma;
+        xxnorm  =   xxnorm  +  z**2;
+        """
+        %     Test for convergence.
+        %     First, estimate the condition of the matrix  Abar,
+        %     and the norms of  rbar  and  Abar'rbar.
+        """
+        acond   =   anorm * sqrt(ddnorm);
+        res1    =   phibar**2;
+        res2    =   res2  +  psi**2;
+        rnorm   =   sqrt( res1 + res2 );
+        arnorm  =   alfa * abs( tau );
+        """
+        %     07 Aug 2002:
+        %     Distinguish between
+        %        r1norm = ||b - Ax|| and
+        %        r2norm = rnorm in current code
+        %               = sqrt(r1norm^2 + damp^2*||x||^2).
+        %        Estimate r1norm from
+        %        r1norm = sqrt(r2norm^2 - damp^2*||x||^2).
+        %     Although there is cancellation, it might be accurate enough.
+        """
+        r1sq    =   rnorm**2  -  dampsq * xxnorm;
+        r1norm  =   sqrt( abs(r1sq) );
+        if r1sq < 0: r1norm = - r1norm; 
+        r2norm  =   rnorm;
+        """
+        %     Now use these norms to estimate certain other quantities,
+        %     some of which will be small near a solution.
+        """
+        test1   =   rnorm / bnorm;
+        test2   =   arnorm/( anorm * rnorm );
+        test3   =       1 / acond;
+        t1      =   test1 / (1    +  anorm * xnorm / bnorm);
+        rtol    =   btol  +  atol *  anorm * xnorm / bnorm;
+        """
+        %     The following tests guard against extremely small values of
+        %     atol, btol  or  ctol.  (The user may have set any or all of
+        %     the parameters  atol, btol, conlim  to 0.)
+        %     The effect is equivalent to the normal tests using
+        %     atol = eps,  btol = eps,  conlim = 1/eps.
+        """
+        if itn >= itnlim  : istop = 7; 
+        if 1 + test3  <= 1: istop = 6; 
+        if 1 + test2  <= 1: istop = 5; 
+        if 1 + t1     <= 1: istop = 4; 
+        """
+        %     Allow for tolerances set by the user.
+        """
+        if  test3 <= ctol:  istop = 3;
+        if  test2 <= atol:  istop = 2;
+        if  test1 <= rtol:  istop = 1;
+        """
+        %     See if it is time to print something.
+        """
+        prnt = False;
+        if n     <= 40       : prnt = True;
+        if itn   <= 10       : prnt = True;
+        if itn   >= itnlim-10: prnt = True;
+        # if itn%10 == 0       : prnt = True;
+        if test3 <=  2*ctol  : prnt = True;
+        if test2 <= 10*atol  : prnt = True;
+        if test1 <= 10*rtol  : prnt = True;
+        if istop !=  0       : prnt = True;
+
+        if prnt:
+            if show:
+                str1 = '%6g %12.5e'%        (itn,   x[0] );
+                str2 = ' %10.3e %10.3e'% (r1norm, r2norm );
+                str3 = '  %8.1e %8.1e'%  ( test1,  test2 );
+                str4 = ' %8.1e %8.1e'%   ( anorm,  acond );
+                print str1, str2, str3, str4
+
+        if istop != 0: break
+
+    """
+    %     End of iteration loop.
+    %     Print the stopping condition.
+    """
+    if show:
+        print ' '
+        print 'LSQR finished'
+        print msg[istop]
+        print ' '
+        str1 = 'istop =%8g   r1norm =%8.1e'%  ( istop, r1norm );
+        str2 = 'anorm =%8.1e   arnorm =%8.1e'%( anorm, arnorm );
+        str3 = 'itn   =%8g   r2norm =%8.1e'%  (   itn, r2norm );
+        str4 = 'acond =%8.1e   xnorm  =%8.1e'%( acond, xnorm  );
+        print str1+ '   ' +str2
+        print str3+ '   ' +str4
+        print ' '
+
+    return x, istop, itn, r1norm, r2norm, anorm, acond, arnorm, xnorm, var 
+            
+    """
+    %-----------------------------------------------------------------------
+    % End of lsqr.m
+    %-----------------------------------------------------------------------
+    """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/cohomology/output.h	Tue Jun 27 09:37:05 2017 -0700
@@ -0,0 +1,66 @@
+#include <iostream>
+#include <sstream>
+#include <fstream>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+#include <cassert>
+
+bool neq(const Smplx& s1, const Smplx& s2)               
+{ 
+    Smplx::VertexComparison cmp;
+    return cmp(s1, s2) || cmp(s2, s1);
+}
+
+template<class Comparison>
+unsigned index(const SimplexVector& v, const Smplx& s, const Comparison& cmp)
+{
+    SimplexVector::const_iterator it = std::lower_bound(v.begin(), v.end(), s, cmp);
+    while (neq(*it, s)) ++it;
+    return it - v.begin();
+}
+
+template<class Comparison>
+void output_boundary_matrix(std::ostream& out, const SimplexVector& v, const Comparison& cmp)
+{
+    unsigned i = 0;