Generated on Wed Apr 29 2015 11:51:40 for GGL-4.1.2 by doxygen 1.8.3.1
MC_Node.hh
Go to the documentation of this file.
1 #ifndef SGM_MC_NODE_HH_
2 #define SGM_MC_NODE_HH_
3 
4 #include <string>
5 #include <set>
6 #include <climits>
7 #include <cassert>
8 
9 #include <sgm/Pattern.hh>
10 #include <sgm/Graph_Interface.hh>
11 #include <sgm/Match_Reporter.hh>
12 
13 
14 #include "sgm/HashMap.hh"
15 #if HAVE_UNORDERED_MAP > 0
16  #include <unordered_map>
17 #elif HAVE_TR1_UNORDERED_MAP > 0
18  #include <tr1/unordered_map>
19 #elif HAVE_GNU_HASH_MAP > 0
20  #include <ext/hash_map>
21 #else
22  #include <map>
23 #endif
24 
25 
26 namespace sgm {
27 
28 
29 //=========================================================================
30 
31 
32  /*! @brief Interface node match constraints
33  *
34  * A match node constraint describes additional properties that have to be
35  * fulfilled by a given matched node on a given target.
36  *
37  * @author Martin Mann - http://www.bioinf.uni-freiburg.de/~mmann/
38  *
39  */
41 
42  public:
43 
44  //! the node ID to be constrained
46 
47  //! construction
48  //! @param constrainedNodeID the node ID to be constrained
49  MC_Node( const size_t constrainedNodeID )
50  : constrainedNodeID(constrainedNodeID)
51  {}
52 
53  //! copy construction
54  //! @param toCopy the MC_Node object to copy
55  MC_Node( const MC_Node& toCopy )
57  {}
58 
59  //! destruction
60  virtual
62  {}
63 
64  /*!
65  * Checks whether or not this constraint covers the node with the
66  * given ID.
67  *
68  * @param nodeID the ID of the node of interest
69  * @return true if the node is covered by the constraint; false
70  * otherwise
71  */
72  virtual
73  bool
74  isConstraining( const size_t nodeID ) const
75  {
76  // check if this ID is constrained
77  return nodeID == constrainedNodeID;
78  }
79 
80  /*!
81  * Creates a new MC_Node heap object that equals the current
82  * object.
83  * NOTE: YOU have to delete it later on! There is no garbage
84  * collection!
85  * @return a new allocated MC_Node object that equals this
86  */
87  virtual
88  MC_Node*
89  clone( void ) const = 0;
90 
91  /*!
92  * Creates a new MC_Node heap object that equals the current
93  * object but uses the new indices given by old2newIndexMapping.
94  * NOTE: YOU have to delete it later on! There is no garbage
95  * collection!
96  * @param old2newIndexMapping the index mapping to be used for the
97  * remapping
98  * @param unmatchedIndex an optional specific index that marks
99  * unmatched nodes within old2newIndexMapping. if this
100  * constrains one of these nodes, no remapping is done and
101  * NULL is returned
102  * @return a new allocated MC_Node object
103  */
104  virtual
105  MC_Node*
106  remap( const Match & old2newIndexMapping, const size_t unmatchedIndex = UINT_MAX ) = 0;
107 
108 
109  /*!
110  * Checks whether or not a match on a given target fulfills the
111  * additional node constraint for the pattern matching.
112  *
113  * @param pattern the pattern graph that was matched
114  * @param target the target graph the pattern was matched on
115  * @param matchedTargetID the matched node index within
116  * the target graph
117  * @return true if the match is valid; false if the constraint is
118  * violated
119  */
120  virtual
121  bool
122  isValidMatch( const Pattern_Interface & pattern,
123  const Graph_Interface & target,
124  const size_t matchedTargetID ) const = 0;
125 
126 
127  /*!
128  * Checks whether or not a match on a given target fulfills the
129  * additional node constraint for the pattern matching.
130  *
131  * @param pattern the pattern graph that was matched
132  * @param target the target graph the pattern was matched on
133  * @param match the match information for the left side pattern of the
134  * pattern on the target graph
135  * @return true if the match is valid; false if the constraint is
136  * violated
137  */
138  virtual
139  bool
140  isValidMatch( const Pattern_Interface & pattern,
141  const Graph_Interface & target,
142  const Match & match ) const
143  {
144  // forward call to specific function
145  return isValidMatch( pattern, target, match.at(constrainedNodeID));
146  }
147  /*!
148  * Equality comparison to another match constraint.
149  * @param toCompare the constraint to compare to
150  * @return true if the constraints are equal; false otherwise
151  */
152  virtual
153  bool
155  const MC_Node* pc = dynamic_cast< const MC_Node* >(&toCompare);
156  if (pc != NULL) {
157  return this->constrainedNodeID == pc->constrainedNodeID;
158  } else {
159  return false;
160  }
161  }
162 
163 
164  };
165 
166 //=========================================================================
167 
168  /*! @brief Constrains a node's adjacency for a match
169  *
170  * This match constraint defines the relation of the number of adjacent
171  * nodes/edges that have a certain label (combination).
172  *
173  * The constraint is fulfilled if:
174  *
175  * (N(constrainedNodeID,nodeLabels,edgeLabels) op count)
176  *
177  * where N(constrainedNodeID,nodeLabels,edgeLabels) gives the number of adjacent
178  * edges of constrainedNodeID that show a label within edgeLabels and where the
179  * connected node shows on of nodeLabels.
180  *
181  * current idea of GML encoding:
182  *
183  * \verbatim
184 *****************************************************
185  constrainAdj [
186  id ::= INTEGER
187  op ::= '=' | '<' | '>'
188  count ::= DIGIT+
189  nodeLabels [
190  label ::= STRING
191  ]
192  edgeLabels [
193  label ::= STRING
194  ]
195  ]
196 *****************************************************
197  * \endverbatim
198  *
199  * a missing nodeLabels/edgeLabels is used to match anything.
200  *
201  * Examples:
202  *
203  * \verbatim
204 *****************************************************
205  constrainAdj [
206  id 5
207  op <
208  count 2
209  nodeLabels [ "N1" "N2" ]
210  edgeLabels [ "E" ]
211  ]
212 *****************************************************
213  * \endverbatim
214  *
215  * constrains the 5th node to show less than 2 edges with label "E" that
216  * target a node with label "N1" or "N2".
217  *
218  * @author Martin Mann - http://www.bioinf.uni-freiburg.de/~mmann/
219  *
220  */
221  class MC_NodeAdjacency : public MC_Node {
222 
223  public:
224 
225  /*!
226  * Possible operators to be applied onto the count of matched adjacent
227  * edges and nodes.
228  */
229  enum MC_Operator { MC_EQ //!< equality operator
230  , MC_L //!< less operator
231  , MC_G //!< greater operator
232  , MC_LQ //!< less or equal operator
233  , MC_GQ //!< greater or equal operator
234  };
235 
236  //! the type that defines a set of labels
237  typedef std::set< std::string > LabelSet;
238 
239  public:
240 
241  //! the index of the node this constraint is for
243 
244  //! the relational operator to be applied using 'count'
246 
247  //! the number of adjacent nodes/edges fulfilling the label condition
248  size_t count;
249 
250  //! the node labels of adjacent nodes that have to be counted
252 
253  //! the labels of adjacent edges that have to be counted
255 
256  /*!
257  * Default construction of the match constraint : undefined values are
258  * initialized with INT_MAX
259  */
261  : MC_Node((size_t)INT_MAX)
262  , op(MC_EQ)
263  , count((size_t)INT_MAX)
264  , nodeLabels()
265  , edgeLabels()
266  {}
267 
268  /*!
269  * Copy construction of the match constraint
270  * @param toCopy the object to make this a copy of
271  */
273  : MC_Node( toCopy )
274  , op(toCopy.op)
275  , count(toCopy.count)
276  , nodeLabels(toCopy.nodeLabels)
277  , edgeLabels(toCopy.edgeLabels)
278  {}
279 
280  /*!
281  * Construction of the match constraint
282  *
283  * @param constrainedNodeID the index of the node this constraint is for
284  * @param op the relational operator to be applied using 'count'
285  * @param count the number of adjacent nodes/edges fulfilling the label condition
286  * @param nodeLabels the node labels of adjacent nodes that have to be counted
287  * @param edgeLabels the labels of adjacent edges that have to be counted
288  */
290  , const MC_Operator op
291  , const size_t count
292  , const LabelSet & nodeLabels
293  , const LabelSet & edgeLabels
294  )
295  : MC_Node(constrainedNodeID)
296  , op(op)
297  , count(count)
298  , nodeLabels(nodeLabels)
299  , edgeLabels(edgeLabels)
300  {}
301 
302  /*!
303  * Construction of the match constraint
304  *
305  * @param constrainedNodeID the index of the node this constraint is for
306  * @param op the relational operator to be applied using 'count'
307  * @param count the number of adjacent nodes/edges fulfilling the label condition
308  * @param nodeLabel a single node label of adjacent nodes that has to be counted
309  */
311  , const MC_Operator op
312  , const size_t count
313  , const std::string & nodeLabel )
314  : MC_Node(constrainedNodeID)
315  , op(op)
316  , count(count)
317  , nodeLabels()
318  , edgeLabels()
319  {
320  nodeLabels.insert(nodeLabel);
321  }
322 
323  //! destruction
324  virtual
326  {}
327 
328  /*!
329  * Checks whether or not a match on a given target fulfills the
330  * additional node adjacency constraint for the pattern matching.
331  *
332  * @param pattern the pattern graph that was matched
333  * @param target the target graph the pattern was matched on
334  * @param matchedTargetID the matched node index within
335  * the target graph
336  * @return true if the match is valid; false if the constraint is
337  * violated
338  */
339  virtual
340  bool
341  isValidMatch( const Pattern_Interface & pattern,
342  const Graph_Interface & target,
343  const size_t matchedTargetID ) const
344  {
345  // will hold the number of label matches among adjacent nodes in target graph
346  size_t hits = 0;
347 
348  // check if wildcard to use and among allowed node labels
349  const bool nodeWildcard = pattern.getUsedWildcard() != NULL
350  && nodeLabels.find(*(pattern.getUsedWildcard())) != nodeLabels.end();
351  // check if wildcard to use and among allowed edge labels
352  const bool edgeWildcard = pattern.getUsedWildcard() != NULL
353  && edgeLabels.find(*(pattern.getUsedWildcard())) != edgeLabels.end();
354 
355  // special case of checking only adjacent nodes, ignoring the edges
356  // -> no edge but only node labels specified but
357  if (edgeLabels.empty() && !(nodeLabels.empty())) {
358  // ONLY NODE LABELS SPECIFIED
359  // will hold the observed adjacent indices to enable correct
360  // node label counting in case multiple parallel edges are
361  // present between this and an adjacent node
362 #if HAVE_UNORDERED_MAP > 0
363  std::unordered_map<Graph_Interface::IndexType, char>
364 #elif HAVE_TR1_UNORDERED_MAP > 0
365  std::tr1::unordered_map<Graph_Interface::IndexType, char>
366 #elif HAVE_GNU_HASH_MAP > 0
367  __gnu_cxx::hash_map<Graph_Interface::IndexType, char>
368 #else
369  std::map<Graph_Interface::IndexType, char>
370 #endif
371  observedNodes;
372  // iterate through all adjacent nodes of match[rC.constrainedNodeID]
373  // and check node label
374  for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
375  curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
376  curEdge != curEdgeEnd; ++curEdge )
377  {
378  // check if the current target node was already checked
379  if (observedNodes.find(curEdge->getToIndex()) == observedNodes.end()) {
380  // add to observed indices
381  observedNodes[curEdge->getToIndex()] = 'T';
382  // check if label of the end of the current edge is among
383  // the labels to count
384  if (nodeWildcard || nodeLabels.find(target.getNodeLabel(curEdge->getToIndex())) != nodeLabels.end()) {
385  hits++;
386  }
387  }
388  }
389  } else {
390 
391  // check if all adjacent nodes are to be counted
392  const bool allNodes = nodeLabels.empty() || nodeWildcard;
393  // check if all edges are to be counted
394  const bool allEdges = edgeLabels.empty() || edgeWildcard;
395 
396  // check if all edges to be counted --> placeholder for matching anything
397  if ( allNodes && allEdges )
398  {
399  // count adjacent edges
400  for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
401  curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
402  curEdge != curEdgeEnd; ++curEdge )
403  {
404  hits++;
405  }
406  } else {
407  // iterate through all edges of match[constrainedNodeID]
408  // and check edge AND node label
409  for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
410  curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
411  curEdge != curEdgeEnd; ++curEdge )
412  {
413  // check if edge and node label are among the labels to count
414  if ((allEdges || edgeLabels.find(curEdge->getEdgeLabel()) != edgeLabels.end())
415  && (allNodes || nodeLabels.find(target.getNodeLabel(curEdge->getToIndex())) != nodeLabels.end()))
416  {
417  hits++;
418  }
419  }
420  }
421  }
422  // check if constraint is fulfilled based on relational operator
423  switch( op ) {
424  case MC_EQ : return ( hits == count ); break;
425  case MC_L : return ( hits < count ); break;
426  case MC_G : return ( hits > count ); break;
427  case MC_LQ : return ( hits <= count ); break;
428  case MC_GQ : return ( hits >= count ); break;
429  default : assert(false /* UNSUPPORTED RELATIONAL OPERATOR */);
430  }
431 
432  // final decision, should never be called
433  return false;
434  }
435 
436  /*!
437  * Creates a new MC_NodeAdjacency heap object that equals the current
438  * object.
439  * NOTE: YOU have to delete it later on! There is no garbage
440  * collection!
441  * @return a new allocated MC_NodeAdjacency object that equals *this
442  */
443  virtual
445  clone( void ) const
446  {
447  return new MC_NodeAdjacency(*this);
448  }
449 
450  virtual
451  bool
452  isConstrainedLabel( const std::string & label ) const
453  {
454  // check if among the node labels
455  for (LabelSet::const_iterator l=nodeLabels.begin(); l!=nodeLabels.end(); ++l)
456  if (l->compare(label)==0)
457  return true;
458  // check if among the edge labels
459  for (LabelSet::const_iterator l=edgeLabels.begin(); l!=edgeLabels.end(); ++l)
460  if (l->compare(label)==0)
461  return true;
462  // not found
463  return false;
464  }
465 
466 
467  /*!
468  * Creates a new MC_NodeAdjacency heap object that equals the current
469  * object but uses the new indices given by old2newIndexMapping.
470  * NOTE: YOU have to delete it later on! There is no garbage
471  * collection!
472  * @param old2newIndexMapping the index mapping to be used for the
473  * remapping
474  * @param unmatchedIndex an optional specific index that marks
475  * unmatched nodes within old2newIndexMapping. if this
476  * constrains one of these nodes, no remapping is done and
477  * NULL is returned
478  * @return a new allocated MC_NodeAdjacency object
479  */
480  virtual
482  remap( const Match & old2newIndexMapping, const size_t unmatchedIndex = UINT_MAX )
483  {
484  assert(this->constrainedNodeID < old2newIndexMapping.size());
485 
486  // check if this constrains an unmatched node
487  if (old2newIndexMapping.at(this->constrainedNodeID) == unmatchedIndex)
488  {
489  return NULL;
490  }
491 
492  // create copy
493  MC_NodeAdjacency* copy = new MC_NodeAdjacency(*this);
494  // do remapping
495  copy->constrainedNodeID = old2newIndexMapping.at(copy->constrainedNodeID);
496  // return remapped copy
497  return copy;
498  }
499 
500 
501  /*!
502  * Equality comparison to another match constraint.
503  * @param toCompare the constraint to compare to
504  * @return true if the constraints are equal; false otherwise
505  */
506  virtual
507  bool
508  operator==( const MC_NodeAdjacency& toCompare ) const
509  {
510  const MC_NodeAdjacency* pc = dynamic_cast< const MC_NodeAdjacency* >(&toCompare);
511  if (pc != NULL) {
512  bool isEqual =
513  MC_Node::operator==( toCompare )
514  && this->op == pc->op
515  && this->count == pc->count
516  && this->nodeLabels.size() == pc->nodeLabels.size()
517  && this->edgeLabels.size() == pc->edgeLabels.size()
518  ;
519  // check if all node labels present
520  for (LabelSet::const_iterator l=this->nodeLabels.begin();
521  isEqual && l!=this->nodeLabels.end(); ++l)
522  {
523  isEqual = pc->nodeLabels.find(*l)!=pc->nodeLabels.end();
524  }
525  // check if all edge labels present
526  for (LabelSet::const_iterator l=this->edgeLabels.begin();
527  isEqual && l!=this->edgeLabels.end(); ++l)
528  {
529  isEqual = pc->edgeLabels.find(*l)!=pc->edgeLabels.end();
530  }
531  // return final comparison result
532  return isEqual;
533  } else {
534  return false;
535  }
536  }
537 
538 
539  };
540 
541 //=========================================================================
542 
543 
544  /*! @brief Constrains a node's labels for a matching
545  *
546  * A match constraint that restricts the allowed matched labels for a given
547  * matched node to a set of maintained labels. Depending on the operator
548  * type, the maintained node label set describes the set of allowed labels
549  * (op =) or the set of forbidden labels (op !). The operator defaults to
550  * allowed (op =).
551  *
552  * NOTE: This constraint is only useful if the according pattern node shows
553  * a wildcard label such that it can be matched on any target node.
554  *
555  * current idea of GML encoding:
556  *
557  * \verbatim
558 *****************************************************
559  constrainNode [
560  id ::= INTEGER
561  op ::= OPERATOR { = | ! }
562  nodeLabels [
563  label ::= STRING
564  ]
565  ]
566 *****************************************************
567  * \endverbatim
568  *
569  * a missing nodeLabels/edgeLabels is used to match anything.
570  *
571  * Examples:
572  *
573  * \verbatim
574 *****************************************************
575  constrainNode [
576  id 1
577  nodeLabels [
578  label "C"
579  label "P"
580  ]
581  ]
582 *****************************************************
583  * \endverbatim
584  *
585  * constrains the allowed labels of the node with index 1 to "C" or "P".
586  *
587  * @author Martin Mann - http://www.bioinf.uni-freiburg.de/~mmann/
588  *
589  */
590  class MC_NodeLabel : public MC_Node {
591 
592  public:
593 
594  //! the type that defines a set of labels
595  typedef std::set< std::string > LabelSet;
596 
598 
599 
600  public:
601 
602  //! the node ID to be constrained
604 
605  //! the set of labels this node can be mapped on
606  //! NOTE: if empty, no matching will be allowed !!!
608 
609  //! the type of comparison to be applied, i.e. if to ensure that the
610  //! edge label is among the edgeLabels (ALLOWED) or that it is not
611  //! present (FORBIDDEN)
613 
614  /*!
615  * Default construction of the match constraint : undefined values are
616  * initialized with INT_MAX or empty sets
617  */
619  : MC_Node((size_t)INT_MAX)
620  , nodeLabels()
622  {}
623 
624  //! construction where the allowed node labels are empty
625  //! @param constrainedNodeID the node ID to be constrained
627  : MC_Node(constrainedNodeID)
628  , nodeLabels()
630  {}
631 
632  //! construction where the allowed node labels are empty
633  //! @param constrainedNodeID the node ID to be constrained
634  //! @param nodeLabels the allowed node labels to be matched on
636  , const LabelSet& nodeLabels)
637  : MC_Node( constrainedNodeID )
638  , nodeLabels( nodeLabels )
640  {}
641 
642  //! construction where the allowed node labels are empty
643  //! @param constrainedNodeID the node ID to be constrained
644  //! @param nodeLabels the allowed node labels to be matched on
645  //! @param compareType the type of comparison to be applied
647  , const LabelSet& nodeLabels
648  , const CompareType& compareType)
649  : MC_Node( constrainedNodeID )
650  , nodeLabels( nodeLabels )
651  , compareType( compareType )
652  {}
653 
654  //! copy construction
655  //! @param toCopy the MC_NodeLabel object to copy
656  MC_NodeLabel( const MC_NodeLabel& toCopy )
657  : MC_Node(toCopy)
658  , nodeLabels( toCopy.nodeLabels )
659  , compareType( toCopy.compareType )
660  {}
661 
662  //! destruction
663  virtual
665  {}
666 
667  /*!
668  * Checks whether or not the matched node holds one of the allowed
669  * labels.
670  *
671  * @param pattern the pattern graph that was matched
672  * @param target the target graph the pattern was matched on
673  * @param matchedTargetID the matched node index within
674  * the target graph
675  * @return true if the match is valid; false if the constraint is
676  * violated
677  */
678  virtual
679  bool
680  isValidMatch( const Pattern_Interface & pattern,
681  const Graph_Interface & target,
682  const size_t matchedTargetID ) const
683  {
684  // handle comparison according to given comparison type
685  switch (compareType) {
686 
687  case ALLOWED : // check if all edge labels are found
688  // no node label given -> no allowed label available
689  if (nodeLabels.empty()) {
690  return false;
691  }
692  // check if a wildcard is to be used and is among the allowed labels
693  if (pattern.getUsedWildcard() != NULL
694  && nodeLabels.find(*(pattern.getUsedWildcard())) != nodeLabels.end() )
695  {
696  return true;
697  }
698  // check if the mapped node shows an allowed label
699  return nodeLabels.find(target.getNodeLabel(matchedTargetID))
700  != nodeLabels.end();
701 
702  case FORBIDDEN : // check that all edge labels are NOT found
703  // no node label given -> no forbidden label available
704  if (nodeLabels.empty()) {
705  return true;
706  }
707  // check if a wildcard is to be used and is among the allowed labels
708  if (pattern.getUsedWildcard() != NULL
709  && nodeLabels.find(*(pattern.getUsedWildcard())) != nodeLabels.end() )
710  {
711  return false;
712  }
713  // check if the mapped node shows no forbidden label
714  return nodeLabels.find(target.getNodeLabel(matchedTargetID))
715  == nodeLabels.end();
716 
717  default :
718  assert(false); /*should never happen*/
719  }
720 
721  // if not satisfied so far, wont be satisfied anymore.. ;)
722  return false;
723  }
724 
725  virtual
726  bool
727  isConstrainedLabel( const std::string & label ) const
728  {
729  // check if among the node labels
730  for (LabelSet::const_iterator l=nodeLabels.begin(); l!=nodeLabels.end(); ++l)
731  if (l->compare(label)==0)
732  return true;
733  // not found
734  return false;
735  }
736 
737 
738  /*!
739  * Creates a new MC_NodeLabel heap object that equals the current
740  * object.
741  * NOTE: YOU have to delete it later on! There is no garbage
742  * collection!
743  * @return a new allocated MC_NodeLabel object that equals *this
744  */
745  virtual
746  MC_NodeLabel*
747  clone( void ) const
748  {
749  return new MC_NodeLabel(*this);
750  }
751 
752 
753  /*!
754  * Creates a new MC_NodeLabel heap object that equals the current
755  * object but uses the new indices given by old2newIndexMapping.
756  * NOTE: YOU have to delete it later on! There is no garbage
757  * collection!
758  * @param old2newIndexMapping the index mapping to be used for the
759  * remapping
760  * @param unmatchedIndex an optional specific index that marks
761  * unmatched nodes within old2newIndexMapping. if this
762  * constrains one of these nodes, no remapping is done and
763  * NULL is returned
764  * @return a new allocated MC_NodeLabel object
765  */
766  virtual
767  MC_NodeLabel*
768  remap( const Match & old2newIndexMapping, const size_t unmatchedIndex = UINT_MAX )
769  {
770  assert(this->constrainedNodeID < old2newIndexMapping.size());
771 
772  // check if this constrains an unmatched node
773  if (old2newIndexMapping.at(this->constrainedNodeID) == unmatchedIndex)
774  {
775  return NULL;
776  }
777 
778  // create copy
779  MC_NodeLabel* copy = new MC_NodeLabel(*this);
780  // do remapping
781  copy->constrainedNodeID = old2newIndexMapping.at(copy->constrainedNodeID);
782  // return remapped copy
783  return copy;
784  }
785 
786 
787  /*!
788  * Equality comparison to another match constraint.
789  * @param toCompare the constraint to compare to
790  * @return true if the constraints are equal; false otherwise
791  */
792  virtual
793  bool
794  operator==( const MC_NodeLabel& toCompare ) const
795  {
796  const MC_NodeLabel* pc = dynamic_cast< const MC_NodeLabel* >(&toCompare);
797  if (pc != NULL) {
798  bool isEqual =
799  MC_Node::operator==( toCompare )
800  && this->nodeLabels.size() == pc->nodeLabels.size()
801  && this->compareType == pc->compareType
802  ;
803  // check if all node labels present
804  for (LabelSet::const_iterator l=this->nodeLabels.begin();
805  isEqual && l!=this->nodeLabels.end(); ++l)
806  {
807  isEqual = pc->nodeLabels.find(*l)!=pc->nodeLabels.end();
808  }
809  // return final comparison result
810  return isEqual;
811  } else {
812  return false;
813  }
814  }
815 
816 
817 
818  };
819 
820 //=========================================================================
821 
822 } // namespace sgm
823 
824 
825 #endif /* SGM_MC_NODE_HH_ */
826