OpenGM  2.3.x
Discrete Graphical Model Library
planar_maxcut_graph.hxx
Go to the documentation of this file.
1 #pragma once
2 #ifndef OPENGM_PLANAR_MAXCUT_GRAPH_HXX
3 #define OPENGM_PLANAR_MAXCUT_GRAPH_HXX
4 
5 
6 #include <queue>
7 #include <cassert>
8 #include <iostream>
9 #include <list>
10 #include <stack>
11 #include "opengm/opengm.hxx"
12 
13 //TODO: Fix include path
14 #include <planarity.src-patched/graph.h>
15 #include <planarity.src-patched/listcoll.h>
16 #include <planarity.src-patched/stack.h>
17 #include <planarity.src-patched/appconst.h>
18 
19 #include <blossom5.src-patched/PerfectMatching.h>
20 #include <blossom5.src-patched/PMimplementation.h>
21 #include <blossom5.src-patched/MinCost/MinCost.h>
22 
23 namespace opengm {
24  namespace external{
25  namespace pmc{
26 
27  typedef double DataType;
28  typedef size_t IDType;
29 
30 
32 // Graph components
34 
35  struct Node;
36  struct Edge;
37  struct Face;
38  struct DualNode;
39  struct DualEdge;
40 
41 
42  struct Node
43  {
44  Node(IDType id_) : id(id_), weight(0.0), adj(0), label(-1) {};
45  Node(IDType id_, DataType weight_) : id(id_), weight(weight_), adj(0), label(-1) {};
46 
47  IDType id;
48  DataType weight;
49  std::list<Edge*> adj; // List of adjacent edges
50  int label;
51  };
52 
53  struct Face
54  {
55  Face() : edges(0), dual_nodes(0) {};
56 
57  std::list<Edge*> edges; // List of edges surrounding the face
58  std::list<DualNode*> dual_nodes; // Clique of dual nodes for this face
59  };
60 
61  struct Edge
62  {
63  Edge(Node* tail_, Node* head_, DataType weight_) : tail(tail_), head(head_), weight(weight_), left_face(NULL), right_face(NULL), in_cut(false) {};
64 
65  Node* tail;
67  DataType weight;
68 
69  Face* left_face; // pointers to the left and right face as seen from
70  Face* right_face; // formal head to tail
71 
72  bool in_cut; // true iff edge is in the cut set
73  };
74 
75  struct DualNode
76  {
77  DualNode(IDType id_) : id(id_), adj(0) {};
78 
79  IDType id;
80  std::list<DualEdge*> adj; // List of adjacent dual edges
81  };
82 
83  struct DualEdge
84  {
85  DualEdge(DualNode* tail_, DualNode* head_, DataType weight_, Edge* original_cross_edge_) :
86  tail(tail_), head(head_), weight(weight_), original_cross_edge(original_cross_edge_), in_matching(false) {};
87 
88  DualNode* tail;
90  DataType weight;
91 
92  Edge* original_cross_edge; // Pointer to the original edge crossed by this dual edge, NULL if its a face clique edge
93 
94  bool in_matching; // true iff dual edge is in the matching
95  };
96 
97 
99  // Returns a pointer to the destination node of Edge e as seen from node v. NULL if e is not incident on v.
100  {
101  if(v == e->tail)
102  return e->head;
103  else if (v == e->head)
104  return e->tail;
105  else
106  return NULL;
107  }
108 
110  // Returns a pointer to the destination node of Edge e as seen from node v. NULL if e is not incident on v.
111  {
112  if(v == e->tail)
113  return e->head;
114  else if (v == e->head)
115  return e->tail;
116  else
117  return NULL;
118  }
119 
121  // Returns edge that succeeds e in v's adjacency list (NULL if e is not incident on v).
122  {
123  std::list<Edge*>::iterator it = v->adj.begin();
124  while( (*it!=e) && (it!=v->adj.end()) ) ++it;
125 
126  if(it==v->adj.end()) // e is not in v's adj list
127  {
128  return NULL;
129  }
130  else // e is in v's adj list
131  {
132  ++it; // Make one more step
133  if(it==v->adj.end()) // e is the last element in v's adj list
134  return v->adj.front();
135  else
136  return *(it);
137  }
138  }
139 
140 
142 // Graph class definition
144 
145  class Graph
146  {
147  public:
148  Graph() : nodes(0), edges(0), faces(0), dual_nodes(0), dual_edges(0) {};
149  ~Graph() {};
150 
151  size_t num_nodes() const { return nodes.size(); };
152  size_t num_edges() const { return edges.size(); };
153  size_t num_faces() const { return faces.size(); };
154  size_t num_dual_nodes() const { return dual_nodes.size(); };
155  size_t num_dual_edges() const { return dual_edges.size(); };
156 
157  void print();
158 
159  Node* add_node(IDType id_, DataType weight_);
160  Edge* add_edge(Node* tail_, Node* head_, DataType weight_);
161 
162  DualNode* add_dual_node(IDType id_);
163  DualEdge* add_dual_edge(DualNode* tail_, DualNode* head_, DataType weight_, Edge* original_cross_edge_);
164 
165  Edge* find_edge(Node* v1, Node* v2);
166 
167  void planarize();
168 
169  void construct_dual();
170 
171  void mcpm();
172  void assign_labels();
173 
174  template<class VEC> void read_labels(VEC& sol) const;
175  std::vector<int> read_labels();
176 
177  private:
178  std::list<Node*> nodes;
179  std::list<Edge*> edges;
180  std::list<Face*> faces;
181 
182  std::list<DualNode*> dual_nodes;
183  std::list<DualEdge*> dual_edges;
184  };
185 
186 
187 
189 // Basic functionality
191 
192  inline Node* Graph::add_node(IDType id_, DataType weight_)
193  {
194  // Create new node and add to graph's list of nodes
195  Node* v = new Node(id_, weight_);
196  nodes.push_back(v);
197 
198  // Return pointer to the new node
199  return v;
200  }
201 
202  inline Edge* Graph::add_edge(Node* tail_, Node* head_, DataType weight_)
203  {
204  // Create new edge and add to graph's list of edges
205  Edge* e = new Edge(tail_, head_, weight_);
206  edges.push_back(e);
207 
208  // Add edge to both nodes' adjacency lists
209  tail_->adj.push_back(e);
210  head_->adj.push_back(e);
211 
212  // Return pointer to the new edge
213  return e;
214  }
215 
216  inline DualNode* Graph::add_dual_node(IDType id_)
217  {
218  // Create new dual node and add to graph's list of dual nodes
219  DualNode* v = new DualNode(id_);
220  dual_nodes.push_back(v);
221 
222  // Return pointer to the new dual node
223  return v;
224  }
225 
226  inline DualEdge* Graph::add_dual_edge(DualNode* tail_, DualNode* head_, DataType weight_, Edge* original_cross_edge_)
227  {
228  // Create new dual edge and add to graph's list of dual edges
229  DualEdge* e = new DualEdge(tail_, head_, weight_, original_cross_edge_);
230  dual_edges.push_back(e);
231 
232  // Add dual edge to both dual nodes' adjacency lists
233  tail_->adj.push_back(e);
234  head_->adj.push_back(e);
235 
236  // Return pointer to the new edge
237  return e;
238  }
239 
240  inline Edge* Graph::find_edge(Node* v1, Node* v2)
241  // Returns edge connecting nodes v1 and v2 (NULL if it does not exist).
242  {
243  // Search v1's adjacency list for an edge connecting it to v2. Return that edge.
244  for(std::list<Edge*>::iterator it=v1->adj.begin(); it!=v1->adj.end(); ++it)
245  {
246  if( (*it)->tail==v2 || (*it)->head==v2 )
247  {
248  return *it;
249  }
250  }
251 
252  // Return NULL if the loop did not find one.
253  return NULL;
254  }
255 
256 
257  inline void Graph::print()
258  // Simple output of graph for debugging
259  {
260  std::cout << "Graph with " << num_nodes() << " nodes and "
261  << num_edges() << " edges. It has " << num_faces() << " faces.\n";
262 
263  // Iterate through the nodes of the graph
264  for(std::list<Node*>::iterator it = nodes.begin(); it != nodes.end(); ++it)
265  {
266  // Print current node's id and weight
267  std::cout << (*it)->id << "\t[weight "<< (*it)->weight << ";\tlabel "
268  << (*it)->label << "]:\t";
269 
270  // For all edges in current node's adjacency list
271  for(std::list<Edge*>::iterator jt = (*it)->adj.begin(); jt != (*it)->adj.end(); ++jt)
272  {
273  // Get the destination of the current edge as seen from current node.
274  // Print destination id and weight of the edge
275  Node* v = get_dest(*it, *jt);
276  std::cout << v->id << " (" << (*jt)->weight << "), ";
277  }
278  std::cout << "\n";
279  }
280  }
281 
282 
284 // Construction of planar embedding
286 
287  inline void Graph::planarize()
288  // Planarizes the graph. Sorts the adjacency lists of all nodes,
289  // constructs faces and assigns the edges their faces
290  {
291  // Important:
292  // The nodes need to have ids from 0 to num_nodes()-1
293  // The graph needs to be biconnected
294  // ToDo: Check for those conditions!
295 
297  std::vector<Node*> nodes_ptr (num_nodes());
298  for(std::list<Node*>::iterator it=nodes.begin(); it!=nodes.end(); ++it)
299  {
300  nodes_ptr[(*it)->id] = *it;
301  }
302 
304  graphP g = gp_New();
305  gp_InitGraph(g, num_nodes());
306  for(std::list<Edge*>::iterator it=edges.begin(); it!=edges.end(); ++it)
307  {
308  Node* u = (*it)->tail;
309  Node* v = (*it)->head;
310 
311  gp_AddEdge(g, u->id, 0, v->id, 0);
312  }
313 
315  if (gp_Embed(g, EMBEDFLAGS_PLANAR) == OK)
316  gp_SortVertices(g);
317  else
318  std::cout << "Graph not planar\n"; // ToDo: Runtime error einfügen!
319 
321  for (size_t i = 0; i < g->N; ++i)
322  {
323  Node* u = nodes_ptr[i];
324 
325  size_t j = g->G[i].link[1];
326  while (j >= g->N)
327  {
328  OPENGM_ASSERT(i != g->G[j].v); // ToDo: Was machen asserts?
329  OPENGM_ASSERT(g->G[j].v < g->N);
330 
331  // Find the node and the connecting edge
332  Node* v = nodes_ptr[g->G[j].v];
333  std::list<Edge*>::iterator it = u->adj.begin();
334  while( (*it)->tail!=v && (*it)->head!=v && it!=u->adj.end())
335  ++it;
336  Edge* e = *it;
337  OPENGM_ASSERT(it != u->adj.end());
338 
339  // Remove the edge from its current position, and insert at the back
340  u->adj.erase(it);
341  u->adj.push_back(e);
342 
343  j = g->G[j].link[1];
344  }
345  }
346 
348  // Pop all elements from the graph's list of faces and delete them
349  while(!faces.empty())
350  {
351  delete faces.back();
352  faces.pop_back();
353  }
354 
355  // Set the face pointer of all edges to NULL
356  for(std::list<Edge*>::iterator it=edges.begin(); it!=edges.end(); ++it)
357  {
358  (*it)->left_face = NULL;
359  (*it)->right_face = NULL;
360  }
361 
363  for(std::list<Edge*>::iterator it=edges.begin(); it!=edges.end(); ++it) // Loop over all edges
364  {
365  Edge* e = (*it); // Current edge
366 
367  // Check if the left face of e has already been dealt with.
368  // If not, construct it!
369  Face* f = e->left_face;
370  if(f==NULL)
371  {
372  f = new Face(); // Create new face object
373  faces.push_back(f); // Add it to the graph's list of faces
374  e->left_face = f; // Set it as left face of current edge
375  f->edges.push_back(e); // Add e to f's list of edges
376 
377  // Follow the orbit in FORWARD direction (i.e. starting with e's head)
378  Node* v = e->head;
379  Edge* ee = get_following_edge(e, v);
380  while(ee!=e) // If ee==e, we went the full circle
381  {
382  // Set f as face of ee, left or right depends on the formal direction of ee
383  if(v==ee->tail)
384  ee->left_face = f;
385  if(v==ee->head)
386  ee->right_face = f;
387  f->edges.push_back(ee); // add e to f's list of edges
388  v = get_dest(v, ee);
389  ee = get_following_edge(ee,v);
390  }
391  }
392 
393  // Check if the right_face of e has already been dealt with.
394  // If not, construct it!
395  f = e->right_face;
396  if (f==NULL)
397  {
398  f = new Face(); // Create new face object
399  faces.push_back(f); // Add it to the graph's list of faces
400  e->right_face = f; // Set it as left face of current edge e
401  f->edges.push_back(e); // Add e to f's list of edges
402 
403  // Follow the orbit in BACKWARD direction (i.e. starting with e's tail)
404  Node* v = e->tail;
405  Edge* ee = get_following_edge(e, v);
406  while(ee!=e) // If ee==e, we went the full circle
407  {
408  // Set f as face of ee, left or right depends on the formal direction of ee
409  if(v==ee->tail)
410  ee->left_face = f;
411  if(v==ee->head)
412  ee->right_face = f;
413  f->edges.push_back(ee); // add e to f's list of edges
414  v = get_dest(v, ee);
415  ee = get_following_edge(ee,v);
416  }
417  }
418  }
419 
421  for(std::list<Edge*>::iterator it=edges.begin(); it!=edges.end(); ++it)
422  {
423  OPENGM_ASSERT((*it)->left_face != NULL); // ToDo: Was machen asserts?
424  OPENGM_ASSERT((*it)->right_face != NULL);
425  }
426 
428  std::cout<<num_nodes()<<" "<<num_edges()<< " "<<num_faces()<<std::endl;
430  if(num_nodes()-num_edges()+num_faces() != 2)
431  std::cout << "Genus not equal to zero\n"; // ToDO: Runtime error einfügen!
432 
434  gp_Free(&g);
435  }
436 
437 
439 // Construction of planar embedding
441 
442  inline void Graph::construct_dual()
443  // Constructs the expanded dual of the graph
444  {
445  // Important:
446  // G needs to be planarized in the sense that faces have to
447  // be constructed and edges have to have faces assigned correclty
448  // (it is not necessary that the adjacency lists are sorted)
449 
450  size_t cnt_dual_nodes = 0;
451 
452  // Loop over all edges
453  for(std::list<Edge*>::iterator it=edges.begin(); it!=edges.end(); ++it)
454  {
455  // For the current edge of G, add two dual nodes, one for each face
456  DualNode* u = add_dual_node(cnt_dual_nodes);
457  DualNode* v = add_dual_node(cnt_dual_nodes + 1);
458  cnt_dual_nodes += 2;
459 
460  // "Integrate" u into the left face: Connect it to all dual nodes already in that face and add
461  // it to the face's list of dual nodes
462  Face* lf = (*it)->left_face;
463  for(std::list<DualNode*>::iterator jt=lf->dual_nodes.begin(); jt!=lf->dual_nodes.end(); ++jt)
464  {
465  add_dual_edge(u, *jt, 0.0, NULL);
466  }
467  lf->dual_nodes.push_back(u);
468 
469  // "Integrate" u into the left face: Connect it to all dual nodes already in that face and add
470  // it to the face's list of dual nodes
471  Face* rf = (*it)->right_face;
472  for(std::list<DualNode*>::iterator jt=rf->dual_nodes.begin(); jt!=rf->dual_nodes.end(); ++jt)
473  {
474  add_dual_edge(v, *jt, 0.0, NULL);
475  }
476  rf->dual_nodes.push_back(v);
477 
478  // Connect the two nodes by a dual edge with weight=negative of the crossed edge's weight
479  add_dual_edge(u, v, (-1.)*(*it)->weight, *it);
480  }
481  }
482 
483 
485 // Max-Cut via a perfect matching
487 
488  inline void Graph::mcpm()
489  // Perform perfect matching in the dual graph
490  {
491  // Important:
492  // Dual graph has to be constructed first
493  // Dual nodes need to have id's from 0 to num_nodes()-1
494 
496  // Note: Blossom V AddEdge assigns automatically edgeids 0,...,num_dual_edges()-1
497  PerfectMatching PM(num_dual_nodes(), num_dual_edges());
498  PerfectMatching::Options options;
499  options.verbose = false;
500  for(std::list<DualEdge*>::iterator it=dual_edges.begin(); it!=dual_edges.end(); ++it)
501  {
502  DualEdge* e = *it;
503  PM.AddEdge(e->tail->id, e->head->id, e->weight);
504  }
505 
507 
508  PM.options = options;
509  PM.Solve();
510 
512  size_t i=0;
513  for(std::list<DualEdge*>::iterator it=dual_edges.begin(); it!=dual_edges.end(); ++it)
514  {
515  DualEdge* e = *it;
516 
517  if(PM.GetSolution(i)==1) // Check solution from blossom v code
518  {
519  // If dual edge is in the matching, tell it. If it crosses an original edge,
520  // tell the original edge that it is in the cut.
521  e->in_matching = true;
522  if(e->original_cross_edge != NULL)
523  {
524  e->original_cross_edge->in_cut = true;
525  }
526  }
527  else
528  {
529  // If dual edge is NOT in the matching, tell it. If it crosses an original edge,
530  // tell the original edge that it is NOT in the cut
531  e->in_matching = false;
532  if(e->original_cross_edge != NULL)
533  {
534  e->original_cross_edge->in_cut = false;
535  }
536  }
537 
538  ++i;
539  }
540  }
541 
542  inline void Graph::assign_labels()
543  // Given a cut (i.e. edges have bool in_cut assigned), assign a labeling to the nodes
544  {
545  // Important:
546  // A cut has to be given first, i.e. edges need to have the boolean in_cut set correctly
547 
549  for(std::list<Node*>::iterator it = nodes.begin(); it!=nodes.end(); ++it)
550  {
551  (*it)->label = -1;
552  }
553 
554  // For a start, put an arbitrary node on a stack and label it arbitrarily
555  std::stack<Node*> s;
556  Node* u = nodes.front();
557  u->label = 0;
558  s.push(u);
559 
560 
561  while(!s.empty()) // As long as stack is not empty
562  {
563  // Take top element from stack
564  u = s.top();
565  s.pop();
566 
567  // Go through all incident edges
568  for(std::list<Edge*>::iterator it = u->adj.begin(); it!=u->adj.end(); ++it)
569  {
570  Edge* e = *it; // Edge and...
571  Node* v = get_dest(u, e); // its destination (i.e. the neighbor)
572 
573  // If the neighbor has not yet been seen, assign the respective label
574  // and put it on the stack.
575  if(v->label==-1)
576  {
577  s.push(v);
578 
579  if(e->in_cut)
580  v->label = !(u->label);
581  else
582  v->label = u->label;
583  }
584  }
585  }
586  }
587 
588  template<class VEC>
589  void Graph::read_labels(VEC& sol) const
590  {
591  if(sol.size()<num_nodes())
592  sol.resize(num_nodes(), -1);
593  for(std::list<Node*>::const_iterator it = nodes.begin(); it!=nodes.end(); ++it){
594  sol[(*it)->id] = (*it)->label;
595  }
596  return;
597  }
598 
599 
600  std::vector<int> Graph::read_labels()
601  {
602  // Important: Nodes need to have id's from 0 to num_nodes()-1, corresponding to the
603  // openGM variable id
604 
605  std::vector<int> sol(num_nodes(), -1);
606 
607  for(std::list<Node*>::iterator it = nodes.begin(); it!=nodes.end(); ++it)
608  {
609  sol[(*it)->id] = (*it)->label;
610  }
611 
612  return sol;
613  }
614 
615  }
616  }
617 }
618 
619 #endif // #ifndef OPENGM_PLANAR_MAXCUT_GRAPH_HXX
The OpenGM namespace.
Definition: config.hxx:43
DualNode * add_dual_node(IDType id_)
DualEdge * add_dual_edge(DualNode *tail_, DualNode *head_, DataType weight_, Edge *original_cross_edge_)
#define OPENGM_ASSERT(expression)
Definition: opengm.hxx:77
Edge(Node *tail_, Node *head_, DataType weight_)
Edge * get_following_edge(Edge *e, Node *v)
std::list< DualNode * > dual_nodes
Edge * find_edge(Node *v1, Node *v2)
Node * add_node(IDType id_, DataType weight_)
Node * get_dest(Node *v, Edge *e)
Edge * add_edge(Node *tail_, Node *head_, DataType weight_)
Node(IDType id_, DataType weight_)
DualEdge(DualNode *tail_, DualNode *head_, DataType weight_, Edge *original_cross_edge_)