12 #ifndef SKELETON_BLOCKER_CONTRACTOR_H_
13 #define SKELETON_BLOCKER_CONTRACTOR_H_
15 #include <gudhi/Contraction/Edge_profile.h>
16 #include <gudhi/Contraction/policies/Cost_policy.h>
17 #include <gudhi/Contraction/policies/Edge_length_cost.h>
18 #include <gudhi/Contraction/policies/Placement_policy.h>
19 #include <gudhi/Contraction/policies/First_vertex_placement.h>
20 #include <gudhi/Contraction/policies/Valid_contraction_policy.h>
21 #include <gudhi/Contraction/policies/Dummy_valid_contraction.h>
22 #include <gudhi/Contraction/policies/Link_condition_valid_contraction.h>
23 #include <gudhi/Contraction/policies/Contraction_visitor.h>
25 #include <gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h>
26 #include <gudhi/Debug_utils.h>
29 #include <CGAL/Modifiable_priority_queue.h>
30 #include <CGAL/version.h>
32 #include <boost/scoped_array.hpp>
33 #include <boost/scoped_ptr.hpp>
42 #if CGAL_VERSION_NR < 1041101000
43 # error Skeleton_blocker_contractor is only available for CGAL >= 4.11
48 namespace contraction {
50 template <
class Profile>
51 Placement_policy<Profile>* make_first_vertex_placement() {
52 return new First_vertex_placement<Profile>();
55 template <
class Profile>
56 Valid_contraction_policy<Profile>* make_link_valid_contraction() {
57 return new Link_condition_valid_contraction<Profile>();
63 template <
class Profile>
66 typedef typename Profile::Point Point;
67 typedef typename Profile::Complex Complex;
70 void on_contracted(
const Profile &profile, boost::optional< Point > placement)
override {
71 profile.complex().remove_all_popable_blockers(profile.v0_handle());
75 template <
class Profile>
96 template<
class GeometricSimplifiableComplex,
class EdgeProfile = Edge_profile<GeometricSimplifiableComplex>>
98 typename GeometricSimplifiableComplex::Vertex_handle> {
99 GeometricSimplifiableComplex& complex_;
102 typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex;
103 typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle;
104 typedef typename GeometricSimplifiableComplex::Simplex Simplex;
105 typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle;
106 typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge;
107 typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle;
108 typedef typename GeometricSimplifiableComplex::Point Point;
110 typedef EdgeProfile Profile;
117 typedef Edge_profile_factory<EdgeProfile> Edge_profile_factory_;
121 typedef boost::optional<double> Cost_type;
122 typedef boost::optional<Point> Placement_type;
124 typedef size_t size_type;
130 Compare_id() : algorithm_(0) { }
132 Compare_id(
Self const* aAlgorithm) : algorithm_(aAlgorithm) { }
134 bool operator()(Edge_handle a, Edge_handle b)
const {
135 return algorithm_->get_undirected_edge_id(a) < algorithm_->get_undirected_edge_id(b);
138 Self const* algorithm_;
141 struct Compare_cost {
142 Compare_cost() : algorithm_(0) { }
144 Compare_cost(
Self const* aAlgorithm) : algorithm_(aAlgorithm) { }
146 bool operator()(Edge_handle a, Edge_handle b)
const {
151 return algorithm_->get_data(a).cost() < algorithm_->get_data(b).cost();
154 Self const* algorithm_;
157 struct Undirected_edge_id : boost::put_get_helper<size_type, Undirected_edge_id> {
158 typedef boost::readable_property_map_tag category;
159 typedef size_type value_type;
160 typedef size_type reference;
161 typedef Edge_handle key_type;
163 Undirected_edge_id() : algorithm_(0) { }
165 Undirected_edge_id(
Self const* aAlgorithm) : algorithm_(aAlgorithm) { }
167 size_type operator[](Edge_handle e)
const {
168 return algorithm_->get_undirected_edge_id(e);
171 Self const* algorithm_;
174 #if CGAL_VERSION_NR < 1050500000
175 typedef CGAL::Modifiable_priority_queue<Edge_handle, Compare_cost, Undirected_edge_id> PQ;
177 typedef CGAL::Modifiable_priority_queue<Edge_handle, Compare_cost, Undirected_edge_id, CGAL::CGAL_BOOST_PENDING_RELAXED_HEAP> PQ;
180 typedef bool pq_handle;
189 Edge_data() : PQHandle_(), cost_() { }
191 Cost_type
const& cost()
const {
199 pq_handle PQ_handle()
const {
203 bool is_in_PQ()
const {
204 return PQHandle_ !=
false;
207 void set_PQ_handle(pq_handle h) {
211 void reset_PQ_handle() {
219 typedef Edge_data* Edge_data_ptr;
220 typedef boost::scoped_array<Edge_data> Edge_data_array;
222 int get_undirected_edge_id(Edge_handle edge)
const {
223 return complex_[edge].index();
226 const Edge_data& get_data(Edge_handle edge)
const {
227 return edge_data_array_[get_undirected_edge_id(edge)];
230 Edge_data& get_data(Edge_handle edge) {
231 return edge_data_array_[get_undirected_edge_id(edge)];
234 Cost_type get_cost(
const Profile & profile)
const {
235 return (*cost_policy_)(profile, get_placement(profile));
238 Profile create_profile(Edge_handle edge)
const {
239 if (edge_profile_factory_)
240 return edge_profile_factory_->make_profile(complex_, edge);
242 return Profile(complex_, edge);
245 void insert_in_PQ(Edge_handle edge, Edge_data& data) {
246 heap_PQ_->push(edge);
247 data.set_PQ_handle(
true);
248 ++current_num_edges_heap_;
251 void update_in_PQ(Edge_handle edge, Edge_data& data) {
252 #if CGAL_VERSION_NR < 1050500000
253 data.set_PQ_handle(heap_PQ_->update(edge, data.PQ_handle()));
255 heap_PQ_->update(edge);
259 void remove_from_PQ(Edge_handle edge, Edge_data& data) {
260 heap_PQ_->erase(edge);
261 data.set_PQ_handle(
false);
262 --current_num_edges_heap_;
265 boost::optional<Edge_handle> pop_from_PQ() {
266 boost::optional<Edge_handle> edge;
267 if (!heap_PQ_->empty()) {
268 edge = heap_PQ_->top();
270 get_data(*edge).reset_PQ_handle();
283 void collect_edges() {
287 size_type size = complex_.num_edges();
288 DBG(
"Collecting edges ...");
289 DBGMSG(
"num edges :", size);
291 edge_data_array_.reset(
new Edge_data[size]);
293 heap_PQ_.reset(
new PQ(size, Compare_cost(
this), Undirected_edge_id(
this)));
298 for (
auto edge : complex_.edge_range()) {
299 complex_[edge].index() =
id++;
300 Profile
const& profile = create_profile(edge);
301 Edge_data& data = get_data(edge);
302 data.cost() = get_cost(profile);
303 ++initial_num_edges_heap_;
304 insert_in_PQ(edge, data);
305 if (contraction_visitor_) contraction_visitor_->on_collected(profile, data.cost());
308 DBG(
"Edges collected.");
311 bool should_stop(
double lCost,
const Profile &profile)
const {
315 boost::optional<Point> get_placement(
const Profile& profile)
const {
316 return (*placement_policy_)(profile);
319 bool is_contraction_valid(Profile
const& profile, Placement_type placement)
const {
320 if (!valid_contraction_policy_)
return true;
321 return (*valid_contraction_policy_)(profile, placement);
335 DBG(
"\n\nContract edges");
336 int num_contraction = 0;
338 bool unspecified_num_contractions = (num_max_contractions == -1);
342 boost::optional<Edge_handle> edge;
343 while ((edge = pop_from_PQ()) && ((num_contraction < num_max_contractions) || (unspecified_num_contractions))) {
344 Profile
const& profile = create_profile(*edge);
345 Cost_type cost(get_data(*edge).cost());
346 if (contraction_visitor_) contraction_visitor_->on_selected(profile, cost, 0, 0);
348 DBGMSG(
"\n\n---- Pop edge - num vertices :", complex_.num_vertices());
351 DBGMSG(
"sqrt(cost):", std::sqrt(*cost));
352 if (should_stop(*cost, profile)) {
353 if (contraction_visitor_) contraction_visitor_->on_stop_condition_reached();
357 Placement_type placement = get_placement(profile);
358 if (is_contraction_valid(profile, placement) && placement) {
359 DBG(
"contraction_valid");
360 contract_edge(profile, placement);
363 DBG(
"contraction not valid");
364 if (contraction_visitor_) contraction_visitor_->on_non_valid(profile);
367 DBG(
"uncomputable cost");
370 if (contraction_visitor_) contraction_visitor_->on_stop_condition_reached();
373 bool is_in_heap(Edge_handle edge)
const {
374 if (heap_PQ_->empty()) {
377 return edge_data_array_[get_undirected_edge_id(edge)].is_in_PQ();
381 bool is_heap_empty()
const {
382 return heap_PQ_->empty();
390 boost::optional<std::pair<Edge_handle, Placement_type > >
top_edge() {
391 boost::optional<std::pair<Edge_handle, Placement_type > > res;
393 if (!heap_PQ_->empty()) {
394 auto edge = heap_PQ_->top();
395 Profile
const& profile = create_profile(edge);
396 Placement_type placement = get_placement(profile);
397 res = std::make_pair(edge, placement);
398 DBGMSG(
"top edge:", complex_[edge]);
415 edge_profile_factory_(0),
416 initial_num_edges_heap_(0),
417 current_num_edges_heap_(0) {
418 complex_.set_visitor(
this);
419 if (contraction_visitor_) contraction_visitor_->on_started(complex);
433 Edge_profile_factory_* edge_profile_factory = NULL) :
435 cost_policy_(cost_policy),
436 placement_policy_(placement_policy),
437 valid_contraction_policy_(valid_contraction_policy),
438 contraction_visitor_(contraction_visitor),
439 edge_profile_factory_(edge_profile_factory),
440 initial_num_edges_heap_(0),
441 current_num_edges_heap_(0) {
442 complex_.set_visitor(
this);
443 if (contraction_visitor) contraction_visitor->on_started(complex);
448 complex_.set_visitor(0);
452 void contract_edge(
const Profile& profile, Placement_type placement) {
453 if (contraction_visitor_) contraction_visitor_->on_contracting(profile, placement);
455 assert(complex_.contains_vertex(profile.v0_handle()));
456 assert(complex_.contains_vertex(profile.v1_handle()));
459 profile.complex().point(profile.v0_handle()) = *placement;
464 complex_.contract_edge(profile.v0_handle(), profile.v1_handle());
466 assert(complex_.contains_vertex(profile.v0_handle()));
467 assert(!complex_.contains_vertex(profile.v1_handle()));
469 update_changed_edges();
472 if (contraction_visitor_) contraction_visitor_->on_contracted(profile, placement);
478 std::vector< Edge_handle > changed_edges_;
485 boost::optional<Edge_handle> ab(complex_[std::make_pair(a, b)]);
487 changed_edges_.push_back(*ab);
490 void update_changed_edges() {
495 for (
auto ab : changed_edges_) {
499 Edge_data& data = get_data(ab);
500 Profile
const& profile = create_profile(ab);
501 data.cost() = get_cost(profile);
502 if (data.is_in_PQ()) {
503 update_in_PQ(ab, data);
505 insert_in_PQ(ab, data);
508 changed_edges_.clear();
514 boost::optional<Edge_handle> ab((complex_[std::make_pair(a, b)]));
516 Edge_data& lData = get_data(*ab);
517 if (lData.is_in_PQ()) {
518 remove_from_PQ(*ab, lData);
529 boost::optional<Edge_handle> ax(complex_[std::make_pair(a, x)]);
530 boost::optional<Edge_handle> bx(complex_[std::make_pair(b, x)]);
532 complex_[*ax].index() = complex_[*bx].index();
541 void on_delete_blocker(
const Simplex * blocker)
override {
548 Simplex blocker_copy(*blocker);
549 for (
auto x = blocker_copy.begin(); x != blocker_copy.end(); ++x) {
550 for (
auto y = x; ++y != blocker_copy.end();) {
551 auto edge_descr(complex_[std::make_pair(*x, *y)]);
553 Edge_data& data = get_data(*edge_descr);
554 Profile
const& profile = create_profile(*edge_descr);
555 data.cost() = get_cost(profile);
562 if (!data.is_in_PQ()) {
563 insert_in_PQ(*edge_descr, data);
571 std::shared_ptr<Cost_policy_> cost_policy_;
572 std::shared_ptr<Placement_policy_> placement_policy_;
573 std::shared_ptr<Valid_contraction_policy_> valid_contraction_policy_;
574 std::shared_ptr<Contraction_visitor_> contraction_visitor_;
578 std::shared_ptr<Edge_profile_factory_> edge_profile_factory_;
579 Edge_data_array edge_data_array_;
581 boost::scoped_ptr<PQ> heap_PQ_;
582 int initial_num_edges_heap_;
583 int current_num_edges_heap_;
Visitor to remove popable blockers after an edge contraction.
Definition: Skeleton_blocker_contractor.h:64
Interface for a visitor of the edge contraction process.
Definition: Contraction_visitor.h:27
Policy to specify the cost of contracting an edge.
Definition: Cost_policy.h:25
return a cost corresponding to the squared length of the edge
Definition: Edge_length_cost.h:24
Places the contracted point onto the first point of the edge.
Definition: First_vertex_placement.h:24
Policy that only accept edges verifying the link condition (and therefore whose contraction preservin...
Definition: Link_condition_valid_contraction.h:27
Policy to specify where the merged point had to be placed after an edge contraction.
Definition: Placement_policy.h:25
Class that allows to contract iteratively edges of a simplicial complex.
Definition: Skeleton_blocker_contractor.h:98
void contract_edges(int num_max_contractions=-1)
Contract edges.
Definition: Skeleton_blocker_contractor.h:334
boost::optional< std::pair< Edge_handle, Placement_type > > top_edge()
Returns an Edge_handle and a Placement_type. This pair consists in the edge with the lowest cost in t...
Definition: Skeleton_blocker_contractor.h:390
Skeleton_blocker_contractor(GeometricSimplifiableComplex &complex, Cost_policy_ *cost_policy, Placement_policy_ *placement_policy=new First_vertex_placement< Profile >, Valid_contraction_policy_ *valid_contraction_policy=new Link_condition_valid_contraction< Profile >, Contraction_visitor_ *contraction_visitor=new Contraction_visitor_(), Edge_profile_factory_ *edge_profile_factory=NULL)
Constructor with customed policies.
Definition: Skeleton_blocker_contractor.h:427
Skeleton_blocker_contractor(GeometricSimplifiableComplex &complex)
Constructor with default policies.
Definition: Skeleton_blocker_contractor.h:409
Policy to specify if an edge contraction is valid or not.
Definition: Valid_contraction_policy.h:23
A dummy visitor of a simplicial complex that does nothing.
Definition: Skeleton_blocker_complex_visitor.h:65
Gudhi namespace.
Definition: SimplicialComplexForAlpha.h:14
Definition: SkeletonBlockerDS.h:56
Handle type for the vertices of a cell complex.
Definition: VertexHandle.h:15