summaryrefslogtreecommitdiff
path: root/src/Skeleton_blocker
diff options
context:
space:
mode:
Diffstat (limited to 'src/Skeleton_blocker')
-rw-r--r--src/Skeleton_blocker/concept/SkeletonBlockerDS.h117
-rw-r--r--src/Skeleton_blocker/concept/SkeletonBlockerGeometricDS.h78
-rw-r--r--src/Skeleton_blocker/doc/COPYRIGHT12
-rw-r--r--src/Skeleton_blocker/doc/blocker_curve.svg2177
-rw-r--r--src/Skeleton_blocker/doc/blockers_curve.pngbin0 -> 38135 bytes
-rw-r--r--src/Skeleton_blocker/doc/ds_representation.pngbin0 -> 36412 bytes
-rw-r--r--src/Skeleton_blocker/doc/ds_representation.svg470
-rw-r--r--src/Skeleton_blocker/doc/ds_scheme.svg477
-rw-r--r--src/Skeleton_blocker/doc/sphere_contraction.pngbin0 -> 48755 bytes
-rw-r--r--src/Skeleton_blocker/example/CMakeLists.txt13
-rw-r--r--src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp65
-rw-r--r--src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp73
-rw-r--r--src/Skeleton_blocker/example/Skeleton_blocker_link.cpp57
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h238
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h132
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h65
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h191
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h87
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h178
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h362
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h261
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h61
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h256
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h122
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h135
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h20
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h390
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h214
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h158
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h1593
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h215
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h287
-rw-r--r--src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h455
-rw-r--r--src/Skeleton_blocker/test/CMakeLists.txt17
-rw-r--r--src/Skeleton_blocker/test/test.off10
-rw-r--r--src/Skeleton_blocker/test/test2.off15
-rw-r--r--src/Skeleton_blocker/test/test_skeleton_blocker_complex.cpp826
-rw-r--r--src/Skeleton_blocker/test/test_skeleton_blocker_geometric_complex.cpp113
-rw-r--r--src/Skeleton_blocker/test/test_skeleton_blocker_simplifiable.cpp348
39 files changed, 10288 insertions, 0 deletions
diff --git a/src/Skeleton_blocker/concept/SkeletonBlockerDS.h b/src/Skeleton_blocker/concept/SkeletonBlockerDS.h
new file mode 100644
index 00000000..0c2014bd
--- /dev/null
+++ b/src/Skeleton_blocker/concept/SkeletonBlockerDS.h
@@ -0,0 +1,117 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef CONCEPT_SKELETON_BLOCKER_SKELETONBLOCKERDS_H_
+#define CONCEPT_SKELETON_BLOCKER_SKELETONBLOCKERDS_H_
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/** \brief Concept for the template class passed for Skeleton_blocker_complex.
+ * Most importantly, it contains the nodes for vertices and edges
+ * (Graph_vertex and Graph_edge) that are stored in the simplicial
+ * complex. The user can redefine these classes to attach
+ * additional information to vertices and edges.
+ */
+struct SkeletonBlockerDS {
+ /**
+ * @brief index that allows to find the vertex in the boost graph
+ */
+ typedef int boost_vertex_handle;
+
+ /**
+ * @brief Root_vertex_handle and Vertex_handle are similar to global and local vertex descriptor
+ * used in <a href="http://www.boost.org/doc/libs/1_38_0/libs/graph/doc/subgraph.html">boost subgraphs</a>
+ * and allow to localize a vertex of a subcomplex on its parent root complex.
+ *
+ * In gross, vertices are stored in a vector
+ * and the Root_vertex_handle and Vertex_handle store indices of a vertex in this vector.
+ *
+ * For the root simplicial complex, the Root_vertex_handle and Vertex_handle of a vertex
+ * are the same.
+ *
+ *
+ * For a subcomplex L of a simplicial complex K, the local descriptor, ie the Vertex_handle, of a
+ * vertex v (that belongs to L) is its position in the vector of vertices
+ * of the subcomplex L whereas its Root_vertex_handle (global descriptor) is the position of v in the vector of the
+ * vertices of the root simplicial complex K.
+ */
+ struct Root_vertex_handle {
+ boost_vertex_handle vertex;
+
+ friend ostream& operator<<(ostream& o, const Root_vertex_handle & v);
+ };
+
+ /**
+ * A Vertex_handle must be Default Constructible, Assignable and Equality Comparable.
+ */
+ struct Vertex_handle {
+ boost_vertex_handle vertex;
+
+ friend ostream& operator<<(ostream& o, const Vertex_handle & v);
+ };
+
+ /**
+ * \brief The type of vertices that are stored the boost graph.
+ * A Vertex must be Default Constructible and Equality Comparable.
+ *
+ */
+ struct Graph_vertex {
+ /** \brief Used to deactivate a vertex for example when contracting an edge.
+ * It allows in some cases to remove the vertex at low cost.
+ */
+ void deactivate();
+
+ /** \brief Used to activate a vertex.
+ */
+ void activate();
+
+ /** \brief Tells if the vertex is active.
+ */
+ bool is_active() const;
+
+ void set_id(Root_vertex_handle i);
+ Root_vertex_handle get_id() const;
+ virtual string to_string() const;
+ friend ostream& operator<<(ostream& o, const Graph_vertex & v);
+ };
+
+ /**
+ * \brief The type of edges that are stored the boost graph.
+ * An Edge must be Default Constructible and Equality Comparable.
+ */
+ struct Graph_edge {
+ /**
+ * @brief Allows to modify vertices of the edge.
+ */
+ void setId(Root_vertex_handle a, Root_vertex_handle b);
+
+ /**
+ * @brief Returns the first vertex of the edge.
+ */
+ Root_vertex_handle first() const;
+
+ /**
+ * @brief Returns the second vertex of the edge.
+ */
+ Root_vertex_handle second() const;
+
+ friend ostream& operator<<(ostream& o, const Simple_edge & v);
+ };
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // CONCEPT_SKELETON_BLOCKER_SKELETONBLOCKERDS_H_
diff --git a/src/Skeleton_blocker/concept/SkeletonBlockerGeometricDS.h b/src/Skeleton_blocker/concept/SkeletonBlockerGeometricDS.h
new file mode 100644
index 00000000..9a81b79c
--- /dev/null
+++ b/src/Skeleton_blocker/concept/SkeletonBlockerGeometricDS.h
@@ -0,0 +1,78 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef CONCEPT_SKELETON_BLOCKER_SKELETONBLOCKERGEOMETRICDS_H_
+#define CONCEPT_SKELETON_BLOCKER_SKELETONBLOCKERGEOMETRICDS_H_
+
+namespace Gudhi {
+namespace skeleton_blocker {
+
+/**
+ * \brief Concept for template class of Skeleton_blocker_geometric_complex .
+ * It must specify a GeometryTrait which contains a Point definition.
+ *
+ * Graph_vertex must specify how to access to a point.
+ * Graph_edge must specify how to access to an index.
+ *
+ */
+// TODO(DS): the index is just for contraction, to remove
+
+template<typename GeometryTrait>
+struct SkeletonBlockerGeometricDS : public SkeletonBlockerDS {
+ /**
+ * Geometry information.
+ */
+ typedef GeometryTrait GT;
+
+ /**
+ * Type of point (should be the same as GT::Point).
+ */
+ typedef typename GeometryTrait::Point Point;
+
+ /**
+ * @brief Vertex that stores a point.
+ */
+ class Graph_vertex : public SkeletonBlockerDS::Graph_vertex {
+ public:
+ /**
+ * @brief Access to the point.
+ */
+ Point& point();
+ /**
+ * @brief Access to the point.
+ */
+ const Point& point();
+ };
+
+ /**
+ * @brief Edge that allows to access to an index.
+ * The indices of the edges are used to store heap information
+ * in the edge contraction algorithm.
+ */
+ class Graph_Edge : public SkeletonBlockerDS::Graph_edge {
+ public:
+ /**
+ * @brief Access to the index.
+ */
+ int& index();
+ /**
+ * @brief Access to the index.
+ */
+ int index();
+ };
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // CONCEPT_SKELETON_BLOCKER_SKELETONBLOCKERGEOMETRICDS_H_
diff --git a/src/Skeleton_blocker/doc/COPYRIGHT b/src/Skeleton_blocker/doc/COPYRIGHT
new file mode 100644
index 00000000..61f17f6d
--- /dev/null
+++ b/src/Skeleton_blocker/doc/COPYRIGHT
@@ -0,0 +1,12 @@
+The files of this directory are part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+
+Author(s): Vincent Rouvreau
+
+Copyright (C) 2015 Inria
+
+This gives everyone the freedoms to use openFrameworks in any context:
+commercial or non-commercial, public or private, open or closed source.
+
+You should have received a copy of the MIT License along with this program.
+If not, see https://opensource.org/licenses/MIT. \ No newline at end of file
diff --git a/src/Skeleton_blocker/doc/blocker_curve.svg b/src/Skeleton_blocker/doc/blocker_curve.svg
new file mode 100644
index 00000000..0094a379
--- /dev/null
+++ b/src/Skeleton_blocker/doc/blocker_curve.svg
@@ -0,0 +1,2177 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg5493"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="New document 8">
+ <defs
+ id="defs5495">
+ <clipPath
+ id="clipPath6477"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6479"
+ d="m 2963.67,3669.26 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6465"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6467"
+ d="m 2762.07,3669.26 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6427"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6429"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6409"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6411"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6399"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6401"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6381"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6383"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6371"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6373"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6353"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6355"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6343"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6345"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6325"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6327"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6315"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6317"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6297"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6299"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6287"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6289"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6269"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6271"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6259"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6261"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6241"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6243"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6231"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6233"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6211"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6213"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6189"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6191"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6169"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6171"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6149"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6151"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6129"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6131"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6109"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6111"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6089"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6091"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6077"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6079"
+ d="m 5151,431 33,0 0,35 -33,0 0,-35 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6065"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6067"
+ d="m 4705,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6053"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6055"
+ d="m 4258,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6041"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6043"
+ d="m 3812,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6029"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6031"
+ d="m 3365,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6017"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6019"
+ d="m 2919,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath6005"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path6007"
+ d="m 2473,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5993"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5995"
+ d="m 2026,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5981"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5983"
+ d="m 1580,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5969"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5971"
+ d="m 1133,431 66,0 0,34 -66,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5957"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5959"
+ d="m 720,431 42,0 0,34 -42,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5947"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5949"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5935"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5937"
+ d="m 5151,539 33,0 0,66 -33,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5923"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5925"
+ d="m 4705.12,525.621 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5911"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5913"
+ d="m 4258.71,513.121 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5899"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5901"
+ d="m 3812.3,499.84 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5887"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5889"
+ d="m 3365.9,482.852 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5875"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5877"
+ d="m 2919.49,469.379 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5863"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5865"
+ d="m 2473,454 66,0 0,66 -66,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5851"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5853"
+ d="m 2026.72,439.648 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5839"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5841"
+ d="m 1580,431 66,0 0,60 -66,0 0,-60 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5827"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5829"
+ d="m 1133,431 66,0 0,47 -66,0 0,-47 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5815"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5817"
+ d="m 720,431 42,0 0,34 -42,0 0,-34 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5805"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5807"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5793"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5795"
+ d="m 5151,3499 33,0 0,66 -33,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5781"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5783"
+ d="m 4705.12,3186.68 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5769"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5771"
+ d="m 4258.71,2878.83 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5757"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5759"
+ d="m 3812.3,2568.4 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5745"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5747"
+ d="m 3365.9,2251.56 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5733"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5735"
+ d="m 2919,1940 66,0 0,66 -66,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5721"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5723"
+ d="m 2473.09,1628.36 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5709"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5711"
+ d="m 2026.72,1312.93 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5697"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5699"
+ d="m 1580,1005 66,0 0,66 -66,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5685"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5687"
+ d="m 1133.91,696.801 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5673"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5675"
+ d="m 720,431 42,0 0,37 -42,0 0,-37 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5663"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5665"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5651"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5653"
+ d="m 5151,1336 33,0 0,66 -33,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5639"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5641"
+ d="m 4705.12,1242.11 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5627"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5629"
+ d="m 4258.71,1148.95 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5615"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5617"
+ d="m 3812.3,1055.12 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5603"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5605"
+ d="m 3365.9,959.73 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5591"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5593"
+ d="m 2919.49,865.699 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5579"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5581"
+ d="m 2473.09,771.52 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5567"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5569"
+ d="m 2026.72,676.449 65,0 0,65 -65,0 0,-65 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5555"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5557"
+ d="m 1580,583 66,0 0,66 -66,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5543"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5545"
+ d="m 1133,490 66,0 0,66 -66,0 0,-66 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5531"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5533"
+ d="m 720,431 42,0 0,35 -42,0 0,-35 z" />
+ </clipPath>
+ <clipPath
+ id="clipPath5521"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ id="path5523"
+ d="m 720,431 4464,0 0,3458 -4464,0 0,-3458 z" />
+ </clipPath>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.979899"
+ inkscape:cx="399.80267"
+ inkscape:cy="523.89309"
+ inkscape:document-units="px"
+ inkscape:current-layer="g5511"
+ showgrid="false"
+ inkscape:window-width="2560"
+ inkscape:window-height="1523"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5498">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ transform="matrix(1.25,0,0,-1.25,15,802.36218)"
+ inkscape:label="ink_ext_XXXXXX"
+ id="g5509">
+ <g
+ transform="scale(0.1,0.1)"
+ id="g5511">
+ <path
+ id="path5513"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 0,0 5760,0 0,4320 L 0,4320 0,0 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5515"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 720,431.988 4463.98,0 0,3456.02 -4463.98,0 0,-3456.02 z"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g5517">
+ <g
+ clip-path="url(#clipPath5521)"
+ id="g5519">
+ <path
+ id="path5525"
+ style="fill:none;stroke:#0000ff;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,432.969 437.461,89.57 446.4,93.32 446.41,93.09 446.37,95.071 446.4,94.179 446.41,94.031 446.4,95.39 446.41,93.83 446.41,93.16 446.36,94.34"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5527">
+ <g
+ clip-path="url(#clipPath5531)"
+ id="g5529">
+ <path
+ id="path5535"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 728.949,402.969 c 7.93,0 15.582,3.16 21.211,8.793 5.621,5.617 8.789,13.238 8.789,21.207 0,7.972 -3.168,15.582 -8.789,21.211 -5.629,5.621 -13.281,8.789 -21.211,8.789 -7.969,0 -15.59,-3.168 -21.25,-8.789 -5.629,-5.629 -8.75,-13.239 -8.75,-21.211 0,-7.969 3.121,-15.59 8.75,-21.207 5.66,-5.633 13.281,-8.793 21.25,-8.793"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5537"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,402.969 c 7.93,0 15.582,3.16 21.211,8.793 5.621,5.617 8.789,13.238 8.789,21.207 0,7.972 -3.168,15.582 -8.789,21.211 -5.629,5.621 -13.281,8.789 -21.211,8.789 -7.969,0 -15.59,-3.168 -21.25,-8.789 -5.629,-5.629 -8.75,-13.239 -8.75,-21.211 0,-7.969 3.121,-15.59 8.75,-21.207 5.66,-5.633 13.281,-8.793 21.25,-8.793 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5539">
+ <g
+ clip-path="url(#clipPath5543)"
+ id="g5541">
+ <path
+ id="path5547"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1166.41,492.539 c 7.97,0 15.58,3.16 21.21,8.789 5.62,5.621 8.79,13.242 8.79,21.211 0,7.93 -3.17,15.582 -8.79,21.211 -5.63,5.629 -13.24,8.789 -21.21,8.789 -7.97,0 -15.59,-3.16 -21.21,-8.789 -5.63,-5.629 -8.79,-13.281 -8.79,-21.211 0,-7.969 3.16,-15.59 8.79,-21.211 5.62,-5.629 13.24,-8.789 21.21,-8.789"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5549"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1166.41,492.539 c 7.97,0 15.58,3.16 21.21,8.789 5.62,5.621 8.79,13.242 8.79,21.211 0,7.93 -3.17,15.582 -8.79,21.211 -5.63,5.629 -13.24,8.789 -21.21,8.789 -7.97,0 -15.59,-3.16 -21.21,-8.789 -5.63,-5.629 -8.79,-13.281 -8.79,-21.211 0,-7.969 3.16,-15.59 8.79,-21.211 5.62,-5.629 13.24,-8.789 21.21,-8.789 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5551">
+ <g
+ clip-path="url(#clipPath5555)"
+ id="g5553">
+ <path
+ id="path5559"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1612.81,585.859 c 7.93,0 15.59,3.161 21.21,8.789 5.63,5.622 8.79,13.243 8.79,21.211 0,7.969 -3.16,15.59 -8.79,21.211 -5.62,5.629 -13.28,8.789 -21.21,8.789 -7.97,0 -15.58,-3.16 -21.21,-8.789 -5.62,-5.621 -8.79,-13.242 -8.79,-21.211 0,-7.968 3.17,-15.589 8.79,-21.211 5.63,-5.628 13.24,-8.789 21.21,-8.789"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5561"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1612.81,585.859 c 7.93,0 15.59,3.161 21.21,8.789 5.63,5.622 8.79,13.243 8.79,21.211 0,7.969 -3.16,15.59 -8.79,21.211 -5.62,5.629 -13.28,8.789 -21.21,8.789 -7.97,0 -15.58,-3.16 -21.21,-8.789 -5.62,-5.621 -8.79,-13.242 -8.79,-21.211 0,-7.968 3.17,-15.589 8.79,-21.211 5.63,-5.628 13.24,-8.789 21.21,-8.789 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5563">
+ <g
+ clip-path="url(#clipPath5567)"
+ id="g5565">
+ <path
+ id="path5571"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2059.22,678.949 c 7.93,0 15.58,3.16 21.21,8.781 5.62,5.629 8.79,13.29 8.79,21.219 0,7.961 -3.17,15.582 -8.79,21.211 -5.63,5.621 -13.28,8.789 -21.21,8.789 -7.97,0 -15.63,-3.168 -21.25,-8.789 -5.63,-5.629 -8.75,-13.25 -8.75,-21.211 0,-7.929 3.12,-15.59 8.75,-21.219 5.62,-5.621 13.28,-8.781 21.25,-8.781"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5573"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2059.22,678.949 c 7.93,0 15.58,3.16 21.21,8.781 5.62,5.629 8.79,13.29 8.79,21.219 0,7.961 -3.17,15.582 -8.79,21.211 -5.63,5.621 -13.28,8.789 -21.21,8.789 -7.97,0 -15.63,-3.168 -21.25,-8.789 -5.63,-5.629 -8.75,-13.25 -8.75,-21.211 0,-7.929 3.12,-15.59 8.75,-21.219 5.62,-5.621 13.28,-8.781 21.25,-8.781 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5575">
+ <g
+ clip-path="url(#clipPath5579)"
+ id="g5577">
+ <path
+ id="path5583"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2505.59,774.02 c 7.96,0 15.58,3.171 21.21,8.789 5.62,5.632 8.79,13.242 8.79,21.211 0,7.968 -3.17,15.589 -8.79,21.21 -5.63,5.629 -13.25,8.79 -21.21,8.79 -7.93,0 -15.59,-3.161 -21.21,-8.79 -5.63,-5.621 -8.79,-13.242 -8.79,-21.21 0,-7.969 3.16,-15.579 8.79,-21.211 5.62,-5.618 13.28,-8.789 21.21,-8.789"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5585"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2505.59,774.02 c 7.96,0 15.58,3.171 21.21,8.789 5.62,5.632 8.79,13.242 8.79,21.211 0,7.968 -3.17,15.589 -8.79,21.21 -5.63,5.629 -13.25,8.79 -21.21,8.79 -7.93,0 -15.59,-3.161 -21.21,-8.79 -5.63,-5.621 -8.79,-13.242 -8.79,-21.21 0,-7.969 3.16,-15.579 8.79,-21.211 5.62,-5.618 13.28,-8.789 21.21,-8.789 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5587">
+ <g
+ clip-path="url(#clipPath5591)"
+ id="g5589">
+ <path
+ id="path5595"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2951.99,868.199 c 7.97,0 15.59,3.172 21.21,8.789 5.63,5.633 8.79,13.242 8.79,21.211 0,7.93 -3.16,15.59 -8.79,21.211 -5.62,5.629 -13.24,8.789 -21.21,8.789 -7.93,0 -15.58,-3.16 -21.21,-8.789 -5.62,-5.621 -8.79,-13.281 -8.79,-21.211 0,-7.969 3.17,-15.578 8.79,-21.211 5.63,-5.617 13.28,-8.789 21.21,-8.789"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5597"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2951.99,868.199 c 7.97,0 15.59,3.172 21.21,8.789 5.63,5.633 8.79,13.242 8.79,21.211 0,7.93 -3.16,15.59 -8.79,21.211 -5.62,5.629 -13.24,8.789 -21.21,8.789 -7.93,0 -15.58,-3.16 -21.21,-8.789 -5.62,-5.621 -8.79,-13.281 -8.79,-21.211 0,-7.969 3.17,-15.578 8.79,-21.211 5.63,-5.617 13.28,-8.789 21.21,-8.789 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5599">
+ <g
+ clip-path="url(#clipPath5603)"
+ id="g5601">
+ <path
+ id="path5607"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3398.4,962.23 c 7.97,0 15.58,3.161 21.21,8.79 5.62,5.621 8.79,13.242 8.79,21.21 0,7.93 -3.17,15.58 -8.79,21.21 -5.63,5.62 -13.24,8.79 -21.21,8.79 -7.97,0 -15.59,-3.17 -21.21,-8.79 -5.63,-5.63 -8.79,-13.28 -8.79,-21.21 0,-7.968 3.16,-15.589 8.79,-21.21 5.62,-5.629 13.24,-8.79 21.21,-8.79"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5609"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3398.4,962.23 c 7.97,0 15.58,3.161 21.21,8.79 5.62,5.621 8.79,13.242 8.79,21.21 0,7.93 -3.17,15.58 -8.79,21.21 -5.63,5.62 -13.24,8.79 -21.21,8.79 -7.97,0 -15.59,-3.17 -21.21,-8.79 -5.63,-5.63 -8.79,-13.28 -8.79,-21.21 0,-7.968 3.16,-15.589 8.79,-21.21 5.62,-5.629 13.24,-8.79 21.21,-8.79 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5611">
+ <g
+ clip-path="url(#clipPath5615)"
+ id="g5613">
+ <path
+ id="path5619"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3844.8,1057.62 c 7.97,0 15.59,3.16 21.22,8.79 5.62,5.62 8.78,13.28 8.78,21.21 0,7.97 -3.16,15.58 -8.78,21.21 -5.63,5.62 -13.25,8.79 -21.22,8.79 -7.96,0 -15.58,-3.17 -21.21,-8.79 -5.62,-5.63 -8.79,-13.24 -8.79,-21.21 0,-7.93 3.17,-15.59 8.79,-21.21 5.63,-5.63 13.25,-8.79 21.21,-8.79"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5621"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3844.8,1057.62 c 7.97,0 15.59,3.16 21.22,8.79 5.62,5.62 8.78,13.28 8.78,21.21 0,7.97 -3.16,15.58 -8.78,21.21 -5.63,5.62 -13.25,8.79 -21.22,8.79 -7.96,0 -15.58,-3.17 -21.21,-8.79 -5.62,-5.63 -8.79,-13.24 -8.79,-21.21 0,-7.93 3.17,-15.59 8.79,-21.21 5.63,-5.63 13.25,-8.79 21.21,-8.79 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5623">
+ <g
+ clip-path="url(#clipPath5627)"
+ id="g5625">
+ <path
+ id="path5631"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4291.21,1151.45 c 7.93,0 15.59,3.16 21.21,8.78 5.63,5.63 8.79,13.25 8.79,21.22 0,7.93 -3.16,15.58 -8.79,21.21 -5.62,5.62 -13.28,8.79 -21.21,8.79 -7.97,0 -15.59,-3.17 -21.21,-8.79 -5.62,-5.63 -8.79,-13.28 -8.79,-21.21 0,-7.97 3.17,-15.59 8.79,-21.22 5.62,-5.62 13.24,-8.78 21.21,-8.78"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5633"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4291.21,1151.45 c 7.93,0 15.59,3.16 21.21,8.78 5.63,5.63 8.79,13.25 8.79,21.22 0,7.93 -3.16,15.58 -8.79,21.21 -5.62,5.62 -13.28,8.79 -21.21,8.79 -7.97,0 -15.59,-3.17 -21.21,-8.79 -5.62,-5.63 -8.79,-13.28 -8.79,-21.21 0,-7.97 3.17,-15.59 8.79,-21.22 5.62,-5.62 13.24,-8.78 21.21,-8.78 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5635">
+ <g
+ clip-path="url(#clipPath5639)"
+ id="g5637">
+ <path
+ id="path5643"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4737.62,1244.61 c 7.93,0 15.58,3.16 21.21,8.79 5.62,5.62 8.79,13.24 8.79,21.21 0,7.93 -3.17,15.59 -8.79,21.21 -5.63,5.63 -13.28,8.79 -21.21,8.79 -7.97,0 -15.59,-3.16 -21.21,-8.79 -5.67,-5.62 -8.79,-13.28 -8.79,-21.21 0,-7.97 3.12,-15.59 8.79,-21.21 5.62,-5.63 13.24,-8.79 21.21,-8.79"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5645"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4737.62,1244.61 c 7.93,0 15.58,3.16 21.21,8.79 5.62,5.62 8.79,13.24 8.79,21.21 0,7.93 -3.17,15.59 -8.79,21.21 -5.63,5.63 -13.28,8.79 -21.21,8.79 -7.97,0 -15.59,-3.16 -21.21,-8.79 -5.67,-5.62 -8.79,-13.28 -8.79,-21.21 0,-7.97 3.12,-15.59 8.79,-21.21 5.62,-5.63 13.24,-8.79 21.21,-8.79 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5647">
+ <g
+ clip-path="url(#clipPath5651)"
+ id="g5649">
+ <path
+ id="path5655"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 5183.98,1338.95 c 7.97,0 15.59,3.16 21.22,8.78 5.62,5.63 8.78,13.29 8.78,21.22 0,7.96 -3.16,15.62 -8.78,21.25 -5.63,5.62 -13.25,8.75 -21.22,8.75 -7.93,0 -15.58,-3.13 -21.21,-8.75 -5.62,-5.63 -8.79,-13.29 -8.79,-21.25 0,-7.93 3.17,-15.59 8.79,-21.22 5.63,-5.62 13.28,-8.78 21.21,-8.78"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5657"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,1338.95 c 7.97,0 15.59,3.16 21.22,8.78 5.62,5.63 8.78,13.29 8.78,21.22 0,7.96 -3.16,15.62 -8.78,21.25 -5.63,5.62 -13.25,8.75 -21.22,8.75 -7.93,0 -15.58,-3.13 -21.21,-8.75 -5.62,-5.63 -8.79,-13.29 -8.79,-21.25 0,-7.93 3.17,-15.59 8.79,-21.22 5.63,-5.62 13.28,-8.78 21.21,-8.78 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5659">
+ <g
+ clip-path="url(#clipPath5663)"
+ id="g5661">
+ <path
+ id="path5667"
+ style="fill:none;stroke:#008000;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,434.609 437.461,294.692 446.4,308.549 446.41,307.58 446.37,315.43 446.4,311.91 446.41,311.29 446.4,316.84 446.41,310.43 446.41,307.85 446.36,312.7"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5669">
+ <g
+ clip-path="url(#clipPath5673)"
+ id="g5671">
+ <path
+ id="path5677"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 728.949,404.609 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5679"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,404.609 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5681">
+ <g
+ clip-path="url(#clipPath5685)"
+ id="g5683">
+ <path
+ id="path5689"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1166.41,699.301 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5691"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1166.41,699.301 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5693">
+ <g
+ clip-path="url(#clipPath5697)"
+ id="g5695">
+ <path
+ id="path5701"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1612.81,1007.85 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5703"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1612.81,1007.85 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5705">
+ <g
+ clip-path="url(#clipPath5709)"
+ id="g5707">
+ <path
+ id="path5713"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2059.22,1315.43 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5715"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2059.22,1315.43 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5717">
+ <g
+ clip-path="url(#clipPath5721)"
+ id="g5719">
+ <path
+ id="path5725"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2505.59,1630.86 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5727"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2505.59,1630.86 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5729">
+ <g
+ clip-path="url(#clipPath5733)"
+ id="g5731">
+ <path
+ id="path5737"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2951.99,1942.77 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5739"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2951.99,1942.77 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5741">
+ <g
+ clip-path="url(#clipPath5745)"
+ id="g5743">
+ <path
+ id="path5749"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3398.4,2254.06 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5751"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3398.4,2254.06 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5753">
+ <g
+ clip-path="url(#clipPath5757)"
+ id="g5755">
+ <path
+ id="path5761"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3844.8,2570.9 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5763"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3844.8,2570.9 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5765">
+ <g
+ clip-path="url(#clipPath5769)"
+ id="g5767">
+ <path
+ id="path5773"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4291.21,2881.33 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5775"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4291.21,2881.33 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5777">
+ <g
+ clip-path="url(#clipPath5781)"
+ id="g5779">
+ <path
+ id="path5785"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4737.62,3189.18 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5787"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4737.62,3189.18 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5789">
+ <g
+ clip-path="url(#clipPath5793)"
+ id="g5791">
+ <path
+ id="path5797"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 5183.98,3501.88 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5799"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,3501.88 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5801">
+ <g
+ clip-path="url(#clipPath5805)"
+ id="g5803">
+ <path
+ id="path5809"
+ style="fill:none;stroke:#ff0000;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,432.148 437.461,13.122 446.4,13.128 446.41,13.75 446.37,14.692 446.4,15.039 446.41,13.473 446.4,16.988 446.41,13.281 446.41,12.5 446.36,13.399"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5811">
+ <g
+ clip-path="url(#clipPath5815)"
+ id="g5813">
+ <path
+ id="path5819"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 698.949,402.148 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5821"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 698.949,402.148 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5823">
+ <g
+ clip-path="url(#clipPath5827)"
+ id="g5825">
+ <path
+ id="path5831"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1136.41,415.27 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5833"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1136.41,415.27 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5835">
+ <g
+ clip-path="url(#clipPath5839)"
+ id="g5837">
+ <path
+ id="path5843"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1582.81,428.398 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5845"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1582.81,428.398 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5847">
+ <g
+ clip-path="url(#clipPath5851)"
+ id="g5849">
+ <path
+ id="path5855"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2029.22,442.148 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5857"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2029.22,442.148 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5859">
+ <g
+ clip-path="url(#clipPath5863)"
+ id="g5861">
+ <path
+ id="path5867"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2475.59,456.84 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5869"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2475.59,456.84 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5871">
+ <g
+ clip-path="url(#clipPath5875)"
+ id="g5873">
+ <path
+ id="path5879"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2921.99,471.879 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5881"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2921.99,471.879 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5883">
+ <g
+ clip-path="url(#clipPath5887)"
+ id="g5885">
+ <path
+ id="path5891"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3368.4,485.352 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5893"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3368.4,485.352 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5895">
+ <g
+ clip-path="url(#clipPath5899)"
+ id="g5897">
+ <path
+ id="path5903"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3814.8,502.34 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5905"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3814.8,502.34 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5907">
+ <g
+ clip-path="url(#clipPath5911)"
+ id="g5909">
+ <path
+ id="path5915"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4261.21,515.621 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5917"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4261.21,515.621 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5919">
+ <g
+ clip-path="url(#clipPath5923)"
+ id="g5921">
+ <path
+ id="path5927"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4707.62,528.121 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5929"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4707.62,528.121 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5931">
+ <g
+ clip-path="url(#clipPath5935)"
+ id="g5933">
+ <path
+ id="path5939"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 5153.98,541.52 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5941"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5153.98,541.52 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5943">
+ <g
+ clip-path="url(#clipPath5947)"
+ id="g5945">
+ <path
+ id="path5951"
+ style="fill:none;stroke:#00bfbf;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,432.07 437.461,0.078 446.4,-0.117 446.41,0.078 446.37,0.161 446.4,0 446.41,-0.079 446.4,-0.043 446.41,-0.078 446.41,0.27 446.36,0.199"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5953">
+ <g
+ clip-path="url(#clipPath5957)"
+ id="g5955">
+ <path
+ id="path5961"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 728.949,462.07 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5963"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 728.949,462.07 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5965">
+ <g
+ clip-path="url(#clipPath5969)"
+ id="g5967">
+ <path
+ id="path5973"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1166.41,462.148 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5975"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1166.41,462.148 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5977">
+ <g
+ clip-path="url(#clipPath5981)"
+ id="g5979">
+ <path
+ id="path5985"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 1612.81,462.031 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5987"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1612.81,462.031 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g5989">
+ <g
+ clip-path="url(#clipPath5993)"
+ id="g5991">
+ <path
+ id="path5997"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2059.22,462.109 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5999"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2059.22,462.109 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6001">
+ <g
+ clip-path="url(#clipPath6005)"
+ id="g6003">
+ <path
+ id="path6009"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2505.59,462.27 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6011"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2505.59,462.27 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6013">
+ <g
+ clip-path="url(#clipPath6017)"
+ id="g6015">
+ <path
+ id="path6021"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2951.99,462.27 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6023"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2951.99,462.27 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6025">
+ <g
+ clip-path="url(#clipPath6029)"
+ id="g6027">
+ <path
+ id="path6033"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3398.4,462.191 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6035"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3398.4,462.191 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6037">
+ <g
+ clip-path="url(#clipPath6041)"
+ id="g6039">
+ <path
+ id="path6045"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3844.8,462.148 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6047"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3844.8,462.148 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6049">
+ <g
+ clip-path="url(#clipPath6053)"
+ id="g6051">
+ <path
+ id="path6057"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4291.21,462.07 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6059"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4291.21,462.07 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6061">
+ <g
+ clip-path="url(#clipPath6065)"
+ id="g6063">
+ <path
+ id="path6069"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 4737.62,462.301 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6071"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4737.62,462.301 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6073">
+ <g
+ clip-path="url(#clipPath6077)"
+ id="g6075">
+ <path
+ id="path6081"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 5183.98,462.539 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6083"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,462.539 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6085">
+ <g
+ clip-path="url(#clipPath6089)"
+ id="g6087">
+ <path
+ id="path6093"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6095"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,431.988 0,40"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6097"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,3888.01 0,-40"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6099">
+ <text
+ id="text6101"
+ transform="matrix(1,0,0,-1,68.9766,30.2938)">
+ <tspan
+ id="tspan6103"
+ y="0"
+ x="0"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">0</tspan>
+ </text>
+ </g>
+ <g
+ id="g6105">
+ <g
+ clip-path="url(#clipPath6109)"
+ id="g6107">
+ <path
+ id="path6113"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 1612.81,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6115"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1612.81,431.988 0,40"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6117"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 1612.81,3888.01 0,-40"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6119">
+ <text
+ id="text6121"
+ transform="matrix(1,0,0,-1,147.054,30.2938)">
+ <tspan
+ id="tspan6123"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">1000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6125">
+ <g
+ clip-path="url(#clipPath6129)"
+ id="g6127">
+ <path
+ id="path6133"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 2505.59,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6135"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2505.59,431.988 0,40"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6137"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2505.59,3888.01 0,-40"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6139">
+ <text
+ id="text6141"
+ transform="matrix(1,0,0,-1,236.115,30.2938)">
+ <tspan
+ id="tspan6143"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">2000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6145">
+ <g
+ clip-path="url(#clipPath6149)"
+ id="g6147">
+ <path
+ id="path6153"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 3398.4,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6155"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3398.4,431.988 0,40"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6157"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 3398.4,3888.01 0,-40"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6159">
+ <text
+ id="text6161"
+ transform="matrix(1,0,0,-1,325.418,30.2938)">
+ <tspan
+ id="tspan6163"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">3000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6165">
+ <g
+ clip-path="url(#clipPath6169)"
+ id="g6167">
+ <path
+ id="path6173"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 4291.21,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6175"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4291.21,431.988 0,40"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6177"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 4291.21,3888.01 0,-40"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6179">
+ <text
+ id="text6181"
+ transform="matrix(1,0,0,-1,414.534,30.2938)">
+ <tspan
+ id="tspan6183"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">4000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6185">
+ <g
+ clip-path="url(#clipPath6189)"
+ id="g6187">
+ <path
+ id="path6193"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 5183.98,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6195"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,431.988 0,40"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6197"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,3888.01 0,-40"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6199">
+ <text
+ id="text6201"
+ transform="matrix(1,0,0,-1,503.978,30.2938)">
+ <tspan
+ id="tspan6203"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">5000</tspan>
+ <tspan
+ id="tspan6205"
+ sodipodi:role="line"
+ y="14.2969"
+ x="-266.052 -257.07599 -249.468 -237.78 -230.16 -222.78 -217.84801 -214.032 -206.688 -202.464 -198.64799 -191.54401 -184.164 -179.23199 -174.528 -171.192 -164.592 -157.21201"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">Number of vertices</tspan>
+ </text>
+ </g>
+ <g
+ id="g6207">
+ <g
+ clip-path="url(#clipPath6211)"
+ id="g6209">
+ <path
+ id="path6215"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,431.988 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6217"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,431.988 40,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6219"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,431.988 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6221">
+ <text
+ id="text6223"
+ transform="matrix(1,0,0,-1,61.9531,38.8328)">
+ <tspan
+ id="tspan6225"
+ y="0"
+ x="0"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">0</tspan>
+ </text>
+ </g>
+ <g
+ id="g6227">
+ <g
+ clip-path="url(#clipPath6231)"
+ id="g6229">
+ <path
+ id="path6235"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,863.98 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6237">
+ <g
+ clip-path="url(#clipPath6241)"
+ id="g6239">
+ <path
+ id="path6245"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,863.98 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6247"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,863.98 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6249">
+ <text
+ id="text6251"
+ transform="matrix(1,0,0,-1,31.4688,82.0328)">
+ <tspan
+ id="tspan6253"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">20000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6255">
+ <g
+ clip-path="url(#clipPath6259)"
+ id="g6257">
+ <path
+ id="path6263"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,1296.02 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6265">
+ <g
+ clip-path="url(#clipPath6269)"
+ id="g6267">
+ <path
+ id="path6273"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,1296.02 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6275"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,1296.02 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6277">
+ <text
+ id="text6279"
+ transform="matrix(1,0,0,-1,31.1875,125.233)">
+ <tspan
+ id="tspan6281"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">40000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6283">
+ <g
+ clip-path="url(#clipPath6287)"
+ id="g6285">
+ <path
+ id="path6291"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,1728.01 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6293">
+ <g
+ clip-path="url(#clipPath6297)"
+ id="g6295">
+ <path
+ id="path6301"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,1728.01 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6303"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,1728.01 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6305">
+ <text
+ id="text6307"
+ transform="matrix(1,0,0,-1,31.4375,168.433)">
+ <tspan
+ id="tspan6309"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">60000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6311">
+ <g
+ clip-path="url(#clipPath6315)"
+ id="g6313">
+ <path
+ id="path6319"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,2160 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6321">
+ <g
+ clip-path="url(#clipPath6325)"
+ id="g6323">
+ <path
+ id="path6329"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,2160 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6331"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,2160 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6333">
+ <text
+ id="text6335"
+ transform="matrix(1,0,0,-1,31.4063,211.633)">
+ <tspan
+ id="tspan6337"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">80000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6339">
+ <g
+ clip-path="url(#clipPath6343)"
+ id="g6341">
+ <path
+ id="path6347"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,2591.99 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6349">
+ <g
+ clip-path="url(#clipPath6353)"
+ id="g6351">
+ <path
+ id="path6357"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,2591.99 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6359"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,2591.99 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6361">
+ <text
+ id="text6363"
+ transform="matrix(1,0,0,-1,24.2656,254.833)">
+ <tspan
+ id="tspan6365"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528 38.16"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">100000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6367">
+ <g
+ clip-path="url(#clipPath6371)"
+ id="g6369">
+ <path
+ id="path6375"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,3023.98 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6377">
+ <g
+ clip-path="url(#clipPath6381)"
+ id="g6379">
+ <path
+ id="path6385"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,3023.98 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6387"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,3023.98 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6389">
+ <text
+ id="text6391"
+ transform="matrix(1,0,0,-1,24.2656,298.033)">
+ <tspan
+ id="tspan6393"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528 38.16"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">120000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6395">
+ <g
+ clip-path="url(#clipPath6399)"
+ id="g6397">
+ <path
+ id="path6403"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,3456.02 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6405">
+ <g
+ clip-path="url(#clipPath6409)"
+ id="g6407">
+ <path
+ id="path6413"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,3456.02 40,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6415"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,3456.02 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6417">
+ <text
+ id="text6419"
+ transform="matrix(1,0,0,-1,24.2656,341.233)">
+ <tspan
+ id="tspan6421"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528 38.16"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">140000</tspan>
+ </text>
+ </g>
+ <g
+ id="g6423">
+ <g
+ clip-path="url(#clipPath6427)"
+ id="g6425">
+ <path
+ id="path6431"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:10, 30;stroke-dashoffset:0"
+ d="m 720,3888.01 4463.98,0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6433"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,3888.01 40,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6435"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,3888.01 -40,0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6437">
+ <text
+ id="text6439"
+ transform="matrix(1,0,0,-1,24.2656,384.433)">
+ <tspan
+ id="tspan6441"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.632 15.264 22.896 30.528 38.16"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">160000</tspan>
+ </text>
+ <text
+ id="text6443"
+ transform="matrix(0,1,1,0,19.0938,204.398)">
+ <tspan
+ id="tspan6445"
+ sodipodi:role="line"
+ y="0"
+ x="0 7.6199999 10.956 17.256001"
+ style="font-size:12px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">Size</tspan>
+ </text>
+ </g>
+ <path
+ id="path6447"
+ style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,3888.01 4463.98,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6449"
+ style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 5183.98,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6451"
+ style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,431.988 4463.98,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6453"
+ style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 720,431.988 0,3456.022"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6455"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2693.75,2938.4 2418.24,0 0,877.621 -2418.24,0 0,-877.621 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6457"
+ style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2693.75,2938.4 2418.24,0 0,877.621 -2418.24,0 0,-877.621 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6459"
+ style="fill:none;stroke:#0000ff;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3701.76 201.6,0"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g6461">
+ <g
+ clip-path="url(#clipPath6465)"
+ id="g6463">
+ <path
+ id="path6469"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2794.57,3671.76 c 7.93,0 15.59,3.16 21.21,8.79 5.63,5.62 8.79,13.28 8.79,21.21 0,7.97 -3.16,15.58 -8.79,21.21 -5.62,5.62 -13.28,8.79 -21.21,8.79 -7.97,0 -15.59,-3.17 -21.21,-8.79 -5.63,-5.63 -8.79,-13.24 -8.79,-21.21 0,-7.93 3.16,-15.59 8.79,-21.21 5.62,-5.63 13.24,-8.79 21.21,-8.79"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6471"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3671.76 c 7.93,0 15.59,3.16 21.21,8.79 5.63,5.62 8.79,13.28 8.79,21.21 0,7.97 -3.16,15.58 -8.79,21.21 -5.62,5.62 -13.28,8.79 -21.21,8.79 -7.97,0 -15.59,-3.17 -21.21,-8.79 -5.63,-5.63 -8.79,-13.24 -8.79,-21.21 0,-7.93 3.16,-15.59 8.79,-21.21 5.62,-5.63 13.24,-8.79 21.21,-8.79 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6473">
+ <g
+ clip-path="url(#clipPath6477)"
+ id="g6475">
+ <path
+ id="path6481"
+ style="fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2996.17,3671.76 c 7.93,0 15.59,3.16 21.21,8.79 5.63,5.62 8.79,13.28 8.79,21.21 0,7.97 -3.16,15.58 -8.79,21.21 -5.62,5.62 -13.28,8.79 -21.21,8.79 -7.97,0 -15.58,-3.17 -21.21,-8.79 -5.62,-5.63 -8.79,-13.24 -8.79,-21.21 0,-7.93 3.17,-15.59 8.79,-21.21 5.63,-5.63 13.24,-8.79 21.21,-8.79"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6483"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2996.17,3671.76 c 7.93,0 15.59,3.16 21.21,8.79 5.63,5.62 8.79,13.28 8.79,21.21 0,7.97 -3.16,15.58 -8.79,21.21 -5.62,5.62 -13.28,8.79 -21.21,8.79 -7.97,0 -15.58,-3.17 -21.21,-8.79 -5.62,-5.63 -8.79,-13.24 -8.79,-21.21 0,-7.93 3.17,-15.59 8.79,-21.21 5.63,-5.63 13.24,-8.79 21.21,-8.79 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <path
+ id="path6491"
+ style="fill:none;stroke:#008000;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3490.39 201.6,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6493"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2794.57,3460.39 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6495"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3460.39 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6497"
+ style="fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2996.17,3460.39 30,60 -60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6499"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2996.17,3460.39 30,60 -60,0 30,-60 z"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6501">
+ <text
+ id="text6503"
+ transform="matrix(1,0,0,-1,315.455,343.999)">
+ <tspan
+ id="tspan6505"
+ sodipodi:role="line"
+ y="0"
+ x="0 9.1295996 18.259199 36.864101 44.366501 48.369701 62.395302 71.539299 75.542503 79.5457 87.465698 96.321701"
+ style="font-size:14.39999962px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">numsimplices</tspan>
+ </text>
+ </g>
+ <path
+ id="path6507"
+ style="fill:none;stroke:#ff0000;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3282.93 201.6,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6509"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2764.57,3252.93 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6511"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2764.57,3252.93 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6513"
+ style="fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2966.17,3252.93 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6515"
+ style="fill:none;stroke:#ff0000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2966.17,3252.93 60,60 m -60,0 60,-60"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6517">
+ <text
+ id="text6519"
+ transform="matrix(1,0,0,-1,315.455,323.252)">
+ <tspan
+ id="tspan6521"
+ sodipodi:role="line"
+ y="0"
+ x="0 9.1295996 18.259199 32.284801 36.863998 46.007999 50.0112 58.824001 66.744003 75.081596 83.937599 89.856003"
+ style="font-size:14.39999962px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">num blockers</tspan>
+ </text>
+ </g>
+ <path
+ id="path6523"
+ style="fill:none;stroke:#00bfbf;stroke-width:20;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3075.47 201.6,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6525"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2794.57,3105.47 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6527"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2794.57,3105.47 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6529"
+ style="fill:#00bfbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2996.17,3105.47 -30,-60 60,0"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6531"
+ style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none"
+ d="m 2996.17,3105.47 -30,-60 60,0 -30,60 z"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="scale(10,10)"
+ id="g6533">
+ <text
+ id="text6535"
+ transform="matrix(1,0,0,-1,315.455,302.505)">
+ <tspan
+ id="tspan6537"
+ sodipodi:role="line"
+ y="0"
+ x="0 9.1295996 18.259199 32.284801 36.863998 45.993599 54.8064 63.936001 68.515198 77.659203 86.472 95.615997 104.4432 113.5872 117.5904 126.4464 131.0256 140.21297 144.21616 153.02896 160.94896 169.28656 178.14256 184.06096"
+ style="font-size:14.39999962px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans">num non popable blockers</tspan>
+ </text>
+ </g>
+ <text
+ style="font-size:120px"
+ y="-3655.6985"
+ x="3153.7925"
+ id="text6487-0"
+ transform="scale(1,-1)">
+ <tspan
+ id="tspan6489-8"
+ sodipodi:role="line"
+ style="font-size:144px;font-variant:normal;font-weight:normal;writing-mode:lr-tb;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:DejaVu Sans;-inkscape-font-specification:DejaVuSans"
+ x="3153.7925"
+ y="-3655.6985">size of the graph</tspan>
+ </text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/src/Skeleton_blocker/doc/blockers_curve.png b/src/Skeleton_blocker/doc/blockers_curve.png
new file mode 100644
index 00000000..58863ece
--- /dev/null
+++ b/src/Skeleton_blocker/doc/blockers_curve.png
Binary files differ
diff --git a/src/Skeleton_blocker/doc/ds_representation.png b/src/Skeleton_blocker/doc/ds_representation.png
new file mode 100644
index 00000000..8136621a
--- /dev/null
+++ b/src/Skeleton_blocker/doc/ds_representation.png
Binary files differ
diff --git a/src/Skeleton_blocker/doc/ds_representation.svg b/src/Skeleton_blocker/doc/ds_representation.svg
new file mode 100644
index 00000000..981b2874
--- /dev/null
+++ b/src/Skeleton_blocker/doc/ds_representation.svg
@@ -0,0 +1,470 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="434.50912"
+ height="113.23431"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="ds_representation.svg"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294">
+ <defs
+ id="defs4">
+ <inkscape:path-effect
+ is_visible="true"
+ id="path-effect4610"
+ effect="spiro" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="3.959798"
+ inkscape:cx="393.78845"
+ inkscape:cy="51.962328"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="2560"
+ inkscape:window-height="1523"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(775.10425,-319.57102)">
+ <path
+ id="path4432"
+ d="m -564.66566,372.78112 -22.51977,46.5698 62.69739,-31.00174 z"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m -553.17597,345.78586 c 0.75762,1.51523 32.57742,14.89975 32.57742,14.89975"
+ id="path3125"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -519.08333,361.44322 31.81981,11.8693"
+ id="path3127"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-7"
+ style="fill:none;stroke:none"
+ d="m -554.02684,345.73906 29.32107,42.08799 7.736,-39.88821"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-1"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -523.3168,376.08402 34.2525,-51.7575"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -564.28765,372.5549 47.47717,-24.4962 -7.82868,39.90103 37.1231,-14.89975 -29.29442,-25.25382 -37.37564,-2.27284 29.54696,42.42641"
+ id="path3121"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-691.68016,428.25063)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-669.37366,382.75481)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-4"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-630.26652,397.04052)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-1"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-659.37366,354.89767)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-42"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-622.23081,358.64766)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-3"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-593.12367,383.11196)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-7"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-1-1"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -378.67395,371.32852 34.2525,-51.7575"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -413.6327,367.61658 37.56127,-20.2544 c 0,0 -4.64286,29.64285 -5.35714,31.42857 -0.71429,1.78571 -32.20413,-11.17417 -32.20413,-11.17417 z"
+ id="path4091"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsc" />
+ <g
+ id="g3909">
+ <path
+ sodipodi:nodetypes="ccc"
+ d="m -409.13145,340.85729 28.31093,41.70918 8.87241,-39.38313"
+ style="fill:none;fill-opacity:0.41568603999999998;fill-rule:nonzero;stroke:none;opacity:0.13580247"
+ id="path14-3-5"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccc"
+ inkscape:connector-curvature="0"
+ style="opacity:0.13580244;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ d="m -420.02281,368.02562 -22.51977,46.5698 62.69739,-31.00174 z"
+ id="path4432-5" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path3125-0"
+ d="m -408.53312,341.03036 c 0.75762,1.51523 32.57742,14.89975 32.57742,14.89975"
+ style="opacity:0.13580244;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path3127-1"
+ d="m -374.44048,356.68772 31.81981,11.8693"
+ style="opacity:0.13580244;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ inkscape:connector-curvature="0"
+ id="path3121-0"
+ d="m -419.6448,367.7994 47.47717,-24.4962 -7.82868,39.90103 37.1231,-14.89975 -29.29442,-25.25382 -37.37564,-2.27284 29.54696,42.42641"
+ style="opacity:0.13580244;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.13580244;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4584-36"
+ sodipodi:cx="93.972473"
+ sodipodi:cy="113.9189"
+ sodipodi:rx="3.4171808"
+ sodipodi:ry="3.4171808"
+ d="m 97.389654,113.9189 a 3.4171808,3.4171808 0 1 1 -6.834362,0 3.4171808,3.4171808 0 1 1 6.834362,0 z"
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-547.03731,423.49513)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.13580244;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4584-4-5"
+ sodipodi:cx="93.972473"
+ sodipodi:cy="113.9189"
+ sodipodi:rx="3.4171808"
+ sodipodi:ry="3.4171808"
+ d="m 97.389654,113.9189 a 3.4171808,3.4171808 0 1 1 -6.834362,0 3.4171808,3.4171808 0 1 1 6.834362,0 z"
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-524.73081,377.99931)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.13580244;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4584-1-6"
+ sodipodi:cx="93.972473"
+ sodipodi:cy="113.9189"
+ sodipodi:rx="3.4171808"
+ sodipodi:ry="3.4171808"
+ d="m 97.389654,113.9189 a 3.4171808,3.4171808 0 1 1 -6.834362,0 3.4171808,3.4171808 0 1 1 6.834362,0 z"
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-485.62367,392.28502)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.13580244;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4584-42-0"
+ sodipodi:cx="93.972473"
+ sodipodi:cy="113.9189"
+ sodipodi:rx="3.4171808"
+ sodipodi:ry="3.4171808"
+ d="m 97.389654,113.9189 a 3.4171808,3.4171808 0 1 1 -6.834362,0 3.4171808,3.4171808 0 1 1 6.834362,0 z"
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-514.73081,350.14217)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.13580244;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4584-3-9"
+ sodipodi:cx="93.972473"
+ sodipodi:cy="113.9189"
+ sodipodi:rx="3.4171808"
+ sodipodi:ry="3.4171808"
+ d="m 97.389654,113.9189 a 3.4171808,3.4171808 0 1 1 -6.834362,0 3.4171808,3.4171808 0 1 1 6.834362,0 z"
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-477.58796,353.89216)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.13580244;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ id="path4584-7-0"
+ sodipodi:cx="93.972473"
+ sodipodi:cy="113.9189"
+ sodipodi:rx="3.4171808"
+ sodipodi:ry="3.4171808"
+ d="m 97.389654,113.9189 a 3.4171808,3.4171808 0 1 1 -6.834362,0 3.4171808,3.4171808 0 1 1 6.834362,0 z"
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-448.48082,378.35646)" />
+ </g>
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -370.55894,347.61837 23.42349,19.75458 c 0,0 -28.39286,9.99999 -29.10714,11.78571 -0.71429,1.78571 5.68365,-31.54029 5.68365,-31.54029 z"
+ id="path4091-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsc" />
+ <path
+ id="path4432-6"
+ d="m -750.37996,370.16849 -22.51977,46.5698 62.69739,-31.00174 z"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0"
+ d="m -738.89027,343.17323 c 0.75762,1.51523 32.57742,14.89975 32.57742,14.89975"
+ id="path3125-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -704.79763,358.83059 31.81981,11.8693"
+ id="path3127-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-12"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -750.60027,369.89548 -21.18655,45.87606 60.51647,-29.53414"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-7-8"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -739.74114,343.12643 29.32107,42.08799 7.736,-39.88821"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-8-0"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -702.3655,345.90435 -2.625,13.17237 29.83309,9.73554"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-2-70"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -704.89087,358.7838 -5.27665,26.68316 35.26265,-15.39201"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-3-2"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -739.4886,343.00016 28.31093,41.70918 8.87241,-39.38313"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-1-2"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -709.0311,373.47139 34.2525,-51.7575"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -750.00195,369.94227 47.47717,-24.4962 -7.82868,39.90103 37.1231,-14.89975 -29.29442,-25.25382 -37.37564,-2.27284 29.54696,42.42641"
+ id="path3121-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-877.39446,425.638)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-79"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-855.08796,380.14218)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-4-9"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-815.98082,394.42789)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-1-61"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-845.08796,352.28504)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-42-8"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-807.94511,356.03503)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-3-5"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-778.83797,380.49933)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-7-1"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-718.37708"
+ y="430.86295"
+ id="text6164-6-56-2"
+ sodipodi:linespacing="125%"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6"
+ x="-718.37708"
+ y="430.86295">Simplicial complex</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-462.22809"
+ y="430.86295"
+ id="text6164-6-56-2-3"
+ sodipodi:linespacing="125%"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9"
+ x="-462.22809"
+ y="430.86295">Encoding</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-535.67126"
+ y="334.7963"
+ id="text6164-6-56-2-3-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9-9"
+ x="-535.67126"
+ y="334.7963">Graph</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-389.50018"
+ y="335.10443"
+ id="text6164-6-56-2-3-0-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9-9-1"
+ x="-389.50018"
+ y="335.10443">Blockers</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-470.03345"
+ y="335.56711"
+ id="text6164-6-56-2-3-0-36"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9-9-3"
+ x="-470.03345"
+ y="335.56711">+</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-618.52417"
+ y="382.18915"
+ id="text6164-6-56-2-1"
+ sodipodi:linespacing="125%"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-4"
+ x="-618.52417"
+ y="382.18915">=</tspan></text>
+ </g>
+</svg>
diff --git a/src/Skeleton_blocker/doc/ds_scheme.svg b/src/Skeleton_blocker/doc/ds_scheme.svg
new file mode 100644
index 00000000..f13a6213
--- /dev/null
+++ b/src/Skeleton_blocker/doc/ds_scheme.svg
@@ -0,0 +1,477 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="434.50912"
+ height="113.23431"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="ds_scheme.svg"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294">
+ <defs
+ id="defs4">
+ <inkscape:path-effect
+ is_visible="true"
+ id="path-effect4610"
+ effect="spiro" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8"
+ inkscape:cx="110.77021"
+ inkscape:cy="32.991372"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="2560"
+ inkscape:window-height="1523"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(775.10425,-319.57102)">
+ <path
+ id="path4432"
+ d="m -564.66566,372.78112 -22.51977,46.5698 62.69739,-31.00174 z"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m -553.17597,345.78586 c 0.75762,1.51523 32.57742,14.89975 32.57742,14.89975"
+ id="path3125"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -519.08333,361.44322 31.81981,11.8693"
+ id="path3127"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-7"
+ style="fill:none;stroke:none"
+ d="m -554.02684,345.73906 29.32107,42.08799 7.736,-39.88821"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-1"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -523.3168,376.08402 34.2525,-51.7575"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -564.28765,372.5549 47.47717,-24.4962 -7.82868,39.90103 37.1231,-14.89975 -29.29442,-25.25382 -37.37564,-2.27284 29.54696,42.42641"
+ id="path3121"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-691.68016,428.25063)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-669.37366,382.75481)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-4"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-630.26652,397.04052)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-1"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-659.37366,354.89767)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-42"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-622.23081,358.64766)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-3"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-593.12367,383.11196)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-7"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ id="path4432-5"
+ d="m -420.02281,368.02562 -22.51977,46.5698 62.69739,-31.00174 z"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0"
+ d="m -408.53312,341.03036 c 0.75762,1.51523 32.57742,14.89975 32.57742,14.89975"
+ id="path3125-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -374.44048,356.68772 31.81981,11.8693"
+ id="path3127-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-79"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -420.24312,367.75261 -21.18655,45.87606 60.51647,-29.53414"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-7-1"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -409.38399,340.98356 29.32107,42.08799 7.736,-39.88821"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-8-6"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -372.00835,343.76148 -2.625,13.17237 29.83309,9.73554"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-2-7"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -374.53372,356.64093 -5.27665,26.68316 35.26265,-15.39201"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-3-5"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -409.13145,340.85729 28.31093,41.70918 8.87241,-39.38313"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-1-1"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -378.67395,371.32852 34.2525,-51.7575"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -419.6448,367.7994 47.47717,-24.4962 -7.82868,39.90103 37.1231,-14.89975 -29.29442,-25.25382 -37.37564,-2.27284 29.54696,42.42641"
+ id="path3121-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-547.03731,423.49513)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-36"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-524.73081,377.99931)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-4-5"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-485.62367,392.28502)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-1-6"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-514.73081,350.14217)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-42-0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-477.58796,353.89216)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-3-9"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-448.48082,378.35646)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-7-0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -413.6327,367.61658 37.56127,-20.2544 c 0,0 -4.64286,29.64285 -5.35714,31.42857 -0.71429,1.78571 -32.20413,-11.17417 -32.20413,-11.17417 z"
+ id="path4091"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsc" />
+ <path
+ style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -370.55894,347.61837 23.42349,19.75458 c 0,0 -28.39286,9.99999 -29.10714,11.78571 -0.71429,1.78571 5.68365,-31.54029 5.68365,-31.54029 z"
+ id="path4091-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsc" />
+ <path
+ id="path4432-6"
+ d="m -750.37996,370.16849 -22.51977,46.5698 62.69739,-31.00174 z"
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;display:inline"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 3;stroke-dashoffset:0"
+ d="m -738.89027,343.17323 c 0.75762,1.51523 32.57742,14.89975 32.57742,14.89975"
+ id="path3125-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -704.79763,358.83059 31.81981,11.8693"
+ id="path3127-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-12"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -750.60027,369.89548 -21.18655,45.87606 60.51647,-29.53414"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-7-8"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -739.74114,343.12643 29.32107,42.08799 7.736,-39.88821"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-8-0"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -702.3655,345.90435 -2.625,13.17237 29.83309,9.73554"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-2-70"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -704.89087,358.7838 -5.27665,26.68316 35.26265,-15.39201"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-3-2"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -739.4886,343.00016 28.31093,41.70918 8.87241,-39.38313"
+ sodipodi:nodetypes="ccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14-1-2"
+ style="fill:#575e9c;fill-opacity:0.41568604;fill-rule:nonzero;stroke:none"
+ d="m -709.0311,373.47139 34.2525,-51.7575"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -750.00195,369.94227 47.47717,-24.4962 -7.82868,39.90103 37.1231,-14.89975 -29.29442,-25.25382 -37.37564,-2.27284 29.54696,42.42641"
+ id="path3121-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-877.39446,425.638)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-79"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-855.08796,380.14218)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-4-9"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-815.98082,394.42789)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-1-61"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-845.08796,352.28504)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-42-8"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-807.94511,356.03503)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-3-5"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.39947101,-0.59295401,0.59295401,0.39947101,-778.83797,380.49933)"
+ d="m 97.389654,113.9189 c 0,1.88726 -1.529924,3.41718 -3.417181,3.41718 -1.887257,0 -3.417181,-1.52992 -3.417181,-3.41718 0,-1.88726 1.529924,-3.41718 3.417181,-3.41718 1.887257,0 3.417181,1.52992 3.417181,3.41718 z"
+ sodipodi:ry="3.4171808"
+ sodipodi:rx="3.4171808"
+ sodipodi:cy="113.9189"
+ sodipodi:cx="93.972473"
+ id="path4584-7-1"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.99118668;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
+ sodipodi:type="arc" />
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-718.37708"
+ y="430.86295"
+ id="text6164-6-56-2"
+ sodipodi:linespacing="125%"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6"
+ x="-718.37708"
+ y="430.86295">Simplicial complex</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-462.22809"
+ y="430.86295"
+ id="text6164-6-56-2-3"
+ sodipodi:linespacing="125%"
+ inkscape:export-xdpi="164.24294"
+ inkscape:export-ydpi="164.24294"
+ inkscape:export-filename="/home/dsalinas/Documents/CodeSVN/gudhi_depot/trunk/src/Skeleton_blocker/doc/ds_representation.png"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9"
+ x="-462.22809"
+ y="430.86295">Encoding</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-535.67126"
+ y="334.7963"
+ id="text6164-6-56-2-3-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9-9"
+ x="-535.67126"
+ y="334.7963">Graph</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-389.50018"
+ y="335.10443"
+ id="text6164-6-56-2-3-0-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9-9-1"
+ x="-389.50018"
+ y="335.10443">Blockers</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Times New Roman;-inkscape-font-specification:'Times New Roman,'"
+ x="-470.03345"
+ y="335.56711"
+ id="text6164-6-56-2-3-0-36"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6166-1-0-6-9-9-3"
+ x="-470.03345"
+ y="335.56711">+</tspan></text>
+ </g>
+</svg>
diff --git a/src/Skeleton_blocker/doc/sphere_contraction.png b/src/Skeleton_blocker/doc/sphere_contraction.png
new file mode 100644
index 00000000..502f73f7
--- /dev/null
+++ b/src/Skeleton_blocker/doc/sphere_contraction.png
Binary files differ
diff --git a/src/Skeleton_blocker/example/CMakeLists.txt b/src/Skeleton_blocker/example/CMakeLists.txt
new file mode 100644
index 00000000..0e5d2f11
--- /dev/null
+++ b/src/Skeleton_blocker/example/CMakeLists.txt
@@ -0,0 +1,13 @@
+project(Skeleton_blocker_examples)
+
+add_executable(Skeleton_blocker_example_from_simplices Skeleton_blocker_from_simplices.cpp)
+add_executable(Skeleton_blocker_example_iteration Skeleton_blocker_iteration.cpp)
+add_executable(Skeleton_blocker_example_link Skeleton_blocker_link.cpp)
+
+add_test(NAME Skeleton_blocker_example_from_simplices COMMAND $<TARGET_FILE:Skeleton_blocker_example_from_simplices>)
+add_test(NAME Skeleton_blocker_example_iteration COMMAND $<TARGET_FILE:Skeleton_blocker_example_iteration>)
+add_test(NAME Skeleton_blocker_example_link COMMAND $<TARGET_FILE:Skeleton_blocker_example_link>)
+
+install(TARGETS Skeleton_blocker_example_from_simplices DESTINATION bin)
+install(TARGETS Skeleton_blocker_example_iteration DESTINATION bin)
+install(TARGETS Skeleton_blocker_example_link DESTINATION bin)
diff --git a/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp b/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp
new file mode 100644
index 00000000..486827eb
--- /dev/null
+++ b/src/Skeleton_blocker/example/Skeleton_blocker_from_simplices.cpp
@@ -0,0 +1,65 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#include <gudhi/Skeleton_blocker.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <vector>
+
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simple_traits Traits;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_complex<Traits> Complex;
+typedef Complex::Vertex_handle Vertex_handle;
+typedef Complex::Simplex Simplex;
+
+int main(int argc, char *argv[]) {
+ std::vector<Simplex> simplices;
+
+ // add 4 triangles of a tetrahedron 0123
+ simplices.push_back(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)));
+ simplices.push_back(Simplex(Vertex_handle(3), Vertex_handle(0), Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(3), Vertex_handle(0), Vertex_handle(1)));
+
+ // get complex from top faces
+ Complex complex(Gudhi::skeleton_blocker::make_complex_from_top_faces<Complex>(simplices.begin(), simplices.end()));
+
+
+ std::cout << "Simplices:" << std::endl;
+ for (const Simplex & s : complex.complex_simplex_range())
+ std::cout << s << " ";
+ std::cout << std::endl;
+
+ // One blocker as simplex 0123 is not in the complex but all its proper faces are.
+ std::cout << "Blockers: " << complex.blockers_to_string() << std::endl;
+
+ // now build a complex from its full list of simplices
+ simplices.clear();
+ simplices.push_back(Simplex(Vertex_handle(0)));
+ simplices.push_back(Simplex(Vertex_handle(1)));
+ simplices.push_back(Simplex(Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(0), Vertex_handle(1)));
+ simplices.push_back(Simplex(Vertex_handle(1), Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(2), Vertex_handle(0)));
+ complex = Complex(simplices.begin(), simplices.end());
+
+ std::cout << "Simplices:" << std::endl;
+ for (const Simplex & s : complex.complex_simplex_range())
+ std::cout << s << " ";
+ std::cout << std::endl;
+
+ // One blocker as simplex 012 is not in the complex but all its proper faces are.
+ std::cout << "Blockers: " << complex.blockers_to_string() << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp b/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp
new file mode 100644
index 00000000..7f301047
--- /dev/null
+++ b/src/Skeleton_blocker/example/Skeleton_blocker_iteration.cpp
@@ -0,0 +1,73 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#include <gudhi/Skeleton_blocker.h>
+#include <gudhi/Clock.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simple_traits Traits;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_complex<Traits> Complex;
+typedef Complex::Vertex_handle Vertex_handle;
+typedef Complex::Simplex Simplex;
+
+Complex build_complete_complex(int n) {
+ // build a full complex with n vertices and 2^n-1 simplices
+ Complex complex;
+ for (int i = 0; i < n; i++)
+ complex.add_vertex();
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < i; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ return complex;
+}
+
+int main(int argc, char *argv[]) {
+ Gudhi::Clock skbl_chrono("Time to build the complete complex, enumerate simplices and Euler Characteristic");
+ const int n = 15;
+
+ // build a full complex with n vertices and 2^n-1 simplices
+ Complex complex(build_complete_complex(n));
+
+ // this is just to illustrate iterators, to count number of vertices
+ // or edges, complex.num_vertices() and complex.num_edges() are
+ // more appropriated!
+ unsigned num_vertices = 0;
+ for (auto v : complex.vertex_range()) {
+ std::cout << "Vertex " << v << std::endl;
+ ++num_vertices;
+ }
+
+ // such loop can also be done directly with distance as iterators are STL compliant
+ auto edges = complex.edge_range();
+ unsigned num_edges = std::distance(edges.begin(), edges.end());
+
+ unsigned euler = 0;
+ unsigned num_simplices = 0;
+ // we use a reference to a simplex instead of a copy
+ // value here because a simplex is a set of integers
+ // and copying it cost time
+ for (const Simplex & s : complex.complex_simplex_range()) {
+ ++num_simplices;
+ if (s.dimension() % 2 == 0)
+ euler += 1;
+ else
+ euler -= 1;
+ }
+ std::cout << "Saw " << num_vertices << " vertices, " << num_edges << " edges and " << num_simplices << " simplices"
+ << std::endl;
+ std::cout << "The Euler Characteristic is " << euler << std::endl;
+ std::cout << skbl_chrono;
+ return EXIT_SUCCESS;
+}
diff --git a/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp b/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp
new file mode 100644
index 00000000..e634b656
--- /dev/null
+++ b/src/Skeleton_blocker/example/Skeleton_blocker_link.cpp
@@ -0,0 +1,57 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#include <gudhi/Skeleton_blocker.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simple_traits Traits;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_complex<Traits> Complex;
+typedef Complex::Vertex_handle Vertex_handle;
+typedef Complex::Root_vertex_handle Root_vertex_handle;
+typedef Complex::Simplex Simplex;
+
+int main(int argc, char *argv[]) {
+ // build a full complex with 4 vertices and 2^4-1 simplices
+
+ // Create a complex with four vertices (0,1,2,3)
+ Complex complex;
+
+ // Add a tetrahedron to this complex
+ Simplex tetrahedron(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3));
+ complex.add_simplex(tetrahedron);
+
+ std::cout << "complex:" << complex.to_string() << std::endl;
+
+ // build the link of vertex 1, eg a triangle {0,2,3}
+ auto link = complex.link(Vertex_handle(1));
+ std::cout << "link:" << link.to_string() << std::endl;
+
+ // Internally link is a subcomplex of 'complex' and its vertices are stored in a vector.
+ // They can be accessed via Vertex_handle(x) where x is an index of the vector.
+ // In that example, link has three vertices and thus it contains only
+ // Vertex_handle(0),Vertex_handle(1) and Vertex_handle(2) are).
+ for (int i = 0; i < 5; ++i)
+ std::cout << "link.contains_vertex(Vertex_handle(" << i << ")):" << link.contains_vertex(Vertex_handle(i)) <<
+ std::endl;
+ std::cout << std::endl;
+
+ // To access to the initial vertices eg (0,1,2,3,4), Root_vertex_handle must be used.
+ // For instance, to test if the link contains the vertex that was labeled i:
+ for (int i = 0; i < 5; ++i)
+ std::cout << "link.contains_vertex(Root_vertex_handle(" << i << ")):" <<
+ link.contains_vertex(Root_vertex_handle(i)) << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h
new file mode 100644
index 00000000..bcca851f
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker.h
@@ -0,0 +1,238 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_H_
+#define SKELETON_BLOCKER_H_
+
+#include <gudhi/Skeleton_blocker_complex.h>
+#include <gudhi/Skeleton_blocker_geometric_complex.h>
+#include <gudhi/Skeleton_blocker_simplifiable_complex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h>
+
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h>
+
+#include <gudhi/Debug_utils.h>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/** \defgroup skbl Skeleton-Blocker
+@{
+
+\author David Salinas
+
+\section skblintroduction Introduction
+The Skeleton-Blocker data-structure proposes a light encoding for simplicial complexes by storing only an *implicit* representation of its
+simplices
+\cite socg_blockers_2011,\cite blockers2012.
+Intuitively, it just stores the 1-skeleton of a simplicial complex with a graph and the set of its "missing faces" that
+is very small in practice (see next section for a formal definition).
+This data-structure handles all simplicial complexes operations such as
+ as simplex enumeration or simplex removal but operations that are particularly efficient
+ are operations that do not require simplex enumeration such as edge iteration, link computation or simplex contraction.
+
+
+\section skbldefinitions Definitions
+
+We recall briefly classical definitions of simplicial complexes
+ \cite Munkres-elementsalgtop1984.
+An abstract simplex is a finite non-empty set and its dimension is its number of elements minus 1.
+Whenever \f$\tau \subset \sigma\f$ and \f$\tau \neq \emptyset \f$, \f$ \tau \f$ is called a face of
+\f$ \sigma\f$ and \f$ \sigma\f$ is called a coface of \f$ \tau \f$ . Furthermore,
+when \f$ \tau \neq \sigma\f$ we say that \f$ \tau\f$ is a proper-face of \f$ \sigma\f$.
+An abstract simplicial complex is a set of simplices that contains all the faces of its simplices.
+The 1-skeleton of a simplicial complex (or its graph) consists of its elements of dimension lower than 2.
+
+ *\image html "ds_representation.png" "Skeleton-blocker representation" width=20cm
+
+
+To encode, a simplicial complex, one can encodes all its simplices.
+In case when this number gets too large,
+a lighter and implicit version consists of encoding only its graph plus some elements called missing faces or blockers.
+A blocker is a simplex of dimension greater than 1
+that does not belong to the complex but whose all proper faces does.
+
+
+Remark that for a clique complex (i.e. a simplicial complex whose simplices are cliques of its graph), the set of blockers
+is empty and the data-structure is then particularly sparse.
+One famous example of clique-complex is the Rips complex which is intensively used
+in topological data-analysis.
+In practice, the set of blockers of a simplicial complex
+remains also small when simplifying a Rips complex with edge contractions
+but also for most of the simplicial complexes used in topological data-analysis such as Delaunay, Cech or Witness complexes.
+For instance, the numbers of blockers is depicted for random 3-dimensional spheres embedded into \f$R^4\f$
+in next figure. Storing the graph and blockers of such simplicial complexes is much compact in this case than storing
+their simplices.
+
+
+ *\image html "blockers_curve.png" "Number of blockers of random triangulations of 3-spheres" width=10cm
+
+
+
+
+\section API
+
+\subsection Overview
+
+Two main classes of this package are Skeleton_blocker_complex and Skeleton_blocker_geometric_complex.
+The first one can be used to represent an abstract simplicial complex and supports most used
+operations in a simplicial complex such as :
+
+\li vertex/edge/simplex enumeration
+\li simplifications operations such as remove star, add star (e.g. general form of collapse),
+edge contractions
+
+The class Skeleton_blocker_geometric_complex supports the same methods as Skeleton_blocker_complex
+and point access in addition.
+
+
+
+\subsection skblvisitor Visitor
+
+The class Skeleton_blocker_complex has a visitor that is called when usual operations such as adding an edge or remove a vertex are called.
+You may want to use this visitor to compute statistics or to update another data-structure (for instance this visitor is heavily used in the \ref contr package).
+
+
+
+
+\section skblexample Example
+
+
+\subsection Iterating Iterating through vertices, edges, blockers and simplices
+
+Iteration through vertices, edges, simplices or blockers is straightforward with c++11 for range loops.
+Note that simplex iteration with this implicit data-structure just takes
+a few more time compared to iteration via an explicit representation
+such as the Simplex Tree. The following example computes the Euler Characteristic
+of a simplicial complex.
+
+ \code{.cpp}
+ typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex;
+ typedef Complex::Vertex_handle Vertex_handle;
+ typedef Complex::Simplex Simplex;
+
+ const int n = 15;
+
+ // build a full complex with 10 vertices and 2^n-1 simplices
+ Complex complex;
+ for(int i=0;i<n;i++)
+ complex.add_vertex();
+ for(int i=0;i<n;i++)
+ for(int j=0;j<i;j++)
+ complex.add_edge_without_blockers(Vertex_handle(i),Vertex_handle(j));
+
+ // this is just to illustrate iterators, to count number of vertices
+ // or edges, complex.num_vertices() and complex.num_edges() are
+ // more appropriated!
+ unsigned num_vertices = 0;
+ for(auto v : complex.vertex_range()){
+ ++num_vertices;
+ }
+
+ unsigned num_edges = 0;
+ for(auto e : complex.edge_range())
+ ++num_edges;
+
+ unsigned euler = 0;
+ unsigned num_simplices = 0;
+ // we use a reference to a simplex instead of a copy
+ // value here because a simplex is a set of integers
+ // and copying it cost time
+ for(const Simplex & s : complex.star_simplex_range()){
+ ++num_simplices;
+ if(s.dimension()%2 == 0)
+ euler += 1;
+ else
+ euler -= 1;
+ }
+ std::cout << "Saw "<<num_vertices<<" vertices, "<<num_edges<<" edges and "<<num_simplices<<" simplices"<<std::endl;
+ std::cout << "The Euler Characteristic is "<<euler<<std::endl;
+ \endcode
+
+
+\verbatim
+./SkeletonBlockerIteration
+Saw 15 vertices, 105 edges and 32767 simplices
+The Euler Characteristic is 1
+ 0.537302s wall, 0.530000s user + 0.000000s system = 0.530000s CPU (98.6%)
+\endverbatim
+
+
+\subsection s Constructing a skeleton-blockers from a list of maximal faces or from a list of faces
+
+ \code{.cpp}
+ std::vector<Simplex> simplices;
+
+ //add 4 triangles of a tetrahedron 0123
+ simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)));
+ simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1)));
+
+ Complex complex;
+ //get complex from top faces
+ make_complex_from_top_faces(complex,simplices.begin(),simplices.end());
+
+ std::cout << "Simplices:"<<std::endl;
+ for(const Simplex & s : complex.star_simplex_range())
+ std::cout << s << " ";
+ std::cout << std::endl;
+
+ //One blocker as simplex 0123 is not in the complex but all its proper faces are.
+ std::cout << "Blockers: "<<complex.blockers_to_string()<<std::endl;
+
+ //now build a complex from its full list of simplices
+ simplices.clear();
+ simplices.push_back(Simplex(Vertex_handle(0)));
+ simplices.push_back(Simplex(Vertex_handle(1)));
+ simplices.push_back(Simplex(Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1)));
+ simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(2),Vertex_handle(0)));
+ complex = Complex(simplices.begin(),simplices.end());
+
+ std::cout << "Simplices:"<<std::endl;
+ for(const Simplex & s : complex.star_simplex_range())
+ std::cout << s << " ";
+ std::cout << std::endl;
+
+ //One blocker as simplex 012 is not in the complex but all its proper faces are.
+ std::cout << "Blockers: "<<complex.blockers_to_string()<<std::endl;
+ \endcode
+\verbatim
+./SkeletonBlockerFromSimplices
+Simplices:
+{0} {0,1} {0,2} {0,3} {0,1,2} {0,1,3} {0,2,3} {1} {1,2} {1,3} {1,2,3} {2} {2,3} {3}
+Blockers: {0,1,2,3}
+
+Simplices:
+{0} {0,1} {0,2} {1} {1,2} {2}
+Blockers: {0,1,2}
+\endverbatim
+
+
+\section Acknowledgements
+The author wishes to thank Dominique Attali and André Lieutier for
+their collaboration to write the two initial papers
+\cite socg_blockers_2011,\cite blockers2012
+ about this data-structure
+ and also Dominique for leaving him use a prototype.
+
+@} */
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h
new file mode 100644
index 00000000..9f145013
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h
@@ -0,0 +1,132 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_
+
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+// TODO(DS): to be constified
+
+/**
+ *@class Skeleton_blocker_complex_visitor
+ *@brief Interface for a visitor of a simplicial complex.
+ */
+template<typename Vertex_handle>
+class Skeleton_blocker_complex_visitor {
+ public:
+ virtual ~Skeleton_blocker_complex_visitor() { }
+
+ virtual void on_add_vertex(Vertex_handle) = 0;
+ virtual void on_remove_vertex(Vertex_handle) = 0;
+
+ virtual void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) = 0;
+ virtual void on_remove_edge(Vertex_handle a, Vertex_handle b) = 0;
+
+ /**
+ * @brief Called when an edge changes, during the contraction of
+ * an edge
+ */
+ virtual void on_changed_edge(Vertex_handle a, Vertex_handle b) = 0;
+
+ /**
+ * @brief Called when performing an edge contraction when
+ * an edge bx is replaced by an edge ax (not already present).
+ * Precisely, this methods is called this way in contract_edge :
+ * add_edge_without_blockers(a,x)
+ * on_swaped_edge(a,b,x)
+ * remove_edge(b,x)
+ */
+ virtual void on_swaped_edge(Vertex_handle a, Vertex_handle b,
+ Vertex_handle x) = 0;
+ virtual void on_add_blocker(
+ const Skeleton_blocker_simplex<Vertex_handle>&) = 0;
+ virtual void on_delete_blocker(
+ const Skeleton_blocker_simplex<Vertex_handle>*) = 0;
+};
+
+/**
+ *@class Dummy_complex_visitor
+ *@brief A dummy visitor of a simplicial complex that does nothing
+ *
+ */
+template<typename Vertex_handle>
+class Dummy_complex_visitor : public Skeleton_blocker_complex_visitor<
+Vertex_handle> {
+ public:
+ void on_add_vertex(Vertex_handle) { }
+
+ void on_remove_vertex(Vertex_handle) { }
+
+ void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { }
+
+ void on_remove_edge(Vertex_handle a, Vertex_handle b) { }
+
+ void on_changed_edge(Vertex_handle a, Vertex_handle b) { }
+
+ void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) { }
+
+ void on_add_blocker(const Skeleton_blocker_simplex<Vertex_handle>&) { }
+
+ void on_delete_blocker(const Skeleton_blocker_simplex<Vertex_handle>*) { }
+};
+
+/**
+ *@class Print_complex_visitor
+ *@brief A visitor that prints the visit information.
+ *
+ */
+template<typename Vertex_handle>
+class Print_complex_visitor : public Skeleton_blocker_complex_visitor<
+Vertex_handle> {
+ public:
+ void on_add_vertex(Vertex_handle v) {
+ std::cerr << "on_add_vertex:" << v << std::endl;
+ }
+
+ void on_remove_vertex(Vertex_handle v) {
+ std::cerr << "on_remove_vertex:" << v << std::endl;
+ }
+
+ void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) {
+ std::cerr << "on_add_edge_without_blockers:" << a << "," << b << std::endl;
+ }
+
+ void on_remove_edge(Vertex_handle a, Vertex_handle b) {
+ std::cerr << "on_remove_edge:" << a << "," << b << std::endl;
+ }
+
+ void on_changed_edge(Vertex_handle a, Vertex_handle b) {
+ std::cerr << "on_changed_edge:" << a << "," << b << std::endl;
+ }
+
+ void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) {
+ std::cerr << "on_swaped_edge:" << a << "," << b << "," << x << std::endl;
+ }
+
+ void on_add_blocker(const Skeleton_blocker_simplex<Vertex_handle>& b) {
+ std::cerr << "on_add_blocker:" << b << std::endl;
+ }
+
+ void on_delete_blocker(const Skeleton_blocker_simplex<Vertex_handle>* b) {
+ std::cerr << "on_delete_blocker:" << b << std::endl;
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h
new file mode 100644
index 00000000..d348b696
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h
@@ -0,0 +1,65 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_
+
+#include <gudhi/Skeleton_blocker_link_complex.h>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+template<class ComplexType> class Skeleton_blocker_sub_complex;
+
+/**
+ * \brief Class representing the link of a simplicial complex encoded by a skeleton/blockers pair.
+ * It computes only vertices greater than the simplex used to build the link.
+ */
+template<typename ComplexType>
+class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex<
+ComplexType> {
+ typedef typename ComplexType::Edge_handle Edge_handle;
+
+ typedef typename ComplexType::boost_vertex_handle boost_vertex_handle;
+
+ public:
+ typedef typename ComplexType::Vertex_handle Vertex_handle;
+ typedef typename ComplexType::Root_vertex_handle Root_vertex_handle;
+ typedef typename ComplexType::Simplex Simplex;
+ typedef typename ComplexType::Root_simplex_handle Root_simplex_handle;
+ typedef typename ComplexType::BlockerMap BlockerMap;
+ typedef typename ComplexType::BlockerPair BlockerPair;
+ typedef typename ComplexType::BlockerMapIterator BlockerMapIterator;
+ typedef typename ComplexType::BlockerMapConstIterator BlockerMapConstIterator;
+ typedef typename ComplexType::Simplex::Simplex_vertex_const_iterator AddressSimplexConstIterator;
+ typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator IdSimplexConstIterator;
+
+ Skeleton_blocker_link_superior()
+ : Skeleton_blocker_link_complex<ComplexType>(true) { }
+
+ Skeleton_blocker_link_superior(const ComplexType & parent_complex,
+ Simplex& alpha_parent_adress)
+ : Skeleton_blocker_link_complex<ComplexType>(parent_complex,
+ alpha_parent_adress, true) { }
+
+ Skeleton_blocker_link_superior(const ComplexType & parent_complex,
+ Vertex_handle a_parent_adress)
+ : Skeleton_blocker_link_complex<ComplexType>(parent_complex,
+ a_parent_adress, true) { }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h
new file mode 100644
index 00000000..52300493
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h
@@ -0,0 +1,191 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_
+
+#include <gudhi/Off_reader.h>
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ *@brief Off reader visitor that can be passed to Off_reader to read a Skeleton_blocker_complex.
+ */
+template<typename Complex>
+class Skeleton_blocker_off_flag_visitor_reader {
+ Complex& complex_;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Point Point;
+
+ const bool load_only_points_;
+
+ public:
+ explicit Skeleton_blocker_off_flag_visitor_reader(Complex& complex, bool load_only_points = false) :
+ complex_(complex),
+ load_only_points_(load_only_points) { }
+
+ void init(int dim, int num_vertices, int num_faces, int num_edges) {
+ // TODO(DS): do an assert to check that this number are correctly read
+ // TODO(DS): reserve size for vector points
+ }
+
+ void point(const std::vector<double>& point) {
+ complex_.add_vertex(Point(point.begin(), point.end()));
+ }
+
+ void maximal_face(const std::vector<int>& face) {
+ if (!load_only_points_) {
+ for (size_t i = 0; i < face.size(); ++i)
+ for (size_t j = i + 1; j < face.size(); ++j) {
+ complex_.add_edge_without_blockers(Vertex_handle(face[i]), Vertex_handle(face[j]));
+ }
+ }
+ }
+
+ void done() { }
+};
+
+/**
+ *@brief Off reader visitor that can be passed to Off_reader to read a Skeleton_blocker_complex.
+ */
+template<typename Complex>
+class Skeleton_blocker_off_visitor_reader {
+ Complex& complex_;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Simplex Simplex;
+ typedef typename Complex::Point Point;
+
+ const bool load_only_points_;
+ std::vector<Point> points_;
+ std::vector<Simplex> maximal_faces_;
+
+ public:
+ explicit Skeleton_blocker_off_visitor_reader(Complex& complex, bool load_only_points = false) :
+ complex_(complex),
+ load_only_points_(load_only_points) { }
+
+ void init(int dim, int num_vertices, int num_faces, int num_edges) {
+ maximal_faces_.reserve(num_faces);
+ points_.reserve(num_vertices);
+ }
+
+ void point(const std::vector<double>& point) {
+ points_.emplace_back(point.begin(), point.end());
+ }
+
+ void maximal_face(const std::vector<int>& face) {
+ if (!load_only_points_) {
+ Simplex s;
+ for (auto x : face)
+ s.add_vertex(Vertex_handle(x));
+ maximal_faces_.emplace_back(s);
+ }
+ }
+
+ void done() {
+ complex_ = make_complex_from_top_faces<Complex>(maximal_faces_.begin(), maximal_faces_.end(),
+ points_.begin(), points_.end());
+ }
+};
+
+/**
+ *@brief Class that allows to load a Skeleton_blocker_complex from an off file.
+ */
+template<typename Complex>
+class Skeleton_blocker_off_reader {
+ public:
+ /**
+ * name_file : file to read
+ * read_complex : complex that will receive the file content
+ * read_only_points : specify true if only the points must be read
+ */
+ Skeleton_blocker_off_reader(const std::string & name_file, Complex& read_complex,
+ bool read_only_points = false, bool is_flag = false) : valid_(false) {
+ std::ifstream stream(name_file);
+ if (stream.is_open()) {
+ if (is_flag || read_only_points) {
+ Skeleton_blocker_off_flag_visitor_reader<Complex> off_visitor(read_complex, read_only_points);
+ Off_reader off_reader(stream);
+ valid_ = off_reader.read(off_visitor);
+ } else {
+ Skeleton_blocker_off_visitor_reader<Complex> off_visitor(read_complex, read_only_points);
+ Off_reader off_reader(stream);
+ valid_ = off_reader.read(off_visitor);
+ }
+ }
+ }
+
+ /**
+ * return true if reading did not meet problems.
+ */
+ bool is_valid() const {
+ return valid_;
+ }
+
+ private:
+ bool valid_;
+};
+
+template<typename Complex>
+class Skeleton_blocker_off_writer {
+ public:
+ /**
+ * name_file : file where the off will be written
+ * save_complex : complex that be outputted in the file
+ * for now only save triangles.
+ */
+ Skeleton_blocker_off_writer(const std::string & name_file, const Complex& save_complex) {
+ typedef typename Complex::Vertex_handle Vertex_handle;
+
+ std::ofstream stream(name_file);
+ if (stream.is_open()) {
+ stream << "OFF\n";
+ size_t num_triangles = std::distance(save_complex.triangle_range().begin(), save_complex.triangle_range().end());
+ stream << save_complex.num_vertices() << " " << num_triangles << " 0 \n";
+
+ // in case the complex has deactivated some vertices, eg only has vertices 0 2 5 7 for instance
+ // we compute a map from 0 2 5 7 to 0 1 2 3
+ std::map<Vertex_handle, size_t> vertex_num;
+ size_t current_vertex = 0;
+
+ for (auto v : save_complex.vertex_range()) {
+ vertex_num[v] = current_vertex++;
+ const auto& pt(save_complex.point(v));
+ for (auto x : pt)
+ stream << x << " ";
+ stream << std::endl;
+ }
+
+ for (const auto & t : save_complex.triangle_range()) {
+ stream << "3 ";
+ for (auto x : t)
+ stream << vertex_num[x] << " ";
+ stream << std::endl;
+ }
+ stream.close();
+ } else {
+ std::cerr << "could not open file " << name_file << std::endl;
+ }
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h
new file mode 100644
index 00000000..772e33aa
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h
@@ -0,0 +1,87 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_
+
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h>
+
+#include <string>
+#include <sstream>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * @extends SkeletonBlockerGeometricDS
+ * @ingroup skbl
+ * @brief Simple traits that is a model of SkeletonBlockerGeometricDS and
+ * can be passed as a template argument to Skeleton_blocker_geometric_complex
+ */
+template<typename GeometryTrait>
+struct Skeleton_blocker_simple_geometric_traits :
+public Skeleton_blocker_simple_traits {
+ public:
+ typedef GeometryTrait GT;
+ typedef typename GT::Point Point;
+ typedef typename Skeleton_blocker_simple_traits::Root_vertex_handle Root_vertex_handle;
+ typedef typename Skeleton_blocker_simple_traits::Graph_vertex Simple_vertex;
+
+ /**
+ * @brief Vertex with a point attached.
+ */
+ class Simple_geometric_vertex : public Simple_vertex {
+ template<class ComplexGeometricTraits> friend class Skeleton_blocker_geometric_complex;
+ private:
+ Point point_;
+
+ Point& point() {
+ return point_;
+ }
+
+ const Point& point() const {
+ return point_;
+ }
+ };
+
+ class Simple_geometric_edge :
+ public Skeleton_blocker_simple_traits::Graph_edge {
+ int index_;
+ public:
+ Simple_geometric_edge()
+ : Skeleton_blocker_simple_traits::Graph_edge(),
+ index_(-1) { }
+
+ /**
+ * @brief Allows to modify the index of the edge.
+ * The indices of the edge are used to store heap information
+ * in the edge contraction algorithm.
+ */
+ int& index() {
+ return index_;
+ }
+
+ int index() const {
+ return index_;
+ }
+ };
+
+ typedef Simple_geometric_vertex Graph_vertex;
+ typedef Skeleton_blocker_simple_traits::Graph_edge Graph_edge;
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h
new file mode 100644
index 00000000..0c0cc624
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h
@@ -0,0 +1,178 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_
+
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
+
+#include <string>
+#include <sstream>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * @extends SkeletonBlockerDS
+ * @ingroup skbl
+ * @brief Simple traits that is a model of SkeletonBlockerDS and
+ * can be passed as a template argument to Skeleton_blocker_complex
+ */
+struct Skeleton_blocker_simple_traits {
+ /**
+ * @brief Global and local handle similar to <a href="http://www.boost.org/doc/libs/1_38_0/libs/graph/doc/subgraph.html">boost subgraphs</a>.
+ * Vertices are stored in a vector.
+ * For the root simplicial complex, the local and global descriptors are the same.
+ * For a subcomplex L and one of its vertices 'v', the local descriptor of 'v' is its position in
+ * the vertex vector of the subcomplex L whereas its global descriptor is the position of 'v'
+ * in the vertex vector of the root simplicial complex.
+ */
+ struct Root_vertex_handle {
+ typedef int boost_vertex_handle;
+
+ explicit Root_vertex_handle(boost_vertex_handle val = -1)
+ : vertex(val) { }
+ boost_vertex_handle vertex;
+
+ bool operator!=(const Root_vertex_handle& other) const {
+ return !(this->vertex == other.vertex);
+ }
+
+ bool operator==(const Root_vertex_handle& other) const {
+ return this->vertex == other.vertex;
+ }
+
+ bool operator<(const Root_vertex_handle& other) const {
+ return this->vertex < other.vertex;
+ }
+
+ friend std::ostream& operator<<(std::ostream& o,
+ const Root_vertex_handle & v) {
+ o << v.vertex;
+ return o;
+ }
+ };
+
+ struct Vertex_handle {
+ typedef int boost_vertex_handle;
+
+ explicit Vertex_handle(boost_vertex_handle val = -1)
+ : vertex(val) { }
+
+ operator int() const {
+ return static_cast<int> (vertex);
+ }
+
+ boost_vertex_handle vertex;
+
+ bool operator==(const Vertex_handle& other) const {
+ return this->vertex == other.vertex;
+ }
+
+ bool operator!=(const Vertex_handle& other) const {
+ return this->vertex != other.vertex;
+ }
+
+ bool operator<(const Vertex_handle& other) const {
+ return this->vertex < other.vertex;
+ }
+
+ friend std::ostream& operator<<(std::ostream& o, const Vertex_handle & v) {
+ o << v.vertex;
+ return o;
+ }
+ };
+
+ class Graph_vertex {
+ bool is_active_;
+ Root_vertex_handle id_;
+
+ public:
+ virtual ~Graph_vertex() { }
+
+ void activate() {
+ is_active_ = true;
+ }
+
+ void deactivate() {
+ is_active_ = false;
+ }
+
+ bool is_active() const {
+ return is_active_;
+ }
+
+ void set_id(Root_vertex_handle i) {
+ id_ = i;
+ }
+
+ Root_vertex_handle get_id() const {
+ return id_;
+ }
+
+ virtual std::string to_string() const {
+ std::ostringstream res;
+ res << id_;
+ return res.str();
+ }
+
+ friend std::ostream& operator<<(std::ostream& o, const Graph_vertex & v) {
+ o << v.to_string();
+ return o;
+ }
+ };
+
+ class Graph_edge {
+ Root_vertex_handle a_;
+ Root_vertex_handle b_;
+ int index_;
+
+ public:
+ Graph_edge()
+ : a_(-1),
+ b_(-1),
+ index_(-1) { }
+
+ int& index() {
+ return index_;
+ }
+
+ int index() const {
+ return index_;
+ }
+
+ void setId(Root_vertex_handle a, Root_vertex_handle b) {
+ a_ = a;
+ b_ = b;
+ }
+
+ Root_vertex_handle first() const {
+ return a_;
+ }
+
+ Root_vertex_handle second() const {
+ return b_;
+ }
+
+ friend std::ostream& operator<<(std::ostream& o, const Graph_edge & v) {
+ o << "(" << v.a_ << "," << v.b_ << " - id = " << v.index();
+ return o;
+ }
+ };
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h
new file mode 100644
index 00000000..12fe6469
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h
@@ -0,0 +1,362 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_
+
+#include <cassert>
+#include <iostream>
+#include <set>
+#include <vector>
+#include <initializer_list>
+#include <string>
+#include <algorithm>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ *@brief Abstract simplex used in Skeleton blockers data-structure.
+ *
+ * An abstract simplex is represented as an ordered set of T elements,
+ * each element representing a vertex.
+ *
+ * The element representing a vertex can be SkeletonBlockerDS::Vertex_handle or SkeletonBlockerDS::Root_vertex_handle.
+ *
+ *
+ */
+template<typename T>
+
+class Skeleton_blocker_simplex {
+ private:
+ std::set<T> simplex_set;
+
+ public:
+ typedef typename T::boost_vertex_handle boost_vertex_handle;
+
+ typedef T Vertex_handle;
+
+ typedef typename std::set<T>::const_iterator Simplex_vertex_const_iterator;
+ typedef typename std::set<T>::iterator Simplex_vertex_iterator;
+
+ /** @name Constructors / Destructors / Initialization
+ */
+ //@{
+
+ void clear() {
+ simplex_set.clear();
+ }
+
+ Skeleton_blocker_simplex(std::initializer_list<T>& list) {
+ std::for_each(list.begin(), list.end(), [&] (T const& elt) {
+ add_vertex(elt);
+ });
+ }
+
+ template<typename ... Args>
+ explicit Skeleton_blocker_simplex(Args ... args) {
+ add_vertices(args...);
+ }
+
+ template<typename ... Args>
+ void add_vertices(T v, Args ... args) {
+ add_vertex(v);
+ add_vertices(args...);
+ }
+
+ void add_vertices(T v) {
+ add_vertex(v);
+ }
+
+ void add_vertices() { }
+
+ /**
+ * Initialize a simplex with a string such as {0,1,2}
+ */
+ explicit Skeleton_blocker_simplex(std::string token) {
+ clear();
+ if ((token[0] == '{') && (token[token.size() - 1] == '}')) {
+ token.erase(0, 1);
+ token.erase(token.size() - 1, 1);
+ while (token.size() != 0) {
+ int coma_position = token.find_first_of(',');
+ // cout << "coma_position:"<<coma_position<<endl;
+ std::string n = token.substr(0, coma_position);
+ // cout << "token:"<<token<<endl;
+ token.erase(0, n.size() + 1);
+ add_vertex((T) (atoi(n.c_str())));
+ }
+ }
+ }
+
+ //@}
+
+ /** @name Simplex manipulation
+ */
+ //@{
+ /**
+ * Add the vertex v to the simplex:
+ * Note that adding two times the same vertex is
+ * the same that adding it once.
+ */
+ void add_vertex(T v) {
+ simplex_set.insert(v);
+ }
+
+ /**
+ * Remove the vertex v from the simplex:
+ */
+ void remove_vertex(T v) {
+ simplex_set.erase(v);
+ }
+
+ /**
+ * Intersects the simplex with the simplex a.
+ */
+ void intersection(const Skeleton_blocker_simplex & a) {
+ std::vector<T> v;
+ v.reserve((std::min)(simplex_set.size(), a.simplex_set.size()));
+
+ set_intersection(simplex_set.begin(), simplex_set.end(),
+ a.simplex_set.begin(), a.simplex_set.end(),
+ std::back_inserter(v));
+ clear();
+ for (auto i : v)
+ simplex_set.insert(i);
+ }
+
+ /**
+ * Substracts a from the simplex.
+ */
+ void difference(const Skeleton_blocker_simplex & a) {
+ std::vector<T> v;
+ v.reserve(simplex_set.size());
+
+ set_difference(simplex_set.begin(), simplex_set.end(),
+ a.simplex_set.begin(), a.simplex_set.end(),
+ std::back_inserter(v));
+
+ clear();
+ for (auto i : v)
+ simplex_set.insert(i);
+ }
+
+ /**
+ * Add vertices of a to the simplex.
+ */
+ void union_vertices(const Skeleton_blocker_simplex & a) {
+ std::vector<T> v;
+ v.reserve(simplex_set.size() + a.simplex_set.size());
+
+ set_union(simplex_set.begin(), simplex_set.end(), a.simplex_set.begin(),
+ a.simplex_set.end(), std::back_inserter(v));
+ clear();
+ simplex_set.insert(v.begin(), v.end());
+ }
+
+ typename std::set<T>::const_iterator begin() const {
+ return simplex_set.cbegin();
+ }
+
+ typename std::set<T>::const_iterator end() const {
+ return simplex_set.cend();
+ }
+
+ typename std::set<T>::const_reverse_iterator rbegin() const {
+ return simplex_set.crbegin();
+ }
+
+ typename std::set<T>::const_reverse_iterator rend() const {
+ return simplex_set.crend();
+ }
+
+ typename std::set<T>::iterator begin() {
+ return simplex_set.begin();
+ }
+
+ typename std::set<T>::iterator end() {
+ return simplex_set.end();
+ }
+
+ //@}
+
+ /** @name Queries
+ */
+ //@{
+ /**
+ * Returns the dimension of the simplex.
+ */
+ int dimension() const {
+ return (simplex_set.size() - 1);
+ }
+
+ bool empty() const {
+ return simplex_set.empty();
+ }
+
+ /**
+ * Returns the first and smallest vertex of the simplex.
+ *
+ * Be careful : assumes the simplex is non-empty.
+ */
+ T first_vertex() const {
+ assert(!empty());
+ return *(begin());
+ }
+
+ /**
+ * Returns the last and greatest vertex of the simplex.
+ *
+ * Be careful : assumes the simplex is non-empty.
+ */
+ T last_vertex() const {
+ assert(!empty());
+ return *(simplex_set.rbegin());
+ }
+
+ /**
+ * @return true iff the simplex contains the simplex a.
+ */
+ bool contains(const Skeleton_blocker_simplex & a) const {
+ return includes(simplex_set.cbegin(), simplex_set.cend(),
+ a.simplex_set.cbegin(), a.simplex_set.cend());
+ }
+
+ /**
+ * @return true iff the simplex contains the difference \f$ a \setminus b \f$.
+ */
+ bool contains_difference(const Skeleton_blocker_simplex& a,
+ const Skeleton_blocker_simplex& b) const {
+ auto first1 = begin();
+ auto last1 = end();
+
+ auto first2 = a.begin();
+ auto last2 = a.end();
+
+ while (first2 != last2) {
+ // we ignore vertices of b
+ if (b.contains(*first2)) {
+ ++first2;
+ } else {
+ if ((first1 == last1) || (*first2 < *first1))
+ return false;
+ if (!(*first1 < *first2))
+ ++first2;
+ ++first1;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return true iff the simplex contains the difference \f$ a \setminus \{ x \} \f$.
+ */
+ bool contains_difference(const Skeleton_blocker_simplex& a, T x) const {
+ auto first1 = begin();
+ auto last1 = end();
+
+ auto first2 = a.begin();
+ auto last2 = a.end();
+
+ while (first2 != last2) {
+ // we ignore vertices x
+ if (x == *first2) {
+ ++first2;
+ } else {
+ if ((first1 == last1) || (*first2 < *first1))
+ return false;
+ if (!(*first1 < *first2))
+ ++first2;
+ ++first1;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return true iff the simplex contains the difference \f$ a \setminus \{ x,y \} \f$.
+ */
+ bool contains_difference(const Skeleton_blocker_simplex& a, T x, T y) const {
+ auto first1 = begin();
+ auto last1 = end();
+
+ auto first2 = a.begin();
+ auto last2 = a.end();
+
+ while (first2 != last2) {
+ // we ignore vertices of x,y
+ if (x == *first2 || y == *first2) {
+ ++first2;
+ } else {
+ if ((first1 == last1) || (*first2 < *first1))
+ return false;
+ if (!(*first1 < *first2))
+ ++first2;
+ ++first1;
+ }
+ }
+ return true;
+ }
+
+ bool contains(T v) const {
+ return (simplex_set.find(v) != simplex_set.end());
+ }
+
+ bool disjoint(const Skeleton_blocker_simplex& a) const {
+ std::vector<T> v;
+ v.reserve(std::min(simplex_set.size(), a.simplex_set.size()));
+
+ set_intersection(simplex_set.cbegin(), simplex_set.cend(),
+ a.simplex_set.cbegin(), a.simplex_set.cend(),
+ std::back_inserter(v));
+
+ return (v.size() == 0);
+ }
+
+ bool operator==(const Skeleton_blocker_simplex& other) const {
+ return (this->simplex_set == other.simplex_set);
+ }
+
+ bool operator!=(const Skeleton_blocker_simplex& other) const {
+ return (this->simplex_set != other.simplex_set);
+ }
+
+ bool operator<(const Skeleton_blocker_simplex& other) const {
+ return (std::lexicographical_compare(this->simplex_set.begin(),
+ this->simplex_set.end(), other.begin(),
+ other.end()));
+ }
+
+ //@}
+
+ friend std::ostream& operator<<(std::ostream& o,
+ const Skeleton_blocker_simplex & sigma) {
+ bool first = true;
+ o << "{";
+ for (auto i : sigma) {
+ if (first)
+ first = false;
+ else
+ o << ",";
+ o << i;
+ }
+ o << "}";
+ return o;
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h
new file mode 100644
index 00000000..4c48ff31
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h
@@ -0,0 +1,261 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_
+#define SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_
+
+#include <gudhi/Skeleton_blocker_complex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
+#include <gudhi/Debug_utils.h>
+
+#include <map>
+#include <vector>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * @brief Simplicial subcomplex of a complex represented by a skeleton/blockers pair.
+ * @extends Skeleton_blocker_complex
+ * @details Stores a subcomplex of a simplicial complex.
+ * To simplify explanations below, we will suppose that :
+ * - K is the root simplicial complex
+ * - L is a subcomplex of K.
+ *
+ * One vertex of K may exists in L but with a different address.
+ * To be able to locate the vertices in K from vertices of L, the class
+ * stores a map 'adresses' between vertices of K and vertices of L.
+ *
+ * Note that the type for handle of vertices of L is 'Vertex_handle' and
+ * the type for handle of vertices of K is 'Root_vertex_handle'.
+ *
+ * The template ComplexType is type of the root complex. It allows to know
+ * if the subcomplex is geometric or not.
+ * It has to be either 'Skeleton_blockers_complex' or 'Skeleton_blockers_geometric_complex'.
+ *
+ */
+template<typename ComplexType>
+class Skeleton_blocker_sub_complex : public ComplexType {
+ protected:
+ template<class T> friend class Skeleton_blocker_link_complex;
+
+ typedef typename ComplexType::Graph Graph;
+ typedef typename ComplexType::Edge_handle Edge_handle;
+
+ typedef typename ComplexType::boost_vertex_handle boost_vertex_handle;
+
+ public:
+ using ComplexType::add_vertex;
+ using ComplexType::add_edge_without_blockers;
+ using ComplexType::add_blocker;
+
+ typedef typename ComplexType::Vertex_handle Vertex_handle;
+ typedef typename ComplexType::Root_vertex_handle Root_vertex_handle;
+ typedef typename ComplexType::Simplex Simplex;
+ typedef typename ComplexType::Root_simplex_handle Root_simplex_handle;
+
+ protected:
+ /**
+ * @brief Determines whether all proper faces of simplex 'sigma' belong to 'link1' \cup 'link2'
+ * where 'link1' and 'link2' are subcomplexes of the same complex of type ComplexType
+ */
+ typedef std::map<Root_vertex_handle, Vertex_handle> IdAddressMap;
+ typedef typename IdAddressMap::value_type AddressPair;
+ typedef typename IdAddressMap::iterator IdAddressMapIterator;
+ typedef typename IdAddressMap::const_iterator IdAddressMapConstIterator;
+ std::map<Root_vertex_handle, Vertex_handle> adresses;
+
+ public:
+ /**
+ * Add a vertex 'global' of K to L. When added to L, this vertex will receive
+ * another number, addresses(global), its local adress.
+ * return the adress where the vertex lay on L.
+ * The vertex corresponding to 'global' must not be already present
+ * in the complex.
+ */
+ Vertex_handle add_vertex(Root_vertex_handle global) {
+ assert(!this->contains_vertex(global));
+ Vertex_handle address(boost::add_vertex(this->skeleton));
+ this->num_vertices_++;
+ (*this)[address].activate();
+ (*this)[address].set_id(global);
+ adresses.insert(AddressPair(global, address));
+ this->degree_.push_back(0);
+ return address;
+ }
+
+ /**
+ * Add an edge (v1_root,v2_root) to the sub-complex.
+ * It assumes that both vertices corresponding to v1_root and v2_root are present
+ * in the sub-complex.
+ */
+ void add_edge_without_blockers(Root_vertex_handle v1_root, Root_vertex_handle v2_root) {
+ auto v1_sub(this->get_address(v1_root));
+ auto v2_sub(this->get_address(v2_root));
+ assert(v1_sub && v2_sub);
+ this->ComplexType::add_edge_without_blockers(*v1_sub, *v2_sub);
+ }
+
+ /**
+ * Add a blocker to the sub-complex.
+ * It assumes that all vertices of blocker_root are present
+ * in the sub-complex.
+ */
+ void add_blocker(const Root_simplex_handle& blocker_root) {
+ auto blocker_sub = this->get_address(blocker_root);
+ assert(blocker_sub);
+ this->add_blocker(new Simplex(*blocker_sub));
+ }
+
+ public:
+ /**
+ * Constructs the restricted complex of 'parent_complex' to
+ * vertices of 'simplex'.
+ */
+ void make_restricted_complex(const ComplexType & parent_complex,
+ const Simplex& simplex) {
+ this->clear();
+ // add vertices to the sub complex
+ for (auto x : simplex) {
+ assert(parent_complex.contains_vertex(x));
+ auto x_local = this->add_vertex(parent_complex[x].get_id());
+ (*this)[x_local] = parent_complex[x];
+ }
+
+ // add edges to the sub complex
+ for (auto x : simplex) {
+ // x_neigh is the neighbor of x intersected with vertices_simplex
+ Simplex x_neigh;
+ parent_complex.add_neighbours(x, x_neigh, true);
+ x_neigh.intersection(simplex);
+ for (auto y : x_neigh) {
+ this->add_edge_without_blockers(parent_complex[x].get_id(), parent_complex[y].get_id());
+ }
+ }
+
+ // add blockers to the sub complex
+ for (auto blocker : parent_complex.const_blocker_range()) {
+ // check if it is the first time we encounter the blocker
+ if (simplex.contains(*blocker)) {
+ Root_simplex_handle blocker_root(parent_complex.get_id(*(blocker)));
+ Simplex blocker_restr(
+ *(this->get_simplex_address(blocker_root)));
+ this->add_blocker(new Simplex(blocker_restr));
+ }
+ }
+ }
+
+ void clear() {
+ adresses.clear();
+ ComplexType::clear();
+ }
+
+ /**
+ * Compute the local vertex in L corresponding to the vertex global in K.
+ * runs in O(log n) if n = num_vertices()
+ */
+ boost::optional<Vertex_handle> get_address(Root_vertex_handle global) const {
+ boost::optional < Vertex_handle > res;
+ IdAddressMapConstIterator it = adresses.find(global);
+ if (it == adresses.end())
+ res.reset();
+ else
+ res = (*it).second;
+ return res;
+ }
+
+ // /**
+ // * Allocates a simplex in L corresponding to the simplex s in K
+ // * with its local adresses and returns an AddressSimplex.
+ // */
+ // boost::optional<Simplex> get_address(const Root_simplex_handle & s) const;
+
+ // private:
+ /**
+ * same as get_address except that it will return a simplex in any case.
+ * The vertices that were not found are not added.
+ */
+ // @remark should be private but problem with VS
+
+ std::vector<boost::optional<Vertex_handle> > get_addresses(
+ const Root_simplex_handle & s) const {
+ std::vector < boost::optional<Vertex_handle> > res;
+ for (auto i : s) {
+ res.push_back(get_address(i));
+ }
+ return res;
+ }
+};
+
+/**
+ * @remark remarque perte de temps a creer un nouveau simplexe a chaque fois
+ * alors qu'on pourrait utiliser a la place de 'addresses_sigma_in_link'
+ * un simplex avec des valeurs sp�ciales ComplexDS::null_vertex par exemple
+ * pour indiquer qu'un vertex n'appartient pas au complex
+ */
+template<typename ComplexType>
+bool proper_face_in_union(
+ Skeleton_blocker_sub_complex<ComplexType> & link,
+ std::vector<boost::optional<typename ComplexType::Vertex_handle> > & addresses_sigma_in_link,
+ std::size_t vertex_to_be_ignored) {
+ // we test that all vertices of 'addresses_sigma_in_link' but 'vertex_to_be_ignored'
+ // are in link1 if it is the case we construct the corresponding simplex
+ bool vertices_sigma_are_in_link = true;
+ typename ComplexType::Simplex sigma_in_link;
+ for (std::size_t i = 0; i < addresses_sigma_in_link.size(); ++i) {
+ if (i != vertex_to_be_ignored) {
+ if (!addresses_sigma_in_link[i]) {
+ vertices_sigma_are_in_link = false;
+ break;
+ } else {
+ sigma_in_link.add_vertex(*addresses_sigma_in_link[i]);
+ }
+ }
+ }
+ // If one of vertices of the simplex is not in the complex then it returns false
+ // Otherwise, it tests if the simplex is in the complex
+ return vertices_sigma_are_in_link && link.contains(sigma_in_link);
+}
+
+// Remark: this function should be friend in order to leave get_adresses private
+// however doing so seemes currently not possible due to a visual studio bug c2668
+// "the compiler does not support partial ordering of template functions as specified in the C++ Standard"
+// http://www.serkey.com/error-c2668-ambiguous-call-to-overloaded-function-bb45ft.html
+
+template<typename ComplexType>
+bool proper_faces_in_union(
+ Skeleton_blocker_simplex<typename ComplexType::Root_vertex_handle> & sigma,
+ Skeleton_blocker_sub_complex<ComplexType> & link1,
+ Skeleton_blocker_sub_complex<ComplexType> & link2) {
+ typedef typename ComplexType::Vertex_handle Vertex_handle;
+ std::vector < boost::optional<Vertex_handle> > addresses_sigma_in_link1 =
+ link1.get_addresses(sigma);
+ std::vector < boost::optional<Vertex_handle> > addresses_sigma_in_link2 =
+ link2.get_addresses(sigma);
+
+ for (std::size_t current_index = 0; current_index < addresses_sigma_in_link1.size();
+ ++current_index) {
+ if (!proper_face_in_union(link1, addresses_sigma_in_link1, current_index)
+ && !proper_face_in_union(link2, addresses_sigma_in_link2,
+ current_index)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h
new file mode 100644
index 00000000..91e79b42
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Top_faces.h
@@ -0,0 +1,61 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_
+#define SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_
+
+#include <list>
+#include <vector>
+#include <set>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+template<typename SimplexHandle>
+std::list<SimplexHandle> subfaces(SimplexHandle top_face) {
+ std::list<SimplexHandle> res;
+ if (top_face.dimension() == -1) return res;
+ if (top_face.dimension() == 0) {
+ res.push_back(top_face);
+ return res;
+ } else {
+ auto first_vertex = top_face.first_vertex();
+ top_face.remove_vertex(first_vertex);
+ res = subfaces(top_face);
+ std::list<SimplexHandle> copy = res;
+ for (auto& simplex : copy) {
+ simplex.add_vertex(first_vertex);
+ }
+ res.push_back(SimplexHandle(first_vertex));
+ res.splice(res.end(), copy);
+ return res;
+ }
+}
+
+/**
+ * add all faces of top_face in simplices_per_dimension
+ */
+template<typename SimplexHandle>
+void register_faces(std::vector< std::set<SimplexHandle> >& simplices_per_dimension,
+ const SimplexHandle& top_face) {
+ std::list<SimplexHandle> subfaces_list = subfaces(top_face);
+ for (auto& simplex : subfaces_list) {
+ simplices_per_dimension[simplex.dimension()].insert(simplex);
+ }
+}
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h
new file mode 100644
index 00000000..a43fa034
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/internal/Trie.h
@@ -0,0 +1,256 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_INTERNAL_TRIE_H_
+#define SKELETON_BLOCKER_INTERNAL_TRIE_H_
+
+#include <memory>
+#include <vector>
+#include <deque>
+#include <set>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+template<typename SimplexHandle>
+struct Trie {
+ typedef SimplexHandle Simplex;
+ typedef typename SimplexHandle::Vertex_handle Vertex_handle;
+
+ Vertex_handle v;
+ std::vector<std::shared_ptr<Trie> > childs;
+ // std::vector<std::unique_ptr<Trie> > childs; -> use of deleted function
+ private:
+ const Trie* parent_;
+
+ public:
+ Trie() : parent_(0) { }
+
+ Trie(Vertex_handle v_) : v(v_), parent_(0) { }
+
+ Trie(Vertex_handle v_, Trie* parent) : v(v_), parent_(parent) { }
+
+ bool operator==(const Trie& other) const {
+ return (v == other.v);
+ }
+
+ void add_child(Trie* child) {
+ if (child) {
+ std::shared_ptr<Trie> ptr_to_add(child);
+ childs.push_back(ptr_to_add);
+ child->parent_ = this;
+ }
+ }
+
+ typedef typename Simplex::Simplex_vertex_const_iterator Simplex_vertex_const_iterator;
+
+ Trie* make_trie(Simplex_vertex_const_iterator s_it, Simplex_vertex_const_iterator s_end) {
+ if (s_it == s_end) {
+ return 0;
+ } else {
+ Trie* res = new Trie(*s_it);
+ Trie* child = make_trie(++s_it, s_end);
+ res->add_child(child);
+ return res;
+ }
+ }
+
+ private:
+ // go down recursively in the tree while advancing the simplex iterator.
+ // when it reaches a leaf, it inserts the remaining that is not present
+ void add_simplex_helper(Simplex_vertex_const_iterator s_it, Simplex_vertex_const_iterator s_end) {
+ assert(*s_it == v);
+ ++s_it;
+ if (s_it == s_end) return;
+ if (!is_leaf()) {
+ for (auto child : childs) {
+ if (child->v == *s_it)
+ return child->add_simplex_helper(s_it, s_end);
+ }
+ // s_it is not found and needs to be inserted
+ }
+ // not leaf -> remaining of s needs to be inserted
+ Trie * son_with_what_remains_of_s(make_trie(s_it, s_end));
+ add_child(son_with_what_remains_of_s);
+ return;
+ }
+
+ void maximal_faces_helper(std::vector<Simplex>& res) const {
+ if (is_leaf()) res.push_back(simplex());
+ else
+ for (auto child : childs)
+ child->maximal_faces_helper(res);
+ }
+
+ public:
+ /**
+ * adds the simplex to the trie
+ */
+ void add_simplex(const Simplex& s) {
+ if (s.empty()) return;
+ assert(v == s.first_vertex());
+ add_simplex_helper(s.begin(), s.end());
+ }
+
+ std::vector<Simplex> maximal_faces() const {
+ std::vector<Simplex> res;
+ maximal_faces_helper(res);
+ return res;
+ }
+
+ /**
+ * Goes to the root in the trie to consitute simplex
+ */
+ void add_vertices_up_to_the_root(Simplex& res) const {
+ res.add_vertex(v);
+ if (parent_)
+ parent_->add_vertices_up_to_the_root(res);
+ }
+
+ Simplex simplex() const {
+ Simplex res;
+ add_vertices_up_to_the_root(res);
+ return res;
+ }
+
+ bool is_leaf() const {
+ return childs.empty();
+ }
+
+ bool is_root() const {
+ return parent_ == 0;
+ }
+
+ const Trie* parent() {
+ return parent_;
+ }
+
+ void remove_leaf() {
+ assert(is_leaf());
+ if (!is_root())
+ parent_->childs.erase(this);
+ }
+
+ /**
+ * true iff the simplex corresponds to one node in the trie
+ */
+ bool contains(const Simplex& s) const {
+ Trie const* current = this;
+ if (s.empty()) return true;
+ if (current->v != s.first_vertex()) return false;
+ auto s_pos = s.begin();
+ ++s_pos;
+ while (s_pos != s.end() && current != 0) {
+ bool found = false;
+ for (const auto child : current->childs) {
+ if (child->v == *s_pos) {
+ ++s_pos;
+ current = child.get();
+ found = true;
+ break;
+ }
+ }
+ if (!found) return false;
+ }
+ return current != 0;
+ }
+
+ Trie* go_bottom_left() {
+ if (is_leaf())
+ return this;
+ else
+ return (*childs.begin())->go_bottom_left();
+ }
+
+ friend std::ostream& operator<<(std::ostream& stream, const Trie& trie) {
+ stream << "T( " << trie.v << " ";
+ for (auto t : trie.childs)
+ stream << *t;
+ stream << ")";
+ return stream;
+ }
+};
+
+template<typename SimplexHandle>
+struct Tries {
+ typedef typename SimplexHandle::Vertex_handle Vertex_handle;
+ typedef SimplexHandle Simplex;
+
+ typedef Trie<Simplex> STrie;
+
+ template<typename SimpleHandleOutputIterator>
+ Tries(unsigned num_vertices, SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end) :
+ cofaces_(num_vertices, 0) {
+ for (auto i = 0u; i < num_vertices; ++i)
+ cofaces_[i] = new STrie(Vertex_handle(i));
+ for (auto s_it = simplex_begin; s_it != simplex_end; ++s_it) {
+ if (s_it->dimension() >= 1)
+ cofaces_[s_it->first_vertex()]->add_simplex(*s_it);
+ }
+ }
+
+ ~Tries() {
+ for (STrie* t : cofaces_)
+ delete t;
+ }
+
+ // return a simplex that consists in all u such uv is an edge and u>v
+
+ Simplex positive_neighbors(Vertex_handle v) const {
+ Simplex res;
+ for (auto child : cofaces_[v]->childs)
+ res.add_vertex(child->v);
+ return res;
+ }
+
+ bool contains(const Simplex& s) const {
+ auto first_v = s.first_vertex();
+ return cofaces_[first_v]->contains(s);
+ }
+
+ friend std::ostream& operator<<(std::ostream& stream, const Tries& tries) {
+ for (auto trie : tries.cofaces_)
+ stream << *trie << std::endl;
+ return stream;
+ }
+
+ // init_next_dimension must be called first
+
+ std::vector<Simplex> next_dimension_simplices() const {
+ std::vector<Simplex> res;
+ while (!(to_see_.empty()) && (to_see_.front()->simplex().dimension() == current_dimension_)) {
+ res.emplace_back(to_see_.front()->simplex());
+ for (auto child : to_see_.front()->childs)
+ to_see_.push_back(child.get());
+ to_see_.pop_front();
+ }
+ ++current_dimension_;
+ return res;
+ }
+
+ void init_next_dimension() const {
+ for (auto trie : cofaces_)
+ to_see_.push_back(trie);
+ }
+
+ private:
+ mutable std::deque<STrie*> to_see_;
+ mutable int current_dimension_ = 0;
+ std::vector<STrie*> cofaces_;
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_INTERNAL_TRIE_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h
new file mode 100644
index 00000000..4f51f572
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h
@@ -0,0 +1,122 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_
+#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_
+
+#include <boost/iterator/iterator_facade.hpp>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * @brief Iterator through the blockers of a vertex.
+ */
+// ReturnType = const Simplex* or Simplex*
+// MapIteratorType = BlockerMapConstIterator or BlockerMapIterator
+
+template<typename MapIteratorType, typename ReturnType>
+class Blocker_iterator_internal : public boost::iterator_facade<
+Blocker_iterator_internal<MapIteratorType, ReturnType>,
+ReturnType,
+boost::forward_traversal_tag,
+ReturnType
+> {
+ private:
+ MapIteratorType current_position;
+ MapIteratorType end_of_map;
+
+ public:
+ Blocker_iterator_internal() : current_position() { }
+
+ Blocker_iterator_internal(MapIteratorType position, MapIteratorType end_of_map_) :
+ current_position(position), end_of_map(end_of_map_) { }
+
+ bool equal(const Blocker_iterator_internal& other) const {
+ return current_position == other.current_position;
+ }
+
+ void increment() {
+ goto_next_blocker();
+ }
+
+ ReturnType dereference() const {
+ return (current_position->second);
+ }
+
+ private:
+ /**
+ * Let the current pair be (v,sigma) where v is a vertex and sigma is a blocker.
+ * If v is not the first vertex of sigma then we already have seen sigma as a blocker
+ * and we look for the next one.
+ */
+ void goto_next_blocker() {
+ do {
+ ++current_position;
+ } while (!(current_position == end_of_map) && !first_time_blocker_is_seen());
+ }
+
+ bool first_time_blocker_is_seen() const {
+ return current_position->first == current_position->second->first_vertex();
+ }
+};
+
+/**
+ * @brief Iterator through the blockers of a vertex
+ */
+// ReturnType = const Simplex* or Simplex*
+// MapIteratorType = BlockerMapConstIterator or BlockerMapIterator
+
+template<typename MapIteratorType, typename ReturnType>
+class Blocker_iterator_around_vertex_internal : public boost::iterator_facade<
+Blocker_iterator_around_vertex_internal<MapIteratorType, ReturnType>,
+ReturnType,
+boost::forward_traversal_tag,
+ReturnType
+> {
+ private:
+ MapIteratorType current_position_;
+
+ public:
+ Blocker_iterator_around_vertex_internal() : current_position_() { }
+
+ Blocker_iterator_around_vertex_internal(MapIteratorType position) :
+ current_position_(position) { }
+
+ Blocker_iterator_around_vertex_internal& operator=(Blocker_iterator_around_vertex_internal other) {
+ this->current_position_ = other.current_position_;
+ return *this;
+ }
+
+ bool equal(const Blocker_iterator_around_vertex_internal& other) const {
+ return current_position_ == other.current_position_;
+ }
+
+ void increment() {
+ current_position_++;
+ }
+
+ ReturnType dereference() const {
+ return (current_position_->second);
+ }
+
+ MapIteratorType current_position() {
+ return this->current_position_;
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h
new file mode 100644
index 00000000..154388a1
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h
@@ -0,0 +1,135 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_
+#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_
+
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/graph/adjacency_list.hpp>
+
+#include <utility> // for pair<>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+template<typename SkeletonBlockerComplex>
+class Edge_around_vertex_iterator : public boost::iterator_facade <Edge_around_vertex_iterator<SkeletonBlockerComplex>
+, typename SkeletonBlockerComplex::Edge_handle const, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Edge_handle const> {
+ friend class boost::iterator_core_access;
+
+ typedef SkeletonBlockerComplex Complex;
+ typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Edge_handle Edge_handle;
+
+ private:
+ const Complex* complex;
+ Vertex_handle v;
+
+ boost_adjacency_iterator current_;
+ boost_adjacency_iterator end_;
+
+ public:
+ Edge_around_vertex_iterator() : complex(NULL) { }
+
+ Edge_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) :
+ complex(complex_),
+ v(v_) {
+ tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
+ }
+
+ /**
+ * returns an iterator to the end
+ */
+ Edge_around_vertex_iterator(const Complex* complex_, Vertex_handle v_, int end) :
+ complex(complex_),
+ v(v_) {
+ tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
+ set_end();
+ }
+
+ bool equal(const Edge_around_vertex_iterator& other) const {
+ return (complex == other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_);
+ }
+
+ void increment() {
+ if (current_ != end_)
+ ++current_;
+ }
+
+ Edge_handle dereference() const {
+ return *(*complex)[std::make_pair(v, static_cast<Vertex_handle> (*current_))];
+ }
+
+ private:
+ // remove this ugly hack
+ void set_end() {
+ current_ = end_;
+ }
+};
+
+/**
+ *@brief Iterator on the edges of a simplicial complex.
+ *
+ */
+template<typename SkeletonBlockerComplex>
+class Edge_iterator : public boost::iterator_facade <Edge_iterator<SkeletonBlockerComplex>
+, typename SkeletonBlockerComplex::Edge_handle const
+, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Edge_handle const> {
+ friend class boost::iterator_core_access;
+
+ public:
+ typedef SkeletonBlockerComplex Complex;
+ typedef typename Complex::boost_edge_iterator boost_edge_iterator;
+ typedef typename Complex::Edge_handle Edge_handle;
+
+ const Complex* complex;
+ std::pair<boost_edge_iterator, boost_edge_iterator> edge_iterator;
+
+ Edge_iterator() : complex(NULL) { }
+
+ Edge_iterator(const SkeletonBlockerComplex* complex_) :
+ complex(complex_),
+ edge_iterator(boost::edges(complex_->skeleton)) { }
+
+ /**
+ * return an iterator to the end
+ */
+ Edge_iterator(const SkeletonBlockerComplex* complex_, int end) :
+ complex(complex_),
+ edge_iterator(boost::edges(complex_->skeleton)) {
+ edge_iterator.first = edge_iterator.second;
+ }
+
+ bool equal(const Edge_iterator& other) const {
+ return (complex == other.complex) && (edge_iterator == other.edge_iterator);
+ }
+
+ void increment() {
+ if (edge_iterator.first != edge_iterator.second) {
+ ++(edge_iterator.first);
+ }
+ }
+
+ Edge_handle dereference() const {
+ return (*(edge_iterator.first));
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h
new file mode 100644
index 00000000..7b43e05f
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h
@@ -0,0 +1,20 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_
+#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_
+
+#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h>
+#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h>
+#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h>
+#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h>
+#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h>
+
+#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h
new file mode 100644
index 00000000..920f8cb6
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h
@@ -0,0 +1,390 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_
+#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_
+
+#include <gudhi/Skeleton_blocker_link_complex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h>
+#include <gudhi/Skeleton_blocker/internal/Trie.h>
+#include <gudhi/Debug_utils.h>
+
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <memory>
+#include <list>
+#include <iostream>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * Link may be Skeleton_blocker_link_complex<SkeletonBlockerComplex> to iterate over all
+ * simplices around a vertex OR
+ * Skeleton_blocker_superior_link_complex<SkeletonBlockerComplex> to iterate over all
+ * superior vertices around a vertex.
+ * The iteration is done by computing a trie with the link and doing a breadth-first traversal
+ * of the trie.
+ */
+template<typename SkeletonBlockerComplex, typename Link>
+class Simplex_around_vertex_iterator :
+public boost::iterator_facade < Simplex_around_vertex_iterator<SkeletonBlockerComplex, Link>
+, typename SkeletonBlockerComplex::Simplex
+, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Simplex
+> {
+ friend class boost::iterator_core_access;
+ typedef SkeletonBlockerComplex Complex;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Edge_handle Edge_handle;
+ typedef typename Complex::Simplex Simplex;
+
+ // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion
+ typedef typename Link::Vertex_handle Link_vertex_handle;
+
+ typedef typename Gudhi::skeleton_blocker::Trie<Simplex> Trie;
+
+ private:
+ const Complex* complex;
+ Vertex_handle v;
+ std::shared_ptr<Link> link_v;
+ std::shared_ptr<Trie> trie;
+ // TODO(DS): use a deque instead
+ std::list<Trie*> nodes_to_be_seen;
+
+ public:
+ Simplex_around_vertex_iterator() : complex(0) { }
+
+ Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) :
+ complex(complex_),
+ v(v_),
+ link_v(new Link(*complex_, v_)),
+ trie(new Trie(v_)) {
+ compute_trie_and_nodes_to_be_seen();
+ }
+
+ // TODO(DS): avoid useless copy
+ // TODO(DS): currently just work if copy begin iterator
+ Simplex_around_vertex_iterator(const Simplex_around_vertex_iterator& other) :
+ complex(other.complex),
+ v(other.v),
+ link_v(other.link_v),
+ trie(other.trie),
+ nodes_to_be_seen(other.nodes_to_be_seen) {
+ if (!other.is_end()) {
+ }
+ }
+
+ /**
+ * returns an iterator to the end
+ */
+ Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_, bool end) :
+ complex(complex_),
+ v(v_) {
+ set_end();
+ }
+
+ private:
+ void compute_trie_and_nodes_to_be_seen() {
+ // once we go through every simplices passing through v0
+ // we remove v0. That way, it prevents from passing a lot of times
+ // though edges leaving v0.
+ // another solution would have been to provides an adjacency iterator
+ // to superior vertices that avoids lower ones.
+ while (!link_v->empty()) {
+ auto v0 = *(link_v->vertex_range().begin());
+ trie->add_child(build_trie(v0, trie.get()));
+ link_v->remove_vertex(v0);
+ }
+ nodes_to_be_seen.push_back(trie.get());
+ }
+
+ Trie* build_trie(Link_vertex_handle link_vh, Trie* parent) {
+ Trie* res = new Trie(parent_vertex(link_vh), parent);
+ for (Link_vertex_handle nv : link_v->vertex_range(link_vh)) {
+ if (link_vh < nv) {
+ Simplex simplex_node_plus_nv(res->simplex());
+ simplex_node_plus_nv.add_vertex(parent_vertex(nv));
+ if (complex->contains(simplex_node_plus_nv)) {
+ res->add_child(build_trie(nv, res));
+ }
+ }
+ }
+ return res;
+ }
+
+ bool is_node_in_complex(Trie* trie) {
+ return true;
+ }
+
+ Vertex_handle parent_vertex(Link_vertex_handle link_vh) const {
+ return complex->convert_handle_from_another_complex(*link_v, link_vh);
+ }
+
+ public:
+ friend std::ostream& operator<<(std::ostream& stream, const Simplex_around_vertex_iterator& savi) {
+ stream << savi.trie << std::endl;
+ stream << "(" << savi.nodes_to_be_seen.size() << ") nodes to see\n";
+ return stream;
+ }
+
+ bool equal(const Simplex_around_vertex_iterator& other) const {
+ bool same_complex = (complex == other.complex);
+ if (!same_complex)
+ return false;
+
+ if (!(v == other.v))
+ return false;
+
+ bool both_empty = nodes_to_be_seen.empty() && other.nodes_to_be_seen.empty();
+ if (both_empty)
+ return true;
+
+ bool both_non_empty = !nodes_to_be_seen.empty() && !other.nodes_to_be_seen.empty();
+
+ // one is empty the other is not
+ if (!both_non_empty) return false;
+
+ bool same_node = (**(nodes_to_be_seen.begin()) == **(other.nodes_to_be_seen.begin()));
+ return same_node;
+ }
+
+ void increment() {
+ assert(!is_end());
+ Trie* first_node = nodes_to_be_seen.front();
+
+ nodes_to_be_seen.pop_front();
+
+ for (auto childs : first_node->childs) {
+ nodes_to_be_seen.push_back(childs.get());
+ }
+ }
+
+ Simplex dereference() const {
+ assert(!nodes_to_be_seen.empty());
+ Trie* first_node = nodes_to_be_seen.front();
+ return first_node->simplex();
+ }
+
+ Simplex get_trie_address() const {
+ assert(!nodes_to_be_seen.empty());
+ return nodes_to_be_seen.front();
+ }
+
+ private:
+ void set_end() {
+ nodes_to_be_seen.clear();
+ }
+
+ bool is_end() const {
+ return nodes_to_be_seen.empty();
+ }
+};
+
+template<typename SkeletonBlockerComplex>
+class Simplex_iterator :
+public boost::iterator_facade < Simplex_iterator<SkeletonBlockerComplex>
+, typename SkeletonBlockerComplex::Simplex
+, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Simplex
+> {
+ typedef Skeleton_blocker_link_superior<SkeletonBlockerComplex> Link;
+
+ friend class boost::iterator_core_access;
+
+ template<class SkBlDS> friend class Skeleton_blocker_complex;
+
+ typedef SkeletonBlockerComplex Complex;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Edge_handle Edge_handle;
+ typedef typename Complex::Simplex Simplex;
+ typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator;
+ typedef typename Link::Vertex_handle Link_vertex_handle;
+
+ private:
+ const Complex* complex_;
+ Complex_vertex_iterator current_vertex_;
+
+ typedef Simplex_around_vertex_iterator<SkeletonBlockerComplex, Link> SAVI;
+ SAVI current_simplex_around_current_vertex_;
+ SAVI simplices_around_current_vertex_end_;
+
+ public:
+ Simplex_iterator() : complex_(0) { }
+
+ Simplex_iterator(const Complex* complex) :
+ complex_(complex),
+ current_vertex_(complex->vertex_range().begin()),
+ current_simplex_around_current_vertex_(complex, *current_vertex_),
+ simplices_around_current_vertex_end_(complex, *current_vertex_, true) {
+ // should not be called if the complex is empty
+ assert(!complex->empty());
+ }
+
+ private:
+ Simplex_iterator(const Complex* complex, bool end) :
+ complex_(complex) {
+ set_end();
+ }
+
+ public:
+ Simplex_iterator(const Simplex_iterator& other)
+ :
+ complex_(other.complex_),
+ current_vertex_(other.current_vertex_),
+ current_simplex_around_current_vertex_(other.current_simplex_around_current_vertex_),
+ simplices_around_current_vertex_end_(other.simplices_around_current_vertex_end_) { }
+
+ friend Simplex_iterator make_begin_iterator(const Complex* complex) {
+ if (complex->empty())
+ return make_end_simplex_iterator(complex);
+ else
+ return Simplex_iterator(complex);
+ }
+
+ friend Simplex_iterator make_end_simplex_iterator(const Complex* complex) {
+ return Simplex_iterator(complex, true);
+ }
+
+ bool equal(const Simplex_iterator& other) const {
+ if (complex_ != other.complex_) return false;
+ if (current_vertex_ != other.current_vertex_) return false;
+ if (is_end() && other.is_end()) return true;
+ if (current_simplex_around_current_vertex_ != other.current_simplex_around_current_vertex_)
+ return false;
+ return true;
+ }
+
+ void increment() {
+ if (current_simplex_around_current_vertex_ != simplices_around_current_vertex_end_) {
+ current_simplex_around_current_vertex_.increment();
+ if (current_simplex_around_current_vertex_ == simplices_around_current_vertex_end_)
+ goto_next_vertex();
+ } else {
+ goto_next_vertex();
+ }
+ }
+
+ void goto_next_vertex() {
+ current_vertex_.increment();
+ if (!is_end()) {
+ current_simplex_around_current_vertex_ = SAVI(complex_, *current_vertex_);
+ simplices_around_current_vertex_end_ = SAVI(complex_, *current_vertex_, true);
+ }
+ }
+
+ Simplex dereference() const {
+ return current_simplex_around_current_vertex_.dereference();
+ }
+
+ private:
+ void set_end() {
+ current_vertex_ = complex_->vertex_range().end();
+ }
+
+ bool is_end() const {
+ return (current_vertex_ == complex_->vertex_range().end());
+ }
+};
+
+/**
+ * Iterator through the maximal faces of the coboundary of a simplex.
+ */
+template<typename SkeletonBlockerComplex, typename Link>
+class Simplex_coboundary_iterator :
+public boost::iterator_facade < Simplex_coboundary_iterator<SkeletonBlockerComplex, Link>
+, typename SkeletonBlockerComplex::Simplex, boost::forward_traversal_tag, typename SkeletonBlockerComplex::Simplex> {
+ friend class boost::iterator_core_access;
+ typedef SkeletonBlockerComplex Complex;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Edge_handle Edge_handle;
+ typedef typename Complex::Simplex Simplex;
+ typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator;
+
+ // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion
+ typedef typename Link::Vertex_handle Link_vertex_handle;
+
+ private:
+ const Complex* complex;
+ const Simplex& sigma;
+ std::shared_ptr<Link> link;
+ Complex_vertex_iterator current_vertex;
+ Complex_vertex_iterator link_vertex_end;
+
+ public:
+ Simplex_coboundary_iterator() : complex(0) { }
+
+ Simplex_coboundary_iterator(const Complex* complex_, const Simplex& sigma_) :
+ complex(complex_),
+ sigma(sigma_),
+ // need only vertices of the link hence the true flag
+ link(new Link(*complex_, sigma_, false, true)) {
+ auto link_vertex_range = link->vertex_range();
+ current_vertex = link_vertex_range.begin();
+ link_vertex_end = link_vertex_range.end();
+ }
+
+ Simplex_coboundary_iterator(const Simplex_coboundary_iterator& other) :
+ complex(other.complex),
+ sigma(other.sigma),
+ link(other.link),
+ current_vertex(other.current_vertex),
+ link_vertex_end(other.link_vertex_end) { }
+
+ // returns an iterator to the end
+ Simplex_coboundary_iterator(const Complex* complex_, const Simplex& sigma_, bool end) :
+ complex(complex_),
+ sigma(sigma_) {
+ // to represent an end iterator without having to build a useless link, we use
+ // the convection that link is not initialized.
+ }
+
+ private:
+ Vertex_handle parent_vertex(Link_vertex_handle link_vh) const {
+ return complex->convert_handle_from_another_complex(*link, link_vh);
+ }
+
+ public:
+ friend std::ostream& operator<<(std::ostream& stream, const Simplex_coboundary_iterator& sci) {
+ return stream;
+ }
+
+ // assume that iterator points to the same complex and comes from the same simplex
+ bool equal(const Simplex_coboundary_iterator& other) const {
+ assert(complex == other.complex && sigma == other.sigma);
+ if (is_end()) return other.is_end();
+ if (other.is_end()) return is_end();
+ return *current_vertex == *(other.current_vertex);
+ }
+
+ void increment() {
+ ++current_vertex;
+ }
+
+ Simplex dereference() const {
+ Simplex res(sigma);
+ res.add_vertex(parent_vertex(*current_vertex));
+ return res;
+ }
+
+ private:
+ bool is_end() const {
+ return !link || current_vertex == link_vertex_end;
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h
new file mode 100644
index 00000000..37c0b4d3
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h
@@ -0,0 +1,214 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_
+#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_
+
+#include <boost/iterator/iterator_facade.hpp>
+#include <memory>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * \brief Iterator over the triangles that are
+ * adjacent to a vertex of the simplicial complex.
+ * \remark Will be removed soon -> dont look
+ */
+template<typename Complex, typename LinkType>
+class Triangle_around_vertex_iterator : public boost::iterator_facade
+< Triangle_around_vertex_iterator <Complex, LinkType>
+, typename Complex::Simplex const
+, boost::forward_traversal_tag
+, typename Complex::Simplex const> {
+ friend class boost::iterator_core_access;
+ template<typename T> friend class Triangle_iterator;
+ private:
+ typedef typename LinkType::Vertex_handle Vertex_handle;
+ typedef typename LinkType::Root_vertex_handle Root_vertex_handle;
+ typedef typename LinkType::Simplex Simplex;
+ typedef typename Complex::Complex_edge_iterator Complex_edge_iterator_;
+
+ const Complex* complex_;
+ Vertex_handle v_;
+ std::shared_ptr<LinkType> link_;
+ Complex_edge_iterator_ current_edge_;
+ bool is_end_;
+
+ public:
+ Triangle_around_vertex_iterator(const Complex* complex, Vertex_handle v) :
+ complex_(complex), v_(v), link_(new LinkType(*complex, v_)),
+ current_edge_(link_->edge_range().begin()),
+ is_end_(current_edge_ == link_->edge_range().end()) { }
+
+ /**
+ * @brief ugly hack to get an iterator to the end
+ */
+ Triangle_around_vertex_iterator(const Complex* complex, Vertex_handle v, bool is_end) :
+ complex_(complex), v_(v), link_(0), is_end_(true) { }
+
+ /**
+ * @brief ugly hack to get an iterator to the end
+ */
+ Triangle_around_vertex_iterator() :
+ complex_(0), v_(-1), link_(0), is_end_(true) { }
+
+ Triangle_around_vertex_iterator(const Triangle_around_vertex_iterator& other) {
+ v_ = other.v_;
+ complex_ = other.complex_;
+ is_end_ = other.is_end_;
+
+ if (!is_end_) {
+ link_ = other.link_;
+ current_edge_ = other.current_edge_;
+ }
+ }
+
+ bool equal(const Triangle_around_vertex_iterator& other) const {
+ return (complex_ == other.complex_) && ((finished() && other.finished()) || current_edge_ == other.current_edge_);
+ }
+
+ Simplex dereference() const {
+ Root_vertex_handle v1 = (*link_)[*current_edge_].first();
+ Root_vertex_handle v2 = (*link_)[*current_edge_].second();
+ return Simplex(v_, *(complex_->get_address(v1)), *(complex_->get_address(v2)));
+ }
+
+ void increment() {
+ ++current_edge_;
+ }
+
+ private:
+ bool finished() const {
+ return is_end_ || (current_edge_ == link_->edge_range().end());
+ }
+};
+
+/**
+ * \brief Iterator over the triangles of the
+ * simplicial complex.
+ * \remark Will be removed soon -> dont look
+ *
+ */
+template<typename SkeletonBlockerComplex>
+class Triangle_iterator : public boost::iterator_facade<
+Triangle_iterator <SkeletonBlockerComplex>,
+typename SkeletonBlockerComplex::Simplex const
+, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Simplex const> {
+ friend class boost::iterator_core_access;
+ private:
+ typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle;
+ typedef typename SkeletonBlockerComplex::Root_vertex_handle Root_vertex_handle;
+ typedef typename SkeletonBlockerComplex::Simplex Simplex;
+ typedef typename SkeletonBlockerComplex::Superior_triangle_around_vertex_iterator STAVI;
+ typedef typename SkeletonBlockerComplex::Complex_vertex_iterator Complex_vertex_iterator;
+
+ const SkeletonBlockerComplex* complex_;
+ Complex_vertex_iterator current_vertex_;
+ STAVI current_triangle_;
+ bool is_end_;
+
+ public:
+ /*
+ * @remark assume that the complex is non-empty
+ */
+ Triangle_iterator(const SkeletonBlockerComplex* complex) :
+ complex_(complex),
+ current_vertex_(complex->vertex_range().begin()),
+ current_triangle_(complex, *current_vertex_), // this line is problematic is the complex is empty
+ is_end_(false) {
+ assert(!complex->empty());
+ gotoFirstTriangle();
+ }
+
+ private:
+ // goto to the first triangle or to the end if none
+ void gotoFirstTriangle() {
+ if (!is_finished() && current_triangle_.finished()) {
+ goto_next_vertex();
+ }
+ }
+
+ public:
+ /**
+ * @brief ugly hack to get an iterator to the end
+ * @remark assume that the complex is non-empty
+ */
+ Triangle_iterator(const SkeletonBlockerComplex* complex, bool is_end) :
+ complex_(complex),
+ current_vertex_(complex->vertex_range().end()),
+ current_triangle_(), // xxx this line is problematic is the complex is empty
+ is_end_(true) { }
+
+ Triangle_iterator& operator=(const Triangle_iterator & other) {
+ complex_ = other.complex_;
+ Complex_vertex_iterator current_vertex_;
+ STAVI current_triangle_;
+ return *this;
+ }
+
+ bool equal(const Triangle_iterator& other) const {
+ bool both_are_finished = is_finished() && other.is_finished();
+ bool both_arent_finished = !is_finished() && !other.is_finished();
+ // if the two iterators are not finished, they must have the same state
+ return (complex_ == other.complex_) && (both_are_finished || ((both_arent_finished) &&
+ current_vertex_ == other.current_vertex_ &&
+ current_triangle_ == other.current_triangle_));
+ }
+
+ Simplex dereference() const {
+ return *current_triangle_;
+ }
+
+ private:
+ // goto the next vertex that has a triangle pending or the
+ // end vertex iterator if none exists
+ void goto_next_vertex() {
+ // we must have consume all triangles passing through the vertex
+ assert(current_triangle_.finished());
+ // we must not be done
+ assert(!is_finished());
+
+ ++current_vertex_;
+
+ if (!is_finished()) {
+ current_triangle_ = STAVI(complex_, *current_vertex_);
+ if (current_triangle_.finished())
+ goto_next_vertex();
+ }
+ }
+
+ public:
+ void increment() {
+ if (!current_triangle_.finished()) {
+ ++current_triangle_; // problem here
+ if (current_triangle_.finished())
+ goto_next_vertex();
+ } else {
+ assert(!is_finished());
+ goto_next_vertex();
+ }
+ }
+
+ private:
+ bool is_finished() const {
+ return is_end_ || current_vertex_ == complex_->vertex_range().end();
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h
new file mode 100644
index 00000000..49e94256
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h
@@ -0,0 +1,158 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_
+#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_
+
+#include <boost/iterator/iterator_facade.hpp>
+
+#include <utility> // for pair<>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ *@brief Iterator on the vertices of a simplicial complex
+ *@remark The increment operator go to the next active vertex.
+ *@remark Incrementation increases Vertex_handle.
+ */
+template<typename SkeletonBlockerComplex>
+class Vertex_iterator : public boost::iterator_facade< Vertex_iterator <SkeletonBlockerComplex>
+, typename SkeletonBlockerComplex::Vertex_handle const
+, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Vertex_handle const> {
+ friend class boost::iterator_core_access;
+
+ typedef typename SkeletonBlockerComplex::boost_vertex_iterator boost_vertex_iterator;
+ typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle;
+ private:
+ const SkeletonBlockerComplex* complex;
+ std::pair<boost_vertex_iterator, boost_vertex_iterator> vertexIterator;
+
+
+ public:
+ Vertex_iterator() : complex(NULL) { }
+
+ Vertex_iterator(const SkeletonBlockerComplex* complex_) :
+ complex(complex_),
+ vertexIterator(vertices(complex_->skeleton)) {
+ if (!finished() && !is_active()) {
+ goto_next_valid();
+ }
+ }
+
+ /**
+ * return an iterator to the end.
+ */
+ Vertex_iterator(const SkeletonBlockerComplex* complex_, int end) :
+ complex(complex_), vertexIterator(vertices(complex_->skeleton)) {
+ vertexIterator.first = vertexIterator.second;
+ }
+
+ public:
+ void increment() {
+ goto_next_valid();
+ }
+
+ Vertex_handle dereference() const {
+ return (Vertex_handle(*(vertexIterator.first)));
+ }
+
+ bool equal(const Vertex_iterator& other) const {
+ return vertexIterator == other.vertexIterator && complex == other.complex;
+ }
+
+ bool operator<(const Vertex_iterator& other) const {
+ return dereference() < other.dereference();
+ }
+
+ private:
+ bool finished() const {
+ return vertexIterator.first == vertexIterator.second;
+ }
+
+ void goto_next_valid() {
+ ++vertexIterator.first;
+ if (!finished() && !is_active()) {
+ goto_next_valid();
+ }
+ }
+
+ bool is_active() const {
+ return ((*complex)[Vertex_handle(*vertexIterator.first)]).is_active();
+ }
+};
+
+template<typename SkeletonBlockerComplex>
+class Neighbors_vertices_iterator : public boost::iterator_facade < Neighbors_vertices_iterator<SkeletonBlockerComplex>
+, typename SkeletonBlockerComplex::Vertex_handle const
+, boost::forward_traversal_tag
+, typename SkeletonBlockerComplex::Vertex_handle const> {
+ friend class boost::iterator_core_access;
+
+ typedef SkeletonBlockerComplex Complex;
+ typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator;
+ typedef typename Complex::Vertex_handle Vertex_handle;
+ typedef typename Complex::Edge_handle Edge_handle;
+
+ private:
+ const Complex* complex;
+ Vertex_handle v;
+
+ boost_adjacency_iterator current_;
+ boost_adjacency_iterator end_;
+
+ public:
+ Neighbors_vertices_iterator() : complex(NULL) { }
+
+ Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_) :
+ complex(complex_),
+ v(v_) {
+ tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
+ }
+
+ /**
+ * returns an iterator to the end
+ */
+ Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_, int end) :
+ complex(complex_),
+ v(v_) {
+ tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
+ set_end();
+ }
+
+ void increment() {
+ if (current_ != end_)
+ ++current_;
+ }
+
+ Vertex_handle dereference() const {
+ return (Vertex_handle(*current_));
+ }
+
+ bool equal(const Neighbors_vertices_iterator& other) const {
+ return (complex == other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_);
+ }
+
+ private:
+ // TODO(DS): remove this ugly hack
+ void set_end() {
+ current_ = end_;
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h
new file mode 100644
index 00000000..125c6387
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h
@@ -0,0 +1,1593 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_COMPLEX_H_
+#define SKELETON_BLOCKER_COMPLEX_H_
+
+#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h>
+#include <gudhi/Skeleton_blocker_link_complex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h>
+#include <gudhi/Skeleton_blocker/internal/Top_faces.h>
+#include <gudhi/Skeleton_blocker/internal/Trie.h>
+#include <gudhi/Debug_utils.h>
+
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/connected_components.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/range/adaptor/map.hpp>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <memory>
+#include <map>
+#include <list>
+#include <set>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <utility>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ *@class Skeleton_blocker_complex
+ *@brief Abstract Simplicial Complex represented with a skeleton/blockers pair.
+ *@ingroup skbl
+ */
+template<class SkeletonBlockerDS>
+class Skeleton_blocker_complex {
+ template<class ComplexType> friend class Vertex_iterator;
+ template<class ComplexType> friend class Neighbors_vertices_iterator;
+ template<class ComplexType> friend class Edge_iterator;
+ template<class ComplexType> friend class Edge_around_vertex_iterator;
+
+ template<class ComplexType> friend class Skeleton_blocker_link_complex;
+ template<class ComplexType> friend class Skeleton_blocker_link_superior;
+ template<class ComplexType> friend class Skeleton_blocker_sub_complex;
+
+ public:
+ /**
+ * @brief The type of stored vertex node, specified by the template SkeletonBlockerDS
+ */
+ typedef typename SkeletonBlockerDS::Graph_vertex Graph_vertex;
+
+ /**
+ * @brief The type of stored edge node, specified by the template SkeletonBlockerDS
+ */
+ typedef typename SkeletonBlockerDS::Graph_edge Graph_edge;
+
+ typedef typename SkeletonBlockerDS::Root_vertex_handle Root_vertex_handle;
+
+ /**
+ * @brief The type of an handle to a vertex of the complex.
+ */
+ typedef typename SkeletonBlockerDS::Vertex_handle Vertex_handle;
+ typedef typename Root_vertex_handle::boost_vertex_handle boost_vertex_handle;
+
+ /**
+ * @brief A ordered set of integers that represents a simplex.
+ */
+ typedef Skeleton_blocker_simplex<Vertex_handle> Simplex;
+ typedef Skeleton_blocker_simplex<Root_vertex_handle> Root_simplex_handle;
+
+ /**
+ * @brief Handle to a blocker of the complex.
+ */
+ typedef Simplex* Blocker_handle;
+
+ typedef typename Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_iterator;
+ typedef typename Simplex::Simplex_vertex_const_iterator Simplex_handle_iterator;
+
+ protected:
+ typedef typename boost::adjacency_list<boost::setS, // edges
+ boost::vecS, // vertices
+ boost::undirectedS, Graph_vertex, Graph_edge> Graph;
+ // todo/remark : edges are not sorted, it heavily penalizes computation for SuperiorLink
+ // (eg Link with greater vertices)
+ // that burdens simplex iteration / complex initialization via list of simplices.
+ // to avoid that, one should modify the graph by storing two lists of adjacency for every
+ // vertex, the one with superior and the one with lower vertices, that way there is
+ // no more extra cost for computation of SuperiorLink
+ typedef typename boost::graph_traits<Graph>::vertex_iterator boost_vertex_iterator;
+ typedef typename boost::graph_traits<Graph>::edge_iterator boost_edge_iterator;
+
+ protected:
+ typedef typename boost::graph_traits<Graph>::adjacency_iterator boost_adjacency_iterator;
+
+ public:
+ /**
+ * @brief Handle to an edge of the complex.
+ */
+ typedef typename boost::graph_traits<Graph>::edge_descriptor Edge_handle;
+
+ protected:
+ typedef std::multimap<Vertex_handle, Simplex *> BlockerMap;
+ typedef typename std::multimap<Vertex_handle, Simplex *>::value_type BlockerPair;
+ typedef typename std::multimap<Vertex_handle, Simplex *>::iterator BlockerMapIterator;
+ typedef typename std::multimap<Vertex_handle, Simplex *>::const_iterator BlockerMapConstIterator;
+
+ protected:
+ size_t num_vertices_;
+ size_t num_blockers_;
+
+ typedef Skeleton_blocker_complex_visitor<Vertex_handle> Visitor;
+ // typedef Visitor* Visitor_ptr;
+ Visitor* visitor;
+
+ /**
+ * @details If 'x' is a Vertex_handle of a vertex in the complex then degree[x] = d is its degree.
+ *
+ * This quantity is updated when adding/removing edge.
+ *
+ * This is useful because the operation
+ * list.size() is done in linear time.
+ */
+ std::vector<boost_vertex_handle> degree_;
+ Graph skeleton; /** 1-skeleton of the simplicial complex. */
+
+ /** Each vertex can access to the blockers passing through it. */
+ BlockerMap blocker_map_;
+
+ public:
+ /////////////////////////////////////////////////////////////////////////////
+ /** @name Constructors, Destructors
+ */
+ //@{
+
+ /**
+ *@brief constructs a simplicial complex with a given number of vertices and a visitor.
+ */
+ explicit Skeleton_blocker_complex(size_t num_vertices_ = 0, Visitor* visitor_ = NULL)
+ : visitor(visitor_) {
+ clear();
+ for (size_t i = 0; i < num_vertices_; ++i) {
+ add_vertex();
+ }
+ }
+
+ private:
+ // typedef Trie<Skeleton_blocker_complex<SkeletonBlockerDS>> STrie;
+ typedef Trie<Simplex> STrie;
+
+ public:
+ /**
+ * @brief Constructor with a list of simplices.
+ * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be computed or not).
+ */
+ template<typename SimpleHandleOutputIterator>
+ Skeleton_blocker_complex(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end,
+ bool is_flag_complex = false, Visitor* visitor_ = NULL)
+ : num_vertices_(0),
+ num_blockers_(0),
+ visitor(visitor_) {
+ add_vertices_and_edges(simplices_begin, simplices_end);
+
+ if (!is_flag_complex)
+ // need to compute blockers
+ add_blockers(simplices_begin, simplices_end);
+ }
+
+ private:
+ /**
+ * Add vertices and edges of a simplex in one pass
+ */
+ template<typename SimpleHandleOutputIterator>
+ void add_vertices_and_edges(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) {
+ std::vector<std::pair<Vertex_handle, Vertex_handle>> edges;
+ // first pass to add vertices and edges
+ int num_vertex = -1;
+ for (auto s_it = simplices_begin; s_it != simplices_end; ++s_it) {
+ if (s_it->dimension() == 0) num_vertex = (std::max)(num_vertex, s_it->first_vertex().vertex);
+ if (s_it->dimension() == 1) edges.emplace_back(s_it->first_vertex(), s_it->last_vertex());
+ }
+ while (num_vertex-- >= 0) add_vertex();
+
+ for (const auto& e : edges)
+ add_edge_without_blockers(e.first, e.second);
+ }
+
+ template<typename SimpleHandleOutputIterator>
+ void add_blockers(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) {
+ Tries<Simplex> tries(num_vertices(), simplices_begin, simplices_end);
+ tries.init_next_dimension();
+ auto simplices(tries.next_dimension_simplices());
+
+ while (!simplices.empty()) {
+ simplices = tries.next_dimension_simplices();
+ for (auto& sigma : simplices) {
+ // common_positive_neighbors is the set of vertices u such that
+ // for all s in sigma, us is an edge and u>s
+ Simplex common_positive_neighbors(tries.positive_neighbors(sigma.last_vertex()));
+ for (auto sigma_it = sigma.rbegin(); sigma_it != sigma.rend(); ++sigma_it)
+ if (sigma_it != sigma.rbegin())
+ common_positive_neighbors.intersection(tries.positive_neighbors(*sigma_it));
+
+ for (auto x : common_positive_neighbors) {
+ // first test that all edges sx are here for all s in sigma
+ bool all_edges_here = true;
+ for (auto s : sigma)
+ if (!contains_edge(x, s)) {
+ all_edges_here = false;
+ break;
+ }
+ if (!all_edges_here) continue;
+
+ // all edges of sigma \cup x are here
+ // we have a blocker if all proper faces of sigma \cup x
+ // are in the complex and if sigma \cup x is not in the complex
+ // the first is equivalent at checking if blocks(sigma \cup x) is true
+ // as all blockers of lower dimension have already been computed
+ sigma.add_vertex(x);
+ if (!tries.contains(sigma) && !blocks(sigma))
+ add_blocker(sigma);
+ sigma.remove_vertex(x);
+ }
+ }
+ }
+ }
+
+ public:
+ // We cannot use the default copy constructor since we need
+ // to make a copy of each of the blockers
+
+ Skeleton_blocker_complex(const Skeleton_blocker_complex& copy) {
+ visitor = NULL;
+ degree_ = copy.degree_;
+ skeleton = Graph(copy.skeleton);
+ num_vertices_ = copy.num_vertices_;
+
+ num_blockers_ = 0;
+ // we copy the blockers
+ for (auto blocker : copy.const_blocker_range()) {
+ add_blocker(*blocker);
+ }
+ }
+
+ /**
+ */
+ Skeleton_blocker_complex& operator=(const Skeleton_blocker_complex& copy) {
+ clear();
+ visitor = NULL;
+ degree_ = copy.degree_;
+ skeleton = Graph(copy.skeleton);
+ num_vertices_ = copy.num_vertices_;
+
+ num_blockers_ = 0;
+ // we copy the blockers
+ for (auto blocker : copy.const_blocker_range())
+ add_blocker(*blocker);
+ return *this;
+ }
+
+ /**
+ * return true if both complexes have the same simplices.
+ */
+ bool operator==(const Skeleton_blocker_complex& other) const {
+ if (other.num_vertices() != num_vertices()) return false;
+ if (other.num_edges() != num_edges()) return false;
+ if (other.num_blockers() != num_blockers()) return false;
+
+ for (auto v : vertex_range())
+ if (!other.contains_vertex(v)) return false;
+
+ for (auto e : edge_range())
+ if (!other.contains_edge(first_vertex(e), second_vertex(e))) return false;
+
+ for (const auto b : const_blocker_range())
+ if (!other.contains_blocker(*b)) return false;
+
+ return true;
+ }
+
+ bool operator!=(const Skeleton_blocker_complex& other) const {
+ return !(*this == other);
+ }
+
+ /**
+ * The destructor delete all blockers allocated.
+ */
+ virtual ~Skeleton_blocker_complex() {
+ clear();
+ }
+
+ /**
+ * @details Clears the simplicial complex. After a call to this function,
+ * blockers are destroyed. The 1-skeleton and the set of blockers
+ * are both empty.
+ */
+ virtual void clear() {
+ // xxx for now the responsabilty of freeing the visitor is for
+ // the user
+ visitor = NULL;
+
+ degree_.clear();
+ num_vertices_ = 0;
+
+ remove_blockers();
+
+ skeleton.clear();
+ }
+
+ /**
+ *@brief allows to change the visitor.
+ */
+ void set_visitor(Visitor* other_visitor) {
+ visitor = other_visitor;
+ }
+
+ //@}
+
+ /////////////////////////////////////////////////////////////////////////////
+ /** @name Vertices operations
+ */
+ //@{
+ public:
+ /**
+ * @brief Return a local Vertex_handle of a vertex given a global one.
+ * @remark Assume that the vertex is present in the complex.
+ */
+ Vertex_handle operator[](Root_vertex_handle global) const {
+ auto local(get_address(global));
+ assert(local);
+ return *local;
+ }
+
+ /**
+ * @brief Return the vertex node associated to local Vertex_handle.
+ * @remark Assume that the vertex is present in the complex.
+ */
+ Graph_vertex& operator[](Vertex_handle address) {
+ assert(
+ 0 <= address.vertex && address.vertex < boost::num_vertices(skeleton));
+ return skeleton[address.vertex];
+ }
+
+ /**
+ * @brief Return the vertex node associated to local Vertex_handle.
+ * @remark Assume that the vertex is present in the complex.
+ */
+ const Graph_vertex& operator[](Vertex_handle address) const {
+ assert(
+ 0 <= address.vertex && address.vertex < boost::num_vertices(skeleton));
+ return skeleton[address.vertex];
+ }
+
+ /**
+ * @brief Adds a vertex to the simplicial complex and returns its Vertex_handle.
+ * @remark Vertex representation is contiguous.
+ */
+ Vertex_handle add_vertex() {
+ Vertex_handle address(boost::add_vertex(skeleton));
+ num_vertices_++;
+ (*this)[address].activate();
+ // safe since we now that we are in the root complex and the field 'address' and 'id'
+ // are identical for every vertices
+ (*this)[address].set_id(Root_vertex_handle(address.vertex));
+ degree_.push_back(0);
+ if (visitor)
+ visitor->on_add_vertex(address);
+ return address;
+ }
+
+ /**
+ * @brief Remove a vertex from the simplicial complex
+ * @remark It just deactivates the vertex with a boolean flag but does not
+ * remove it from vertices from complexity issues.
+ */
+ void remove_vertex(Vertex_handle address) {
+ assert(contains_vertex(address));
+ // We remove b
+ boost::clear_vertex(address.vertex, skeleton);
+ (*this)[address].deactivate();
+ num_vertices_--;
+ degree_[address.vertex] = -1;
+ if (visitor)
+ visitor->on_remove_vertex(address);
+ }
+
+ /**
+ */
+ bool contains_vertex(Vertex_handle u) const {
+ Vertex_handle num_vertices(boost::num_vertices(skeleton));
+ if (u.vertex < 0 || u.vertex >= num_vertices)
+ return false;
+ return (*this)[u].is_active();
+ }
+
+ /**
+ */
+ bool contains_vertex(Root_vertex_handle u) const {
+ boost::optional<Vertex_handle> address = get_address(u);
+ return address && (*this)[*address].is_active();
+ }
+
+ /**
+ * @return true iff the simplicial complex contains all vertices
+ * of simplex sigma
+ */
+ bool contains_vertices(const Simplex & sigma) const {
+ for (auto vertex : sigma)
+ if (!contains_vertex(vertex))
+ return false;
+ return true;
+ }
+
+ /**
+ * @brief Given an Id return the address of the vertex having this Id in the complex.
+ * @remark For a simplicial complex, the address is the id but it may not be the case for a SubComplex.
+ */
+ virtual boost::optional<Vertex_handle> get_address(Root_vertex_handle id) const {
+ boost::optional<Vertex_handle> res;
+ int num_vertices = boost::num_vertices(skeleton);
+ if (id.vertex < num_vertices)
+ res = Vertex_handle(id.vertex);
+ return res;
+ }
+
+ /**
+ * return the id of a vertex of adress local present in the graph
+ */
+ Root_vertex_handle get_id(Vertex_handle local) const {
+ assert(0 <= local.vertex && local.vertex < boost::num_vertices(skeleton));
+ return (*this)[local].get_id();
+ }
+
+ /**
+ * @brief Convert an address of a vertex of a complex to the address in
+ * the current complex.
+ * @details
+ * If the current complex is a sub (or sup) complex of 'other', it converts
+ * the address of a vertex v expressed in 'other' to the address of the vertex
+ * v in the current one.
+ * @remark this methods uses Root_vertex_handle to identify the vertex and
+ * assumes the vertex is present in the current complex.
+ */
+ Vertex_handle convert_handle_from_another_complex(const Skeleton_blocker_complex& other,
+ Vertex_handle vh_in_other) const {
+ auto vh_in_current_complex = get_address(other.get_id(vh_in_other));
+ assert(vh_in_current_complex);
+ return *vh_in_current_complex;
+ }
+
+ /**
+ * @brief return the graph degree of a vertex.
+ */
+ int degree(Vertex_handle local) const {
+ assert(0 <= local.vertex && local.vertex < boost::num_vertices(skeleton));
+ return degree_[local.vertex];
+ }
+
+ //@}
+
+ /////////////////////////////////////////////////////////////////////////////
+ /** @name Edges operations
+ */
+ //@{
+ public:
+ /**
+ * @brief return an edge handle if the two vertices forms
+ * an edge in the complex
+ */
+ boost::optional<Edge_handle> operator[](
+ const std::pair<Vertex_handle, Vertex_handle>& ab) const {
+ boost::optional<Edge_handle> res;
+ std::pair<Edge_handle, bool> edge_pair(
+ boost::edge(ab.first.vertex, ab.second.vertex, skeleton));
+ if (edge_pair.second)
+ res = edge_pair.first;
+ return res;
+ }
+
+ /**
+ * @brief returns the stored node associated to an edge
+ */
+ Graph_edge& operator[](Edge_handle edge_handle) {
+ return skeleton[edge_handle];
+ }
+
+ /**
+ * @brief returns the stored node associated to an edge
+ */
+ const Graph_edge& operator[](Edge_handle edge_handle) const {
+ return skeleton[edge_handle];
+ }
+
+ /**
+ * @brief returns the first vertex of an edge
+ * @details it assumes that the edge is present in the complex
+ */
+ Vertex_handle first_vertex(Edge_handle edge_handle) const {
+ return static_cast<Vertex_handle> (source(edge_handle, skeleton));
+ }
+
+ /**
+ * @brief returns the first vertex of an edge
+ * @details it assumes that the edge is present in the complex
+ */
+ Vertex_handle second_vertex(Edge_handle edge_handle) const {
+ return static_cast<Vertex_handle> (target(edge_handle, skeleton));
+ }
+
+ /**
+ * @brief returns the simplex made with the two vertices of the edge
+ * @details it assumes that the edge is present in the complex
+
+ */
+ Simplex get_vertices(Edge_handle edge_handle) const {
+ auto edge((*this)[edge_handle]);
+ return Simplex((*this)[edge.first()], (*this)[edge.second()]);
+ }
+
+ /**
+ * @brief Adds an edge between vertices a and b.
+ * @details For instance, the complex contains edge 01 and 12, then calling
+ * add_edge with vertex 0 and 2 will create a complex containing
+ * the edges 01, 12, 20 but not the triangle 012 (and hence this complex
+ * will contains a blocker 012).
+ */
+ Edge_handle add_edge(Vertex_handle a, Vertex_handle b) {
+ // if the edge is already there we musnt go further
+ // as we may add blockers that should not be here
+ if (contains_edge(a, b))
+ return *((*this)[std::make_pair(a, b)]);
+ auto res = add_edge_without_blockers(a, b);
+ add_blockers_after_simplex_insertion(Simplex(a, b));
+ return res;
+ }
+
+ /**
+ * @brief Adds all edges of s in the complex.
+ */
+ void add_edge(const Simplex& s) {
+ for (auto i = s.begin(); i != s.end(); ++i)
+ for (auto j = i; ++j != s.end(); /**/)
+ add_edge(*i, *j);
+ }
+
+ /**
+ * @brief Adds an edge between vertices a and b without blockers.
+ * @details For instance, the complex contains edge 01 and 12, then calling
+ * add_edge with vertex 0 and 2 will create a complex containing
+ * the triangle 012.
+ */
+ Edge_handle add_edge_without_blockers(Vertex_handle a, Vertex_handle b) {
+ assert(contains_vertex(a) && contains_vertex(b));
+ assert(a != b);
+
+ auto edge_handle((*this)[std::make_pair(a, b)]);
+ if (!edge_handle) {
+ edge_handle = boost::add_edge(a.vertex, b.vertex, skeleton).first;
+ (*this)[*edge_handle].setId(get_id(a), get_id(b));
+ degree_[a.vertex]++;
+ degree_[b.vertex]++;
+ if (visitor)
+ visitor->on_add_edge_without_blockers(a, b);
+ }
+ return *edge_handle;
+ }
+
+ /**
+ * @brief Adds all edges of s in the complex without adding blockers.
+ */
+ void add_edge_without_blockers(Simplex s) {
+ for (auto i = s.begin(); i != s.end(); ++i) {
+ for (auto j = i; ++j != s.end(); /**/)
+ add_edge_without_blockers(*i, *j);
+ }
+ }
+
+ /**
+ * @brief Removes an edge from the simplicial complex and all its cofaces.
+ * @details returns the former Edge_handle representing the edge
+ */
+ virtual Edge_handle remove_edge(Vertex_handle a, Vertex_handle b) {
+ bool found;
+ Edge_handle edge;
+ tie(edge, found) = boost::edge(a.vertex, b.vertex, skeleton);
+ if (found) {
+ if (visitor)
+ visitor->on_remove_edge(a, b);
+ boost::remove_edge(a.vertex, b.vertex, skeleton);
+ degree_[a.vertex]--;
+ degree_[b.vertex]--;
+ }
+ return edge;
+ }
+
+ /**
+ * @brief Removes edge and its cofaces from the simplicial complex.
+ */
+ void remove_edge(Edge_handle edge) {
+ assert(contains_vertex(first_vertex(edge)));
+ assert(contains_vertex(second_vertex(edge)));
+ remove_edge(first_vertex(edge), second_vertex(edge));
+ }
+
+ /**
+ * @brief The complex is reduced to its set of vertices.
+ * All the edges and blockers are removed.
+ */
+ void keep_only_vertices() {
+ remove_blockers();
+
+ for (auto u : vertex_range()) {
+ while (this->degree(u) > 0) {
+ Vertex_handle v(*(adjacent_vertices(u.vertex, this->skeleton).first));
+ this->remove_edge(u, v);
+ }
+ }
+ }
+
+ /**
+ * @return true iff the simplicial complex contains an edge between
+ * vertices a and b
+ */
+ bool contains_edge(Vertex_handle a, Vertex_handle b) const {
+ // if (a.vertex<0 || b.vertex <0) return false;
+ return boost::edge(a.vertex, b.vertex, skeleton).second;
+ }
+
+ /**
+ * @return true iff the simplicial complex contains all vertices
+ * and all edges of simplex sigma
+ */
+ bool contains_edges(const Simplex & sigma) const {
+ for (auto i = sigma.begin(); i != sigma.end(); ++i) {
+ if (!contains_vertex(*i))
+ return false;
+ for (auto j = i; ++j != sigma.end();) {
+ if (!contains_edge(*i, *j))
+ return false;
+ }
+ }
+ return true;
+ }
+ //@}
+
+ /////////////////////////////////////////////////////////////////////////////
+ /** @name Blockers operations
+ */
+ //@{
+
+ /**
+ * @brief Adds the simplex to the set of blockers and
+ * returns a Blocker_handle toward it if was not present before and 0 otherwise.
+ */
+ Blocker_handle add_blocker(const Simplex& blocker) {
+ assert(blocker.dimension() > 1);
+ if (contains_blocker(blocker)) {
+ return 0;
+ } else {
+ if (visitor)
+ visitor->on_add_blocker(blocker);
+ Blocker_handle blocker_pt = new Simplex(blocker);
+ num_blockers_++;
+ auto vertex = blocker_pt->begin();
+ while (vertex != blocker_pt->end()) {
+ blocker_map_.insert(BlockerPair(*vertex, blocker_pt));
+ ++vertex;
+ }
+ return blocker_pt;
+ }
+ }
+
+ protected:
+ /**
+ * @brief Adds the simplex to the set of blockers
+ */
+ void add_blocker(Blocker_handle blocker) {
+ if (contains_blocker(*blocker)) {
+ // std::cerr << "ATTEMPT TO ADD A BLOCKER ALREADY THERE ---> BLOCKER IGNORED" << endl;
+ return;
+ } else {
+ if (visitor)
+ visitor->on_add_blocker(*blocker);
+ num_blockers_++;
+ auto vertex = blocker->begin();
+ while (vertex != blocker->end()) {
+ blocker_map_.insert(BlockerPair(*vertex, blocker));
+ ++vertex;
+ }
+ }
+ }
+
+ protected:
+ /**
+ * Removes sigma from the blocker map of vertex v
+ */
+ void remove_blocker(const Blocker_handle sigma, Vertex_handle v) {
+ Complex_blocker_around_vertex_iterator blocker;
+ for (blocker = blocker_range(v).begin(); blocker != blocker_range(v).end();
+ ++blocker) {
+ if (*blocker == sigma)
+ break;
+ }
+ if (*blocker != sigma) {
+ std::cerr
+ << "bug ((*blocker).second == sigma) ie try to remove a blocker not present\n";
+ assert(false);
+ } else {
+ blocker_map_.erase(blocker.current_position());
+ }
+ }
+
+ public:
+ /**
+ * @brief Removes the simplex from the set of blockers.
+ * @remark sigma has to belongs to the set of blockers
+ */
+ void remove_blocker(const Blocker_handle sigma) {
+ for (auto vertex : *sigma)
+ remove_blocker(sigma, vertex);
+ num_blockers_--;
+ }
+
+ /**
+ * @brief Remove all blockers, in other words, it expand the simplicial
+ * complex to the smallest flag complex that contains it.
+ */
+ void remove_blockers() {
+ // Desallocate the blockers
+ while (!blocker_map_.empty()) {
+ delete_blocker(blocker_map_.begin()->second);
+ }
+ num_blockers_ = 0;
+ blocker_map_.clear();
+ }
+
+ protected:
+ /**
+ * Removes the simplex sigma from the set of blockers.
+ * sigma has to belongs to the set of blockers
+ *
+ * @remark contrarily to delete_blockers does not call the destructor
+ */
+ void remove_blocker(const Simplex& sigma) {
+ assert(contains_blocker(sigma));
+ for (auto vertex : sigma)
+ remove_blocker(sigma, vertex);
+ num_blockers_--;
+ }
+
+ public:
+ /**
+ * Removes the simplex s from the set of blockers
+ * and desallocate s.
+ */
+ void delete_blocker(Blocker_handle sigma) {
+ if (visitor)
+ visitor->on_delete_blocker(sigma);
+ remove_blocker(sigma);
+ delete sigma;
+ }
+
+ /**
+ * @return true iff s is a blocker of the simplicial complex
+ */
+ bool contains_blocker(const Blocker_handle s) const {
+ if (s->dimension() < 2)
+ return false;
+
+ Vertex_handle a = s->first_vertex();
+
+ for (const auto blocker : const_blocker_range(a)) {
+ if (s == *blocker)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return true iff s is a blocker of the simplicial complex
+ */
+ bool contains_blocker(const Simplex & s) const {
+ if (s.dimension() < 2)
+ return false;
+
+ Vertex_handle a = s.first_vertex();
+
+ for (auto blocker : const_blocker_range(a)) {
+ if (s == *blocker)
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ /**
+ * @return true iff a blocker of the simplicial complex
+ * is a face of sigma.
+ */
+ bool blocks(const Simplex & sigma) const {
+ for (auto s : sigma)
+ for (auto blocker : const_blocker_range(s))
+ if (sigma.contains(*blocker))
+ return true;
+ return false;
+ }
+
+ //@}
+
+ protected:
+ /**
+ * @details Adds to simplex the neighbours of v e.g. \f$ n \leftarrow n \cup N(v) \f$.
+ * If keep_only_superior is true then only vertices that are greater than v are added.
+ */
+ virtual void add_neighbours(Vertex_handle v, Simplex & n,
+ bool keep_only_superior = false) const {
+ boost_adjacency_iterator ai, ai_end;
+ for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end;
+ ++ai) {
+ Vertex_handle value(*ai);
+ if (keep_only_superior) {
+ if (value > v.vertex) {
+ n.add_vertex(value);
+ }
+ } else {
+ n.add_vertex(value);
+ }
+ }
+ }
+
+ /**
+ * @details Add to simplex res all vertices which are
+ * neighbours of alpha: ie \f$ res \leftarrow res \cup N(alpha) \f$.
+ *
+ * If 'keep_only_superior' is true then only vertices that are greater than alpha are added.
+ * todo revoir
+ *
+ */
+ virtual void add_neighbours(const Simplex &alpha, Simplex & res,
+ bool keep_only_superior = false) const {
+ res.clear();
+ auto alpha_vertex = alpha.begin();
+ add_neighbours(*alpha_vertex, res, keep_only_superior);
+ for (alpha_vertex = (alpha.begin())++; alpha_vertex != alpha.end();
+ ++alpha_vertex)
+ keep_neighbours(*alpha_vertex, res, keep_only_superior);
+ }
+
+ /**
+ * @details Remove from simplex n all vertices which are
+ * not neighbours of v e.g. \f$ res \leftarrow res \cap N(v) \f$.
+ * If 'keep_only_superior' is true then only vertices that are greater than v are keeped.
+ */
+ virtual void keep_neighbours(Vertex_handle v, Simplex& res,
+ bool keep_only_superior = false) const {
+ Simplex nv;
+ add_neighbours(v, nv, keep_only_superior);
+ res.intersection(nv);
+ }
+
+ /**
+ * @details Remove from simplex all vertices which are
+ * neighbours of v eg \f$ res \leftarrow res \setminus N(v) \f$.
+ * If 'keep_only_superior' is true then only vertices that are greater than v are added.
+ */
+ virtual void remove_neighbours(Vertex_handle v, Simplex & res,
+ bool keep_only_superior = false) const {
+ Simplex nv;
+ add_neighbours(v, nv, keep_only_superior);
+ res.difference(nv);
+ }
+
+ public:
+ typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex> Link_complex;
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Link_complex link(Vertex_handle v) const {
+ return Link_complex(*this, Simplex(v));
+ }
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Link_complex link(Edge_handle edge) const {
+ return Link_complex(*this, edge);
+ }
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Link_complex link(const Simplex& simplex) const {
+ return Link_complex(*this, simplex);
+ }
+
+ /**
+ * @brief Compute the local vertices of 's' in the current complex
+ * If one of them is not present in the complex then the return value is uninitialized.
+ *
+ *
+ */
+ // xxx rename get_address et place un using dans sub_complex
+
+ boost::optional<Simplex> get_simplex_address(
+ const Root_simplex_handle& s) const {
+ boost::optional<Simplex> res;
+
+ Simplex s_address;
+ // Root_simplex_const_iterator i;
+ for (auto i = s.begin(); i != s.end(); ++i) {
+ boost::optional<Vertex_handle> address = get_address(*i);
+ if (!address)
+ return res;
+ else
+ s_address.add_vertex(*address);
+ }
+ res = s_address;
+ return res;
+ }
+
+ /**
+ * @brief returns a simplex with vertices which are the id of vertices of the
+ * argument.
+ */
+ Root_simplex_handle get_id(const Simplex& local_simplex) const {
+ Root_simplex_handle global_simplex;
+ for (auto x = local_simplex.begin(); x != local_simplex.end(); ++x) {
+ global_simplex.add_vertex(get_id(*x));
+ }
+ return global_simplex;
+ }
+
+ /**
+ * @brief returns true iff the simplex s belongs to the simplicial
+ * complex.
+ */
+ virtual bool contains(const Simplex & s) const {
+ if (s.dimension() == -1) {
+ return false;
+ } else if (s.dimension() == 0) {
+ return contains_vertex(s.first_vertex());
+ } else {
+ return (contains_edges(s) && !blocks(s));
+ }
+ }
+
+ /*
+ * @brief returnrs true iff the complex is empty.
+ */
+ bool empty() const {
+ return num_vertices() == 0;
+ }
+
+ /*
+ * @brief returns the number of vertices in the complex.
+ */
+ int num_vertices() const {
+ // remark boost::num_vertices(skeleton) counts deactivated vertices
+ return num_vertices_;
+ }
+
+ /*
+ * @brief returns the number of edges in the complex.
+ * @details currently in O(n)
+ */
+ // todo cache the value
+
+ int num_edges() const {
+ return boost::num_edges(skeleton);
+ }
+
+ int num_triangles() const {
+ auto triangles = triangle_range();
+ return std::distance(triangles.begin(), triangles.end());
+ }
+
+ /*
+ * @brief returns the number of simplices of a given dimension in the complex.
+ */
+ size_t num_simplices() const {
+ auto simplices = complex_simplex_range();
+ return std::distance(simplices.begin(), simplices.end());
+ }
+
+ /*
+ * @brief returns the number of simplices of a given dimension in the complex.
+ */
+ size_t num_simplices(int dimension) const {
+ // TODO(DS): iterator on k-simplices
+ size_t res = 0;
+ for (const auto& s : complex_simplex_range())
+ if (s.dimension() == dimension)
+ ++res;
+ return res;
+ }
+
+ /*
+ * @brief returns the number of blockers in the complex.
+ */
+ size_t num_blockers() const {
+ return num_blockers_;
+ }
+
+ /*
+ * @brief returns true iff the graph of the 1-skeleton of the complex is complete.
+ */
+ bool complete() const {
+ return (num_vertices() * (num_vertices() - 1)) / 2 == num_edges();
+ }
+
+ /**
+ * @brief returns the number of connected components in the graph of the 1-skeleton.
+ */
+ int num_connected_components() const {
+ int num_vert_collapsed = skeleton.vertex_set().size() - num_vertices();
+ std::vector<int> component(skeleton.vertex_set().size());
+ return boost::connected_components(this->skeleton, &component[0])
+ - num_vert_collapsed;
+ }
+
+ /**
+ * @brief %Test if the complex is a cone.
+ * @details Runs in O(n) where n is the number of vertices.
+ */
+ bool is_cone() const {
+ if (num_vertices() == 0)
+ return false;
+ if (num_vertices() == 1)
+ return true;
+ for (auto vi : vertex_range()) {
+ // xxx todo faire une methode bool is_in_blocker(Vertex_handle)
+ if (blocker_map_.find(vi) == blocker_map_.end()) {
+ // no blocker passes through the vertex, we just need to
+ // check if the current vertex is linked to all others vertices of the complex
+ if (degree_[vi.vertex] == num_vertices() - 1)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ //@}
+ /** @name Simplification operations
+ */
+ //@{
+
+ /**
+ * Returns true iff the blocker 'sigma' is popable.
+ * To define popable, let us call 'L' the complex that
+ * consists in the current complex without the blocker 'sigma'.
+ * A blocker 'sigma' is then "popable" if the link of 'sigma'
+ * in L is reducible.
+ *
+ */
+ bool is_popable_blocker(Blocker_handle sigma) const;
+
+ /**
+ * Removes all the popable blockers of the complex and delete them.
+ * @returns the number of popable blockers deleted
+ */
+ void remove_popable_blockers();
+
+ /**
+ * Removes all the popable blockers of the complex passing through v and delete them.
+ */
+ void remove_popable_blockers(Vertex_handle v);
+
+ /**
+ * @brief Removes all the popable blockers of the complex passing through v and delete them.
+ * Also remove popable blockers in the neighborhood if they became popable.
+ *
+ */
+ void remove_all_popable_blockers(Vertex_handle v);
+
+ /**
+ * Remove the star of the vertex 'v'
+ */
+ void remove_star(Vertex_handle v);
+
+ private:
+ /**
+ * after removing the star of a simplex, blockers sigma that contains this simplex must be removed.
+ * Furthermore, all simplices tau of the form sigma \setminus simplex_to_be_removed must be added
+ * whenever the dimension of tau is at least 2.
+ */
+ void update_blockers_after_remove_star_of_vertex_or_edge(const Simplex& simplex_to_be_removed);
+
+ public:
+ /**
+ * Remove the star of the edge connecting vertices a and b.
+ * @returns the number of blocker that have been removed
+ */
+ void remove_star(Vertex_handle a, Vertex_handle b);
+
+ /**
+ * Remove the star of the edge 'e'.
+ */
+ void remove_star(Edge_handle e);
+
+ /**
+ * Remove the star of the simplex 'sigma' which needs to belong to the complex
+ */
+ void remove_star(const Simplex& sigma);
+
+ /**
+ * @brief add a simplex and all its faces.
+ * @details the simplex must have dimension greater than one (otherwise use add_vertex or add_edge_without_blockers).
+ */
+ void add_simplex(const Simplex& sigma);
+
+ private:
+ void add_blockers_after_simplex_insertion(Simplex s);
+
+ /**
+ * remove all blockers that contains sigma
+ */
+ void remove_blocker_containing_simplex(const Simplex& sigma);
+
+ /**
+ * remove all blockers that contains sigma
+ */
+ void remove_blocker_include_in_simplex(const Simplex& sigma);
+
+ public:
+ enum simplifiable_status {
+ NOT_HOMOTOPY_EQ, MAYBE_HOMOTOPY_EQ, HOMOTOPY_EQ
+ };
+
+ simplifiable_status is_remove_star_homotopy_preserving(const Simplex& simplex) {
+ // todo write a virtual method 'link' in Skeleton_blocker_complex which will be overloaded by the current one of
+ // Skeleton_blocker_geometric_complex
+ // then call it there to build the link and return the value of link.is_contractible()
+ return MAYBE_HOMOTOPY_EQ;
+ }
+
+ enum contractible_status {
+ NOT_CONTRACTIBLE, MAYBE_CONTRACTIBLE, CONTRACTIBLE
+ };
+
+ /**
+ * @brief %Test if the complex is reducible using a strategy defined in the class
+ * (by default it tests if the complex is a cone)
+ * @details Note that NO could be returned if some invariant ensures that the complex
+ * is not a point (for instance if the euler characteristic is different from 1).
+ * This function will surely have to return MAYBE in some case because the
+ * associated problem is undecidable but it in practice, it can often
+ * be solved with the help of geometry.
+ */
+ virtual contractible_status is_contractible() const {
+ if (this->is_cone()) {
+ return CONTRACTIBLE;
+ } else {
+ return MAYBE_CONTRACTIBLE;
+ }
+ }
+ //@}
+
+ /** @name Edge contraction operations
+ */
+ //@{
+
+ /**
+ * @return If ignore_popable_blockers is true
+ * then the result is true iff the link condition at edge ab is satisfied
+ * or equivalently iff no blocker contains ab.
+ * If ignore_popable_blockers is false then the
+ * result is true iff all blocker containing ab are popable.
+ */
+ bool link_condition(Vertex_handle a, Vertex_handle b, bool ignore_popable_blockers = false) const {
+ for (auto blocker : this->const_blocker_range(a))
+ if (blocker->contains(b)) {
+ // false if ignore_popable_blockers is false
+ // otherwise the blocker has to be popable
+ return ignore_popable_blockers && is_popable_blocker(blocker);
+ }
+ return true;
+ }
+
+ /**
+ * @return If ignore_popable_blockers is true
+ * then the result is true iff the link condition at edge ab is satisfied
+ * or equivalently iff no blocker contains ab.
+ * If ignore_popable_blockers is false then the
+ * result is true iff all blocker containing ab are popable.
+ */
+ bool link_condition(Edge_handle e, bool ignore_popable_blockers = false) const {
+ const Graph_edge& edge = (*this)[e];
+ assert(this->get_address(edge.first()));
+ assert(this->get_address(edge.second()));
+ Vertex_handle a(*this->get_address(edge.first()));
+ Vertex_handle b(*this->get_address(edge.second()));
+ return link_condition(a, b, ignore_popable_blockers);
+ }
+
+ protected:
+ /**
+ * Compute simplices beta such that a.beta is an order 0 blocker
+ * that may be used to construct a new blocker after contracting ab.
+ * It requires that the link condition is satisfied.
+ */
+ void tip_blockers(Vertex_handle a, Vertex_handle b, std::vector<Simplex> & buffer) const;
+
+ private:
+ /**
+ * @brief "Replace" the edge 'bx' by the edge 'ax'.
+ * Assume that the edge 'bx' was present whereas 'ax' was not.
+ * Precisely, it does not replace edges, but remove 'bx' and then add 'ax'.
+ * The visitor 'on_swaped_edge' is called just after edge 'ax' had been added
+ * and just before edge 'bx' had been removed. That way, it can
+ * eventually access to information of 'ax'.
+ */
+ void swap_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x);
+
+ private:
+ /**
+ * @brief removes all blockers passing through the edge 'ab'
+ */
+ void delete_blockers_around_vertex(Vertex_handle v);
+
+ /**
+ * @brief removes all blockers passing through the edge 'ab'
+ */
+ void delete_blockers_around_edge(Vertex_handle a, Vertex_handle b);
+
+ public:
+ /**
+ * Contracts the edge.
+ * @remark If the link condition Link(ab) = Link(a) inter Link(b) is not satisfied,
+ * it removes first all blockers passing through 'ab'
+ */
+ void contract_edge(Edge_handle edge) {
+ contract_edge(this->first_vertex(edge), this->second_vertex(edge));
+ }
+
+ /**
+ * Contracts the edge connecting vertices a and b.
+ * @remark If the link condition Link(ab) = Link(a) inter Link(b) is not satisfied,
+ * it removes first all blockers passing through 'ab'
+ */
+ void contract_edge(Vertex_handle a, Vertex_handle b);
+
+ private:
+ void get_blockers_to_be_added_after_contraction(Vertex_handle a, Vertex_handle b,
+ std::set<Simplex>& blockers_to_add);
+ /**
+ * delete all blockers that passes through a or b
+ */
+ void delete_blockers_around_vertices(Vertex_handle a, Vertex_handle b);
+ void update_edges_after_contraction(Vertex_handle a, Vertex_handle b);
+ void notify_changed_edges(Vertex_handle a);
+ //@}
+
+ public:
+ /////////////////////////////////////////////////////////////////////////////
+ /** @name Vertex iterators
+ */
+ //@{
+ typedef Vertex_iterator<Skeleton_blocker_complex> Complex_vertex_iterator;
+
+ //
+ // Range over the vertices of the simplicial complex.
+ // Methods .begin() and .end() return a Complex_vertex_iterator.
+ //
+ typedef boost::iterator_range<Complex_vertex_iterator> Complex_vertex_range;
+
+ /**
+ * @brief Returns a Complex_vertex_range over all vertices of the complex
+ */
+ Complex_vertex_range vertex_range() const {
+ auto begin = Complex_vertex_iterator(this);
+ auto end = Complex_vertex_iterator(this, 0);
+ return Complex_vertex_range(begin, end);
+ }
+
+ typedef Neighbors_vertices_iterator<Skeleton_blocker_complex> Complex_neighbors_vertices_iterator;
+
+
+ typedef boost::iterator_range<Complex_neighbors_vertices_iterator> Complex_neighbors_vertices_range;
+
+ /**
+ * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes trough v
+ */
+ Complex_neighbors_vertices_range vertex_range(Vertex_handle v) const {
+ auto begin = Complex_neighbors_vertices_iterator(this, v);
+ auto end = Complex_neighbors_vertices_iterator(this, v, 0);
+ return Complex_neighbors_vertices_range(begin, end);
+ }
+
+ //@}
+
+ /** @name Edge iterators
+ */
+ //@{
+
+ typedef Edge_iterator<Skeleton_blocker_complex> Complex_edge_iterator;
+
+
+ typedef boost::iterator_range<Complex_edge_iterator> Complex_edge_range;
+
+ /**
+ * @brief Returns a Complex_edge_range over all edges of the simplicial complex
+ */
+ Complex_edge_range edge_range() const {
+ auto begin = Complex_edge_iterator(this);
+ auto end = Complex_edge_iterator(this, 0);
+ return Complex_edge_range(begin, end);
+ }
+
+
+ typedef Edge_around_vertex_iterator<Skeleton_blocker_complex> Complex_edge_around_vertex_iterator;
+
+
+ typedef boost::iterator_range <Complex_edge_around_vertex_iterator> Complex_edge_around_vertex_range;
+
+ /**
+ * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes
+ * through 'v'
+ */
+ Complex_edge_around_vertex_range edge_range(Vertex_handle v) const {
+ auto begin = Complex_edge_around_vertex_iterator(this, v);
+ auto end = Complex_edge_around_vertex_iterator(this, v, 0);
+ return Complex_edge_around_vertex_range(begin, end);
+ }
+
+ //@}
+
+ /** @name Triangles iterators
+ */
+ //@{
+ private:
+ typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerDS> > Link;
+ typedef Skeleton_blocker_link_superior<Skeleton_blocker_complex<SkeletonBlockerDS> > Superior_link;
+
+ public:
+ typedef Triangle_around_vertex_iterator<Skeleton_blocker_complex, Superior_link>
+ Superior_triangle_around_vertex_iterator;
+ typedef boost::iterator_range < Triangle_around_vertex_iterator<Skeleton_blocker_complex, Link> >
+ Complex_triangle_around_vertex_range;
+
+ /**
+ * @brief Range over triangles around a vertex of the simplicial complex.
+ * Methods .begin() and .end() return a Triangle_around_vertex_iterator.
+ *
+ */
+ Complex_triangle_around_vertex_range triangle_range(Vertex_handle v) const {
+ auto begin = Triangle_around_vertex_iterator<Skeleton_blocker_complex, Link>(this, v);
+ auto end = Triangle_around_vertex_iterator<Skeleton_blocker_complex, Link>(this, v, 0);
+ return Complex_triangle_around_vertex_range(begin, end);
+ }
+
+ typedef boost::iterator_range<Triangle_iterator<Skeleton_blocker_complex> > Complex_triangle_range;
+ typedef Triangle_iterator<Skeleton_blocker_complex> Complex_triangle_iterator;
+
+ /**
+ * @brief Range over triangles of the simplicial complex.
+ * Methods .begin() and .end() return a Triangle_around_vertex_iterator.
+ *
+ */
+ Complex_triangle_range triangle_range() const {
+ auto end = Triangle_iterator<Skeleton_blocker_complex>(this, 0);
+ if (empty()) {
+ return Complex_triangle_range(end, end);
+ } else {
+ auto begin = Triangle_iterator<Skeleton_blocker_complex>(this);
+ return Complex_triangle_range(begin, end);
+ }
+ }
+
+ //@}
+
+ /** @name Simplices iterators
+ */
+ //@{
+ typedef Simplex_around_vertex_iterator<Skeleton_blocker_complex, Link> Complex_simplex_around_vertex_iterator;
+
+ /**
+ * @brief Range over the simplices of the simplicial complex around a vertex.
+ * Methods .begin() and .end() return a Complex_simplex_around_vertex_iterator.
+ */
+ typedef boost::iterator_range < Complex_simplex_around_vertex_iterator > Complex_simplex_around_vertex_range;
+
+ /**
+ * @brief Returns a Complex_simplex_around_vertex_range over all the simplices around a vertex of the complex
+ */
+ Complex_simplex_around_vertex_range star_simplex_range(Vertex_handle v) const {
+ assert(contains_vertex(v));
+ return Complex_simplex_around_vertex_range(
+ Complex_simplex_around_vertex_iterator(this, v),
+ Complex_simplex_around_vertex_iterator(this, v, true));
+ }
+ typedef Simplex_coboundary_iterator<Skeleton_blocker_complex, Link> Complex_simplex_coboundary_iterator;
+
+ /**
+ * @brief Range over the simplices of the coboundary of a simplex.
+ * Methods .begin() and .end() return a Complex_simplex_coboundary_iterator.
+ */
+ typedef boost::iterator_range < Complex_simplex_coboundary_iterator > Complex_coboundary_range;
+
+ /**
+ * @brief Returns a Complex_simplex_coboundary_iterator over the simplices of the coboundary of a simplex.
+ */
+ Complex_coboundary_range coboundary_range(const Simplex& s) const {
+ assert(contains(s));
+ return Complex_coboundary_range(Complex_simplex_coboundary_iterator(this, s),
+ Complex_simplex_coboundary_iterator(this, s, true));
+ }
+
+ // typedef Simplex_iterator<Skeleton_blocker_complex,Superior_link> Complex_simplex_iterator;
+ typedef Simplex_iterator<Skeleton_blocker_complex> Complex_simplex_iterator;
+
+ typedef boost::iterator_range < Complex_simplex_iterator > Complex_simplex_range;
+
+ /**
+ * @brief Returns a Complex_simplex_range over all the simplices of the complex
+ */
+ Complex_simplex_range complex_simplex_range() const {
+ Complex_simplex_iterator end(this, true);
+ if (empty()) {
+ return Complex_simplex_range(end, end);
+ } else {
+ Complex_simplex_iterator begin(this);
+ return Complex_simplex_range(begin, end);
+ }
+ }
+
+ //@}
+
+ /** @name Blockers iterators
+ */
+ //@{
+ private:
+ /**
+ * @brief Iterator over the blockers adjacent to a vertex
+ */
+ typedef Blocker_iterator_around_vertex_internal<
+ typename std::multimap<Vertex_handle, Simplex *>::iterator,
+ Blocker_handle>
+ Complex_blocker_around_vertex_iterator;
+
+ /**
+ * @brief Iterator over (constant) blockers adjacent to a vertex
+ */
+ typedef Blocker_iterator_around_vertex_internal<
+ typename std::multimap<Vertex_handle, Simplex *>::const_iterator,
+ const Blocker_handle>
+ Const_complex_blocker_around_vertex_iterator;
+
+ typedef boost::iterator_range <Complex_blocker_around_vertex_iterator> Complex_blocker_around_vertex_range;
+ typedef boost::iterator_range <Const_complex_blocker_around_vertex_iterator>
+ Const_complex_blocker_around_vertex_range;
+
+ public:
+ /**
+ * @brief Returns a range of the blockers of the complex passing through a vertex
+ */
+ Complex_blocker_around_vertex_range blocker_range(Vertex_handle v) {
+ auto begin = Complex_blocker_around_vertex_iterator(blocker_map_.lower_bound(v));
+ auto end = Complex_blocker_around_vertex_iterator(blocker_map_.upper_bound(v));
+ return Complex_blocker_around_vertex_range(begin, end);
+ }
+
+ /**
+ * @brief Returns a range of the blockers of the complex passing through a vertex
+ */
+ Const_complex_blocker_around_vertex_range const_blocker_range(Vertex_handle v) const {
+ auto begin = Const_complex_blocker_around_vertex_iterator(blocker_map_.lower_bound(v));
+ auto end = Const_complex_blocker_around_vertex_iterator(blocker_map_.upper_bound(v));
+ return Const_complex_blocker_around_vertex_range(begin, end);
+ }
+
+ private:
+ /**
+ * @brief Iterator over the blockers.
+ */
+ typedef Blocker_iterator_internal<
+ typename std::multimap<Vertex_handle, Simplex *>::iterator,
+ Blocker_handle>
+ Complex_blocker_iterator;
+
+ /**
+ * @brief Iterator over the (constant) blockers.
+ */
+ typedef Blocker_iterator_internal<
+ typename std::multimap<Vertex_handle, Simplex *>::const_iterator,
+ const Blocker_handle>
+ Const_complex_blocker_iterator;
+
+ typedef boost::iterator_range <Complex_blocker_iterator> Complex_blocker_range;
+ typedef boost::iterator_range <Const_complex_blocker_iterator> Const_complex_blocker_range;
+
+ public:
+ /**
+ * @brief Returns a range of the blockers of the complex
+ */
+ Complex_blocker_range blocker_range() {
+ auto begin = Complex_blocker_iterator(blocker_map_.begin(), blocker_map_.end());
+ auto end = Complex_blocker_iterator(blocker_map_.end(), blocker_map_.end());
+ return Complex_blocker_range(begin, end);
+ }
+
+ /**
+ * @brief Returns a range of the blockers of the complex
+ */
+ Const_complex_blocker_range const_blocker_range() const {
+ auto begin = Const_complex_blocker_iterator(blocker_map_.begin(), blocker_map_.end());
+ auto end = Const_complex_blocker_iterator(blocker_map_.end(), blocker_map_.end());
+ return Const_complex_blocker_range(begin, end);
+ }
+
+ //@}
+
+ /////////////////////////////////////////////////////////////////////////////
+ /** @name Print and IO methods
+ */
+ //@{
+ public:
+ std::string to_string() const {
+ std::ostringstream stream;
+ stream << num_vertices() << " vertices:\n" << vertices_to_string() << std::endl;
+ stream << num_edges() << " edges:\n" << edges_to_string() << std::endl;
+ stream << num_blockers() << " blockers:\n" << blockers_to_string() << std::endl;
+ return stream.str();
+ }
+
+ std::string vertices_to_string() const {
+ std::ostringstream stream;
+ for (auto vertex : vertex_range()) {
+ stream << "{" << (*this)[vertex].get_id() << "} ";
+ }
+ stream << std::endl;
+ return stream.str();
+ }
+
+ std::string edges_to_string() const {
+ std::ostringstream stream;
+ for (auto edge : edge_range())
+ stream << "{" << (*this)[edge].first() << "," << (*this)[edge].second() << "} ";
+ stream << std::endl;
+ return stream.str();
+ }
+
+ std::string blockers_to_string() const {
+ std::ostringstream stream;
+
+ for (auto b : const_blocker_range())
+ stream << *b << std::endl;
+ return stream.str();
+ }
+ //@}
+};
+
+/**
+ * build a simplicial complex from a collection
+ * of top faces.
+ * return the total number of simplices
+ */
+template<typename Complex, typename SimplexHandleIterator>
+Complex make_complex_from_top_faces(SimplexHandleIterator simplices_begin, SimplexHandleIterator simplices_end,
+ bool is_flag_complex = false) {
+ // TODO(DS): use add_simplex instead! should be more efficient and more elegant :)
+ typedef typename Complex::Simplex Simplex;
+ std::vector<Simplex> simplices;
+ for (auto top_face = simplices_begin; top_face != simplices_end; ++top_face) {
+ auto subfaces_topface = subfaces(*top_face);
+ simplices.insert(simplices.end(), subfaces_topface.begin(), subfaces_topface.end());
+ }
+ return Complex(simplices.begin(), simplices.end(), is_flag_complex);
+}
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#include "Skeleton_blocker_simplifiable_complex.h"
+
+#endif // SKELETON_BLOCKER_COMPLEX_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h
new file mode 100644
index 00000000..b8f75e0f
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_geometric_complex.h
@@ -0,0 +1,215 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_
+#define SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_
+
+#include <gudhi/Skeleton_blocker_complex.h>
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h>
+#include <gudhi/Debug_utils.h>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * @brief Class that represents a geometric complex that can be simplified.
+ * The class allows access to points of vertices.
+ * @ingroup skbl
+ */
+template<typename SkeletonBlockerGeometricDS>
+class Skeleton_blocker_geometric_complex :
+public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> {
+ public:
+ typedef typename SkeletonBlockerGeometricDS::GT GT;
+
+ typedef Skeleton_blocker_complex<SkeletonBlockerGeometricDS> SimplifiableSkeletonblocker;
+
+ typedef typename SimplifiableSkeletonblocker::Vertex_handle Vertex_handle;
+ typedef typename SimplifiableSkeletonblocker::Root_vertex_handle Root_vertex_handle;
+ typedef typename SimplifiableSkeletonblocker::Edge_handle Edge_handle;
+ typedef typename SimplifiableSkeletonblocker::Simplex Simplex;
+
+ typedef typename SimplifiableSkeletonblocker::Graph_vertex Graph_vertex;
+
+ typedef typename SkeletonBlockerGeometricDS::Point Point;
+
+ Skeleton_blocker_geometric_complex() { }
+
+ /**
+ * constructor given a list of points
+ */
+ template<typename PointIterator>
+ explicit Skeleton_blocker_geometric_complex(int num_vertices, PointIterator begin, PointIterator end) {
+ for (auto point = begin; point != end; ++point)
+ add_vertex(*point);
+ }
+
+ /**
+ * @brief Constructor with a list of simplices.
+ * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be
+ * computed or not).
+ */
+ template<typename SimpleHandleOutputIterator, typename PointIterator>
+ Skeleton_blocker_geometric_complex(
+ SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end,
+ PointIterator points_begin, PointIterator points_end,
+ bool is_flag_complex = false)
+ : Skeleton_blocker_complex<SkeletonBlockerGeometricDS>(simplex_begin, simplex_end, is_flag_complex) {
+ unsigned current = 0;
+ for (auto point = points_begin; point != points_end; ++point)
+ (*this)[Vertex_handle(current++)].point() = Point(point->begin(), point->end());
+ }
+
+ /**
+ * @brief Constructor with a list of simplices.
+ * Points of every vertex are the point constructed with default constructor.
+ * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be computed or not).
+ */
+ template<typename SimpleHandleOutputIterator>
+ Skeleton_blocker_geometric_complex(
+ SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end,
+ bool is_flag_complex = false)
+ : Skeleton_blocker_complex<SkeletonBlockerGeometricDS>(simplex_begin, simplex_end, is_flag_complex) { }
+
+ /**
+ * @brief Add a vertex to the complex with a default constructed associated point.
+ */
+ Vertex_handle add_vertex() {
+ return SimplifiableSkeletonblocker::add_vertex();
+ }
+
+ /**
+ * @brief Add a vertex to the complex with its associated point.
+ */
+ Vertex_handle add_vertex(const Point& point) {
+ Vertex_handle ad = SimplifiableSkeletonblocker::add_vertex();
+ (*this)[ad].point() = point;
+ return ad;
+ }
+
+ /**
+ * @brief Returns the Point associated to the vertex v.
+ */
+ const Point& point(Vertex_handle v) const {
+ assert(this->contains_vertex(v));
+ return (*this)[v].point();
+ }
+
+ /**
+ * @brief Returns the Point associated to the vertex v.
+ */
+ Point& point(Vertex_handle v) {
+ assert(this->contains_vertex(v));
+ return (*this)[v].point();
+ }
+
+ const Point& point(Root_vertex_handle global_v) const {
+ Vertex_handle local_v((*this)[global_v]);
+ assert(this->contains_vertex(local_v));
+ return (*this)[local_v].point();
+ }
+
+ Point& point(Root_vertex_handle global_v) {
+ Vertex_handle local_v((*this)[global_v]);
+ assert(this->contains_vertex(local_v));
+ return (*this)[local_v].point();
+ }
+
+ typedef Skeleton_blocker_link_complex<Skeleton_blocker_geometric_complex> Geometric_link;
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Geometric_link link(Vertex_handle v) const {
+ Geometric_link link(*this, Simplex(v));
+ // we now add the point info
+ add_points_to_link(link);
+ return link;
+ }
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Geometric_link link(const Simplex& simplex) const {
+ Geometric_link link(*this, simplex);
+ // we now add the point info
+ add_points_to_link(link);
+ return link;
+ }
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Geometric_link link(Edge_handle edge) const {
+ Geometric_link link(*this, edge);
+ // we now add the point info
+ add_points_to_link(link);
+ return link;
+ }
+
+ typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerGeometricDS>> Abstract_link;
+
+ /**
+ * Constructs the abstract link of v (without points coordinates).
+ */
+ Abstract_link abstract_link(Vertex_handle v) const {
+ return Abstract_link(*this, Simplex(v));
+ }
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Abstract_link abstract_link(const Simplex& simplex) const {
+ return Abstract_link(*this, simplex);
+ }
+
+ /**
+ * Constructs the link of 'simplex' with points coordinates.
+ */
+ Abstract_link abstract_link(Edge_handle edge) const {
+ return Abstract_link(*this, edge);
+ }
+
+ private:
+ void add_points_to_link(Geometric_link& link) const {
+ for (Vertex_handle v : link.vertex_range()) {
+ Root_vertex_handle v_root(link.get_id(v));
+ link.point(v) = (*this).point(v_root);
+ }
+ }
+};
+
+
+template<typename SkeletonBlockerGeometricComplex, typename SimpleHandleOutputIterator, typename PointIterator>
+SkeletonBlockerGeometricComplex make_complex_from_top_faces(
+ SimpleHandleOutputIterator simplex_begin,
+ SimpleHandleOutputIterator simplex_end,
+ PointIterator points_begin,
+ PointIterator points_end,
+ bool is_flag_complex = false) {
+ typedef SkeletonBlockerGeometricComplex SBGC;
+ SkeletonBlockerGeometricComplex complex;
+ unsigned current = 0;
+ complex =
+ make_complex_from_top_faces<SBGC>(simplex_begin, simplex_end, is_flag_complex);
+ for (auto point = points_begin; point != points_end; ++point)
+ // complex.point(Vertex_handle(current++)) = Point(point->begin(),point->end());
+ complex.point(typename SBGC::Vertex_handle(current++)) = typename SBGC::Point(*point);
+ return complex;
+}
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h
new file mode 100644
index 00000000..a2637da3
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_link_complex.h
@@ -0,0 +1,287 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_LINK_COMPLEX_H_
+#define SKELETON_BLOCKER_LINK_COMPLEX_H_
+
+#include <gudhi/Skeleton_blocker_complex.h>
+#include <gudhi/Debug_utils.h>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+template<class ComplexType> class Skeleton_blocker_sub_complex;
+
+/**
+ * \brief Class representing the link of a simplicial complex encoded by a skeleton/blockers pair.
+ * It inherits from Skeleton_blocker_sub_complex because such complex is a sub complex of a
+ * root complex.
+ * \ingroup skbl
+ */
+template<typename ComplexType>
+class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex<
+ComplexType> {
+ template<typename T> friend class Skeleton_blocker_link_superior;
+ typedef typename ComplexType::Edge_handle Edge_handle;
+
+ typedef typename ComplexType::boost_vertex_handle boost_vertex_handle;
+
+ private:
+ bool only_superior_vertices_;
+
+ public:
+ typedef typename ComplexType::Vertex_handle Vertex_handle;
+ typedef typename ComplexType::Root_vertex_handle Root_vertex_handle;
+
+ typedef typename ComplexType::Simplex Simplex;
+ typedef typename ComplexType::Root_simplex_handle Root_simplex_handle;
+
+ typedef typename ComplexType::Blocker_handle Blocker_handle;
+
+ typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_handle_iterator;
+
+ explicit Skeleton_blocker_link_complex(bool only_superior_vertices = false)
+ : only_superior_vertices_(only_superior_vertices) { }
+
+ /**
+ * If the parameter only_superior_vertices is true,
+ * only vertices greater than the one of alpha are added.
+ * Only vertices are computed if only_vertices is true.
+ */
+ Skeleton_blocker_link_complex(const ComplexType & parent_complex,
+ const Simplex& alpha_parent_adress,
+ bool only_superior_vertices = false,
+ bool only_vertices = false)
+ : only_superior_vertices_(only_superior_vertices) {
+ if (!alpha_parent_adress.empty())
+ build_link(parent_complex, alpha_parent_adress, only_vertices);
+ }
+
+ /**
+ * If the parameter only_superior_vertices is true,
+ * only vertices greater than the one of the vertex are added.
+ */
+ Skeleton_blocker_link_complex(const ComplexType & parent_complex,
+ Vertex_handle a_parent_adress,
+ bool only_superior_vertices = false)
+ : only_superior_vertices_(only_superior_vertices) {
+ Simplex alpha_simplex(a_parent_adress);
+ build_link(parent_complex, alpha_simplex);
+ }
+
+ /**
+ * If the parameter only_superior_vertices is true,
+ * only vertices greater than the one of the edge are added.
+ */
+ Skeleton_blocker_link_complex(const ComplexType & parent_complex,
+ Edge_handle edge, bool only_superior_vertices =
+ false)
+ : only_superior_vertices_(only_superior_vertices) {
+ Simplex alpha_simplex(parent_complex.first_vertex(edge),
+ parent_complex.second_vertex(edge));
+ build_link(parent_complex, alpha_simplex);
+ }
+
+ protected:
+ /**
+ * @brief compute vertices of the link.
+ * If the boolean only_superior_vertices is true, then only the vertices
+ * are greater than vertices of alpha_parent_adress are added.
+ */
+ void compute_link_vertices(const ComplexType & parent_complex,
+ const Simplex& alpha_parent_adress,
+ bool only_superior_vertices,
+ bool is_alpha_blocker = false) {
+ if (alpha_parent_adress.dimension() == 0) {
+ // for a vertex we know exactly the number of vertices of the link (and the size of the corresponding vector)
+ // thus we call a specific function that will reserve a vector with appropriate size
+ this->compute_link_vertices(parent_complex,
+ alpha_parent_adress.first_vertex(),
+ only_superior_vertices_);
+ } else {
+ // we compute the intersection of neighbors of alpha and store it in link_vertices
+ Simplex link_vertices_parent;
+ parent_complex.add_neighbours(alpha_parent_adress, link_vertices_parent,
+ only_superior_vertices);
+ // For all vertex 'v' in this intersection, we go through all its adjacent blockers.
+ // If one blocker minus 'v' is included in alpha then the vertex is not in the link complex.
+ for (auto v_parent : link_vertices_parent) {
+ bool new_vertex = true;
+ for (auto beta : parent_complex.const_blocker_range(v_parent)) {
+ if (!is_alpha_blocker || *beta != alpha_parent_adress) {
+ new_vertex = !(alpha_parent_adress.contains_difference(*beta,
+ v_parent));
+ if (!new_vertex)
+ break;
+ }
+ }
+ if (new_vertex)
+ this->add_vertex(parent_complex.get_id(v_parent));
+ }
+ }
+ }
+
+ /**
+ * @brief compute vertices of the link.
+ * If the boolean only_superior_vertices is true, then only the vertices
+ * are greater than vertices of alpha_parent_adress are added.
+ */
+ void compute_link_vertices(const ComplexType & parent_complex,
+ Vertex_handle alpha_parent_adress,
+ bool only_superior_vertices) {
+ // for a vertex we know exactly the number of vertices of the link (and the size of the corresponding vector
+ this->skeleton.m_vertices.reserve(
+ parent_complex.degree(alpha_parent_adress));
+
+ // For all vertex 'v' in this intersection, we go through all its adjacent blockers.
+ // If one blocker minus 'v' is included in alpha then the vertex is not in the link complex.
+ for (auto v_parent : parent_complex.vertex_range(alpha_parent_adress)) {
+ if (!only_superior_vertices
+ || v_parent.vertex > alpha_parent_adress.vertex)
+ this->add_vertex(parent_complex.get_id(v_parent));
+ }
+ }
+
+ void compute_link_edges(const ComplexType & parent_complex,
+ const Simplex& alpha_parent_adress,
+ bool is_alpha_blocker = false) {
+ if (this->num_vertices() <= 1)
+ return;
+
+ for (auto x_link = this->vertex_range().begin();
+ x_link != this->vertex_range().end(); ++x_link) {
+ for (auto y_link = x_link; ++y_link != this->vertex_range().end();) {
+ Vertex_handle x_parent = *parent_complex.get_address(
+ this->get_id(*x_link));
+ Vertex_handle y_parent = *parent_complex.get_address(
+ this->get_id(*y_link));
+ if (parent_complex.contains_edge(x_parent, y_parent)) {
+ // we check that there is no blocker subset of alpha passing trough x and y
+ bool new_edge = true;
+ for (auto blocker_parent : parent_complex.const_blocker_range(
+ x_parent)) {
+ if (!is_alpha_blocker || *blocker_parent != alpha_parent_adress) {
+ if (blocker_parent->contains(y_parent)) {
+ new_edge = !(alpha_parent_adress.contains_difference(
+ *blocker_parent, x_parent, y_parent));
+ if (!new_edge)
+ break;
+ }
+ }
+ }
+ if (new_edge)
+ this->add_edge_without_blockers(*x_link, *y_link);
+ }
+ }
+ }
+ }
+
+ /**
+ * @brief : Given an address in the current complex, it returns the
+ * corresponding address in 'other_complex'.
+ * It assumes that other_complex have a vertex 'this.get_id(address)'
+ */
+ boost::optional<Vertex_handle> give_equivalent_vertex(const ComplexType & other_complex,
+ Vertex_handle address) const {
+ Root_vertex_handle id((*this)[address].get_id());
+ return other_complex.get_address(id);
+ }
+
+ /*
+ * compute the blockers of the link if is_alpha_blocker is false.
+ * Otherwise, alpha is a blocker, and the link is computed in the complex where
+ * the blocker is anticollapsed.
+ */
+ void compute_link_blockers(const ComplexType & parent_complex,
+ const Simplex& alpha_parent,
+ bool is_alpha_blocker = false) {
+ for (auto x_link : this->vertex_range()) {
+ Vertex_handle x_parent = *this->give_equivalent_vertex(parent_complex,
+ x_link);
+
+ for (auto blocker_parent : parent_complex.const_blocker_range(x_parent)) {
+ if (!is_alpha_blocker || *blocker_parent != alpha_parent) {
+ Simplex sigma_parent(*blocker_parent);
+
+ sigma_parent.difference(alpha_parent);
+
+ if (sigma_parent.dimension() >= 2
+ && sigma_parent.first_vertex() == x_parent) {
+ Root_simplex_handle sigma_id(parent_complex.get_id(sigma_parent));
+ auto sigma_link = this->get_simplex_address(sigma_id);
+ // ie if the vertices of sigma are vertices of the link
+ if (sigma_link) {
+ bool is_new_blocker = true;
+ for (auto a : alpha_parent) {
+ for (auto eta_parent : parent_complex.const_blocker_range(a)) {
+ if (!is_alpha_blocker || *eta_parent != alpha_parent) {
+ Simplex eta_minus_alpha(*eta_parent);
+ eta_minus_alpha.difference(alpha_parent);
+ if (eta_minus_alpha != sigma_parent
+ && sigma_parent.contains_difference(*eta_parent,
+ alpha_parent)) {
+ is_new_blocker = false;
+ break;
+ }
+ }
+ }
+ if (!is_new_blocker)
+ break;
+ }
+ if (is_new_blocker)
+ this->add_blocker(new Simplex(*sigma_link));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public:
+ /**
+ * @brief compute vertices, edges and blockers of the link.
+ * @details If the boolean only_superior_vertices is true, then the link is computed only
+ * with vertices that are greater than vertices of alpha_parent_adress.
+ */
+ void build_link(const ComplexType & parent_complex,
+ const Simplex& alpha_parent_adress,
+ bool is_alpha_blocker = false,
+ bool only_vertices = false) {
+ assert(is_alpha_blocker || parent_complex.contains(alpha_parent_adress));
+ compute_link_vertices(parent_complex, alpha_parent_adress, only_superior_vertices_);
+ if (!only_vertices) {
+ compute_link_edges(parent_complex, alpha_parent_adress, is_alpha_blocker);
+ compute_link_blockers(parent_complex, alpha_parent_adress, is_alpha_blocker);
+ }
+ }
+
+ /**
+ * @brief build the link of a blocker which is the link
+ * of the blocker's simplex if this simplex had been
+ * removed from the blockers of the complex.
+ */
+ friend void build_link_of_blocker(const ComplexType & parent_complex,
+ Simplex& blocker,
+ Skeleton_blocker_link_complex & result) {
+ assert(blocker.dimension() >= 2);
+ assert(parent_complex.contains_blocker(blocker));
+ result.clear();
+ result.build_link(parent_complex, blocker, true);
+ }
+};
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_LINK_COMPLEX_H_
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h
new file mode 100644
index 00000000..404f04f9
--- /dev/null
+++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_simplifiable_complex.h
@@ -0,0 +1,455 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#ifndef SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_
+#define SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_
+
+#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h>
+
+#include <list>
+#include <vector>
+#include <set>
+
+namespace Gudhi {
+
+namespace skeleton_blocker {
+
+/**
+ * Returns true if the blocker 'sigma' is popable.
+ * To define popable, let us call 'L' the complex that
+ * consists in the current complex without the blocker 'sigma'.
+ * A blocker 'sigma' is then "popable" if the link of 'sigma'
+ * in L is reducible.
+ *
+ */
+template<typename SkeletonBlockerDS>
+bool Skeleton_blocker_complex<SkeletonBlockerDS>::is_popable_blocker(Blocker_handle sigma) const {
+ assert(this->contains_blocker(*sigma));
+ Skeleton_blocker_link_complex<Skeleton_blocker_complex> link_blocker_sigma;
+ build_link_of_blocker(*this, *sigma, link_blocker_sigma);
+ return link_blocker_sigma.is_contractible() == CONTRACTIBLE;
+}
+
+/**
+ * Removes all the popable blockers of the complex and delete them.
+ * @returns the number of popable blockers deleted
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_popable_blockers() {
+ std::list<Vertex_handle> vertex_to_check;
+ for (auto v : this->vertex_range())
+ vertex_to_check.push_front(v);
+
+ while (!vertex_to_check.empty()) {
+ Vertex_handle v = vertex_to_check.front();
+ vertex_to_check.pop_front();
+
+ bool blocker_popable_found = true;
+ while (blocker_popable_found) {
+ blocker_popable_found = false;
+ for (auto block : this->blocker_range(v)) {
+ if (this->is_popable_blocker(block)) {
+ for (Vertex_handle nv : *block)
+ if (nv != v) vertex_to_check.push_back(nv);
+ this->delete_blocker(block);
+ blocker_popable_found = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Removes all the popable blockers of the complex passing through v and delete them.
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_popable_blockers(Vertex_handle v) {
+ bool blocker_popable_found = true;
+ while (blocker_popable_found) {
+ blocker_popable_found = false;
+ for (auto block : this->blocker_range(v)) {
+ if (is_popable_blocker(block)) {
+ this->delete_blocker(block);
+ blocker_popable_found = true;
+ }
+ }
+ }
+}
+
+/**
+ * @brief Removes all the popable blockers of the complex passing through v and delete them.
+ * Also remove popable blockers in the neighborhood if they became popable.
+ *
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_all_popable_blockers(Vertex_handle v) {
+ std::list<Vertex_handle> vertex_to_check;
+ vertex_to_check.push_front(v);
+
+ while (!vertex_to_check.empty()) {
+ Vertex_handle v = vertex_to_check.front();
+ vertex_to_check.pop_front();
+
+ bool blocker_popable_found = true;
+ while (blocker_popable_found) {
+ blocker_popable_found = false;
+ for (auto block : this->blocker_range(v)) {
+ if (this->is_popable_blocker(block)) {
+ for (Vertex_handle nv : *block)
+ if (nv != v) vertex_to_check.push_back(nv);
+ this->delete_blocker(block);
+ blocker_popable_found = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Remove the star of the vertice 'v'
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle v) {
+ // we remove the blockers that are not consistent anymore
+ update_blockers_after_remove_star_of_vertex_or_edge(Simplex(v));
+ while (this->degree(v) > 0) {
+ Vertex_handle w(* (adjacent_vertices(v.vertex, this->skeleton).first));
+ this->remove_edge(v, w);
+ }
+ this->remove_vertex(v);
+}
+
+/**
+ * after removing the star of a simplex, blockers sigma that contains this simplex must be removed.
+ * Furthermore, all simplices tau of the form sigma \setminus simplex_to_be_removed must be added
+ * whenever the dimension of tau is at least 2.
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::update_blockers_after_remove_star_of_vertex_or_edge(const Simplex& simplex_to_be_removed) {
+ std::list <Blocker_handle> blockers_to_update;
+ if (simplex_to_be_removed.empty()) return;
+
+ auto v0 = simplex_to_be_removed.first_vertex();
+ for (auto blocker : this->blocker_range(v0)) {
+ if (blocker->contains(simplex_to_be_removed))
+ blockers_to_update.push_back(blocker);
+ }
+
+ for (auto blocker_to_update : blockers_to_update) {
+ Simplex sub_blocker_to_be_added;
+ bool sub_blocker_need_to_be_added =
+ (blocker_to_update->dimension() - simplex_to_be_removed.dimension()) >= 2;
+ if (sub_blocker_need_to_be_added) {
+ sub_blocker_to_be_added = *blocker_to_update;
+ sub_blocker_to_be_added.difference(simplex_to_be_removed);
+ }
+ this->delete_blocker(blocker_to_update);
+ if (sub_blocker_need_to_be_added)
+ this->add_blocker(sub_blocker_to_be_added);
+ }
+}
+
+/**
+ * Remove the star of the edge connecting vertices a and b.
+ * @returns the number of blocker that have been removed
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle a, Vertex_handle b) {
+ update_blockers_after_remove_star_of_vertex_or_edge(Simplex(a, b));
+ // we remove the edge
+ this->remove_edge(a, b);
+}
+
+/**
+ * Remove the star of the edge 'e'.
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Edge_handle e) {
+ return remove_star(this->first_vertex(e), this->second_vertex(e));
+}
+
+/**
+ * Remove the star of the simplex 'sigma' which needs to belong to the complex
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(const Simplex& sigma) {
+ assert(this->contains(sigma));
+ if (sigma.dimension() == 0) {
+ remove_star(sigma.first_vertex());
+ } else if (sigma.dimension() == 1) {
+ remove_star(sigma.first_vertex(), sigma.last_vertex());
+ } else {
+ remove_blocker_containing_simplex(sigma);
+ this->add_blocker(sigma);
+ }
+}
+
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::add_simplex(const Simplex& sigma) {
+ // to add a simplex s, all blockers included in s are first removed
+ // and then all simplex in the coboundary of s are added as blockers
+ assert(!this->contains(sigma));
+ assert(sigma.dimension() > 1);
+ if (!contains_vertices(sigma)) {
+ std::cerr << "add_simplex: Some vertices were not present in the complex, adding them" << std::endl;
+ size_t num_vertices_to_add = sigma.last_vertex() - this->num_vertices() + 1;
+ for (size_t i = 0; i < num_vertices_to_add; ++i)
+ this->add_vertex();
+ }
+ assert(contains_vertices(sigma));
+ if (!contains_edges(sigma))
+ add_edge(sigma);
+ remove_blocker_include_in_simplex(sigma);
+ add_blockers_after_simplex_insertion(sigma);
+}
+
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::add_blockers_after_simplex_insertion(Simplex sigma) {
+ if (sigma.dimension() < 1) return;
+
+ for (auto s : coboundary_range(sigma)) {
+ this->add_blocker(s);
+ }
+}
+
+/**
+ * remove all blockers that contains sigma
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_containing_simplex(const Simplex& sigma) {
+ std::vector <Blocker_handle> blockers_to_remove;
+ for (auto blocker : this->blocker_range(sigma.first_vertex())) {
+ if (blocker->contains(sigma))
+ blockers_to_remove.push_back(blocker);
+ }
+ for (auto blocker_to_update : blockers_to_remove)
+ this->delete_blocker(blocker_to_update);
+}
+
+/**
+ * remove all blockers that contains sigma
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_include_in_simplex(const Simplex& sigma) {
+ // TODO(DS): write efficiently by using only superior blockers
+ // eg for all s, check blockers whose vertices are all greater than s
+ std::set <Blocker_handle> blockers_to_remove;
+ for (auto s : sigma) {
+ for (auto blocker : this->blocker_range(s)) {
+ if (sigma.contains(*blocker))
+ blockers_to_remove.insert(blocker);
+ }
+ }
+ for (auto blocker_to_update : blockers_to_remove) {
+ auto s = *blocker_to_update;
+ this->delete_blocker(blocker_to_update);
+ // now if there is a vertex v in the link of s
+ // and v is not included in sigma then v.s is a blocker
+ // (all faces of v.s are there since v belongs to the link of s)
+ for (const auto& b : coboundary_range(s))
+ if (!sigma.contains(b))
+ this->add_blocker(b);
+ }
+}
+
+/**
+ * Compute simplices beta such that a.beta is an order 0 blocker
+ * that may be used to construct a new blocker after contracting ab.
+ * It requires that the link condition is satisfied.
+ */
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::tip_blockers(Vertex_handle a, Vertex_handle b,
+ std::vector<Simplex> & buffer) const {
+ for (auto const & blocker : this->const_blocker_range(a)) {
+ Simplex beta = (*blocker);
+ beta.remove_vertex(a);
+ buffer.push_back(beta);
+ }
+
+ Simplex n;
+ this->add_neighbours(b, n);
+ this->remove_neighbours(a, n);
+ n.remove_vertex(a);
+
+
+ for (Vertex_handle y : n) {
+ Simplex beta;
+ beta.add_vertex(y);
+ buffer.push_back(beta);
+ }
+}
+
+/**
+ * @brief "Replace" the edge 'bx' by the edge 'ax'.
+ * Assume that the edge 'bx' was present whereas 'ax' was not.
+ * Precisely, it does not replace edges, but remove 'bx' and then add 'ax'.
+ * The visitor 'on_swaped_edge' is called just after edge 'ax' had been added
+ * and just before edge 'bx' had been removed. That way, it can
+ * eventually access to information of 'ax'.
+ */
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::swap_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) {
+ this->add_edge_without_blockers(a, x);
+ if (this->visitor) this->visitor->on_swaped_edge(a, b, x);
+ this->remove_edge(b, x);
+}
+
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::delete_blockers_around_vertex(Vertex_handle v) {
+ std::list <Blocker_handle> blockers_to_delete;
+ for (auto blocker : this->blocker_range(v)) {
+ blockers_to_delete.push_back(blocker);
+ }
+ while (!blockers_to_delete.empty()) {
+ this->remove_blocker(blockers_to_delete.back());
+ blockers_to_delete.pop_back();
+ }
+}
+
+/**
+ * @brief removes all blockers passing through the edge 'ab'
+ */
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::delete_blockers_around_edge(Vertex_handle a, Vertex_handle b) {
+ std::list<Blocker_handle> blocker_to_delete;
+ for (auto blocker : this->blocker_range(a))
+ if (blocker->contains(b)) blocker_to_delete.push_back(blocker);
+ while (!blocker_to_delete.empty()) {
+ this->delete_blocker(blocker_to_delete.back());
+ blocker_to_delete.pop_back();
+ }
+}
+
+/**
+ * Contracts the edge connecting vertices a and b.
+ * @remark If the link condition Link(ab) = Link(a) inter Link(b) is not satisfied,
+ * it removes first all blockers passing through 'ab'
+ */
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::contract_edge(Vertex_handle a, Vertex_handle b) {
+ assert(this->contains_vertex(a));
+ assert(this->contains_vertex(b));
+
+ if (this->contains_edge(a, b))
+ this->add_edge_without_blockers(a, b);
+
+ // if some blockers passes through 'ab', we need to remove them.
+ if (!link_condition(a, b))
+ delete_blockers_around_edge(a, b);
+
+ std::set<Simplex> blockers_to_add;
+
+ get_blockers_to_be_added_after_contraction(a, b, blockers_to_add);
+
+ delete_blockers_around_vertices(a, b);
+
+ update_edges_after_contraction(a, b);
+
+ this->remove_vertex(b);
+
+ notify_changed_edges(a);
+
+ for (auto block : blockers_to_add)
+ this->add_blocker(block);
+
+ assert(this->contains_vertex(a));
+ assert(!this->contains_vertex(b));
+}
+
+template<typename SkeletonBlockerDS>
+void Skeleton_blocker_complex<SkeletonBlockerDS>::get_blockers_to_be_added_after_contraction(Vertex_handle a,
+ Vertex_handle b,
+ std::set<Simplex>& blockers_to_add) {
+ blockers_to_add.clear();
+
+ typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerDS> > LinkComplexType;
+
+ LinkComplexType link_a(*this, a);
+ LinkComplexType link_b(*this, b);
+
+ std::vector<Simplex> vector_alpha, vector_beta;
+
+ tip_blockers(a, b, vector_alpha);
+ tip_blockers(b, a, vector_beta);
+
+ for (auto alpha = vector_alpha.begin(); alpha != vector_alpha.end(); ++alpha) {
+ for (auto beta = vector_beta.begin(); beta != vector_beta.end(); ++beta) {
+ Simplex sigma = *alpha;
+ sigma.union_vertices(*beta);
+ Root_simplex_handle sigma_id = this->get_id(sigma);
+ if (this->contains(sigma) &&
+ proper_faces_in_union<Skeleton_blocker_complex < SkeletonBlockerDS >> (sigma_id, link_a, link_b)) {
+ // Blocker_handle blocker = new Simplex(sigma);
+ sigma.add_vertex(a);
+ blockers_to_add.insert(sigma);
+ }
+ }
+ }
+}
+
+/**
+ * delete all blockers that passes through a or b
+ */
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::delete_blockers_around_vertices(Vertex_handle a, Vertex_handle b) {
+ std::vector<Blocker_handle> blocker_to_delete;
+ for (auto bl : this->blocker_range(a))
+ blocker_to_delete.push_back(bl);
+ for (auto bl : this->blocker_range(b))
+ blocker_to_delete.push_back(bl);
+ while (!blocker_to_delete.empty()) {
+ this->delete_blocker(blocker_to_delete.back());
+ blocker_to_delete.pop_back();
+ }
+}
+
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::update_edges_after_contraction(Vertex_handle a, Vertex_handle b) {
+ // We update the set of edges
+ this->remove_edge(a, b);
+
+ // For all edges {b,x} incident to b,
+ // we remove {b,x} and add {a,x} if not already there.
+ while (this->degree(b) > 0) {
+ Vertex_handle x(*(adjacent_vertices(b.vertex, this->skeleton).first));
+ if (!this->contains_edge(a, x))
+ // we 'replace' the edge 'bx' by the edge 'ax'
+ this->swap_edge(a, b, x);
+ else
+ this->remove_edge(b, x);
+ }
+}
+
+template<typename SkeletonBlockerDS>
+void
+Skeleton_blocker_complex<SkeletonBlockerDS>::notify_changed_edges(Vertex_handle a) {
+ // We notify the visitor that all edges incident to 'a' had changed
+ boost_adjacency_iterator v, v_end;
+
+ for (tie(v, v_end) = adjacent_vertices(a.vertex, this->skeleton); v != v_end; ++v)
+ if (this->visitor) this->visitor->on_changed_edge(a, Vertex_handle(*v));
+}
+
+
+} // namespace skeleton_blocker
+
+namespace skbl = skeleton_blocker;
+
+} // namespace Gudhi
+
+#endif // SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_
diff --git a/src/Skeleton_blocker/test/CMakeLists.txt b/src/Skeleton_blocker/test/CMakeLists.txt
new file mode 100644
index 00000000..19c65871
--- /dev/null
+++ b/src/Skeleton_blocker/test/CMakeLists.txt
@@ -0,0 +1,17 @@
+project(Skeleton_blocker_tests)
+
+include(GUDHI_test_coverage)
+
+add_executable ( Skeleton_blocker_test_unit test_skeleton_blocker_complex.cpp )
+target_link_libraries(Skeleton_blocker_test_unit ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+add_executable ( Skeleton_blocker_test_geometric_complex test_skeleton_blocker_geometric_complex.cpp )
+target_link_libraries(Skeleton_blocker_test_geometric_complex ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+add_executable ( Skeleton_blocker_test_simplifiable test_skeleton_blocker_simplifiable.cpp )
+target_link_libraries(Skeleton_blocker_test_simplifiable ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+
+# Do not forget to copy test files in current binary dir
+file(COPY "test2.off" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
+
+gudhi_add_coverage_test(Skeleton_blocker_test_unit)
+gudhi_add_coverage_test(Skeleton_blocker_test_geometric_complex)
+gudhi_add_coverage_test(Skeleton_blocker_test_simplifiable)
diff --git a/src/Skeleton_blocker/test/test.off b/src/Skeleton_blocker/test/test.off
new file mode 100644
index 00000000..61ef2d2b
--- /dev/null
+++ b/src/Skeleton_blocker/test/test.off
@@ -0,0 +1,10 @@
+OFF
+4 4 0
+0 0 0
+1 0 0
+0 1 0
+.5 .5 1
+3 0 1 2
+3 0 1 3
+3 0 2 3
+3 1 2 3
diff --git a/src/Skeleton_blocker/test/test2.off b/src/Skeleton_blocker/test/test2.off
new file mode 100644
index 00000000..b12ce572
--- /dev/null
+++ b/src/Skeleton_blocker/test/test2.off
@@ -0,0 +1,15 @@
+OFF
+7 6 0
+-1.5 2 0
+0 2 0
+1.5 2 0
+0 1.5 0
+-1 1 0
+1 1 0
+0 0 0
+3 0 1 4
+3 1 3 4
+3 1 3 5
+3 1 2 5
+3 3 4 5
+3 4 5 6
diff --git a/src/Skeleton_blocker/test/test_skeleton_blocker_complex.cpp b/src/Skeleton_blocker/test/test_skeleton_blocker_complex.cpp
new file mode 100644
index 00000000..4336e33b
--- /dev/null
+++ b/src/Skeleton_blocker/test/test_skeleton_blocker_complex.cpp
@@ -0,0 +1,826 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "skeleton_blocker_complex"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <gudhi/Skeleton_blocker.h>
+
+template<typename ComplexType> class Skeleton_blocker_sub_complex;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simple_traits Traits;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_complex<Traits> Complex;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_link_complex<Complex> Skeleton_blocker_link_complex;
+typedef Complex::Vertex_handle Vertex_handle;
+typedef Complex::Root_vertex_handle Root_vertex_handle;
+typedef Complex::Simplex Simplex;
+typedef Complex::Root_simplex_handle Root_simplex_handle;
+typedef Simplex::Simplex_vertex_const_iterator Simplex_vertex_const_iterator;
+typedef Complex::Edge_handle Edge_handle;
+
+bool assert_vertex(Complex &complex, Vertex_handle v) {
+ //assert(complex.contains(v));
+ return complex.contains(static_cast<Simplex> (v));
+}
+
+bool assert_simplex(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c) {
+ return true;
+ // AddressSimplex simplex((a),(b),(c));
+ // return complex.contains(&simplex);
+}
+
+// true iff the blocker (a,b,c) is in complex
+
+bool assert_blocker(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c) {
+ return true;
+ //return complex.contains_blocker((a),(b),(c));
+}
+
+// true iff the blocker (a,b,c,d) is in complex
+
+bool assert_blocker(Complex &complex, Root_vertex_handle a, Root_vertex_handle b, Root_vertex_handle c, Root_vertex_handle d) {
+ return true;
+ //Simplex blocker (a,b,c,d);
+ //return complex.contains_blocker(&blocker);
+}
+
+void build_complete(int n, Complex& complex) {
+ complex.clear();
+ for (int i = 0; i < n; i++)
+ complex.add_vertex();
+
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < i; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplex) {
+ Simplex simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3));
+ BOOST_CHECK(simplex.dimension() == 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_num_simplices) {
+ int n = 4;
+ Complex complex;
+ build_complete(n, complex);
+ size_t sum = 0;
+ for (int i = 0; i < n; i++) {
+ sum += complex.num_simplices(i);
+ }
+ BOOST_CHECK(complex.num_vertices() == n);
+ BOOST_CHECK(complex.num_edges() == 6);
+ BOOST_CHECK(sum == 15);
+ BOOST_CHECK(complex.num_simplices() == 15);
+}
+
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_vertices1) {
+ int n = 10;
+ Complex complex(10);
+ std::cout << "complex.num_vertices():" << complex.num_vertices() << std::endl;
+ int num_vertex_seen = 0;
+ for (auto vi : complex.vertex_range()) {
+ std::cout << "vertex:" << vi << std::endl;
+ ++num_vertex_seen;
+ }
+ BOOST_CHECK(num_vertex_seen == n);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_vertices2) {
+ int n = 10;
+ Complex complex;
+ build_complete(10, complex);
+ std::cout << "complex.num_vertices():" << complex.num_vertices() << std::endl;
+ std::cout << "complex.num_edges():" << complex.num_edges() << std::endl;
+ int num_vertex_seen = 0;
+ for (auto vi : complex.vertex_range(Vertex_handle(2))) {
+ std::cout << "vertex:" << vi << std::endl;
+ ++num_vertex_seen;
+ }
+ std::cout << "num_vertex_seen:" << num_vertex_seen << std::endl;
+ BOOST_CHECK(num_vertex_seen == (n -1));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_edge) {
+ const int n = 10;
+ Complex complex(n);
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < i; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ complex.remove_edge(Vertex_handle(2), Vertex_handle(3));
+ complex.remove_edge(Vertex_handle(3), Vertex_handle(5));
+ std::cout << "complex.num_edges():" << complex.num_edges() << std::endl;
+ int num_edges_seen = 0;
+ for (auto edge : complex.edge_range()) {
+ std::cout << "edge :" << complex[edge] << std::endl;
+ ++num_edges_seen;
+ }
+
+ BOOST_CHECK(num_edges_seen == n * (n - 1) / 2 - 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_edge2) {
+ const int n = 10;
+ Complex complex(n);
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < i; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ complex.remove_edge(Vertex_handle(2), Vertex_handle(3));
+ complex.remove_edge(Vertex_handle(3), Vertex_handle(5));
+ std::cout << "complex.num_edges():" << complex.num_edges() << std::endl;
+ int num_neigbors_seen = 0;
+ for (auto neighbor : complex.vertex_range(Vertex_handle(2))) {
+ std::cout << "neighbor" << neighbor << std::endl;
+ ++num_neigbors_seen;
+ }
+ BOOST_CHECK(num_neigbors_seen == 8);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_triangles) {
+ const int n = 7;
+ Complex complex(n);
+ //create a "ring" around '0'
+ for (int i = 1; i < n; i++)
+ complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(i));
+ for (int i = 1; i < n - 1; i++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(i + 1));
+ complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(6));
+
+ std::cout << complex.to_string() << std::endl;
+
+ int num_triangles_seen = 0;
+ //for (auto t : complex.triangle_range(5)){
+ for (auto t : complex.triangle_range(Vertex_handle(5))) {
+ ++num_triangles_seen;
+ }
+ BOOST_CHECK(num_triangles_seen == 2);
+
+ num_triangles_seen = 0;
+ for (auto t : complex.triangle_range(Vertex_handle(0))) {
+ ++num_triangles_seen;
+ }
+ BOOST_CHECK(num_triangles_seen == 6);
+
+ // we now add another triangle
+ complex.add_vertex();
+ complex.add_edge_without_blockers(Vertex_handle(4), Vertex_handle(7));
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(7));
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(6)));
+ num_triangles_seen = 0;
+
+ num_triangles_seen = 0;
+ for (auto t : complex.triangle_range()) {
+ ++num_triangles_seen;
+ }
+ BOOST_CHECK(num_triangles_seen == 6);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_simplices) {
+ Complex complex(6);
+ complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(1));
+ complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(2));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(0));
+ complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(3));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(3));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(5));
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(5));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(4), Vertex_handle(5));
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4));
+
+ complex.add_blocker(Simplex(Vertex_handle(2), Vertex_handle(3), Vertex_handle(4), Vertex_handle(5)));
+
+ std::map<Vertex_handle, unsigned> expected_num_simplices;
+
+ expected_num_simplices[Vertex_handle(0)] = 4;
+ expected_num_simplices[Vertex_handle(1)] = 6;
+ expected_num_simplices[Vertex_handle(2)] = 11;
+ expected_num_simplices[Vertex_handle(3)] = 9;
+ expected_num_simplices[Vertex_handle(4)] = 7;
+ expected_num_simplices[Vertex_handle(5)] = 7;
+
+ for (auto pair : expected_num_simplices) {
+ std::cout << "found list: ";
+ unsigned num_simplices_around = 0;
+ for (const auto& simplex : complex.star_simplex_range(pair.first)) {
+ simplex.dimension();
+ std::cout << simplex << " - ";
+ ++num_simplices_around;
+ }
+
+ BOOST_CHECK(num_simplices_around == pair.second);
+
+ std::cout << std::endl << "current vertex:" << pair.first << " - ";
+ std::cout << "expected_num_simplices:" << pair.second << " - ";
+ std::cout << "found:" << num_simplices_around << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_simplices2) {
+ Complex complex(2);
+ complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(1));
+
+ // Check there is no triangle
+ BOOST_CHECK(std::distance(complex.triangle_range().begin(), complex.triangle_range().end()) == 0);
+
+ // Star(0) is [{0},{0,1}]
+ BOOST_CHECK(std::distance(complex.star_simplex_range(Vertex_handle(0)).begin(),
+ complex.star_simplex_range(Vertex_handle(0)).end()) == 2);
+
+ // No blocker
+ BOOST_CHECK(std::distance(complex.blocker_range(Vertex_handle(0)).begin(),
+ complex.blocker_range(Vertex_handle(0)).end()) == 0);
+
+ // Complex is [{0},{0,1},{1}]
+ BOOST_CHECK(std::distance(complex.complex_simplex_range().begin(),
+ complex.complex_simplex_range().end()) == 3);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_simplices3) {
+ Complex complex(3);
+ complex.add_edge_without_blockers(Vertex_handle(0), Vertex_handle(1));
+ complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(2));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(0));
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)));
+
+ // Check there is no triangle
+ BOOST_CHECK(std::distance(complex.triangle_range().begin(), complex.triangle_range().end()) == 0);
+
+ // Star(0) is [{0},{0,1},{0,2}]
+ BOOST_CHECK(std::distance(complex.star_simplex_range(Vertex_handle(0)).begin(),
+ complex.star_simplex_range(Vertex_handle(0)).end()) == 3);
+
+ // blocker(0) is [{0,1,2}]
+ BOOST_CHECK(std::distance(complex.blocker_range(Vertex_handle(0)).begin(),
+ complex.blocker_range(Vertex_handle(0)).end()) == 1);
+
+ // Complex is [{0},{0,1},{0,2},{1},{1,2},{2}]
+ BOOST_CHECK(std::distance(complex.complex_simplex_range().begin(),
+ complex.complex_simplex_range().end()) == 6);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_simplices4) {
+ Complex empty_complex;
+ for (auto v : empty_complex.vertex_range()) {
+ std::cout << v;
+ BOOST_CHECK(false);
+ }
+ for (auto e : empty_complex.edge_range()) {
+ std::cout << e;
+ BOOST_CHECK(false);
+ }
+ for (auto t : empty_complex.triangle_range()) {
+ std::cout << t;
+ BOOST_CHECK(false);
+ }
+ for (auto s : empty_complex.complex_simplex_range()) {
+ std::cout << s;
+ BOOST_CHECK(false);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_coboundary) {
+ Complex c;
+ build_complete(4, c);
+ c.remove_edge(Vertex_handle(1), Vertex_handle(3));
+ std::cout << c.to_string();
+ Simplex s02(Vertex_handle(0), Vertex_handle(2));
+ int n = 0;
+ std::set<Simplex> expected;
+ expected.insert(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)));
+ expected.insert(Simplex(Vertex_handle(0), Vertex_handle(2), Vertex_handle(3)));
+ for (const auto & s : c.coboundary_range(s02)) {
+ BOOST_CHECK(expected.find(s) != expected.end());
+ ++n;
+ }
+ BOOST_CHECK(n == 2);
+}
+
+template<typename Map>
+auto blocker_range(Map map) -> decltype(map | boost::adaptors::map_values) {
+ return map | boost::adaptors::map_values;
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_iterator_blockers) {
+ Complex complex;
+ Simplex alpha;
+ Simplex vertex_set_expected;
+ // Build the complexes
+ for (int i = 0; i < 20; i++) {
+ complex.add_vertex();
+ }
+ for (int i = 10; i < 15; i++) {
+ for (int j = i + 1; j < 15; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ }
+
+ std::vector<Simplex> myBlockers;
+ myBlockers.push_back(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(12)));
+ myBlockers.push_back(Simplex(Vertex_handle(2), Vertex_handle(1), Vertex_handle(10)));
+ myBlockers.push_back(Simplex(Vertex_handle(10), Vertex_handle(9), Vertex_handle(15)));
+ myBlockers.push_back(Simplex(Vertex_handle(1), Vertex_handle(9), Vertex_handle(8)));
+
+ for (auto blocker : myBlockers)
+ complex.add_blocker(blocker);
+
+ int num_blockers = 0;
+ for (auto blockers : complex.blocker_range(Vertex_handle(10))) {
+ // Only the first 3 blockers contain vertex 10
+ BOOST_CHECK(*blockers == myBlockers[num_blockers]);
+ num_blockers++;
+ }
+ BOOST_CHECK(num_blockers == 3);
+
+ num_blockers = 0;
+ for (auto blockers : complex.blocker_range()) {
+// If not windows - _WIN32 is for windows 32 and 64 bits
+#ifndef _WIN32
+ for (auto block_ptr = myBlockers.begin(); block_ptr < myBlockers.end(); block_ptr++)
+ if (*block_ptr == *blockers)
+ myBlockers.erase(block_ptr);
+#endif
+ num_blockers++;
+ }
+ BOOST_CHECK(num_blockers == 4);
+// If not windows - _WIN32 is for windows 32 and 64 bits
+#ifndef _WIN32
+ BOOST_CHECK(myBlockers.empty());
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link0) {
+ enum { a, b, c, d, n };
+ Complex complex(n);
+ complex.add_edge_without_blockers(Vertex_handle(b), Vertex_handle(c));
+ complex.add_edge_without_blockers(Vertex_handle(c), Vertex_handle(d));
+ Simplex alpha = Simplex(Vertex_handle(c));
+ Skeleton_blocker_link_complex L(complex, alpha);
+
+ auto L2 = complex.link(alpha);
+ BOOST_CHECK(L == L2);
+
+ std::cout << L.to_string();
+
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(b))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(d))));
+ BOOST_CHECK(L.num_edges() == 0);
+ BOOST_CHECK(L.num_blockers() == 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link1) {
+ Complex complex;
+
+ // Build the complexes
+ for (int i = 0; i < 20; i++) {
+ complex.add_vertex();
+ }
+ for (int i = 10; i < 15; i++) {
+ for (int j = i + 1; j < 15; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ }
+ Simplex alpha(Vertex_handle(12), Vertex_handle(14));
+ Skeleton_blocker_link_complex L(complex, alpha);
+ // Complexes built
+
+ auto L2 = complex.link(alpha);
+ BOOST_CHECK(L == L2);
+
+ // verification
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(10))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(11))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(13))));
+ BOOST_CHECK(L.num_edges() == 3);
+ BOOST_CHECK(L.num_blockers() == 0);
+ Root_simplex_handle simplex;
+ simplex.add_vertex(Root_vertex_handle(10));
+ simplex.add_vertex(Root_vertex_handle(11));
+ simplex.add_vertex(Root_vertex_handle(13));
+ BOOST_CHECK(L.get_simplex_address(simplex));
+ BOOST_CHECK(L.contains(*(L.get_simplex_address(simplex))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link2) {
+ Complex complex;
+
+ Simplex alpha;
+ Simplex vertex_set_expected;
+ // Build the complexes
+ for (int i = 0; i < 20; i++) {
+ complex.add_vertex();
+ }
+ for (int i = 10; i < 15; i++) {
+ for (int j = i + 1; j < 15; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ }
+ complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(13)));
+ alpha = Simplex(Vertex_handle(12), Vertex_handle(14));
+ Skeleton_blocker_link_complex L(complex, alpha);
+ // Complexes built
+
+ // Print result
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ std::cout << "L= Link_complex(" << alpha << ") : \n" << L.to_string();
+
+ auto L2 = complex.link(alpha);
+ BOOST_CHECK(L == L2);
+
+
+ // verification
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(10))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(11))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(13))));
+ BOOST_CHECK(L.num_edges() == 3);
+ BOOST_CHECK(L.num_blockers() == 1);
+ Root_simplex_handle simplex;
+ simplex.add_vertex(Root_vertex_handle(10));
+ simplex.add_vertex(Root_vertex_handle(11));
+ simplex.add_vertex(Root_vertex_handle(13));
+ BOOST_CHECK(L.contains_blocker(*(L.get_simplex_address(simplex))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link3) {
+ Complex complex;
+
+ Simplex alpha;
+ Simplex vertex_set_expected;
+ // Build the complexes
+ for (int i = 0; i < 20; i++) {
+ complex.add_vertex();
+ }
+ for (int i = 10; i < 15; i++) {
+ for (int j = i + 1; j < 15; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ }
+ complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(12)));
+ alpha = Simplex(Vertex_handle(12), Vertex_handle(14));
+ Skeleton_blocker_link_complex L(complex, alpha);
+ // Complexes built
+
+ // Print result
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ std::cout << "L= Link_complex(" << alpha << ") : \n" << L.to_string();
+
+ auto L2 = complex.link(alpha);
+ BOOST_CHECK(L == L2);
+
+ // verification
+ BOOST_CHECK(L.contains(static_cast<Simplex> (*L.get_address(Root_vertex_handle(10)))));
+ BOOST_CHECK(L.contains(static_cast<Simplex> (*L.get_address(Root_vertex_handle(11)))));
+ BOOST_CHECK(L.contains(static_cast<Simplex> (*L.get_address(Root_vertex_handle(13)))));
+ BOOST_CHECK(L.num_edges() == 2);
+ BOOST_CHECK(L.contains_edge(*L.get_address(Root_vertex_handle(10)), *L.get_address(Root_vertex_handle(13))));
+ BOOST_CHECK(L.contains_edge(*L.get_address(Root_vertex_handle(13)), *L.get_address(Root_vertex_handle(11))));
+ BOOST_CHECK(L.num_blockers() == 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link4) {
+ Complex complex;
+
+ // Build the complexes
+ for (int i = 0; i < 20; i++) {
+ complex.add_vertex();
+ }
+ for (int i = 10; i < 15; i++) {
+ for (int j = i + 1; j < 15; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+ }
+ complex.add_blocker(Simplex(Vertex_handle(10), Vertex_handle(11), Vertex_handle(12), Vertex_handle(13)));
+ Simplex alpha(Vertex_handle(12), Vertex_handle(14));
+ Skeleton_blocker_link_complex L(complex, alpha);
+ // Complexes built
+
+ // verification
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(10))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(11))));
+ BOOST_CHECK(L.contains_vertex(*L.get_address(Root_vertex_handle(13))));
+ BOOST_CHECK(L.num_edges() == 3);
+ BOOST_CHECK(L.num_blockers() == 1);
+ Root_simplex_handle simplex;
+ simplex.add_vertex(Root_vertex_handle(10));
+ simplex.add_vertex(Root_vertex_handle(11));
+ simplex.add_vertex(Root_vertex_handle(13));
+ BOOST_CHECK(L.contains_blocker(*(L.get_simplex_address(simplex))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link5) {
+ Complex complex(0);
+ // Build the complexes
+ build_complete(4, complex);
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)));
+
+ Simplex alpha(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2));
+ Skeleton_blocker_link_complex L(complex, alpha);
+ // Complexes built
+
+ // Print result
+ std::cout << "Complex: " << complex.to_string()<< std::endl << std::endl;
+ std::cout << "Link: " << L.to_string() << std::endl;
+
+ // verification
+ BOOST_CHECK(L.num_vertices() == 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link6) {
+ Complex complex(0);
+ // Build the complexes
+ build_complete(4, complex);
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)));
+
+ Simplex alpha(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2));
+
+ Skeleton_blocker_link_complex link_blocker_alpha;
+
+ build_link_of_blocker(complex, alpha, link_blocker_alpha);
+
+ // Print result
+ std::cout << "Complex: " << complex.to_string()<< std::endl << std::endl;
+ std::cout << "Link: " << link_blocker_alpha.to_string() << std::endl;
+
+ // verification
+ BOOST_CHECK(link_blocker_alpha.num_vertices() == 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_link7) {
+ Complex complex(0);
+ // Build the complexes
+ build_complete(6, complex);
+ complex.add_vertex();
+ complex.add_vertex();
+ for (int i = 3; i < 6; ++i) {
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(6));
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(7));
+ }
+ complex.add_edge_without_blockers(Vertex_handle(6), Vertex_handle(7));
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2)));
+ complex.add_blocker(Simplex(Vertex_handle(3), Vertex_handle(4), Vertex_handle(5)));
+
+ Simplex alpha(Vertex_handle(3), Vertex_handle(4), Vertex_handle(5));
+
+ Skeleton_blocker_link_complex link_blocker_alpha;
+
+ build_link_of_blocker(complex, alpha, link_blocker_alpha);
+
+ //the result should be the edge {6,7} plus the blocker {0,1,2}
+
+ // Print result
+ std::cout << "Complex: " << complex.to_string()<< std::endl << std::endl;
+ std::cout << "Link: " << link_blocker_alpha.to_string() << std::endl;
+
+ Skeleton_blocker_link_complex link_blocker_alpha_cpy = link_blocker_alpha;
+
+ std::cout << "Link copy: " << link_blocker_alpha_cpy.to_string() << std::endl;
+
+ BOOST_CHECK(link_blocker_alpha.num_vertices() == link_blocker_alpha_cpy.num_vertices());
+ BOOST_CHECK(link_blocker_alpha.num_blockers() == link_blocker_alpha_cpy.num_blockers());
+ BOOST_CHECK(link_blocker_alpha.num_edges() == link_blocker_alpha_cpy.num_edges());
+ BOOST_CHECK((link_blocker_alpha.num_blockers() == link_blocker_alpha_cpy.num_blockers()));
+
+ // verification
+ BOOST_CHECK(link_blocker_alpha.num_vertices() == 5);
+ BOOST_CHECK(link_blocker_alpha.num_edges() == 4);
+ BOOST_CHECK(link_blocker_alpha.num_blockers() == 1);
+}
+
+template<typename SimplexHandle>
+void add_triangle_edges(int a, int b, int c, std::list<SimplexHandle>& simplices) {
+ typedef SimplexHandle Simplex;
+ typedef typename SimplexHandle::Vertex_handle Vertex_handle;
+
+ simplices.push_back(Simplex(Vertex_handle(a), Vertex_handle(b)));
+ simplices.push_back(Simplex(Vertex_handle(b), Vertex_handle(c)));
+ simplices.push_back(Simplex(Vertex_handle(c), Vertex_handle(a)));
+}
+
+template<typename SimplexHandle>
+void add_triangle(int a, int b, int c, std::list<SimplexHandle>& simplices) {
+ typedef SimplexHandle Simplex;
+ typedef typename SimplexHandle::Vertex_handle Vertex_handle;
+ simplices.push_back(Simplex(Vertex_handle(a), Vertex_handle(b), Vertex_handle(c)));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor) {
+ std::list <Simplex> simplices;
+
+ simplices.push_back(Simplex(Vertex_handle(0)));
+ simplices.push_back(Simplex(Vertex_handle(1)));
+ simplices.push_back(Simplex(Vertex_handle(2)));
+ simplices.push_back(Simplex(Vertex_handle(3)));
+ simplices.push_back(Simplex(Vertex_handle(4)));
+ simplices.push_back(Simplex(Vertex_handle(5)));
+
+ simplices.push_back(Simplex(Vertex_handle(3), Vertex_handle(5)));
+
+ add_triangle_edges(0, 1, 5, simplices);
+ add_triangle_edges(1, 2, 3, simplices);
+ add_triangle_edges(2, 3, 4, simplices);
+ add_triangle_edges(1, 3, 4, simplices);
+ add_triangle_edges(1, 2, 4, simplices);
+
+ add_triangle(0, 1, 5, simplices);
+ add_triangle(1, 2, 3, simplices);
+ add_triangle(1, 3, 4, simplices);
+ add_triangle(1, 2, 4, simplices);
+ add_triangle(2, 3, 4, simplices);
+
+ Complex complex(simplices.begin(), simplices.end());
+
+ std::cout << "Constructor 1:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.num_vertices() == 6);
+ BOOST_CHECK(complex.num_edges() == 10);
+ BOOST_CHECK(complex.num_blockers() == 2);
+}
+
+std::list<Simplex> subfaces(Simplex top_face) {
+ std::list<Simplex> res;
+ if (top_face.dimension() == -1) return res;
+ if (top_face.dimension() == 0) {
+ res.push_back(top_face);
+ return res;
+ } else {
+ Vertex_handle first_vertex = top_face.first_vertex();
+ top_face.remove_vertex(first_vertex);
+ res = subfaces(top_face);
+ std::list<Simplex> copy = res;
+ for (auto& simplex : copy) {
+ simplex.add_vertex(first_vertex);
+ }
+ res.push_back(Simplex(first_vertex));
+ res.splice(res.end(), copy);
+ return res;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor2) {
+ Simplex simplex;
+ for (int i = 0; i < 5; ++i)
+ simplex.add_vertex(static_cast<Vertex_handle> (i));
+
+ std::list <Simplex> simplices(subfaces(simplex));
+ simplices.remove(simplex);
+
+ Complex complex(simplices.begin(), simplices.end());
+
+ std::cout << "Constructor 2:\n" << complex.to_string();
+
+ for (auto b : complex.const_blocker_range()) {
+ std::cout << "b:" << b << std::endl;
+ }
+
+ BOOST_CHECK(complex.num_vertices() == 5);
+ BOOST_CHECK(complex.num_edges() == 10);
+ BOOST_CHECK(complex.num_blockers() == 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor3) {
+ typedef Vertex_handle Vh;
+ typedef Simplex Sh;
+ std::vector<Simplex> simplices;
+ auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2))));
+ subf.pop_back(); //remove max face -> now a blocker 012
+ simplices.insert(simplices.begin(), subf.begin(), subf.end());
+
+ Complex complex(simplices.begin(), simplices.end());
+
+ std::cout << "Constructor 3:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.num_blockers() == 1);
+ Sh expected_blocker(Vh(0), Vh(1), Vh(2));
+ for (auto b : complex.const_blocker_range())
+ BOOST_CHECK(*b == expected_blocker);
+
+
+ BOOST_CHECK(complex.num_vertices() == 3);
+ BOOST_CHECK(complex.num_blockers() == 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor4) {
+ typedef Vertex_handle Vh;
+ typedef Simplex Sh;
+ std::vector<Simplex> simplices;
+ auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2), Vh(3))));
+ simplices.insert(simplices.begin(), subf.begin(), subf.end());
+
+ simplices.push_back(Sh(Vh(4)));
+ simplices.push_back(Sh(Vh(4), Vh(1)));
+ simplices.push_back(Sh(Vh(4), Vh(0)));
+
+ Complex complex(simplices.begin(), simplices.end());
+
+ std::cout << "Constructor 4:\n" << complex.to_string();
+ BOOST_CHECK(complex.num_blockers() == 1);
+ Sh expected_blocker(Vh(0), Vh(1), Vh(4));
+ for (auto b : complex.const_blocker_range())
+ BOOST_CHECK(*b == expected_blocker);
+
+ BOOST_CHECK(complex.num_vertices() == 5);
+ BOOST_CHECK(complex.num_blockers() == 1);
+ BOOST_CHECK(complex.num_edges() == 8);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor5) {
+ typedef Vertex_handle Vh;
+ typedef Simplex Sh;
+ std::vector<Simplex> simplices;
+ auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2))));
+ simplices.insert(simplices.begin(), subf.begin(), subf.end());
+
+ simplices.push_back(Sh(Vh(3)));
+ simplices.push_back(Sh(Vh(3), Vh(1)));
+ simplices.push_back(Sh(Vh(3), Vh(2)));
+ simplices.push_back(Sh(Vh(4)));
+ simplices.push_back(Sh(Vh(4), Vh(1)));
+ simplices.push_back(Sh(Vh(4), Vh(0)));
+ simplices.push_back(Sh(Vh(5)));
+ simplices.push_back(Sh(Vh(5), Vh(2)));
+ simplices.push_back(Sh(Vh(5), Vh(0)));
+
+ Complex complex(simplices.begin(), simplices.end());
+
+ std::cout << "Constructor 5:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.num_vertices() == 6);
+ BOOST_CHECK(complex.num_blockers() == 3);
+ BOOST_CHECK(complex.num_edges() == 9);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor6) {
+ typedef Vertex_handle Vh;
+ typedef Simplex Sh;
+ std::vector<Simplex> simplices;
+ auto subf(subfaces(Sh(Vh(0), Vh(1), Vh(2), Vh(3))));
+ for (auto s : subf) {
+ Sh s1(Vh(0), Vh(1), Vh(2), Vh(3));
+ Sh s2(Vh(1), Vh(2), Vh(3));
+ if (s != s1 && s != s2) simplices.push_back(s);
+ }
+
+ Complex complex(simplices.begin(), simplices.end());
+
+ std::cout << "Constructor 6:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.num_vertices() == 4);
+ BOOST_CHECK(complex.num_blockers() == 1);
+ BOOST_CHECK(complex.num_edges() == 6);
+ Sh expected_blocker(Vh(1), Vh(2), Vh(3));
+ for (auto b : complex.const_blocker_range())
+ BOOST_CHECK(*b == expected_blocker);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor7) {
+ typedef Vertex_handle Vh;
+ typedef Simplex Sh;
+ std::vector<Simplex> simplices;
+ simplices.push_back(Sh(Vh(0), Vh(1), Vh(2)));
+ simplices.push_back(Sh(Vh(1), Vh(2), Vh(3)));
+ simplices.push_back(Sh(Vh(3), Vh(0), Vh(2)));
+ simplices.push_back(Sh(Vh(3), Vh(0), Vh(1)));
+
+ //get complex from top faces
+ Complex complex(Gudhi::skeleton_blocker::make_complex_from_top_faces<Complex>(simplices.begin(), simplices.end()));
+
+ std::cout << "Constructor 7:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.num_vertices() == 4);
+ BOOST_CHECK(complex.num_blockers() == 1);
+ BOOST_CHECK(complex.num_edges() == 6);
+ Sh expected_blocker(Vh(0), Vh(1), Vh(2), Vh(3));
+ for (auto b : complex.const_blocker_range())
+ BOOST_CHECK(*b == expected_blocker);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_complex_constructor8) {
+ typedef Vertex_handle Vh;
+ typedef Simplex Sh;
+ std::vector<Simplex> simplices;
+ simplices.push_back(Sh(Vh(0), Vh(1)));
+ simplices.push_back(Sh(Vh(2), Vh(1)));
+ simplices.push_back(Sh(Vh(0), Vh(2)));
+ simplices.push_back(Sh(Vh(3), Vh(1)));
+ simplices.push_back(Sh(Vh(2), Vh(3)));
+
+ //get complex from top faces
+ Complex complex(Gudhi::skeleton_blocker::make_complex_from_top_faces<Complex>(simplices.begin(), simplices.end()));
+
+ std::cout << "Constructor 8:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.num_vertices() == 4);
+ BOOST_CHECK(complex.num_blockers() == 2);
+ BOOST_CHECK(complex.num_edges() == 5);
+}
diff --git a/src/Skeleton_blocker/test/test_skeleton_blocker_geometric_complex.cpp b/src/Skeleton_blocker/test/test_skeleton_blocker_geometric_complex.cpp
new file mode 100644
index 00000000..8cad97a1
--- /dev/null
+++ b/src/Skeleton_blocker/test/test_skeleton_blocker_geometric_complex.cpp
@@ -0,0 +1,113 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "skeleton_blocker_geometric_complex"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <gudhi/Skeleton_blocker.h>
+
+struct Geometry_trait {
+ typedef std::vector<double> Point;
+};
+
+typedef Geometry_trait::Point Point;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simple_geometric_traits<Geometry_trait> Complex_geometric_traits;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_geometric_complex< Complex_geometric_traits > Complex;
+typedef Complex::Vertex_handle Vertex_handle;
+typedef Complex_geometric_traits::Root_vertex_handle Root_vertex_handle;
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_off_reader_writer) {
+ Complex complex;
+ Gudhi::skeleton_blocker::Skeleton_blocker_off_reader<Complex> off_reader("test2.off", complex);
+ BOOST_CHECK(off_reader.is_valid());
+
+ std::cout << "complex has " <<
+ complex.num_vertices() << " vertices, " <<
+ complex.num_blockers() << " blockers, " <<
+ complex.num_edges() << " edges and " <<
+ complex.num_triangles() << " triangles.";
+
+ BOOST_CHECK(complex.num_vertices() == 7);
+ BOOST_CHECK(complex.num_edges() == 12);
+ BOOST_CHECK(complex.num_triangles() == 6);
+
+ Gudhi::skeleton_blocker::Skeleton_blocker_off_writer<Complex> off_writer("tmp.off", complex);
+ Complex same;
+ Gudhi::skeleton_blocker::Skeleton_blocker_off_reader<Complex> off_reader2("tmp.off", same);
+
+ std::cout << "\ncomplex:" << complex.to_string() << std::endl;
+ std::cout << "\nsame:" << same.to_string() << std::endl;
+
+ BOOST_CHECK(complex == same);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_abstract_link) {
+ Complex complex;
+ Gudhi::skeleton_blocker::Skeleton_blocker_off_reader<Complex> off_reader("test2.off", complex);
+ BOOST_CHECK(off_reader.is_valid());
+
+ std::cout << "complex has " <<
+ complex.num_vertices() << " vertices, " <<
+ complex.num_blockers() << " blockers, " <<
+ complex.num_edges() << " edges and " <<
+ complex.num_triangles() << " triangles.";
+
+ BOOST_CHECK(complex.num_vertices() == 7);
+ BOOST_CHECK(complex.num_edges() == 12);
+ BOOST_CHECK(complex.num_triangles() == 6);
+
+ auto link_0 = complex.abstract_link(Vertex_handle(0));
+
+ std::cout << "\n link(0):" << link_0.to_string() << std::endl;
+
+ BOOST_CHECK(link_0.num_vertices() == 2);
+ BOOST_CHECK(link_0.num_edges() == 1);
+ BOOST_CHECK(link_0.num_blockers() == 0);
+
+ // Check the 2 link vertices
+ auto vertex_handle = link_0.vertex_range().begin();
+ BOOST_CHECK(link_0[*vertex_handle].get_id() == Root_vertex_handle(1));
+ vertex_handle++;
+ BOOST_CHECK(link_0[*(vertex_handle)].get_id() == Root_vertex_handle(4));
+
+ // Check the lonely link edge
+ auto edge_handle = link_0.edge_range().begin();
+ BOOST_CHECK(link_0[*edge_handle].first() == Root_vertex_handle(1));
+ BOOST_CHECK(link_0[*(edge_handle)].second() == Root_vertex_handle(4));
+
+ auto link_geometric_0 = complex.link(Vertex_handle(0));
+ std::cout << "\n link_geometric(0):" << link_geometric_0.to_string() << std::endl;
+
+ BOOST_CHECK(link_0 == link_geometric_0);
+
+ auto print_point = [&](Vertex_handle v) {
+ for (auto x : link_geometric_0.point(v)) std::cout << x << " ";
+ std::cout << std::endl;
+ };
+
+ std::for_each(link_geometric_0.vertex_range().begin(), link_geometric_0.vertex_range().end(), print_point);
+
+ // Check the 2 link vertices
+ vertex_handle = link_geometric_0.vertex_range().begin();
+ std::vector<double> point_1 = {0,2,0};
+ std::vector<double> point_4 = {-1,1,0};
+ BOOST_CHECK(link_geometric_0.point(*vertex_handle) == point_1);
+ vertex_handle++;
+ BOOST_CHECK(link_geometric_0.point(*vertex_handle) == point_4);
+
+}
diff --git a/src/Skeleton_blocker/test/test_skeleton_blocker_simplifiable.cpp b/src/Skeleton_blocker/test/test_skeleton_blocker_simplifiable.cpp
new file mode 100644
index 00000000..b714753d
--- /dev/null
+++ b/src/Skeleton_blocker/test/test_skeleton_blocker_simplifiable.cpp
@@ -0,0 +1,348 @@
+/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
+ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
+ * Author(s): David Salinas
+ *
+ * Copyright (C) 2014 Inria
+ *
+ * Modification(s):
+ * - YYYY/MM Author: Description of the modification
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <fstream>
+#include <sstream>
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE "skeleton_blocker_simplifiable"
+#include <boost/test/unit_test.hpp>
+#include <boost/mpl/list.hpp>
+
+#include <gudhi/Skeleton_blocker.h>
+
+template<typename ComplexType> class Skeleton_blocker_sub_complex;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simple_traits Traits;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_complex<Traits> Complex;
+typedef Complex::Vertex_handle Vertex_handle;
+typedef Complex::Root_vertex_handle Root_vertex_handle;
+typedef Gudhi::skeleton_blocker::Skeleton_blocker_simplex<Vertex_handle> Simplex;
+
+
+void build_complete(int n, Complex& complex) {
+ complex.clear();
+ for (int i = 0; i < n; i++)
+ complex.add_vertex();
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < i; j++)
+ complex.add_edge_without_blockers(Vertex_handle(i), Vertex_handle(j));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_contraction1) {
+ enum { a, b, x, y, z, n };
+ Complex complex(n);
+ build_complete(n, complex);
+ complex.remove_edge(static_cast<Vertex_handle> (b), static_cast<Vertex_handle> (z));
+ complex.add_blocker(Simplex(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (x),
+ static_cast<Vertex_handle> (y)));
+ complex.add_blocker(Simplex(static_cast<Vertex_handle> (b), static_cast<Vertex_handle> (x),
+ static_cast<Vertex_handle> (y)));
+
+ // Print result
+ std::cout << "complex before complex" << complex.to_string() << std::endl;
+
+ std::cout << std::endl << std::endl;
+ complex.contract_edge(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (b));
+ // Print result
+ std::cout << "ContractEdge(0,1)\n";
+ PRINT(complex.to_string());
+
+ // verification
+ for (int i = 0; i < 5; i++)
+ if (i != 1) BOOST_CHECK(complex.contains(Simplex(static_cast<Vertex_handle> (i))));
+ BOOST_CHECK(!complex.contains_edge(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (b)));
+
+ BOOST_CHECK(complex.contains_blocker(Simplex(*complex.get_address(Root_vertex_handle(a)),
+ *complex.get_address(Root_vertex_handle(x)),
+ *complex.get_address(Root_vertex_handle(y)))));
+
+ BOOST_CHECK(complex.num_edges() == 6);
+ BOOST_CHECK(complex.num_blockers() == 1);
+ Simplex sigma;
+ sigma.add_vertex(static_cast<Vertex_handle> (a));
+ sigma.add_vertex(static_cast<Vertex_handle> (x));
+ sigma.add_vertex(static_cast<Vertex_handle> (y));
+ sigma.add_vertex(static_cast<Vertex_handle> (z));
+ BOOST_CHECK(!(complex.contains(sigma)));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_contraction2) {
+ enum { a, b, x, y, z, n };
+ Complex complex(n);
+ build_complete(n, complex);
+ complex.remove_edge(static_cast<Vertex_handle> (b), static_cast<Vertex_handle> (x));
+ Simplex blocker;
+ blocker.add_vertex(static_cast<Vertex_handle> (a));
+ blocker.add_vertex(static_cast<Vertex_handle> (y));
+ blocker.add_vertex(static_cast<Vertex_handle> (z));
+
+ complex.add_blocker(blocker);
+
+ // Print result
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ complex.contract_edge(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (b));
+
+ std::cout << "complex.ContractEdge(a,b)" << complex.to_string();
+
+ std::cout << std::endl << std::endl;
+
+ // there should be one blocker (a,c,d,e) in the complex
+ BOOST_CHECK(complex.contains_blocker(Simplex(static_cast<Vertex_handle> (a), static_cast<Vertex_handle> (x),
+ static_cast<Vertex_handle> (y), static_cast<Vertex_handle> (z))));
+ BOOST_CHECK(complex.num_blockers() == 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_link_condition1) {
+ Complex complex(0);
+ // Build the complexes
+ build_complete(4, complex);
+ complex.add_blocker(Simplex(static_cast<Vertex_handle> (0), static_cast<Vertex_handle> (1), static_cast<Vertex_handle> (2)));
+
+ // Print result
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ BOOST_CHECK(complex.link_condition(Vertex_handle(1), Vertex_handle(2), true));
+
+ BOOST_CHECK(!complex.link_condition(Vertex_handle(1), Vertex_handle(2), false));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_collapse0) {
+ Complex complex(5);
+ build_complete(4, complex);
+ complex.add_vertex();
+ complex.add_edge_without_blockers(static_cast<Vertex_handle> (2), static_cast<Vertex_handle> (4));
+ complex.add_edge_without_blockers(static_cast<Vertex_handle> (3), static_cast<Vertex_handle> (4));
+ // Print result
+ std::cout << "initial complex :\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ Simplex simplex_123(static_cast<Vertex_handle> (1), static_cast<Vertex_handle> (2), static_cast<Vertex_handle> (3));
+ complex.remove_star(simplex_123);
+ std::cout << "complex.remove_star(1,2,3):\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ // verification
+ BOOST_CHECK(complex.contains_blocker(simplex_123));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_collapse1) {
+ Complex complex(5);
+ build_complete(4, complex);
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2), Vertex_handle(3)));
+ // Print result
+ std::cout << "initial complex :\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ Simplex simplex_123(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3));
+ complex.remove_star(simplex_123);
+ std::cout << "complex.remove_star(1,2,3):\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ // verification
+ BOOST_CHECK(complex.contains_blocker(simplex_123));
+ BOOST_CHECK(complex.num_blockers() == 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_collapse2) {
+ Complex complex(5);
+ build_complete(4, complex);
+ complex.add_vertex();
+ complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4));
+ complex.add_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3), Vertex_handle(4)));
+ // Print result
+ std::cout << "initial complex :\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ Simplex sigma(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3));
+ complex.remove_star(sigma);
+ std::cout << "complex.remove_star(1,2,3):\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ // verification
+ BOOST_CHECK(!complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(2),
+ Vertex_handle(3), Vertex_handle(4))));
+ BOOST_CHECK(complex.contains_blocker(sigma));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_collapse3) {
+ Complex complex(5);
+ build_complete(4, complex);
+ complex.add_vertex();
+ complex.add_edge_without_blockers(Vertex_handle(1), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4));
+ complex.add_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3), Vertex_handle(4)));
+ // Print result
+ std::cout << "initial complex:\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ complex.remove_star(static_cast<Vertex_handle> (2));
+ std::cout << "complex after remove star of 2:\n" << complex.to_string();
+
+ BOOST_CHECK(complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(3), Vertex_handle(4))));
+ BOOST_CHECK(!complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(2),
+ Vertex_handle(3), Vertex_handle(4))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_add_simplex) {
+ Complex complex(4);
+ build_complete(4, complex);
+ complex.add_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(3)));
+ std::cout << "initial complex:\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ complex.add_simplex(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(3)));
+ std::cout << "complex after add_simplex:\n" << complex.to_string();
+ BOOST_CHECK(complex.num_blockers() == 1);
+ BOOST_CHECK(complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1),
+ Vertex_handle(2), Vertex_handle(3))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_add_simplex2) {
+ Complex complex;
+ build_complete(4, complex);
+ // Print result
+ std::cout << "initial complex:\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ Complex copy(complex.num_vertices());
+
+ std::vector<Simplex> simplices(complex.complex_simplex_range().begin(), complex.complex_simplex_range().end());
+ sort(simplices.begin(), simplices.end(), [&](const Simplex& s1, const Simplex & s2) {
+ return s1.dimension() < s2.dimension();
+ });
+ for (const auto & simplex : simplices) {
+ if (!copy.contains(simplex) && simplex.dimension() == 1)
+ copy.add_edge_without_blockers(simplex.first_vertex(), simplex.last_vertex());
+ if (!copy.contains(simplex) && simplex.dimension() > 1)
+ copy.add_simplex(simplex);
+ }
+
+ std::cout << "complex after add_simplex:\n" << copy.to_string();
+
+ BOOST_CHECK(complex.num_blockers() == copy.num_blockers());
+ BOOST_CHECK(complex.num_edges() == copy.num_edges());
+ BOOST_CHECK(complex.num_vertices() == copy.num_vertices());
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_add_simplex3) {
+ Complex complex(5);
+ build_complete(5, complex);
+ complex.remove_edge(Vertex_handle(3), Vertex_handle(4));
+ Simplex sigma(Vertex_handle(0), Vertex_handle(1), Vertex_handle(2));
+ complex.add_blocker(sigma);
+ // Print result
+ std::cout << "initial complex:\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ complex.add_simplex(sigma);
+ //should create two blockers 0123 and 0124
+ std::cout << "complex after adding simplex 012:\n" << complex.to_string();
+ BOOST_CHECK(complex.num_blockers() == 2);
+ BOOST_CHECK(complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1),
+ Vertex_handle(2), Vertex_handle(3))));
+ BOOST_CHECK(complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1),
+ Vertex_handle(2), Vertex_handle(4))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_add_simplex4) {
+ int n = 6;
+ Complex complex(n);
+
+ // add all simplex 0..n without i
+ for (int i = 0; i < n; i++) {
+ Simplex s;
+ for (int k = 0; k < n; k++)
+ s.add_vertex(Vertex_handle(k));
+ s.remove_vertex(Vertex_handle(i));
+ complex.add_simplex(s);
+
+ //at step i there is only blocker 0..i
+ BOOST_CHECK(!(i < 2 && complex.num_blockers() > 0));
+ if (i >= 2 && complex.num_blockers() != 1) {
+ Simplex b;
+ for (int k = 0; k < i; k++)
+ b.add_vertex(Vertex_handle(i));
+ BOOST_CHECK(complex.contains_blocker(b));
+ }
+ }
+ Simplex s;
+ for (int k = 0; k < n; k++)
+ s.add_vertex(Vertex_handle(k));
+ BOOST_CHECK(complex.num_blockers() == 1);
+ BOOST_CHECK(complex.contains_blocker(s));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_add_edge) {
+ Complex complex(4);
+ for (unsigned i = 0u; i < 4; i++)
+ complex.add_edge(Vertex_handle(i), Vertex_handle((i + 1) % 4));
+
+ // Print result
+ std::cout << "initial complex:\n" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ complex.add_edge(Vertex_handle(1), Vertex_handle(3));
+ //should create two blockers 013 and 012
+ std::cout << "complex after adding edge 13:\n" << complex.to_string();
+ BOOST_CHECK(complex.num_blockers() == 2);
+ BOOST_CHECK(complex.contains_blocker(Simplex(Vertex_handle(0), Vertex_handle(1), Vertex_handle(3))));
+ BOOST_CHECK(complex.contains_blocker(Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3))));
+}
+
+BOOST_AUTO_TEST_CASE(test_skeleton_blocker_simplifiable_remove_popable_blockers) {
+ Complex complex;
+ build_complete(4, complex);
+ complex.add_vertex();
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4));
+ Simplex sigma1 = Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3));
+ Simplex sigma2 = Simplex(Vertex_handle(2), Vertex_handle(3), Vertex_handle(4));
+
+ complex.add_blocker(sigma1);
+ complex.add_blocker(sigma2);
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ std::cout << "complex.RemovePopableBlockers();" << std::endl;
+ complex.remove_popable_blockers();
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+
+ BOOST_CHECK(complex.num_blockers() == 1);
+
+ // test 2
+ complex.clear();
+ build_complete(4, complex);
+ complex.add_vertex();
+ complex.add_vertex();
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(4));
+ complex.add_edge_without_blockers(Vertex_handle(2), Vertex_handle(5));
+ complex.add_edge_without_blockers(Vertex_handle(3), Vertex_handle(5));
+ complex.add_edge_without_blockers(Vertex_handle(4), Vertex_handle(5));
+ sigma1 = Simplex(Vertex_handle(1), Vertex_handle(2), Vertex_handle(3));
+ sigma2 = Simplex(Vertex_handle(2), Vertex_handle(3), Vertex_handle(4));
+
+ complex.add_blocker(sigma1);
+ complex.add_blocker(sigma2);
+ std::cout << "complex complex" << complex.to_string();
+ std::cout << std::endl << std::endl;
+ std::cout << "complex.RemovePopableBlockers();" << std::endl;
+ complex.remove_popable_blockers();
+ std::cout << "complex complex" << complex.to_string();
+
+ std::cout << std::endl << std::endl;
+ BOOST_CHECK(complex.num_blockers() == 0);
+}