23 #ifndef GUDHI_SKELETON_BLOCKER_CONTRACTOR_H_
24 #define GUDHI_SKELETON_BLOCKER_CONTRACTOR_H_
30 #include "gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h"
34 #include <boost/scoped_array.hpp>
35 #include <boost/scoped_ptr.hpp>
38 #include "gudhi/Contraction/Edge_profile.h"
39 #include "gudhi/Contraction/policies/Cost_policy.h"
40 #include "gudhi/Contraction/policies/Edge_length_cost.h"
41 #include "gudhi/Contraction/policies/Placement_policy.h"
42 #include "gudhi/Contraction/policies/First_vertex_placement.h"
44 #include "gudhi/Contraction/policies/Valid_contraction_policy.h"
45 #include "gudhi/Contraction/policies/Dummy_valid_contraction.h"
46 #include "gudhi/Contraction/policies/Link_condition_valid_contraction.h"
48 #include "gudhi/Contraction/policies/Contraction_visitor.h"
50 #include "gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h"
52 #include "gudhi/Utils.h"
56 namespace contraction {
61 template <
class Profile>
62 Placement_policy<Profile>* make_first_vertex_placement(){
63 return new First_vertex_placement<Profile>();
66 template <
class Profile>
67 Valid_contraction_policy<Profile>* make_link_valid_contraction(){
68 return new Link_condition_valid_contraction<Profile>();
75 template <
class Profile>
78 typedef typename Profile::Point Point;
79 typedef typename Profile::Complex Complex;
80 typedef typename Complex::Vertex_handle Vertex_handle;
83 void on_contracted(
const Profile &profile, boost::optional< Point > placement)
override{
84 std::list<Vertex_handle> vertex_to_check;
85 vertex_to_check.push_front(profile.v0_handle());
87 while(!vertex_to_check.empty()){
88 Vertex_handle v = vertex_to_check.front();
89 vertex_to_check.pop_front();
91 bool blocker_popable_found=
true;
92 while (blocker_popable_found){
93 blocker_popable_found =
false;
94 for(
auto block : profile.complex().blocker_range(v)){
95 if (profile.complex().is_popable_blocker(block)) {
96 for(Vertex_handle nv : *block)
97 if(nv!=v) vertex_to_check.push_back(nv);
98 profile.complex().delete_blocker(block);
99 blocker_popable_found =
true;
108 template <
class Profile>
135 class GeometricSimplifiableComplex,
136 class EdgeProfile = Edge_profile<GeometricSimplifiableComplex>
140 GeometricSimplifiableComplex& complex_;
143 typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex;
144 typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle;
145 typedef typename GeometricSimplifiableComplex::Simplex_handle Simplex_handle;
146 typedef typename GeometricSimplifiableComplex::Simplex_handle_iterator Simplex_handle_iterator;
150 typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle;
152 typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge;
153 typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle;
154 typedef typename GeometricSimplifiableComplex::Point Point;
156 typedef EdgeProfile Profile;
163 typedef Edge_profile_factory<EdgeProfile> Edge_profile_factory_;
167 typedef boost::optional<double> Cost_type;
168 typedef boost::optional<Point> Placement_type ;
170 typedef size_t size_type;
180 Compare_id() : algorithm_(0) {}
182 Compare_id(
Self const* aAlgorithm ) : algorithm_(aAlgorithm) {}
184 bool operator() ( Edge_handle a, Edge_handle b )
const
186 return algorithm_->get_undirected_edge_id(a) < algorithm_->get_undirected_edge_id(b);
189 Self const* algorithm_ ;
194 Compare_cost() : algorithm_(0) {
197 Compare_cost(
Self const* aAlgorithm ) : algorithm_(aAlgorithm) {
200 bool operator() ( Edge_handle a, Edge_handle b )
const
205 return algorithm_->get_data(a).cost() < algorithm_->get_data(b).cost();
208 Self const* algorithm_ ;
212 struct Undirected_edge_id : boost::put_get_helper<size_type, Undirected_edge_id>
214 typedef boost::readable_property_map_tag category;
215 typedef size_type value_type;
216 typedef size_type reference;
217 typedef Edge_handle key_type;
219 Undirected_edge_id() : algorithm_(0) {}
221 Undirected_edge_id(
Self const* aAlgorithm ) : algorithm_(aAlgorithm) {}
223 size_type operator[] ( Edge_handle e )
const {
return algorithm_->get_undirected_edge_id(e); }
225 Self const* algorithm_ ;
228 typedef CGAL::Modifiable_priority_queue<Edge_handle,Compare_cost,Undirected_edge_id> PQ ;
229 typedef typename PQ::handle pq_handle ;
239 Edge_data() : PQHandle_(),cost_() {}
241 Cost_type
const& cost()
const {
return cost_ ; }
242 Cost_type & cost() {
return cost_ ; }
244 pq_handle PQ_handle()
const {
return PQHandle_ ;}
246 bool is_in_PQ()
const {
return PQHandle_ != PQ::null_handle() ; }
248 void set_PQ_handle( pq_handle h ) { PQHandle_ = h ; }
250 void reset_PQ_handle() { PQHandle_ = PQ::null_handle() ; }
253 pq_handle PQHandle_ ;
257 typedef Edge_data* Edge_data_ptr ;
258 typedef boost::scoped_array<Edge_data> Edge_data_array ;
261 int get_undirected_edge_id ( Edge_handle edge )
const {
262 return complex_[edge].index() ;
266 const Edge_data& get_data ( Edge_handle edge )
const
268 return edge_data_array_[get_undirected_edge_id(edge)];
272 Edge_data& get_data ( Edge_handle edge )
274 return edge_data_array_[get_undirected_edge_id(edge)];
277 Cost_type get_cost(
const Profile & profile)
const{
278 return (*cost_policy_)(profile,get_placement(profile));
281 Profile create_profile(Edge_handle edge)
const{
282 if(edge_profile_factory_)
283 return edge_profile_factory_->make_profile(complex_,edge);
285 return Profile(complex_,edge);
289 void insert_in_PQ( Edge_handle edge, Edge_data& data )
291 data.set_PQ_handle(heap_PQ_->push(edge));
292 ++current_num_edges_heap_;
295 void update_in_PQ( Edge_handle edge, Edge_data& data )
297 data.set_PQ_handle(heap_PQ_->update(edge,data.PQ_handle())) ;
300 void remove_from_PQ( Edge_handle edge, Edge_data& data )
302 data.set_PQ_handle(heap_PQ_->erase(edge,data.PQ_handle()));
303 --current_num_edges_heap_;
306 boost::optional<Edge_handle> pop_from_PQ() {
307 boost::optional<Edge_handle> edge = heap_PQ_->extract_top();
310 get_data(*edge).reset_PQ_handle();
326 void collect_edges(){
330 size_type size = complex_.num_edges();
331 DBG(
"Collecting edges ...");
332 DBGMSG(
"num edges :",size);
334 edge_data_array_.reset(
new Edge_data[size] ) ;
336 heap_PQ_.reset(
new PQ (size, Compare_cost(
this), Undirected_edge_id(
this) ) ) ;
341 for(
auto edge : complex_.edge_range()){
343 complex_[edge].index() =
id++;
344 Profile
const& profile = create_profile(edge);
345 Edge_data& data = get_data(edge);
346 data.cost() = get_cost(profile) ;
347 ++initial_num_edges_heap_;
348 insert_in_PQ(edge,data);
349 if(contraction_visitor_) contraction_visitor_->on_collected(profile,data.cost());
352 DBG(
"Edges collected.");
356 bool should_stop(
double lCost,
const Profile &profile)
const{
360 boost::optional<Point> get_placement(
const Profile& profile)
const{
361 return (*placement_policy_)(profile);
364 bool is_contraction_valid( Profile
const& profile, Placement_type placement )
const{
365 return (*valid_contraction_policy_)(profile,placement);
380 DBG(
"\n\nContract edges");
381 int num_contraction = 0 ;
383 bool unspecified_num_contractions = (num_max_contractions == -1);
387 boost::optional<Edge_handle> edge ;
388 while ( (edge = pop_from_PQ())&& ((num_contraction<num_max_contractions)||(unspecified_num_contractions)))
390 Profile
const& profile = create_profile(*edge);
391 Cost_type cost(get_data(*edge).cost());
392 if(contraction_visitor_) contraction_visitor_->on_selected(profile,cost,0,0);
394 DBGMSG(
"\n\n---- Pop edge - num vertices :",complex_.num_vertices());
397 DBGMSG(
"sqrt(cost):",std::sqrt(*cost));
398 if (should_stop(*cost,profile) )
400 if(contraction_visitor_) contraction_visitor_->on_stop_condition_reached();
404 Placement_type placement = get_placement(profile);
405 if ( is_contraction_valid(profile,placement) && placement )
407 DBG(
"contraction_valid");
408 contract_edge(profile,placement);
413 DBG(
"contraction not valid");
414 if(contraction_visitor_) contraction_visitor_->on_non_valid(profile);
419 DBG(
"uncomputable cost");
422 if(contraction_visitor_) contraction_visitor_->on_stop_condition_reached();
426 bool is_in_heap(Edge_handle edge)
const{
427 if(heap_PQ_->empty())
return false;
429 return edge_data_array_[get_undirected_edge_id(edge)].is_in_PQ();
433 bool is_heap_empty()
const{
434 return heap_PQ_->empty();
443 boost::optional<std::pair<Edge_handle,Placement_type > >
top_edge(){
444 boost::optional<std::pair<Edge_handle,Placement_type > > res;
446 if(!heap_PQ_->empty()) {
447 auto edge = heap_PQ_->top();
448 Profile
const& profile = create_profile(edge);
449 Placement_type placement = get_placement(profile);
450 res = make_pair(edge,placement);
451 DBGMSG(
"top edge:",complex_[edge]);
470 edge_profile_factory_(0),
471 initial_num_edges_heap_(0),
472 current_num_edges_heap_(0)
474 complex_.set_visitor(
this);
475 if(contraction_visitor_) contraction_visitor_->on_started(complex);
488 Edge_profile_factory_* edge_profile_factory = NULL
491 cost_policy_(cost_policy),
492 placement_policy_(placement_policy),
493 valid_contraction_policy_(valid_contraction_policy),
494 contraction_visitor_(contraction_visitor),
495 edge_profile_factory_(edge_profile_factory),
496 initial_num_edges_heap_(0),
497 current_num_edges_heap_(0)
499 complex_.set_visitor(
this);
500 if(contraction_visitor) contraction_visitor->on_started(complex);
506 complex_.set_visitor(0);
512 void contract_edge(
const Profile& profile, Placement_type placement ) {
513 if(contraction_visitor_) contraction_visitor_->on_contracting(profile,placement);
515 assert(complex_.contains_vertex(profile.v0_handle()));
516 assert(complex_.contains_vertex(profile.v1_handle()));
519 profile.complex().point(profile.v0_handle()) = *placement;
524 complex_.contract_edge(profile.v0_handle(),profile.v1_handle());
526 assert(complex_.contains_vertex(profile.v0_handle()));
527 assert(!complex_.contains_vertex(profile.v1_handle()));
529 update_changed_edges();
532 if(contraction_visitor_) contraction_visitor_->on_contracted(profile,placement);
539 std::vector< Edge_handle > changed_edges_;
545 inline void on_changed_edge(Vertex_handle a,Vertex_handle b)
override{
546 boost::optional<Edge_handle> ab(complex_[std::make_pair(a,b)]);
548 changed_edges_.push_back(*ab);
551 void update_changed_edges(){
557 for(
auto ab : changed_edges_){
561 Edge_data& data = get_data(ab);
562 Profile
const& profile = create_profile(ab);
563 data.cost() = get_cost(profile) ;
564 if ( data.is_in_PQ()){
565 update_in_PQ(ab,data);
568 insert_in_PQ(ab,data);
571 changed_edges_.clear();
576 void on_remove_edge(Vertex_handle a,Vertex_handle b)
override{
578 boost::optional<Edge_handle> ab((complex_[std::make_pair(a,b)]));
580 Edge_data& lData = get_data(*ab) ;
581 if ( lData.is_in_PQ() )
583 remove_from_PQ(*ab,lData) ;
592 void on_swaped_edge(Vertex_handle a,Vertex_handle b,Vertex_handle x)
override{
593 boost::optional<Edge_handle> ax(complex_[std::make_pair(a,x)]);
594 boost::optional<Edge_handle> bx(complex_[std::make_pair(b,x)]);
596 complex_[*ax].index() =complex_[*bx].index();
604 void on_delete_blocker(
const Simplex_handle * blocker)
override{
611 Simplex_handle blocker_copy(*blocker);
612 for (
auto x = blocker_copy.begin(); x!= blocker_copy.end(); ++x){
613 for(
auto y=x ; ++y != blocker_copy.end(); ){
614 auto edge_descr(complex_[std::make_pair(*x,*y)]);
616 Edge_data& data = get_data(*edge_descr);
617 Profile
const& profile = create_profile(*edge_descr);
618 data.cost() = get_cost(profile) ;
625 if ( !data.is_in_PQ() ){
626 insert_in_PQ(*edge_descr,data);
634 std::shared_ptr<Cost_policy_> cost_policy_;
635 std::shared_ptr<Placement_policy_> placement_policy_;
636 std::shared_ptr<Valid_contraction_policy_> valid_contraction_policy_;
637 std::shared_ptr<Contraction_visitor_> contraction_visitor_;
641 std::shared_ptr<Edge_profile_factory_> edge_profile_factory_;
642 Edge_data_array edge_data_array_ ;
644 boost::scoped_ptr<PQ> heap_PQ_ ;
645 int initial_num_edges_heap_;
646 int current_num_edges_heap_;
Skeleton_blocker_contractor(GeometricSimplifiableComplex &complex)
Constructor with default policies.
Definition: Skeleton_blocker_contractor.h:464
Places the contracted point onto the first point of the edge.
Definition: First_vertex_placement.h:36
void contract_edges(int num_max_contractions=-1)
Contract edges.
Definition: Skeleton_blocker_contractor.h:378
Policy that only accept edges verifying the link condition (and therefore whose contraction preservin...
Definition: Link_condition_valid_contraction.h:39
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:483
Interface for a visitor of the edge contraction process.
Definition: Contraction_visitor.h:39
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:443
A dummy visitor of a simplicial complex that does nothing.
Definition: Skeleton_blocker_complex_visitor.h:74
Policy to specify the cost of contracting an edge.
Definition: Cost_policy.h:36
return a cost corresponding to the squared length of the edge
Definition: Edge_length_cost.h:36
Class that allows to contract iteratively edges of a simplicial complex.
Definition: Skeleton_blocker_contractor.h:138
Policy to specify if an edge contraction is valid or not.
Definition: Valid_contraction_policy.h:33
Visitor to remove popable blockers after an edge contraction.
Definition: Skeleton_blocker_contractor.h:76
Policy to specify where the merged point had to be placed after an edge contraction.
Definition: Placement_policy.h:36