summaryrefslogtreecommitdiff
path: root/blossom5-v2.05.src/PMinterface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'blossom5-v2.05.src/PMinterface.cpp')
-rw-r--r--blossom5-v2.05.src/PMinterface.cpp270
1 files changed, 270 insertions, 0 deletions
diff --git a/blossom5-v2.05.src/PMinterface.cpp b/blossom5-v2.05.src/PMinterface.cpp
new file mode 100644
index 0000000..baab2d6
--- /dev/null
+++ b/blossom5-v2.05.src/PMinterface.cpp
@@ -0,0 +1,270 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "PMimplementation.h"
+
+
+PerfectMatching::PerfectMatching(int nodeNum, int edgeNumMax)
+ : node_num(nodeNum),
+ edge_num(0),
+ edge_num_max(edgeNumMax),
+ trees(NULL),
+ tree_num_max(0),
+ removed_first(NULL),
+ blossom_num(0),
+ removed_num(0),
+ first_solve(true)
+{
+ if (node_num & 1) { printf("# of nodes is odd: perfect matching cannot exist\n"); exit(1); }
+ nodes = (Node*) malloc((node_num+1)*sizeof(Node));
+ edges_orig = (char*) malloc(edge_num_max*sizeof(Edge)+1);
+ edges = (Edge*) ( ( ((POINTER_TYPE)edges_orig) & 1 ) ? (edges_orig + 1) : edges_orig );
+ memset(nodes, 0, (node_num+1)*sizeof(Node));
+
+ blossoms = new DBlock<Node>(256);
+ tree_edges = new DBlock<TreeEdge>(256);
+ expand_tmp_list = new Block<ExpandTmpItem>(256);
+ pq_buf = PriorityQueue<REAL>::AllocateBuf();
+}
+
+
+void PerfectMatching::Save(char* filename, int format)
+{
+ if (!first_solve) { printf("Save() cannot be called after Solve()!\n"); exit(1); }
+ int e;
+ FILE* fp = fopen(filename, "w");
+ if (!fp) { printf("Can't open %s\n", filename); exit(1); }
+ if (format == 0)
+ {
+ fprintf(fp, "p edge %d %d\n", node_num, edge_num);
+ for (e=0; e<edge_num; e++)
+ {
+ fprintf(fp, "e %d %d %d\n", 1+(int)(edges[e].head0[1]-nodes), 1+(int)(edges[e].head0[0]-nodes), (int)edges[e].slack/COST_FACTOR);
+ }
+ }
+ else
+ {
+ fprintf(fp, "%d %d\n", node_num, edge_num);
+ for (e=0; e<edge_num; e++)
+ {
+ fprintf(fp, "%d %d %d\n", (int)(edges[e].head0[1]-nodes), (int)(edges[e].head0[0]-nodes), (int)edges[e].slack/COST_FACTOR);
+ }
+ }
+ fclose(fp);
+}
+
+
+PerfectMatching::~PerfectMatching()
+{
+ free(nodes);
+ free(edges_orig);
+ delete blossoms;
+ delete tree_edges;
+ delete expand_tmp_list;
+ if (trees) free(trees);
+ PriorityQueue<REAL>::DeallocateBuf(pq_buf);
+}
+
+
+PerfectMatching::EdgeId PerfectMatching::AddEdge(NodeId _i, NodeId _j, REAL cost)
+{
+ if (_i<0 || _i>=node_num || _j<0 || _j>node_num || _i==_j)
+ {
+ printf("wrong node id's! (%d,%d)\n", _i, _j); exit(1);
+ }
+ if (edge_num >= edge_num_max) ReallocateEdges();
+ Node* i = nodes + _i;
+ Node* j = nodes + _j;
+ Edge* a = edges + edge_num;
+
+ ADD_EDGE(i, a, 0);
+ ADD_EDGE(j, a, 1);
+ a->head0[0] = j;
+ a->head0[1] = i;
+
+ a->slack = cost*COST_FACTOR;
+ PriorityQueue<REAL>::ResetItem(a);
+
+ return edge_num ++;
+}
+
+int PerfectMatching::GetSolution(EdgeId e)
+{
+ assert(e>=0 && e<edge_num);
+ Edge* a = edges + e;
+ return (a->head0[1]->match == EDGE_DIR_TO_ARC(a, 0)) ? 1 : 0;
+}
+
+PerfectMatching::NodeId PerfectMatching::GetMatch(NodeId i)
+{
+ assert(i>=0 && i<node_num);
+ return (int)(ARC_HEAD0(nodes[i].match)-nodes);
+}
+
+void PerfectMatching::GetRealEndpoints(Edge* a, Node*& tail, Node*& head)
+{
+ Node* i;
+ Node* j;
+ int delta = 0;
+
+ for (i=a->head0[1]; !i->is_outer; i=i->blossom_parent, delta--) {}
+ for (j=a->head0[0]; !j->is_outer; j=j->blossom_parent, delta++) {}
+ if ( i == j )
+ {
+ i = a->head0[1];
+ j = a->head0[0];
+ while ( delta < 0 ) { i = i->blossom_parent; delta ++; }
+ while ( delta > 0 ) { j = j->blossom_parent; delta --; }
+ while ( i->blossom_parent != j->blossom_parent )
+ {
+ i = i->blossom_parent;
+ j = j->blossom_parent;
+ }
+ }
+ tail = i;
+ head = j;
+ assert((i->is_outer && j->is_outer) || (i->blossom_parent==j->blossom_parent && !i->is_outer && !j->is_outer));
+}
+
+void PerfectMatching::ReallocateEdges()
+{
+ printf("Warning: reallocating edges. Increasing edge_num_max in the constructor may improve memory efficiency!\n");
+ edge_num_max = edge_num_max*3/2 + 16;
+ char* edges_orig_old = edges_orig;
+ Edge* edges_old = edges;
+ edges_orig = (char*) realloc(edges_orig_old, edge_num_max*sizeof(Edge)+1);
+ edges = (Edge*) ( ( ((POINTER_TYPE)edges_orig_old) & 1 ) ? (edges_orig + 1) : edges_orig );
+ if ( ((POINTER_TYPE)edges) & 1 )
+ {
+ char* edges_orig_old2 = edges_orig;
+ Edge* edges_old2 = edges;
+
+ edges_orig = (char*) malloc(edge_num_max*sizeof(Edge)+1);
+ edges = (Edge*) ( ( ((POINTER_TYPE)edges_orig_old) & 1 ) ? (edges_orig + 1) : edges_orig );
+ memcpy(edges, edges_old2, edge_num*sizeof(Edge));
+ free(edges_orig_old2);
+ }
+
+#define UPDATE_EDGE_PTR(ptr) ptr = (Edge*)((char*)(ptr) + ((char*)edges - (char*)edges_old))
+#define UPDATE_ARC_PTR(ptr) ptr = (Arc*)((char*)(ptr) + ((char*)edges - (char*)edges_old))
+
+ Node* i;
+ Edge* a;
+ for (a=edges; a<edges+edge_num; a++)
+ {
+ if (a->next[0]) UPDATE_EDGE_PTR(a->next[0]);
+ if (a->next[1]) UPDATE_EDGE_PTR(a->next[1]);
+ if (a->prev[0]) UPDATE_EDGE_PTR(a->prev[0]);
+ if (a->prev[1]) UPDATE_EDGE_PTR(a->prev[1]);
+ }
+ if (first_solve)
+ {
+ for (i=nodes; i<nodes+node_num; i++)
+ {
+ if (i->first[0]) UPDATE_EDGE_PTR(i->first[0]);
+ if (i->first[1]) UPDATE_EDGE_PTR(i->first[1]);
+ }
+ }
+ else
+ {
+ Node* i0;
+ for (i0=nodes; i0<nodes+node_num; i0++)
+ {
+ i = i0;
+ while ( 1 )
+ {
+ if (i->is_outer)
+ {
+ UPDATE_ARC_PTR(i->match);
+ if (i->first[0]) UPDATE_EDGE_PTR(i->first[0]);
+ if (i->first[1]) UPDATE_EDGE_PTR(i->first[1]);
+ break;
+ }
+ UPDATE_ARC_PTR(i->blossom_sibling);
+ if (i->first[0]) UPDATE_EDGE_PTR(i->first[0]);
+ if (i->first[1]) UPDATE_EDGE_PTR(i->first[1]);
+
+ i = i->blossom_parent;
+ if (i->is_outer) { if ( i->is_marked) break; i->is_marked = 1; }
+ else { if (!i->is_marked) break; i->is_marked = 0; }
+ }
+ }
+ for (i0=nodes; i0<nodes+node_num; i0++)
+ {
+ i = i0;
+ while ( 1 )
+ {
+ if (i->is_outer) break;
+
+ i = i->blossom_parent;
+ if (i->is_outer) { if (!i->is_marked) break; i->is_marked = 0; }
+ else { if ( i->is_marked) break; i->is_marked = 1; }
+ }
+ }
+ }
+}
+
+int PerfectMatching::GetBlossomNum()
+{
+ return blossom_num;
+}
+
+void PerfectMatching::GetDualSolution(int* blossom_parents, REAL* twice_y)
+{
+ int _i0, id = node_num;
+ int* child_ptr;
+ Node* i0;
+ Node* i;
+ int* tmp_array = new int[blossom_num];
+
+ int* tmp_array_ptr = tmp_array;
+ for (_i0=0, i0=nodes; _i0<node_num; _i0++, i0++)
+ {
+ twice_y[_i0] = i0->y;
+ if (i0->is_outer)
+ {
+ blossom_parents[_i0] = -1;
+ continue;
+ }
+ child_ptr = &blossom_parents[_i0];
+ i = i0->blossom_parent;
+ while ( 1 )
+ {
+ if (i->is_marked)
+ {
+ *child_ptr = i->lca_preorder;
+ break;
+ }
+ i->is_marked = 1;
+ *tmp_array_ptr ++ = i->lca_preorder;
+ *child_ptr = i->lca_preorder = id ++;
+ child_ptr = &blossom_parents[i->lca_preorder];
+ twice_y[i->lca_preorder] = i->y;
+ if (i->is_outer)
+ {
+ *child_ptr = -1;
+ break;
+ }
+ i = i->blossom_parent;
+ }
+ }
+
+ assert(id == node_num+blossom_num && tmp_array_ptr == tmp_array + blossom_num);
+
+ tmp_array_ptr = tmp_array;
+ for (_i0=0, i0=nodes; _i0<node_num; _i0++, i0++)
+ {
+ if (i0->is_outer) continue;
+ i = i0->blossom_parent;
+ while ( 1 )
+ {
+ if (!i->is_marked) break;
+ i->is_marked = 0;
+ i->lca_preorder = *tmp_array_ptr ++;
+ if (i->is_outer) break;
+ i = i->blossom_parent;
+ }
+ }
+
+ delete [] tmp_array;
+}