Generated on Wed Apr 29 2015 11:51:40 for GGL-4.1.2 by doxygen 1.8.3.1
MC_MC_Node.hh
Go to the documentation of this file.
1 #ifndef GGL_CHEM_MC_MC_NODE_HH_
2 #define GGL_CHEM_MC_MC_NODE_HH_
3 
4 #include <sgm/MC_Node.hh>
5 
7 
8 
9 namespace ggl {
10 namespace chem {
11 
12 
13 
14 //=========================================================================
15 
16  /*! @brief Match constraints of MoleculeComponents
17  *
18  * This an sgm::MC_NodeAdjacency constraint for MoleculeComponent
19  * descriptions. Therefore, it assumes valid (complex) atom labels for
20  * all nodes.
21  *
22  * NOTE: Only the atom identifier is used for comparisons. All charge,
23  * class, or proton information is ignored.
24  *
25  * @author Martin Mann - http://www.bioinf.uni-freiburg.de/~mmann/
26  *
27  */
29 
30 
31  //! the type that defines a set of labels
32  typedef MC_NodeAdjacency::LabelSet LabelSet;
33 
34  public:
35 
36  //! the index of the node this constraint is for
37  using MC_NodeAdjacency::constrainedNodeID;
38 
39  //! the relational operator to be applied using 'count'
40  using MC_NodeAdjacency::op;
41 
42  //! the number of adjacent nodes/edges fulfilling the label condition
43  using MC_NodeAdjacency::count;
44 
45  //! the node labels of adjacent nodes that have to be counted
46  using MC_NodeAdjacency::nodeLabels;
47 
48  //! the labels of adjacent edges that have to be counted
49  using MC_NodeAdjacency::edgeLabels;
50 
51  /*!
52  * Default construction of the match constraint : undefined values are
53  * initialized with INT_MAX
54  */
56  : sgm::MC_NodeAdjacency()
57  {}
58 
59  /*!
60  * Copy construction of the match constraint
61  */
63  : MC_NodeAdjacency(toCopy)
64  {}
65 
66  /*!
67  * Copy construction of the match constraint
68  */
70  : sgm::MC_NodeAdjacency(toCopy)
71  {}
72 
73  /*!
74  * Construction of the match constraint
75  *
76  * @param constrainedNodeID the index of the node this constraint is for
77  * @param op the relational operator to be applied using 'count'
78  * @param count the number of adjacent nodes/edges fulfilling the label condition
79  * @param nodeLabels the node labels of adjacent nodes that have to be counted
80  * @param edgeLabels the labels of adjacent edges that have to be counted
81  */
83  , const MC_Operator op
84  , const size_t count
85  , const LabelSet & nodeLabels
86  , const LabelSet & edgeLabels
87  )
88  : sgm::MC_NodeAdjacency( constrainedNodeID , op , count , nodeLabels , edgeLabels )
89  {}
90 
91  /*!
92  * Construction of the match constraint
93  *
94  * @param constrainedNodeID the index of the node this constraint is for
95  * @param op the relational operator to be applied using 'count'
96  * @param count the number of adjacent nodes/edges fulfilling the label condition
97  * @param nodeLabel a single node label of adjacent nodes that has to be counted
98  */
100  , const MC_Operator op
101  , const size_t count
102  , const std::string & nodeLabel )
103  : sgm::MC_NodeAdjacency( constrainedNodeID, op, count, nodeLabel )
104  {}
105 
106  //! destruction
107  virtual
109  {}
110 
111 
112  /*!
113  * Checks whether or not a match on a given target fulfills the
114  * additional node adjacency constraint for the pattern matching.
115  *
116  * NOTE: If node labels are given, only checking the atom identifier,
117  * not the whole node label is checked against the label set.
118  *
119  * @param pattern the pattern graph that was matched
120  * @param target the target graph the pattern was matched on
121  * @param matchedTargetID the matched node index within
122  * the target graph
123  * @return true if the match is valid; false if the constraint is
124  * violated
125  */
126  virtual
127  bool
129  const sgm::Graph_Interface & target,
130  const size_t matchedTargetID ) const
131  {
132  // will hold the number of label matches among adjacent nodes in target graph
133  size_t hits = 0;
134 
135  // check if wildcard to use and among allowed node labels
136  const bool nodeWildcard = pattern.getUsedWildcard() != NULL
137  && nodeLabels.find(*(pattern.getUsedWildcard())) != nodeLabels.end();
138  // check if wildcard to use and among allowed edge labels
139  const bool edgeWildcard = pattern.getUsedWildcard() != NULL
140  && edgeLabels.find(*(pattern.getUsedWildcard())) != edgeLabels.end();
141 
142  // special case of checking only adjacent nodes, ignoring the edges
143  // -> no edge but only node labels specified but
144  if (edgeLabels.empty() && !(nodeLabels.empty())) {
145  // ONLY NODE LABELS SPECIFIED
146  // will hold the observed adjacent indices to enable correct
147  // node label counting in case multiple parallel edges are
148  // present between this and an adjacent node
149 #if HAVE_UNORDERED_MAP > 0
150  std::unordered_map<sgm::Graph_Interface::IndexType, char>
151 #elif HAVE_TR1_UNORDERED_MAP > 0
152  std::tr1::unordered_map<sgm::Graph_Interface::IndexType, char>
153 #elif HAVE_GNU_HASH_MAP > 0
154  __gnu_cxx::hash_map<sgm::Graph_Interface::IndexType, char>
155 #else
156  std::map<sgm::Graph_Interface::IndexType, char>
157 #endif
158  observedNodes;
159  // iterate through all adjacent nodes of match[rC.constrainedNodeID]
160  // and check node label
161  for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
162  curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
163  curEdge != curEdgeEnd; ++curEdge )
164  {
165  // check if the current target node was already checked
166  if (observedNodes.find(curEdge->getToIndex()) == observedNodes.end()) {
167  // add to observed indices
168  observedNodes[curEdge->getToIndex()] = 'T';
169  // check if label of the end of the current edge is among
170  // the labels to count
171  if (nodeWildcard || nodeLabels.find(MoleculeUtil::getAtom(target.getNodeLabel(curEdge->getToIndex()))) != nodeLabels.end()) {
172  hits++;
173  }
174  }
175  }
176  } else {
177 
178  // check if all adjacent nodes are to be counted
179  const bool allNodes = nodeLabels.empty() || nodeWildcard;
180  // check if all edges are to be counted
181  const bool allEdges = edgeLabels.empty() || edgeWildcard;
182 
183  // check if all edges to be counted --> placeholder for matching anything
184  if ( allNodes && allEdges )
185  {
186  // count adjacent edges
187  for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
188  curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
189  curEdge != curEdgeEnd; ++curEdge )
190  {
191  hits++;
192  }
193  } else {
194  // iterate through all edges of match[constrainedNodeID]
195  // and check edge AND node label
196  for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
197  curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
198  curEdge != curEdgeEnd; ++curEdge )
199  {
200  // check if edge and node label are among the labels to count
201  if ((allEdges || edgeLabels.find(curEdge->getEdgeLabel()) != edgeLabels.end())
202  && (allNodes || nodeLabels.find(MoleculeUtil::getAtom(target.getNodeLabel(curEdge->getToIndex()))) != nodeLabels.end()))
203  {
204  hits++;
205  }
206  }
207  }
208  }
209  // check if constraint is fulfilled based on relational operator
210  switch( op ) {
211  case MC_EQ : return ( hits == count ); break;
212  case MC_L : return ( hits < count ); break;
213  case MC_G : return ( hits > count ); break;
214  case MC_LQ : return ( hits <= count ); break;
215  case MC_GQ : return ( hits >= count ); break;
216  default : assert(false /* UNSUPPORTED RELATIONAL OPERATOR */);
217  }
218 
219  // final decision, should never be called
220  return false;
221 //
222 // // will hold the number of label matches among adjacent nodes in target graph
223 // size_t hits = 0;
224 //
225 // // check if nodeLabels && edgeLabels empty --> placeholder for matching anything
226 // if (nodeLabels.size() == 0 && edgeLabels.size() == 0 ) {
227 // // count adjacent edges
228 // for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
229 // curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
230 // curEdge != curEdgeEnd; ++curEdge )
231 // {
232 // hits++;
233 // }
234 // } else
235 // // ONLY NODE LABELS SPECIFIED
236 // if (edgeLabels.size() == 0) {
237 // // iterate through all adjacent nodes of match[rC.constrainedNodeID]
238 // // and check node label
239 // for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
240 // curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
241 // curEdge != curEdgeEnd; ++curEdge )
242 // {
243 // // check if atom label of the end of the current edge is among
244 // // the labels to count
245 // if (nodeLabels.find(MoleculeUtil::getAtom(target.getNodeLabel(curEdge->getToIndex()))) != nodeLabels.end()) {
246 // hits++;
247 // }
248 // }
249 // } else
250 // // ONLY EDGE LABELS SPECIFIED
251 // if (nodeLabels.size() == 0) {
252 // // iterate through all edges of match[constrainedNodeID]
253 // // and check edge label
254 // for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
255 // curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
256 // curEdge != curEdgeEnd; ++curEdge )
257 // {
258 // // check if edge label is among the labels to count
259 // if (edgeLabels.find(curEdge->getEdgeLabel()) != edgeLabels.end()) {
260 // hits++;
261 // }
262 // }
263 // // BOTH : NODE AND EDGE LABELS SPECIFIED
264 // } else {
265 // // iterate through all edges of match[constrainedNodeID]
266 // // and check edge AND node label
267 // for( sgm::Graph_Interface::OutEdge_iterator curEdge = target.getOutEdgesBegin(matchedTargetID),
268 // curEdgeEnd = target.getOutEdgesEnd(matchedTargetID);
269 // curEdge != curEdgeEnd; ++curEdge )
270 // {
271 // // check if edge and node label are among the labels to count
272 // if (edgeLabels.find(curEdge->getEdgeLabel()) != edgeLabels.end()
273 // && nodeLabels.find(MoleculeUtil::getAtom(target.getNodeLabel(curEdge->getToIndex()))) != nodeLabels.end())
274 // {
275 // hits++;
276 // }
277 // }
278 // }
279 //
280 // // check if constraint is fulfilled based on relational operator
281 // switch( op ) {
282 // case MC_EQ : return ( hits == count ); break;
283 // case MC_L : return ( hits < count ); break;
284 // case MC_G : return ( hits > count ); break;
285 // case MC_LQ : return ( hits <= count ); break;
286 // case MC_GQ : return ( hits >= count ); break;
287 // default : assert(false /* UNSUPPORTED RELATIONAL OPERATOR */);
288 // }
289 //
290 // // final decision, should never be called
291 // return false;
292  }
293 
294  /*!
295  * Creates a new MC_NodeAdjacency heap object that equals the current
296  * object.
297  * NOTE: YOU have to delete it later on! There is no garbage
298  * collection!
299  * @return a new allocated MC_NodeAdjacency object that equals *this
300  */
301  virtual
303  clone( void ) const
304  {
305  return new MC_MC_NodeAdjacency(*this);
306  }
307 
308 
309  /*!
310  * Creates a new MC_NodeAdjacency heap object that equals the current
311  * object but uses the new indices given by old2newIndexMapping.
312  * NOTE: YOU have to delete it later on! There is no garbage
313  * collection!
314  * @param old2newIndexMapping the index mapping to be used for the
315  * remapping
316  * @param unmatchedIndex an optional specific index that marks
317  * unmatched nodes within old2newIndexMapping. if this
318  * constrains one of these nodes, no remapping is done and
319  * NULL is returned
320  * @return a new allocated MC_NodeAdjacency object
321  */
322  virtual
324  remap( const sgm::Match & old2newIndexMapping, const size_t unmatchedIndex = UINT_MAX )
325  {
326  assert(this->constrainedNodeID < old2newIndexMapping.size());
327  // check if this node is an unmatched node and thus to be ignored
328  if (old2newIndexMapping.at(this->constrainedNodeID)==unmatchedIndex) {
329  return NULL;
330  }
331  // create copy
332  MC_MC_NodeAdjacency* copy = new MC_MC_NodeAdjacency(*this);
333  // do remapping
334  copy->constrainedNodeID = old2newIndexMapping.at(copy->constrainedNodeID);
335  // return remapped copy
336  return copy;
337  }
338 
339 
340  /*!
341  * Equality comparison to another match constraint.
342  * @param toCompare the constraint to compare to
343  * @return true if the constraints are equal; false otherwise
344  */
345  virtual
346  bool
347  operator==( const MC_MC_NodeAdjacency& toCompare ) const
348  {
349  return sgm::MC_NodeAdjacency::operator==(toCompare);
350  }
351 
352 
353  };
354 
355 //=========================================================================
356 
357 
358  /*!
359  * A an sgm::MC_NodeLabel constraint for MoleculeComponent
360  * descriptions. Therefore, it assumes valid (complex) atom labels for
361  * all nodes.
362  *
363  * NOTE: Only the atom identifier is used for comparisons. All charge,
364  * class, or proton information is ignored.
365  *
366  * NOTE: This constraint is only useful if the according pattern node shows
367  * a wildcard label such that it can be matched on any target node.
368  *
369  * @author Martin Mann - http://www.bioinf.uni-freiburg.de/~mmann/
370  *
371  */
373 
374  public:
375 
376  //! the type that defines a set of labels
377  typedef MC_NodeLabel::LabelSet LabelSet;
378 
379 
380  public:
381 
382  //! the node ID to be constrained
383  using MC_NodeLabel::constrainedNodeID;
384 
385  //! the set of labels this node can be mapped on
386  //! NOTE: if empty, no matching will be allowed !!!
387  using MC_NodeLabel::nodeLabels;
388 
389  //! the type of comparison to be applied, i.e. if to ensure that the
390  //! edge label is among the edgeLabels (ALLOWED) or that it is not
391  //! present (FORBIDDEN)
392  using MC_NodeLabel::compareType;
393 
394  /*!
395  * Default construction of the match constraint : undefined values are
396  * initialized with INT_MAX or empty sets
397  */
399  : MC_NodeLabel()
400  {}
401 
402  //! construction where the allowed node labels are empty
403  //! @param constrainedNodeID the node ID to be constrained
405  : MC_NodeLabel(constrainedNodeID)
406  {}
407 
408  //! construction where the allowed node labels are empty
409  //! @param constrainedNodeID the node ID to be constrained
410  //! @param nodeLabels the allowed node labels to be matched on
412  , const LabelSet& nodeLabels)
413  : MC_NodeLabel( constrainedNodeID, nodeLabels )
414  {}
415 
416 
417  //! construction where the allowed node labels are empty
418  //! @param constrainedNodeID the node ID to be constrained
419  //! @param nodeLabels the allowed node labels to be matched on
420  //! @param compareType the type of comparison to be applied
422  , const LabelSet& nodeLabels
423  , const CompareType& compareType)
424  : MC_NodeLabel( constrainedNodeID, nodeLabels, compareType )
425  {}
426 
427  //! copy construction
428  //! @param toCopy the MC_NodeLabel object to copy
429  MC_MC_NodeLabel( const MC_NodeLabel& toCopy )
430  : MC_NodeLabel(toCopy)
431  {}
432 
433  //! copy construction
434  //! @param toCopy the MC_MC_NodeLabel object to copy
436  : MC_NodeLabel(toCopy)
437  {}
438 
439  //! destruction
440  virtual
442  {}
443 
444  /*!
445  * Checks whether or not the matched node holds one of the allowed
446  * labels.
447  *
448  * NOTE: If node labels are given, only checking the atom identifier,
449  * not the whole node label is checked against the label set.
450  *
451  * @param pattern the pattern graph that was matched
452  * @param target the target graph the pattern was matched on
453  * @param matchedTargetID matched node index within the target graph
454  * @return true if the match is valid; false if the constraint is
455  * violated
456  */
457  virtual
458  bool
460  const sgm::Graph_Interface & target,
461  const size_t matchedTargetID ) const
462  {
463  // check if the mapped node shows an allowed label
464  // handle comparison according to given comparison type
465  switch (compareType) {
466 
467  case ALLOWED : // check if all edge labels are found
468  // no node label given -> no allowed label available
469  if (nodeLabels.empty()) {
470  return false;
471  }
472  // check if a wildcard is to be used and is among the allowed labels
473  if (pattern.getUsedWildcard() != NULL
474  && nodeLabels.find(*(pattern.getUsedWildcard())) != nodeLabels.end() )
475  {
476  return true;
477  }
478  // check if the mapped node shows an allowed label
479  return nodeLabels.find(MoleculeUtil::getAtom(target.getNodeLabel(matchedTargetID)))
480  != nodeLabels.end();
481 
482  case FORBIDDEN : // check that all edge labels are NOT found
483  // no node label given -> no forbidden label available
484  if (nodeLabels.empty()) {
485  return true;
486  }
487  // check if a wildcard is to be used and is among the allowed labels
488  if (pattern.getUsedWildcard() != NULL
489  && nodeLabels.find(*(pattern.getUsedWildcard())) != nodeLabels.end() )
490  {
491  return false;
492  }
493  // check if the mapped node shows no forbidden label
494  return nodeLabels.find(MoleculeUtil::getAtom(target.getNodeLabel(matchedTargetID)))
495  == nodeLabels.end();
496 
497  default :
498  assert(false); /*should never happen*/
499  }
500 
501  // if not satisfied so far, wont be satisfied anymore.. ;)
502  return false;
503  }
504 
505 
506  /*!
507  * Creates a new MC_NodeLabel heap object that equals the current
508  * object.
509  * NOTE: YOU have to delete it later on! There is no garbage
510  * collection!
511  * @return a new allocated MC_NodeLabel object that equals *this
512  */
513  virtual
515  clone( void ) const
516  {
517  return new MC_MC_NodeLabel(*this);
518  }
519 
520 
521  /*!
522  * Creates a new MC_NodeLabel heap object that equals the current
523  * object but uses the new indices given by old2newIndexMapping.
524  * NOTE: YOU have to delete it later on! There is no garbage
525  * collection!
526  * @param old2newIndexMapping the index mapping to be used for the
527  * remapping
528  * @param unmatchedIndex an optional specific index that marks
529  * unmatched nodes within old2newIndexMapping. if this
530  * constrains one of these nodes, no remapping is done and
531  * NULL is returned
532  * @return a new allocated MC_NodeLabel object
533  */
534  virtual
536  remap( const sgm::Match & old2newIndexMapping, const size_t unmatchedIndex = UINT_MAX )
537  {
538  assert(this->constrainedNodeID < old2newIndexMapping.size());
539  // check if this node is an unmatched node and thus to be ignored
540  if (old2newIndexMapping.at(this->constrainedNodeID)==unmatchedIndex) {
541  return NULL;
542  }
543  // create copy
544  MC_MC_NodeLabel* copy = new MC_MC_NodeLabel(*this);
545  // do remapping
546  copy->constrainedNodeID = old2newIndexMapping.at(copy->constrainedNodeID);
547  // return remapped copy
548  return copy;
549  }
550 
551 
552  /*!
553  * Equality comparison to another match constraint.
554  * @param toCompare the constraint to compare to
555  * @return true if the constraints are equal; false otherwise
556  */
557  virtual
558  bool
559  operator==( const MC_MC_NodeLabel& toCompare ) const
560  {
561  return MC_NodeLabel::operator==(toCompare);
562  }
563 
564 
565 
566  };
567 
568 //=========================================================================
569 
570 }} // namespace ggl
571 
572 
573 #endif /* GGL_CHEM_MC_MC_NODE_HH_ */
574