[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

merge_graph_adaptor.hxx
1
2/************************************************************************/
3/* */
4/* Copyright 2014 by Thorsten Beier and Ullrich Koethe */
5/* */
6/* This file is part of the VIGRA computer vision library. */
7/* The VIGRA Website is */
8/* http://hci.iwr.uni-heidelberg.de/vigra/ */
9/* Please direct questions, bug reports, and contributions to */
10/* ullrich.koethe@iwr.uni-heidelberg.de or */
11/* vigra@informatik.uni-hamburg.de */
12/* */
13/* Permission is hereby granted, free of charge, to any person */
14/* obtaining a copy of this software and associated documentation */
15/* files (the "Software"), to deal in the Software without */
16/* restriction, including without limitation the rights to use, */
17/* copy, modify, merge, publish, distribute, sublicense, and/or */
18/* sell copies of the Software, and to permit persons to whom the */
19/* Software is furnished to do so, subject to the following */
20/* conditions: */
21/* */
22/* The above copyright notice and this permission notice shall be */
23/* included in all copies or substantial portions of the */
24/* Software. */
25/* */
26/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
27/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
28/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
29/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
30/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
31/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
32/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
33/* OTHER DEALINGS IN THE SOFTWARE. */
34/* */
35/************************************************************************/
36
37
38#ifndef VIGRA_NEW_MERGE_GRAPH_HXX
39#define VIGRA_NEW_MERGE_GRAPH_HXX
40
41
42/* delegates / callbacks */
43#include "delegate/delegate.hxx"
44
45/* std library */
46#include <vector>
47#include <algorithm>
48#include <cmath>
49#include <stdexcept>
50#include <map>
51
52/* vigra */
53#include "multi_array.hxx"
54#include "tinyvector.hxx"
55#include "multi_array.hxx"
56#include "graphs.hxx"
57#include "graph_maps.hxx"
58#include "graph_item_impl.hxx"
59#include "random_access_set.hxx"
60#include "iteratorfacade.hxx"
61
62
63namespace vigra {
64
65namespace merge_graph_detail {
66
67// ufd data structure structure for merge graph
68// only useful for merge graphs internal usage
69template<class T>
70class IterablePartition;
71
72// representative element iterator
73// for IterablePartition
74// only useful for merge graphs internal usage
75template<class T>
76struct ConstRepIter
77: public ForwardIteratorFacade<
78 ConstRepIter<T>,T,true
79 >
80
81{
82 typedef IterablePartition<T> IterablePartitionType;
83 ConstRepIter(const IterablePartitionType & p,const T cr)
84 : partition_(&p),
85 currentRep_(cr){
86 }
87
88
89 ConstRepIter()
90 : partition_(NULL),
91 currentRep_()
92 {
93 }
94
95private:
96 friend class vigra::IteratorFacadeCoreAccess;
97
98
99 bool isBegin()const{
100 return partition_!=NULL && currentRep_==partition_->firstRep();
101 }
102 bool isEnd()const{
103 return partition_==NULL || currentRep_>partition_->lastRep();
104 }
105
106 bool equal(const ConstRepIter & other)const{
107 return (this->isEnd() && other.isEnd() ) || ((this->isEnd()==other.isEnd() ) && this->currentRep_==other.currentRep_);
108 }
109
110 void increment(){
111 if(partition_->jumpVec_[currentRep_].second==0){
112 currentRep_+=1;
113 }
114 else{
115 currentRep_+=partition_->jumpVec_[currentRep_].second;
116 }
117 }
118
119 void decrement(){
120 if(partition_->jumpVec_[currentRep_].first==0){
121 //VIGRA_ASSERT_OP(currentRep_,==,partition_->firstRep());
122 //currentRep_+=1;
123 }
124 else{
125 currentRep_-=partition_->jumpVec_[currentRep_].first;
126 }
127 }
128
129 const T & dereference()const{
130 return currentRep_;
131 }
132
133
134
135 const IterablePartitionType * partition_;
136 T currentRep_;
137
138};
139
140
141
142// ufd data structure structure for merge graph
143// only useful for merge graphs internal usage
144/// Disjoint set data structure with path compression.
145/// \ingroup datastructures
146template<class T>
148public:
149 friend struct ConstRepIter<T>;
150 typedef T value_type;
151 typedef std::size_t SizeTType;
153 IterablePartition(const value_type&);
154
155 // query
156 value_type find(const value_type&) const; // without path compression
157 value_type find(value_type); // with path compression
158 value_type numberOfElements() const;
159 value_type numberOfSets() const;
160 template<class Iterator> void elementLabeling(Iterator) const;
161 template<class Iterator> void representatives(Iterator) const;
162 void representativeLabeling(std::map<value_type, value_type>&) const;
163
164 // manipulation
165 void reset(const value_type&);
166 void merge(value_type, value_type);
167
168 value_type firstRep()const{
169 return firstRep_;
170 }
171 value_type lastRep()const{
172 return lastRep_;
173 }
174 typedef ConstRepIter<T> const_iterator;
175
176 const_iterator begin()const{
177 if(numberOfSets_!=0)
178 return ConstRepIter<T>(*this,firstRep_);
179 else
180 return ConstRepIter<T>(*this,lastRep_+1);
181 }
182 const_iterator end()const{
183 return ConstRepIter<T>(*this,lastRep_+1);
184 }
185
186
187 const_iterator iteratorAt(const value_type & rep)const{
188 if(numberOfSets_!=0)
189 return ConstRepIter<T>(*this,rep);
190 else
191 return ConstRepIter<T>(*this,lastRep_+1);
192 }
193
194 bool isErased(const value_type & value)const{
195 return jumpVec_[value].first == -1 && jumpVec_[value].second == -1;
196 }
197
198 void eraseElement(const value_type & value,const bool reduceSize=true){
199 const T notRep=value;
200 const T jumpMinus = jumpVec_[notRep].first;
201 const T jumpPlus = jumpVec_[notRep].second;
202
203 if(jumpMinus==0){
204 const T nextRep = notRep+jumpPlus;
205 firstRep_=nextRep;
206 jumpVec_[nextRep].first=0;
207 }
208 else if(jumpPlus==0){
209 //VIGRA_ASSERT_OP(lastRep_,==,notRep);
210 const T prevRep = notRep-jumpMinus;
211 lastRep_=prevRep;
212 jumpVec_[prevRep].second=0;
213
214 }
215 else{
216 const T nextRep = notRep+jumpPlus;
217 const T prevRep = notRep-jumpMinus;
218 jumpVec_[nextRep].first+=jumpVec_[notRep].first;
219 jumpVec_[prevRep].second+=jumpVec_[notRep].second;
220 }
221 if(reduceSize){
222 --numberOfSets_;
223 }
224 jumpVec_[notRep].first =-1;
225 jumpVec_[notRep].second =-1;
226 }
227
228private:
229 std::vector<value_type> parents_;
230 std::vector<value_type> ranks_;
231 std::vector< std::pair< vigra::Int64, vigra::Int64> > jumpVec_;
232 value_type firstRep_;
233 value_type lastRep_;
234 value_type numberOfElements_;
235 value_type numberOfSets_;
236};
237
238
239} // end namespa merge graph detail
240
241
242
243// helper classes to generalize
244// some functionality for
245// nodes,edges and arcs
246template<class GRAPH,class ITEM>
247struct MergeGraphItemHelper;
248
249template<class MG>
250struct MergeGraphItemHelper<MG,typename MG::Edge>{
251 typedef typename MG::Graph Graph;
252 typedef typename MG::index_type index_type ;
253 typedef typename MG::Edge Item;
254 typedef typename Graph::Edge GraphItem;
255 typedef typename MG::EdgeIt ItemIt;
256
257
258 static index_type maxItemId(const MG & g){
259 return g.maxEdgeId();
260 }
261 static index_type itemNum(const MG & g){
262 return g.edgeNum();
263 }
264
265 static GraphItem itemToGraphItem(const MG & g,const Item & item){
266 const index_type id = g.id(item);
267 return g.graph().edgeFromId(id);
268 }
269};
270
271template<class MG>
272struct MergeGraphItemHelper<MG,typename MG::Node>{
273 typedef typename MG::Graph Graph;
274 typedef typename MG::index_type index_type ;
275 typedef typename MG::Node Item;
276 typedef typename Graph::Node GraphItem;
277 typedef typename MG::NodeIt ItemIt;
278
279
280 static index_type maxItemId(const MG & g){
281 return g.maxNodeId();
282 }
283 static index_type itemNum(const MG & g){
284 return g.nodeNum();
285 }
286 static GraphItem itemToGraphItem(const MG & g,const Item & item){
287 const index_type id = g.id(item);
288 return g.graph().nodeFromId(id);
289 }
290};
291
292// merge graphs LEMON compatible iterator
293template<class MERGE_GRAPH>
294class MergeGraphNodeIt
295: public ForwardIteratorFacade<MergeGraphNodeIt<MERGE_GRAPH>,typename MERGE_GRAPH::Node,true>{
296public:
297 typedef MERGE_GRAPH Graph;
298 typedef typename Graph::Node Node;
299 // Invalid constructor & conversion.
300 MergeGraphNodeIt(const lemon::Invalid & /*invalid*/ = lemon::INVALID)
301 : graph_(NULL),
302 nodeIdIt_(),
303 node_(){
304
305 }
306 MergeGraphNodeIt(const Graph & g)
307 : graph_(&g),
308 nodeIdIt_(g.nodeUfd_.begin()),
309 node_(){
310 }
311 MergeGraphNodeIt(const Graph & g,const Node & node)
312 : graph_(&g),
313 nodeIdIt_(g.nodeUfd_.iteratorAt(g.id(node))),
314 node_(){
315
316 }
317 bool isEnd()const{
318 return graph_==NULL || nodeIdIt_==graph_->nodeUfd_.end();
319 }
320 bool isBegin()const{
321 return graph_!=NULL && nodeIdIt_==graph_->nodeUfd_.begin();
322 }
323private:
324 friend class vigra::IteratorFacadeCoreAccess;
325
326
327 bool equal(const MergeGraphNodeIt<MERGE_GRAPH> & other)const{
328 return (isEnd()&&other.isEnd()) || nodeIdIt_==other.nodeIdIt_;
329 }
330 void increment(){++nodeIdIt_;}
331 const Node & dereference()const{
332 node_=Node(*nodeIdIt_);
333 return node_;
334 }
335 // members
336 const Graph * graph_;
337 typename Graph::NodeIdIt nodeIdIt_;
338 mutable Node node_;
339};
340
341// merge graphs LEMON compatible iterator
342template<class MERGE_GRAPH>
343class MergeGraphEdgeIt
344: public ForwardIteratorFacade<MergeGraphEdgeIt<MERGE_GRAPH>,typename MERGE_GRAPH::Edge,true>{
345public:
346 typedef MERGE_GRAPH Graph;
347 typedef typename Graph::Edge Edge;
348 // Invalid constructor & conversion.
349 MergeGraphEdgeIt(const lemon::Invalid & /*invalid*/ = lemon::INVALID)
350 : graph_(NULL),
351 edgeIdIt_(),
352 edge_(){
353 }
354 MergeGraphEdgeIt(const Graph & g)
355 : graph_(&g),
356 edgeIdIt_(g.edgeUfd_.begin()),
357 edge_(){
358
359 }
360 MergeGraphEdgeIt(const Graph & g,const Edge & node)
361 : graph_(&g),
362 edgeIdIt_(g.edgeUfd_.iteratorAt(g.id(node))),
363 edge_(){
364 }
365 bool isEnd()const{
366 return graph_==NULL || edgeIdIt_==graph_->edgeUfd_.end();
367 }
368 bool isBegin()const{
369 return graph_!=NULL && edgeIdIt_==graph_->edgeUfd_.begin();
370 }
371private:
372 friend class vigra::IteratorFacadeCoreAccess;
373
374
375 bool equal(const MergeGraphEdgeIt<MERGE_GRAPH> & other)const{
376 return (isEnd()&&other.isEnd()) || edgeIdIt_==other.edgeIdIt_;
377 }
378 void increment(){
379 ++edgeIdIt_;
380 }
381 const Edge & dereference()const{
382 edge_=Edge(*edgeIdIt_);
383 return edge_;
384 }
385 // members
386 const Graph * graph_;
387 typename Graph::EdgeIdIt edgeIdIt_;
388 mutable Edge edge_;
389};
390
391// merge graphs LEMON compatible iterator
392template<class GRAPH>
393class MergeGraphArcIt
394: public ForwardIteratorFacade<
395 MergeGraphArcIt<GRAPH>,typename GRAPH::Arc,true
396>
397{
398public:
399 typedef GRAPH Graph;
400 typedef typename Graph::Arc Arc;
401 typedef typename Graph::Edge Edge;
402 typedef typename Graph::EdgeIt EdgeIt;
403 MergeGraphArcIt(const lemon::Invalid /*invalid*/ = lemon::INVALID )
404 : graph_(NULL),
405 pos_(),
406 inFirstHalf_(false),
407 veryEnd_(true),
408 arc_(){
409 }
410 MergeGraphArcIt(const GRAPH & g )
411 : graph_(&g),
412 pos_(g),
413 inFirstHalf_(true),
414 veryEnd_( g.edgeNum()==0 ? true : false),
415 arc_(){
416 }
417
418 MergeGraphArcIt(const GRAPH & g , const Arc & arc )
419 : graph_(&g),
420 pos_(g,arc.edgeId()),
421 inFirstHalf_(g.id(arc)<=g.maxEdgeId()),
422 veryEnd_(false),
423 arc_(){
424 }
425private:
426 friend class vigra::IteratorFacadeCoreAccess;
427 bool isEnd()const{
428 return veryEnd_ || graph_==NULL;
429 }
430
431 bool isBegin()const{
432 return graph_!=NULL && veryEnd_==false && pos_ == EdgeIt(*graph_);
433 }
434
435 void increment() {
436 if(inFirstHalf_){
437 ++pos_;
438 if(pos_ == lemon::INVALID ) {
439 pos_ = EdgeIt(*graph_);
440 inFirstHalf_=false;
441 }
442 return;
443 }
444 else{
445 ++pos_;
446 if(pos_ == lemon::INVALID){
447 veryEnd_=true;
448 }
449 return;
450 }
451
452
453 }
454 bool equal(MergeGraphArcIt const& other) const{
455 return (
456 (
457 isEnd()==other.isEnd() &&
458 inFirstHalf_==other.inFirstHalf_
459 ) &&
460 (isEnd() || graph_==NULL || pos_==other.pos_ )
461 );
462
463 }
464
465 const Arc & dereference() const {
466 //std::cout<<graph_->id(*pos_)<<"\n";
467 arc_ = graph_->direct(*pos_,inFirstHalf_);
468 return arc_;
469 }
470
471
472 const GRAPH * graph_;
473 EdgeIt pos_;
474 bool inFirstHalf_;
475 bool veryEnd_;
476 mutable Arc arc_;
477};
478
479
480// callbacks of merge graph
481// to update node and edge maps w.r.t. edge contractions
482template<class NODE,class EDGE>
483class MergeGraphCallbacks{
484 public:
485
486 typedef delegate2<void ,const NODE & ,const NODE &> MergeNodeCallBackType;
487 typedef delegate2<void ,const EDGE & ,const EDGE &> MergeEdgeCallBackType;
488 typedef delegate1<void ,const EDGE &> EraseEdgeCallBackType;
489
490 MergeGraphCallbacks(){}
491
492 void registerMergeNodeCallBack(MergeNodeCallBackType f){
493 mergeNodeCallbacks_.push_back(f);
494 }
495 void registerMergeEdgeCallBack(MergeEdgeCallBackType f){
496 mergeEdgeCallbacks_.push_back(f);
497 }
498 void registerEraseEdgeCallBack(EraseEdgeCallBackType f){
499 eraseEdgeCallbacks_.push_back(f);
500 }
501
502 protected:
503 void callMergeNodeCallbacks(const NODE & a,const NODE & b){
504 for(size_t i=0;i<mergeNodeCallbacks_.size();++i)
505 mergeNodeCallbacks_[i](a,b);
506 }
507 void callMergeEdgeCallbacks(const EDGE & a,const EDGE & b){
508 for(size_t i=0;i<mergeEdgeCallbacks_.size();++i)
509 mergeEdgeCallbacks_[i](a,b);
510 }
511 void callEraseEdgeCallbacks(const EDGE & a){
512 for(size_t i=0;i<eraseEdgeCallbacks_.size();++i)
513 eraseEdgeCallbacks_[i](a);
514 }
515 void clearCallbacks(){
516 mergeNodeCallbacks_.clear();
517 mergeEdgeCallbacks_.clear();
518 eraseEdgeCallbacks_.clear();
519 }
520 private:
521 std::vector<MergeNodeCallBackType> mergeNodeCallbacks_;
522 std::vector<MergeEdgeCallBackType> mergeEdgeCallbacks_;
523 std::vector<EraseEdgeCallBackType> eraseEdgeCallbacks_;
524};
525
526
527
528/** \brief undirected graph adaptor
529 for edge contraction and feature merging
530 */
531template<class GRAPH>
533: public MergeGraphCallbacks<
534 detail::GenericNode<vigra::Int64> ,
535 detail::GenericEdge<vigra::Int64>
536 >
537
538{
539
540 public:
541 typedef vigra::Int64 IdType;
542 typedef IdType index_type;
544
545
546 typedef detail::GenericNode<index_type> Node;
547 typedef detail::GenericEdge<index_type> Edge;
548 typedef detail::GenericArc<index_type> Arc;
549
550 typedef GRAPH Graph;
551 typedef typename Graph::Node GraphNode;
552 typedef typename Graph::Edge GraphEdge;
553 typedef typename Graph::Node GraphArc;
554
555
556
557
558
559 //typedef std::set<index_type> NodeStorageEdgeSet;
560 typedef detail::GenericNodeImpl<index_type,false > NodeStorage;
561 typedef detail::GenericEdgeImpl<index_type > EdgeStorage;
562
563
564
565 private:
566
567 typedef std::map<vigra::UInt64 , std::vector<IdType> > DoubleMap;
569 typedef typename UfdType::const_iterator ConstUdfIter;
570 typedef ConstUdfIter EdgeIdIt;
571 typedef ConstUdfIter NodeIdIt;
572 typedef detail::NeighborNodeFilter<MergeGraphType> NnFilter;
573 typedef detail::IncEdgeFilter<MergeGraphType> IncFilter;
574 typedef detail::IsInFilter<MergeGraphType> InFlter;
575 typedef detail::IsOutFilter<MergeGraphType> OutFilter;
576 public:
580 typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,NnFilter > NeighborNodeIt;
581 typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,IncFilter > IncEdgeIt;
582 typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,InFlter > InArcIt;
583 typedef detail::GenericIncEdgeIt<MergeGraphType,NodeStorage,OutFilter > OutArcIt;
584
585
586
587 template<class T>
588 struct EdgeMap : DenseEdgeReferenceMap<MergeGraphType,T> {
590 }
591 EdgeMap(const MergeGraphType & g)
593 }
594 EdgeMap(const MergeGraphType & g,const T & val)
596 }
597 };
598
599 template<class T>
600 struct NodeMap : DenseNodeReferenceMap<MergeGraphType,T> {
602 }
603 NodeMap(const MergeGraphType & g)
605 }
606 NodeMap(const MergeGraphType & g,const T & val)
608 }
609 };
610
611 template<class T>
612 struct ArcMap : DenseArcReferenceMap<MergeGraphType,T> {
614 }
615 ArcMap(const MergeGraphType & g)
617 }
618 ArcMap(const MergeGraphType & g,const T & val)
620 }
621 };
622
623
624
625 private:
626 MergeGraphAdaptor(); // non empty-construction
627 MergeGraphAdaptor( const MergeGraphAdaptor& other ); // non construction-copyable
628 MergeGraphAdaptor& operator=( const MergeGraphAdaptor& ); // non copyable
629 public:
630 MergeGraphAdaptor(const Graph & graph);
631 //void setInitalEdge(const size_t initEdge,const size_t initNode0,const size_t initNode1);
632
633 // query (sizes)
634 size_t edgeNum()const;
635 size_t nodeNum()const;
636 size_t arcNum()const;
637
638 IdType maxEdgeId()const;
639 IdType maxNodeId()const;
640 IdType maxArcId()const;
641
642
643 // query (iterators )
644 EdgeIdIt edgeIdsBegin()const;
645 EdgeIdIt edgeIdsEnd()const;
646 NodeIdIt nodeIdsBegin()const;
647 NodeIdIt nodeIdsEnd()const;
648
649
650
651
652 // query (get edge / nodes from id)
653 Edge edgeFromId(const IdType index)const;
654 Node nodeFromId(const IdType index)const;
655 Arc arcFromId( const IdType index)const;
656
657
658
659
660
661 // query ( has edge )
662 bool hasEdgeId(const IdType edgeIndex)const;
663 bool hasNodeId(const IdType nodeIndex)const;
664 bool hasArcId(const IdType arcId)const{
665 return hasEdgeId(arcFromId(arcId).edgeId());
666 }
667
668
669 Edge findEdge(const Node & a,const Node & b)const;
670 Arc findArc(const Node & u,const Node & v)const;
671
672
673 IdType id(const Edge & edge)const;
674 IdType id(const Node & node)const;
675 IdType id(const Arc & arc)const;
676
677
678 size_t degree(const Node & node)const;
679
680
681
682 Node u(const Edge & edge)const;
683 Node v(const Edge & edge)const;
684
685 Node source(const Arc & arc)const{
686 if(arc!=lemon::INVALID)
687 return direction(arc) ? u(Edge(arc)) : v(Edge(arc));
688 else
689 return Node(lemon::INVALID);
690 }
691 Node target(const Arc & arc)const{
692 if(arc!=lemon::INVALID)
693 return direction(arc) ? v(Edge(arc)) : u(Edge(arc));
694 else
695 return Node(lemon::INVALID);
696 }
697
698
699 // query (w.r.t. inital nodesIds/edgesIds)
700 IdType reprEdgeId(const IdType edgeIndex)const;
701 IdType reprNodeId(const IdType nodeIndex)const;
702 bool stateOfInitalEdge(const IdType initalEdge)const;
703 // modification
704 void contractEdge(const Edge & edge);
705
706
707 Node oppositeNode(Node const &n, const Edge &e) const {
708 const Node uNode = u(e);
709 const Node vNode = v(e);
710 if(id(uNode)==id(n)){
711 return vNode;
712 }
713 else if(id(vNode)==id(n)){
714 return uNode;
715 }
716 else{
717 return Node(lemon::INVALID);
718 }
719 }
720
721
722 Arc direct(const Edge & edge,const bool forward)const{
723 if(edge!=lemon::INVALID){
724 if(forward)
725 return Arc(id(edge),id(edge));
726 else
727 return Arc(id(edge)+(maxEdgeId()+1),id(edge));
728 }
729 else{
730 return Arc(lemon::INVALID);
731 }
732 }
733 Arc direct(const Edge & edge,const Node & node)const{
734 if(u(edge)==node)
735 return direct(edge,true);
736 else if(v(edge)==node)
737 return direct(edge,false);
738 else
739 return Arc(lemon::INVALID);
740 }
741
742 bool direction(const Arc & arc)const{
743 return arc.id()==arc.edgeId();
744 }
745
746
747 // special merge graph members
748 GraphEdge reprGraphEdge(const GraphEdge & edge)const{
749 return graph_.edgeFromId(reprEdgeId(graph_.id(edge)));
750 }
751 GraphNode reprGraphNode(const GraphNode & node)const{
752 return graph_.nodeFromId(reprNodeId(graph_.id(node)));
753 }
754
755
756 Edge reprEdge(const GraphEdge & edge)const{
757 return edgeFromId(reprEdgeId(graph_.id(edge)));
758 }
759 Node reprNode(const GraphNode & node)const{
760 return nodeFromId(reprNodeId(graph_.id(node)));
761 }
762
763 const Graph & graph()const{
764 return graph_;
765 }
766 const Graph & graph(){
767 return graph_;
768 }
769
770 // in which node is a "merged inactive" edge
771 Node inactiveEdgesNode(const Edge edge)const{
772 return reprNodeId(graphUId(id(edge)));
773 }
774 size_t maxDegree()const{
775 size_t md=0;
776 for(NodeIt it(*this);it!=lemon::INVALID;++it){
777 md = std::max(md, size_t( degree(*it) ) );
778 }
779 return md;
780 }
781
782 void reset();
783
784 private:
785 // needs acces to const nodeImpl
786 template<class G,class NIMPL,class FILT>
787 friend class detail::GenericIncEdgeIt;
788
789 template<class G>
790 friend struct detail::NeighborNodeFilter;
791 template<class G>
792 friend struct detail::IncEdgeFilter;
793 template<class G>
794 friend struct detail::BackEdgeFilter;
795 template<class G>
796 friend struct detail::IsOutFilter;
797 template<class G>
798 friend struct detail::IsInFilter;
799 friend class MergeGraphNodeIt<MergeGraphType>;
800 friend class MergeGraphArcIt<MergeGraphType>;
801 friend class MergeGraphEdgeIt<MergeGraphType>;
802
803 Edge edgeFromIdUnsave(const IdType index)const;
804
805 index_type uId(const index_type edgeId)const;
806 index_type vId(const index_type edgeId)const;
807 index_type graphUId(const index_type edgeId)const;
808 index_type graphVId(const index_type edgeId)const;
809 //index_type uId(const Edge & edge)const{return uId(id(edge));}
810 //index_type vId(const Edge & edge)const{return vId(id(edge));}
811 const NodeStorage & nodeImpl(const Node & node)const{
812 return nodeVector_[id(node)];
813 }
814 NodeStorage & nodeImpl(const Node & node){
815 return nodeVector_[id(node)];
816 }
817
818
819 const GRAPH & graph_;
820 UfdType nodeUfd_;
821 UfdType edgeUfd_;
822
823 std::vector< NodeStorage > nodeVector_;
824
825 size_t nDoubleEdges_;
826 std::vector<std::pair<index_type,index_type> > doubleEdges_;
827};
828
829
830template<class GRAPH>
832: MergeGraphCallbacks<Node,Edge >(),
833 graph_(graph),
834 nodeUfd_(graph.maxNodeId()+1),
835 edgeUfd_(graph.maxEdgeId()+1),
836 nodeVector_(graph.maxNodeId()+1),
837 nDoubleEdges_(0),
838 doubleEdges_(graph_.edgeNum()/2 +1)
839{
840 for(index_type possibleNodeId = 0 ; possibleNodeId <= graph_.maxNodeId(); ++possibleNodeId){
841 if(graph_.nodeFromId(possibleNodeId)==lemon::INVALID){
842 nodeUfd_.eraseElement(possibleNodeId);
843 }
844 else{
845 nodeVector_[possibleNodeId].id_ = possibleNodeId;
846 }
847 }
848 for(index_type possibleEdgeId = 0 ; possibleEdgeId <= graph_.maxEdgeId(); ++possibleEdgeId){
849 const GraphEdge possibleEdge(graph_.edgeFromId(possibleEdgeId));
850 if(possibleEdge==lemon::INVALID){
851 edgeUfd_.eraseElement(possibleEdgeId);
852 }
853 else{
854 const index_type guid = graphUId(possibleEdgeId);
855 const index_type gvid = graphVId(possibleEdgeId);
856 nodeVector_[ guid ].insert(gvid,possibleEdgeId);
857 nodeVector_[ gvid ].insert(guid,possibleEdgeId);
858 }
859 }
860
861}
862
863
864template<class GRAPH>
865void MergeGraphAdaptor<GRAPH>::reset (){
866
867 nodeUfd_.reset(graph_.maxNodeId()+1),
868 edgeUfd_.reset(graph_.maxEdgeId()+1),
869
870 this->clearCallbacks();
871
872 // clean nodes_
873 for(index_type possibleNodeId = 0 ; possibleNodeId <= graph_.maxNodeId(); ++possibleNodeId){
874
875 nodeVector_[possibleNodeId].clear();
876 if(graph_.nodeFromId(possibleNodeId)==lemon::INVALID){
877 nodeUfd_.eraseElement(possibleNodeId);
878 }
879 else{
880 nodeVector_[possibleNodeId].id_ = possibleNodeId;
881 }
882 }
883
884 for(index_type possibleEdgeId = 0 ; possibleEdgeId <= graph_.maxEdgeId(); ++possibleEdgeId){
885 const GraphEdge possibleEdge(graph_.edgeFromId(possibleEdgeId));
886 if(possibleEdge==lemon::INVALID){
887 edgeUfd_.eraseElement(possibleEdgeId);
888 }
889 else{
890 const index_type guid = graphUId(possibleEdgeId);
891 const index_type gvid = graphVId(possibleEdgeId);
892 nodeVector_[ guid ].insert(gvid,possibleEdgeId);
893 nodeVector_[ gvid ].insert(guid,possibleEdgeId);
894 }
895 }
896}
897
898
899template<class GRAPH>
900inline typename MergeGraphAdaptor<GRAPH>::Edge
901MergeGraphAdaptor<GRAPH>::findEdge (
902 const typename MergeGraphAdaptor<GRAPH>::Node & a,
903 const typename MergeGraphAdaptor<GRAPH>::Node & b
904)const{
905
906 if(a!=b){
907 std::pair<index_type,bool> res = nodeVector_[id(a)].findEdge(id(b));
908 if(res.second){
909 return Edge(res.first);
910 }
911 }
912 return Edge(lemon::INVALID);
913}
914
915template<class GRAPH>
916inline typename MergeGraphAdaptor<GRAPH>::Arc
917MergeGraphAdaptor<GRAPH>::findArc (
918 const typename MergeGraphAdaptor<GRAPH>::Node & uNode,
919 const typename MergeGraphAdaptor<GRAPH>::Node & vNode
920)const{
921 const Edge edge = findEdge(uNode,vNode);
922 if(edge==lemon::INVALID)
923 return Arc(lemon::INVALID);
924 else
925 return direct(edge,u(edge)==uNode);
926}
927
928
929template<class GRAPH>
930inline typename MergeGraphAdaptor<GRAPH>::Node
931MergeGraphAdaptor<GRAPH>::u(const Edge & edge)const{
932 return nodeFromId(uId(id(edge)));
933}
934
935template<class GRAPH>
936inline typename MergeGraphAdaptor<GRAPH>::Node
937MergeGraphAdaptor<GRAPH>::v(const Edge & edge)const{
938 return nodeFromId(vId(id(edge)));
939}
940
941template<class GRAPH>
942inline typename MergeGraphAdaptor<GRAPH>::index_type
943MergeGraphAdaptor<GRAPH>::uId(const index_type edgeId)const{
944 return reprNodeId(graphUId(edgeId));
945}
946
947template<class GRAPH>
948inline typename MergeGraphAdaptor<GRAPH>::index_type
949MergeGraphAdaptor<GRAPH>::vId(const index_type edgeId)const{
950 return reprNodeId(graphVId(edgeId));
951}
952
953
954
955template<class GRAPH>
956inline typename MergeGraphAdaptor<GRAPH>::index_type
957MergeGraphAdaptor<GRAPH>::graphUId(const index_type edgeId)const{
958 return graph_.id(graph_.u(graph_.edgeFromId(edgeId)));
959}
960
961template<class GRAPH>
962inline typename MergeGraphAdaptor<GRAPH>::index_type
963MergeGraphAdaptor<GRAPH>::graphVId(const index_type edgeId)const{
964 return graph_.id(graph_.v(graph_.edgeFromId(edgeId)));
965}
966
967
968template<class GRAPH>
969inline typename MergeGraphAdaptor<GRAPH>::IdType
970MergeGraphAdaptor<GRAPH>::maxEdgeId()const {
971 return static_cast<index_type>(edgeUfd_.lastRep());
972}
973template<class GRAPH>
974inline typename MergeGraphAdaptor<GRAPH>::IdType
975MergeGraphAdaptor<GRAPH>::maxNodeId()const {
976 return static_cast<index_type>(nodeUfd_.lastRep());
977}
978
979template<class GRAPH>
980inline typename MergeGraphAdaptor<GRAPH>::IdType
981MergeGraphAdaptor<GRAPH>::maxArcId()const {
982 return maxEdgeId()*2 +1 ;
983}
984
985
986#ifndef DOXYGEN // doxygen doesn't understand this
987
988template<class GRAPH>
989inline typename MergeGraphAdaptor<GRAPH>::IdType
990MergeGraphAdaptor<GRAPH>::id(
991 const typename MergeGraphAdaptor<GRAPH>::Edge & edge
992)const{
993 return edge.id();
994}
995
996template<class GRAPH>
997inline typename MergeGraphAdaptor<GRAPH>::IdType
998MergeGraphAdaptor<GRAPH>::id(
999 const typename MergeGraphAdaptor<GRAPH>::Node & node
1000)const{
1001 return node.id();
1002}
1003
1004template<class GRAPH>
1005inline typename MergeGraphAdaptor<GRAPH>::IdType
1006MergeGraphAdaptor<GRAPH>::id(
1007 const typename MergeGraphAdaptor<GRAPH>::Arc & arc
1008)const{
1009 return arc.id();
1010}
1011
1012#endif //DOXYGEN
1013
1014
1015template<class GRAPH>
1016inline size_t
1017MergeGraphAdaptor<GRAPH>::degree(
1018 typename MergeGraphAdaptor<GRAPH>::Node const & node
1019)const{
1020 return static_cast<size_t>( nodeVector_[id(node)].edgeNum() );
1021}
1022
1023
1024
1025template<class GRAPH>
1026inline typename MergeGraphAdaptor<GRAPH>::EdgeIdIt
1027MergeGraphAdaptor<GRAPH>::edgeIdsBegin()const{
1028 return edgeUfd_.begin();
1029}
1030
1031template<class GRAPH>
1032inline typename MergeGraphAdaptor<GRAPH>::EdgeIdIt
1033MergeGraphAdaptor<GRAPH>::edgeIdsEnd()const{
1034 return edgeUfd_.end();
1035}
1036
1037
1038template<class GRAPH>
1039inline typename MergeGraphAdaptor<GRAPH>::NodeIdIt
1040MergeGraphAdaptor<GRAPH>::nodeIdsBegin()const{
1041 return nodeUfd_.begin();
1042}
1043
1044template<class GRAPH>
1045inline typename MergeGraphAdaptor<GRAPH>::NodeIdIt
1046MergeGraphAdaptor<GRAPH>::nodeIdsEnd()const{
1047 return nodeUfd_.end();
1048}
1049
1050
1051template<class GRAPH>
1052inline typename MergeGraphAdaptor<GRAPH>::Edge
1053MergeGraphAdaptor<GRAPH>::edgeFromIdUnsave(
1054 const typename MergeGraphAdaptor<GRAPH>::IdType index
1055)const{
1056 return Edge(index);
1057}
1058
1059template<class GRAPH>
1060inline typename MergeGraphAdaptor<GRAPH>::Edge
1061MergeGraphAdaptor<GRAPH>::edgeFromId(
1062 const typename MergeGraphAdaptor<GRAPH>::IdType index
1063)const{
1064 if (hasEdgeId(index))
1065 return Edge(index);
1066 else
1067 return Edge(lemon::INVALID);
1068}
1069
1070template<class GRAPH>
1071inline typename MergeGraphAdaptor<GRAPH>::Node
1072MergeGraphAdaptor<GRAPH>::nodeFromId(
1073 const typename MergeGraphAdaptor<GRAPH>::IdType index
1074)const{
1075 if(hasNodeId(index))
1076 return Node(index);
1077 else
1078 return Node(lemon::INVALID);
1079}
1080
1081template<class GRAPH>
1082inline typename MergeGraphAdaptor<GRAPH>::Arc
1083MergeGraphAdaptor<GRAPH>::arcFromId(
1084 const typename MergeGraphAdaptor<GRAPH>::IdType index
1085)const{
1086 if(index<=maxEdgeId( ))
1087 return Arc(index,index);
1088 else
1089 return Arc(index, index-maxEdgeId() -1);
1090}
1091
1092template<class GRAPH>
1093inline bool
1094MergeGraphAdaptor<GRAPH>::hasEdgeId(
1095 const typename MergeGraphAdaptor<GRAPH>::IdType edgeIndex
1096)const{
1097 if(edgeIndex<=maxEdgeId() && !edgeUfd_.isErased(edgeIndex)){
1098 const IdType reprEdgeIndex = reprEdgeId(edgeIndex);
1099 if(reprEdgeIndex!=edgeIndex){
1100 return false;
1101 }
1102 else{
1103 const index_type rnid0= uId(reprEdgeIndex);
1104 const index_type rnid1= vId(reprEdgeIndex);
1105 return rnid0!=rnid1;
1106 }
1107 }
1108 else{
1109 return false;
1110 }
1111}
1112
1113template<class GRAPH>
1114inline bool
1115MergeGraphAdaptor<GRAPH>::hasNodeId(
1116 const typename MergeGraphAdaptor<GRAPH>::IdType nodeIndex
1117)const{
1118
1119 return nodeIndex<=maxNodeId() && !nodeUfd_.isErased(nodeIndex) && nodeUfd_.find(nodeIndex)==nodeIndex;
1120}
1121
1122template<class GRAPH>
1123inline typename MergeGraphAdaptor<GRAPH>::IdType
1124MergeGraphAdaptor<GRAPH>::reprEdgeId(
1125 const typename MergeGraphAdaptor<GRAPH>::IdType edgeIndex
1126)const{
1127 return edgeUfd_.find(edgeIndex);
1128}
1129
1130template<class GRAPH>
1131inline typename MergeGraphAdaptor<GRAPH>::IdType
1132MergeGraphAdaptor<GRAPH>::reprNodeId(
1133 const typename MergeGraphAdaptor<GRAPH>::IdType nodeIndex
1134)const{
1135 return nodeUfd_.find(nodeIndex);
1136}
1137
1138template<class GRAPH>
1139inline bool MergeGraphAdaptor<GRAPH>::stateOfInitalEdge(
1140 const typename MergeGraphAdaptor<GRAPH>::IdType initalEdge
1141)const{
1142
1143 const index_type rnid0= reprNodeId( graphUId(initalEdge) );
1144 const index_type rnid1= reprNodeId( graphVId(initalEdge) );
1145 return rnid0!=rnid1;
1146}
1147
1148template<class GRAPH>
1149inline size_t MergeGraphAdaptor<GRAPH>::nodeNum()const{
1150 return nodeUfd_.numberOfSets();
1151}
1152
1153template<class GRAPH>
1154inline size_t MergeGraphAdaptor<GRAPH>::arcNum()const{
1155 return edgeNum()*2;
1156}
1157
1158template<class GRAPH>
1159inline size_t MergeGraphAdaptor<GRAPH>::edgeNum()const{
1160 return edgeUfd_.numberOfSets();
1161}
1162
1163template<class GRAPH>
1164void MergeGraphAdaptor<GRAPH>::contractEdge(
1165 const typename MergeGraphAdaptor<GRAPH>::Edge & toDeleteEdge
1166){
1167 //std::cout<<"node num "<<nodeNum()<<"\n";
1168 const index_type toDeleteEdgeIndex = id(toDeleteEdge);
1169 const index_type nodesIds[2]={id(u(toDeleteEdge)),id(v(toDeleteEdge))};
1170
1171 // merge the two nodes
1172 nodeUfd_.merge(nodesIds[0],nodesIds[1]);
1173 const IdType newNodeRep = reprNodeId(nodesIds[0]);
1174 const IdType notNewNodeRep = (newNodeRep == nodesIds[0] ? nodesIds[1] : nodesIds[0] );
1175
1176 typename NodeStorage::AdjIt iter=nodeVector_[notNewNodeRep].adjacencyBegin();
1177 typename NodeStorage::AdjIt end =nodeVector_[notNewNodeRep].adjacencyEnd();
1178
1179 nDoubleEdges_=0;
1180 for(;iter!=end;++iter){
1181 const size_t adjToDeadNodeId = iter->nodeId();
1182 if(newNodeRep < 0 || adjToDeadNodeId!=static_cast<unsigned long long>(newNodeRep)){
1183
1184 // REFACTOR ME, we can make that faster if
1185 // we do that in set intersect style
1186 std::pair<index_type,bool> found=nodeVector_[adjToDeadNodeId].findEdge(newNodeRep);
1187
1188
1189 if(found.second){
1190 edgeUfd_.merge(iter->edgeId(),found.first);
1191
1192 const index_type edgeA = iter->edgeId();
1193 const index_type edgeB = found.first;
1194 const index_type edgeR = edgeUfd_.find(edgeA);
1195 const index_type edgeNR = edgeR==edgeA ? edgeB : edgeA;
1196
1197 nodeVector_[adjToDeadNodeId].eraseFromAdjacency(notNewNodeRep);
1198
1199 // refactor me ... this DOES NOT change the key
1200 nodeVector_[adjToDeadNodeId].eraseFromAdjacency(newNodeRep);
1201 nodeVector_[adjToDeadNodeId].insert(newNodeRep,edgeR);
1202
1203 // refactor me .. this DOES NOT change the key
1204 nodeVector_[newNodeRep].eraseFromAdjacency(adjToDeadNodeId);
1205 nodeVector_[newNodeRep].insert(adjToDeadNodeId,edgeR);
1206
1207 doubleEdges_[nDoubleEdges_]=std::pair<index_type,index_type>(edgeR,edgeNR );
1208 ++nDoubleEdges_;
1209 }
1210 else{
1211 nodeVector_[adjToDeadNodeId].eraseFromAdjacency(notNewNodeRep);
1212 //nodeVector_[adjToDeadNodeId].eraseFromAdjacency(newNodeRep);
1213 nodeVector_[adjToDeadNodeId].insert(newNodeRep,iter->edgeId());
1214
1215 // symetric
1216 //nodeVector_[newNodeRep].eraseFromAdjacency(adjToDeadNodeId);
1217 nodeVector_[newNodeRep].insert(adjToDeadNodeId,iter->edgeId());
1218
1219 }
1220 }
1221 }
1222
1223 //nodeVector_[newNodeRep].merge(nodeVector_[notNewNodeRep]);
1224 nodeVector_[newNodeRep].eraseFromAdjacency(notNewNodeRep);
1225 //nodeVector_[newNodeRep].eraseFromAdjacency(newNodeRep); // no self adjacecy
1226 nodeVector_[notNewNodeRep].clear();
1227
1228 edgeUfd_.eraseElement(toDeleteEdgeIndex);
1229
1230 //std::cout<<"merge nodes callbacks\n";
1231
1232 this->callMergeNodeCallbacks(Node(newNodeRep),Node(notNewNodeRep));
1233
1234 //std::cout<<"merge double edge callbacks\n";
1235 for(size_t de=0;de<nDoubleEdges_;++de){
1236 this->callMergeEdgeCallbacks(Edge(doubleEdges_[de].first),Edge(doubleEdges_[de].second));
1237 }
1238 //std::cout<<"erase edge callbacks\n";
1239 this->callEraseEdgeCallbacks(Edge(toDeleteEdgeIndex));
1240
1241 //std::cout<<"and done\n";
1242}
1243
1244
1245
1246namespace merge_graph_detail {
1247/// Construct a partition.
1248template<class T>
1250: parents_(),
1251 ranks_(),
1252 jumpVec_(),
1253 firstRep_(0),
1254 lastRep_(0),
1255 numberOfElements_(0),
1256 numberOfSets_(0)
1257{}
1258
1259/// Construct a partition.
1260///
1261/// \param size Number of distinct sets.
1262///
1263template<class T>
1264inline
1266(
1267 const value_type& size
1268)
1269: parents_(static_cast<SizeTType>(size)),
1270 ranks_(static_cast<SizeTType>(size)),
1271 jumpVec_(static_cast<SizeTType>(size)),
1272 firstRep_(0),
1273 lastRep_(static_cast<SizeTType>(size)-1),
1274 numberOfElements_(size),
1275 numberOfSets_(size)
1276{
1277 for(T j=0; j<size; ++j) {
1278 parents_[static_cast<SizeTType>(j)] = j;
1279 }
1280
1281 jumpVec_.front().first=0;
1282 jumpVec_.front().second=1;
1283 for(T j=1; j<size-1;++j){
1284 jumpVec_[j].first =1;
1285 jumpVec_[j].second=1;
1286 }
1287 jumpVec_.back().first=1;
1288 jumpVec_.back().second=0;
1289}
1290
1291/// Reset a partition such that each set contains precisely one element
1292///
1293/// \param size Number of distinct sets.
1294///
1295template<class T>
1296inline void
1298(
1299 const value_type& size
1300)
1301{
1302 numberOfElements_ = size;
1303 numberOfSets_ = size;
1304 ranks_.resize(static_cast<SizeTType>(size));
1305 parents_.resize(static_cast<SizeTType>(size));
1306 jumpVec_.resize(static_cast<SizeTType>(size));
1307 firstRep_=0;
1308 lastRep_=static_cast<SizeTType>(size)-1;
1309 for(T j=0; j<size; ++j) {
1310 ranks_[static_cast<SizeTType>(j)] = 0;
1311 parents_[static_cast<SizeTType>(j)] = j;
1312 }
1313
1314 jumpVec_.front().first=0;
1315 jumpVec_.front().second=1;
1316 for(T j=1; j<size-1;++j){
1317 jumpVec_[j].first =1;
1318 jumpVec_[j].second=1;
1319 }
1320 jumpVec_.back().first=1;
1321 jumpVec_.back().second=0;
1322}
1323
1324/// Find the representative element of the set that contains the given element.
1325///
1326/// This constant function does not compress the search path.
1327///
1328/// \param element Element.
1329///
1330template<class T>
1331inline typename IterablePartition<T>::value_type
1333(
1334 const value_type& element
1335) const
1336{
1337 // find the root
1338 value_type root = element;
1339 while(parents_[static_cast<SizeTType>(root)] != root) {
1340 root = parents_[static_cast<SizeTType>(root)];
1341 }
1342 return root;
1343}
1344
1345/// Find the representative element of the set that contains the given element.
1346///
1347/// This mutable function compresses the search path.
1348///
1349/// \param element Element.
1350///
1351template<class T>
1352inline typename IterablePartition<T>::value_type
1354(
1355 value_type element // copy to work with
1356)
1357{
1358 // find the root
1359 value_type root = element;
1360 while(parents_[static_cast<SizeTType>(root)] != root) {
1361 root = parents_[static_cast<SizeTType>(root)];
1362 }
1363 // path compression
1364 while(element != root) {
1365 value_type tmp = parents_[static_cast<SizeTType>(element)];
1366 parents_[static_cast<SizeTType>(element)] = root;
1367 element = tmp;
1368 }
1369 return root;
1370}
1371
1372/// Merge two sets.
1373///
1374/// \param element1 Element in the first set.
1375/// \param element2 Element in the second set.
1376///
1377template<class T>
1378inline void
1380(
1381 value_type element1,
1382 value_type element2
1383)
1384{
1385 // merge by rank
1386 element1 = find(element1);
1387 element2 = find(element2);
1388 if(element1!=element2){
1389 T notRep;
1390 if(ranks_[static_cast<SizeTType>(element1)] < ranks_[static_cast<SizeTType>(element2)]) {
1391 parents_[static_cast<SizeTType>(element1)] = element2;
1392 --numberOfSets_;
1393 //rep=element2;
1395 }
1396 else if(ranks_[static_cast<SizeTType>(element1)] > ranks_[static_cast<SizeTType>(element2)]) {
1397 parents_[static_cast<SizeTType>(element2)] = element1;
1398 --numberOfSets_;
1399 //rep=element1;
1401 }
1402 else if(element1 != element2) {
1403 parents_[static_cast<SizeTType>(element2)] = element1;
1404 ++ranks_[static_cast<SizeTType>(element1)];
1405 --numberOfSets_;
1406 //rep=element1;
1408 }
1409 this->eraseElement(notRep,false);
1410 }
1411}
1412
1413template<class T>
1414inline typename IterablePartition<T>::value_type
1416{
1417 return numberOfElements_;
1418}
1419
1420template<class T>
1421inline typename IterablePartition<T>::value_type
1422IterablePartition<T>::numberOfSets() const
1423{
1424 return numberOfSets_;
1425}
1426
1427template<class T>
1428inline bool operator == (const ConstRepIter<T> & iter,const lemon::Invalid & /*iv*/){
1429 return iter.isEnd();
1430}
1431template<class T>
1432inline bool operator == (const lemon::Invalid & /*iv*/ , const ConstRepIter<T> & iter){
1433 return iter.isEnd();
1434}
1435
1436template<class T>
1437inline bool operator != (const ConstRepIter<T> & iter,const lemon::Invalid & /*iv*/){
1438 return !iter.isEnd();
1439}
1440template<class T>
1441inline bool operator != (const lemon::Invalid & /*iv*/ , const ConstRepIter<T> & iter){
1442 return !iter.isEnd();
1443}
1444
1445
1446} // end namespace merge_graph_detail
1447
1448
1449} // end namespace vigra
1450
1451
1452
1453#endif //VIGRA_NEW_MERGE_GRAPH_HXX
undirected graph adaptor for edge contraction and feature merging
Definition merge_graph_adaptor.hxx:538
Class for a single RGB value.
Definition rgbvalue.hxx:128
RGBValue()
Definition rgbvalue.hxx:209
iterator end()
Definition tinyvector.hxx:864
Definition merge_graph_adaptor.hxx:147
IterablePartition(const value_type &)
Definition merge_graph_adaptor.hxx:1266
value_type find(const value_type &) const
Definition merge_graph_adaptor.hxx:1333
IterablePartition()
Construct a partition.
Definition merge_graph_adaptor.hxx:1249
void reset(const value_type &)
Definition merge_graph_adaptor.hxx:1298
void merge(value_type, value_type)
Definition merge_graph_adaptor.hxx:1380
value_type find(value_type)
Definition merge_graph_adaptor.hxx:1354
detail::SelectIntegerType< 64, detail::SignedIntTypes >::type Int64
64-bit signed int
Definition sized_int.hxx:177

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.12.1