LLVM API Documentation

PBQP.cpp

Go to the documentation of this file.
00001 //===---------------- PBQP.cpp --------- PBQP Solver ------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // Developed by:                   Bernhard Scholz
00011 //                             The University of Sydney
00012 //                         http://www.it.usyd.edu.au/~scholz
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "PBQP.h"
00016 #include "llvm/Config/alloca.h"
00017 #include <limits>
00018 #include <cassert>
00019 #include <cstring>
00020 
00021 namespace llvm {
00022 
00023 /**************************************************************************
00024  * Data Structures 
00025  **************************************************************************/
00026 
00027 /* edge of PBQP graph */
00028 typedef struct adjnode {
00029   struct adjnode *prev,      /* doubly chained list */ 
00030                  *succ, 
00031                  *reverse;   /* reverse edge */
00032   int adj;                   /* adj. node */
00033   PBQPMatrix *costs;         /* cost matrix of edge */
00034 
00035   bool tc_valid;              /* flag whether following fields are valid */
00036   int *tc_safe_regs;          /* safe registers */
00037   int tc_impact;              /* impact */ 
00038 } adjnode;
00039 
00040 /* bucket node */
00041 typedef struct bucketnode {
00042   struct bucketnode *prev;   /* doubly chained list */
00043   struct bucketnode *succ;   
00044   int u;                     /* node */
00045 } bucketnode;
00046 
00047 /* data structure of partitioned boolean quadratic problem */
00048 struct pbqp {
00049   int num_nodes;             /* number of nodes */
00050   int max_deg;               /* maximal degree of a node */
00051   bool solved;               /* flag that indicates whether PBQP has been solved yet */
00052   bool optimal;              /* flag that indicates whether PBQP is optimal */
00053   PBQPNum min;
00054   bool changed;              /* flag whether graph has changed in simplification */
00055 
00056                              /* node fields */
00057   PBQPVector **node_costs;   /* cost vectors of nodes */
00058   int *node_deg;             /* node degree of nodes */
00059   int *solution;             /* solution for node */
00060   adjnode **adj_list;        /* adj. list */
00061   bucketnode **bucket_ptr;   /* bucket pointer of a node */
00062 
00063                              /* node stack */
00064   int *stack;                /* stack of nodes */
00065   int stack_ptr;             /* stack pointer */
00066 
00067                              /* bucket fields */
00068   bucketnode **bucket_list;  /* bucket list */
00069 
00070   int num_r0;                /* counters for number statistics */
00071   int num_ri;
00072   int num_rii;
00073   int num_rn; 
00074   int num_rn_special;      
00075 };
00076 
00077 bool isInf(PBQPNum n) { return n == std::numeric_limits<PBQPNum>::infinity(); } 
00078 
00079 /*****************************************************************************
00080  * allocation/de-allocation of pbqp problem 
00081  ****************************************************************************/
00082 
00083 /* allocate new partitioned boolean quadratic program problem */
00084 pbqp *alloc_pbqp(int num_nodes)
00085 {
00086   pbqp *this_;
00087   int u;
00088   
00089   assert(num_nodes > 0);
00090   
00091   /* allocate memory for pbqp data structure */   
00092   this_ = (pbqp *)malloc(sizeof(pbqp));
00093 
00094   /* Initialize pbqp fields */
00095   this_->num_nodes = num_nodes;
00096   this_->solved = false;
00097   this_->optimal = true;
00098   this_->min = 0.0;
00099   this_->max_deg = 0;
00100   this_->changed = false;
00101   this_->num_r0 = 0;
00102   this_->num_ri = 0;
00103   this_->num_rii = 0;
00104   this_->num_rn = 0;
00105   this_->num_rn_special = 0;
00106   
00107   /* initialize/allocate stack fields of pbqp */ 
00108   this_->stack = (int *) malloc(sizeof(int)*num_nodes);
00109   this_->stack_ptr = 0;
00110   
00111   /* initialize/allocate node fields of pbqp */
00112   this_->adj_list = (adjnode **) malloc(sizeof(adjnode *)*num_nodes);
00113   this_->node_deg = (int *) malloc(sizeof(int)*num_nodes);
00114   this_->solution = (int *) malloc(sizeof(int)*num_nodes);
00115   this_->bucket_ptr = (bucketnode **) malloc(sizeof(bucketnode **)*num_nodes);
00116   this_->node_costs = (PBQPVector**) malloc(sizeof(PBQPVector*) * num_nodes);
00117   for(u=0;u<num_nodes;u++) {
00118     this_->solution[u]=-1;
00119     this_->adj_list[u]=NULL;
00120     this_->node_deg[u]=0;
00121     this_->bucket_ptr[u]=NULL;
00122     this_->node_costs[u]=NULL;
00123   }
00124   
00125   /* initialize bucket list */
00126   this_->bucket_list = NULL;
00127   
00128   return this_;
00129 }
00130 
00131 /* free pbqp problem */
00132 void free_pbqp(pbqp *this_)
00133 {
00134   int u;
00135   int deg;
00136   adjnode *adj_ptr,*adj_next;
00137   bucketnode *bucket,*bucket_next;
00138   
00139   assert(this_ != NULL);
00140   
00141   /* free node cost fields */
00142   for(u=0;u < this_->num_nodes;u++) {
00143     delete this_->node_costs[u];
00144   }
00145   free(this_->node_costs);
00146   
00147   /* free bucket list */
00148   for(deg=0;deg<=this_->max_deg;deg++) {
00149     for(bucket=this_->bucket_list[deg];bucket!=NULL;bucket=bucket_next) {
00150       this_->bucket_ptr[bucket->u] = NULL;
00151       bucket_next = bucket-> succ;
00152       free(bucket);
00153     }
00154   }
00155   free(this_->bucket_list);
00156   
00157   /* free adj. list */
00158   assert(this_->adj_list != NULL);
00159   for(u=0;u < this_->num_nodes; u++) {
00160     for(adj_ptr = this_->adj_list[u]; adj_ptr != NULL; adj_ptr = adj_next) {
00161       adj_next = adj_ptr -> succ;
00162       if (u < adj_ptr->adj) {
00163         assert(adj_ptr != NULL);
00164         delete adj_ptr->costs;
00165       }
00166       if (adj_ptr -> tc_safe_regs != NULL) {
00167            free(adj_ptr -> tc_safe_regs);
00168       }
00169       free(adj_ptr);
00170     }
00171   }
00172   free(this_->adj_list);
00173   
00174   /* free other node fields */
00175   free(this_->node_deg);
00176   free(this_->solution);
00177   free(this_->bucket_ptr);
00178 
00179   /* free stack */
00180   free(this_->stack);
00181 
00182   /* free pbqp data structure itself */
00183   free(this_);
00184 }
00185 
00186 
00187 /****************************************************************************
00188  * adj. node routines 
00189  ****************************************************************************/
00190 
00191 /* find data structure of adj. node of a given node */
00192 static
00193 adjnode *find_adjnode(pbqp *this_,int u,int v)
00194 {
00195   adjnode *adj_ptr;
00196   
00197   assert (this_ != NULL);
00198   assert (u >= 0 && u < this_->num_nodes);
00199   assert (v >= 0 && v < this_->num_nodes);
00200   assert(this_->adj_list != NULL);
00201 
00202   for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
00203     if (adj_ptr->adj == v) {
00204       return adj_ptr;
00205     }
00206   }
00207   return NULL;
00208 }
00209 
00210 /* allocate a new data structure for adj. node */
00211 static
00212 adjnode *alloc_adjnode(pbqp *this_,int u, PBQPMatrix *costs)
00213 {
00214   adjnode *p;
00215 
00216   assert(this_ != NULL);
00217   assert(costs != NULL);
00218   assert(u >= 0 && u < this_->num_nodes);
00219 
00220   p = (adjnode *)malloc(sizeof(adjnode));
00221   assert(p != NULL);
00222   
00223   p->adj = u;
00224   p->costs = costs;  
00225 
00226   p->tc_valid= false;
00227   p->tc_safe_regs = NULL;
00228   p->tc_impact = 0;
00229 
00230   return p;
00231 }
00232 
00233 /* insert adjacence node to adj. list */
00234 static
00235 void insert_adjnode(pbqp *this_, int u, adjnode *adj_ptr)
00236 {
00237 
00238   assert(this_ != NULL);
00239   assert(adj_ptr != NULL);
00240   assert(u >= 0 && u < this_->num_nodes);
00241 
00242   /* if adjacency list of node is not empty -> update
00243      first node of the list */
00244   if (this_ -> adj_list[u] != NULL) {
00245     assert(this_->adj_list[u]->prev == NULL);
00246     this_->adj_list[u] -> prev = adj_ptr;
00247   }
00248 
00249   /* update doubly chained list pointers of pointers */
00250   adj_ptr -> succ = this_->adj_list[u];
00251   adj_ptr -> prev = NULL;
00252 
00253   /* update adjacency list pointer of node u */
00254   this_->adj_list[u] = adj_ptr;
00255 }
00256 
00257 /* remove entry in an adj. list */
00258 static
00259 void remove_adjnode(pbqp *this_, int u, adjnode *adj_ptr)
00260 {
00261   assert(this_!= NULL);
00262   assert(u >= 0 && u <= this_->num_nodes);
00263   assert(this_->adj_list != NULL);
00264   assert(adj_ptr != NULL);
00265   
00266   if (adj_ptr -> prev == NULL) {
00267     this_->adj_list[u] = adj_ptr -> succ;
00268   } else {
00269     adj_ptr -> prev -> succ = adj_ptr -> succ;
00270   } 
00271 
00272   if (adj_ptr -> succ != NULL) {
00273     adj_ptr -> succ -> prev = adj_ptr -> prev;
00274   }
00275 
00276   if(adj_ptr->reverse != NULL) {
00277     adjnode *rev = adj_ptr->reverse;
00278     rev->reverse = NULL;
00279   }
00280 
00281   if (adj_ptr -> tc_safe_regs != NULL) {
00282      free(adj_ptr -> tc_safe_regs);
00283   }
00284 
00285   free(adj_ptr);
00286 }
00287 
00288 /*****************************************************************************
00289  * node functions 
00290  ****************************************************************************/
00291 
00292 /* get degree of a node */
00293 static
00294 int get_deg(pbqp *this_,int u)
00295 {
00296   adjnode *adj_ptr;
00297   int deg = 0;
00298   
00299   assert(this_ != NULL);
00300   assert(u >= 0 && u < this_->num_nodes);
00301   assert(this_->adj_list != NULL);
00302 
00303   for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
00304     deg ++;
00305   }
00306   return deg;
00307 }
00308 
00309 /* reinsert node */
00310 static
00311 void reinsert_node(pbqp *this_,int u)
00312 {
00313   adjnode *adj_u,
00314           *adj_v;
00315 
00316   assert(this_!= NULL);
00317   assert(u >= 0 && u <= this_->num_nodes);
00318   assert(this_->adj_list != NULL);
00319 
00320   for(adj_u = this_ -> adj_list[u]; adj_u != NULL; adj_u = adj_u -> succ) {
00321     int v = adj_u -> adj;
00322     adj_v = alloc_adjnode(this_,u,adj_u->costs);
00323     insert_adjnode(this_,v,adj_v);
00324   }
00325 }
00326 
00327 /* remove node */
00328 static
00329 void remove_node(pbqp *this_,int u)
00330 {
00331   adjnode *adj_ptr;
00332 
00333   assert(this_!= NULL);
00334   assert(u >= 0 && u <= this_->num_nodes);
00335   assert(this_->adj_list != NULL);
00336 
00337   for(adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
00338     remove_adjnode(this_,adj_ptr->adj,adj_ptr -> reverse);
00339   }
00340 }
00341 
00342 /*****************************************************************************
00343  * edge functions
00344  ****************************************************************************/
00345 
00346 /* insert edge to graph */
00347 /* (does not check whether edge exists in graph */
00348 static
00349 void insert_edge(pbqp *this_, int u, int v, PBQPMatrix *costs)
00350 {
00351   adjnode *adj_u,
00352           *adj_v;
00353   
00354   /* create adjanceny entry for u */
00355   adj_u = alloc_adjnode(this_,v,costs);
00356   insert_adjnode(this_,u,adj_u);
00357 
00358 
00359   /* create adjanceny entry for v */
00360   adj_v = alloc_adjnode(this_,u,costs);
00361   insert_adjnode(this_,v,adj_v);
00362   
00363   /* create link for reverse edge */
00364   adj_u -> reverse = adj_v;
00365   adj_v -> reverse = adj_u;
00366 }
00367 
00368 /* delete edge */
00369 static
00370 void delete_edge(pbqp *this_,int u,int v)
00371 {
00372   adjnode *adj_ptr;
00373   adjnode *rev;
00374   
00375   assert(this_ != NULL);
00376   assert( u >= 0 && u < this_->num_nodes);
00377   assert( v >= 0 && v < this_->num_nodes);
00378 
00379   adj_ptr=find_adjnode(this_,u,v);
00380   assert(adj_ptr != NULL);
00381   assert(adj_ptr->reverse != NULL);
00382 
00383   delete adj_ptr -> costs;
00384  
00385   rev = adj_ptr->reverse; 
00386   remove_adjnode(this_,u,adj_ptr);
00387   remove_adjnode(this_,v,rev);
00388 } 
00389 
00390 /*****************************************************************************
00391  * cost functions 
00392  ****************************************************************************/
00393 
00394 /* Note: Since cost(u,v) = transpose(cost(v,u)), it would be necessary to store 
00395    two matrices for both edges (u,v) and (v,u). However, we only store the 
00396    matrix for the case u < v. For the other case we transpose the stored matrix
00397    if required. 
00398 */
00399 
00400 /* add costs to cost vector of a node */
00401 void add_pbqp_nodecosts(pbqp *this_,int u, PBQPVector *costs)
00402 {
00403   assert(this_ != NULL);
00404   assert(costs != NULL);
00405   assert(u >= 0 && u <= this_->num_nodes);
00406   
00407   if (!this_->node_costs[u]) {
00408     this_->node_costs[u] = new PBQPVector(*costs);
00409   } else {
00410     *this_->node_costs[u] += *costs;
00411   }
00412 }
00413 
00414 /* get cost matrix ptr */
00415 static
00416 PBQPMatrix *get_costmatrix_ptr(pbqp *this_, int u, int v)
00417 {
00418   adjnode *adj_ptr;
00419   PBQPMatrix *m = NULL;
00420 
00421   assert (this_ != NULL);
00422   assert (u >= 0 && u < this_->num_nodes);
00423   assert (v >= 0 && v < this_->num_nodes); 
00424 
00425   adj_ptr = find_adjnode(this_,u,v);
00426 
00427   if (adj_ptr != NULL) {
00428     m = adj_ptr -> costs;
00429   } 
00430 
00431   return m;
00432 }
00433 
00434 /* get cost matrix ptr */
00435 /* Note: only the pointer is returned for 
00436    cost(u,v), if u < v.
00437 */ 
00438 static
00439 PBQPMatrix *pbqp_get_costmatrix(pbqp *this_, int u, int v)
00440 {
00441   adjnode *adj_ptr = find_adjnode(this_,u,v);
00442   
00443   if (adj_ptr != NULL) {
00444     if ( u < v) {
00445       return new PBQPMatrix(*adj_ptr->costs);
00446     } else {
00447       return new PBQPMatrix(adj_ptr->costs->transpose());
00448     }
00449   } else {
00450     return NULL;
00451   }  
00452 }
00453 
00454 /* add costs to cost matrix of an edge */
00455 void add_pbqp_edgecosts(pbqp *this_,int u,int v, PBQPMatrix *costs)
00456 {
00457   PBQPMatrix *adj_costs;
00458 
00459   assert(this_!= NULL);
00460   assert(costs != NULL);
00461   assert(u >= 0 && u <= this_->num_nodes);
00462   assert(v >= 0 && v <= this_->num_nodes);
00463   
00464   /* does the edge u-v exists ? */
00465   if (u == v) {
00466     PBQPVector *diag = new PBQPVector(costs->diagonalize());
00467     add_pbqp_nodecosts(this_,v,diag);
00468     delete diag;
00469   } else if ((adj_costs = get_costmatrix_ptr(this_,u,v))!=NULL) {
00470     if ( u < v) {
00471       *adj_costs += *costs;
00472     } else {
00473       *adj_costs += costs->transpose();
00474     }
00475   } else {
00476     adj_costs = new PBQPMatrix((u < v) ? *costs : costs->transpose());
00477     insert_edge(this_,u,v,adj_costs);
00478   } 
00479 }
00480 
00481 /* remove bucket from bucket list */
00482 static
00483 void pbqp_remove_bucket(pbqp *this_, bucketnode *bucket)
00484 {
00485   int u = bucket->u;
00486   
00487   assert(this_ != NULL);
00488   assert(u >= 0 && u < this_->num_nodes);
00489   assert(this_->bucket_list != NULL);
00490   assert(this_->bucket_ptr[u] != NULL);
00491   
00492   /* update predecessor node in bucket list 
00493      (if no preceeding bucket exists, then
00494      the bucket_list pointer needs to be 
00495      updated.)
00496   */    
00497   if (bucket->prev != NULL) {
00498     bucket->prev-> succ = bucket->succ; 
00499   } else {
00500     this_->bucket_list[this_->node_deg[u]] = bucket -> succ;
00501   }
00502   
00503   /* update successor node in bucket list */ 
00504   if (bucket->succ != NULL) { 
00505     bucket->succ-> prev = bucket->prev;
00506   }
00507 }
00508 
00509 /**********************************************************************************
00510  * pop functions
00511  **********************************************************************************/
00512 
00513 /* pop node of given degree */
00514 static
00515 int pop_node(pbqp *this_,int deg)
00516 {
00517   bucketnode *bucket;
00518   int u;
00519 
00520   assert(this_ != NULL);
00521   assert(deg >= 0 && deg <= this_->max_deg);
00522   assert(this_->bucket_list != NULL);
00523    
00524   /* get first bucket of bucket list */
00525   bucket = this_->bucket_list[deg];
00526   assert(bucket != NULL);
00527 
00528   /* remove bucket */
00529   pbqp_remove_bucket(this_,bucket);
00530   u = bucket->u;
00531   free(bucket);
00532   return u;
00533 }
00534 
00535 /**********************************************************************************
00536  * reorder functions
00537  **********************************************************************************/
00538 
00539 /* add bucket to bucketlist */
00540 static
00541 void add_to_bucketlist(pbqp *this_,bucketnode *bucket, int deg)
00542 {
00543   bucketnode *old_head;
00544   
00545   assert(bucket != NULL);
00546   assert(this_ != NULL);
00547   assert(deg >= 0 && deg <= this_->max_deg);
00548   assert(this_->bucket_list != NULL);
00549 
00550   /* store node degree (for re-ordering purposes)*/
00551   this_->node_deg[bucket->u] = deg;
00552   
00553   /* put bucket to front of doubly chained list */
00554   old_head = this_->bucket_list[deg];
00555   bucket -> prev = NULL;
00556   bucket -> succ = old_head;
00557   this_ -> bucket_list[deg] = bucket;
00558   if (bucket -> succ != NULL ) {
00559     assert ( old_head -> prev == NULL);
00560     old_head -> prev = bucket;
00561   }
00562 }
00563 
00564 
00565 /* reorder node in bucket list according to 
00566    current node degree */
00567 static
00568 void reorder_node(pbqp *this_, int u)
00569 {
00570   int deg; 
00571   
00572   assert(this_ != NULL);
00573   assert(u>= 0 && u < this_->num_nodes);
00574   assert(this_->bucket_list != NULL);
00575   assert(this_->bucket_ptr[u] != NULL);
00576 
00577   /* get current node degree */
00578   deg = get_deg(this_,u);
00579   
00580   /* remove bucket from old bucket list only
00581      if degree of node has changed. */
00582   if (deg != this_->node_deg[u]) {
00583     pbqp_remove_bucket(this_,this_->bucket_ptr[u]);
00584     add_to_bucketlist(this_,this_->bucket_ptr[u],deg);
00585   } 
00586 }
00587 
00588 /* reorder adj. nodes of a node */
00589 static
00590 void reorder_adjnodes(pbqp *this_,int u)
00591 {
00592   adjnode *adj_ptr;
00593   
00594   assert(this_!= NULL);
00595   assert(u >= 0 && u <= this_->num_nodes);
00596   assert(this_->adj_list != NULL);
00597 
00598   for(adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
00599     reorder_node(this_,adj_ptr->adj);
00600   }
00601 }
00602 
00603 /**********************************************************************************
00604  * creation functions
00605  **********************************************************************************/
00606 
00607 /* create new bucket entry */
00608 /* consistency of the bucket list is not checked! */
00609 static
00610 void create_bucket(pbqp *this_,int u,int deg)
00611 {
00612   bucketnode *bucket;
00613   
00614   assert(this_ != NULL);
00615   assert(u >= 0 && u < this_->num_nodes);
00616   assert(this_->bucket_list != NULL);
00617   
00618   bucket = (bucketnode *)malloc(sizeof(bucketnode));
00619   assert(bucket != NULL);
00620 
00621   bucket -> u = u;
00622   this_->bucket_ptr[u] = bucket;
00623 
00624   add_to_bucketlist(this_,bucket,deg);
00625 }
00626 
00627 /* create bucket list */
00628 static
00629 void create_bucketlist(pbqp *this_)
00630 {
00631   int u;
00632   int max_deg;
00633   int deg;
00634 
00635   assert(this_ != NULL);
00636   assert(this_->bucket_list == NULL);
00637 
00638   /* determine max. degree of the nodes */
00639   max_deg = 2;  /* at least of degree two! */
00640   for(u=0;u<this_->num_nodes;u++) {
00641     deg = this_->node_deg[u] = get_deg(this_,u);
00642     if (deg > max_deg) {
00643       max_deg = deg;
00644     }
00645   }
00646   this_->max_deg = max_deg;
00647   
00648   /* allocate bucket list */
00649   this_ -> bucket_list = (bucketnode **)malloc(sizeof(bucketnode *)*(max_deg + 1));
00650   memset(this_->bucket_list,0,sizeof(bucketnode *)*(max_deg + 1));
00651   assert(this_->bucket_list != NULL);
00652   
00653   /* insert nodes to the list */
00654   for(u=0;u<this_->num_nodes;u++) {
00655     create_bucket(this_,u,this_->node_deg[u]);  
00656   }
00657 }
00658 
00659 /*****************************************************************************
00660  * PBQP simplification for trivial nodes
00661  ****************************************************************************/
00662 
00663 /* remove trivial node with cost vector length of one */
00664 static
00665 void disconnect_trivialnode(pbqp *this_,int u)
00666 {
00667   int v;
00668   adjnode *adj_ptr, 
00669           *next;
00670   PBQPMatrix *c_uv;
00671   PBQPVector *c_v;
00672   
00673   assert(this_ != NULL);
00674   assert(this_->node_costs != NULL);
00675   assert(u >= 0 && u < this_ -> num_nodes);
00676   assert(this_->node_costs[u]->getLength() == 1);
00677   
00678   /* add edge costs to node costs of adj. nodes */
00679   for(adj_ptr = this_->adj_list[u]; adj_ptr != NULL; adj_ptr = next){
00680     next = adj_ptr -> succ;
00681     v = adj_ptr -> adj;
00682     assert(v >= 0 && v < this_ -> num_nodes);
00683     
00684     /* convert matrix to cost vector offset for adj. node */
00685     c_uv = pbqp_get_costmatrix(this_,u,v);
00686     c_v = new PBQPVector(c_uv->getRowAsVector(0));
00687     *this_->node_costs[v] += *c_v;
00688     
00689     /* delete edge & free vec/mat */
00690     delete c_v;
00691     delete c_uv;
00692     delete_edge(this_,u,v);
00693   }   
00694 }
00695 
00696 /* find all trivial nodes and disconnect them */
00697 static   
00698 void eliminate_trivial_nodes(pbqp *this_)
00699 {
00700    int u;
00701    
00702    assert(this_ != NULL);
00703    assert(this_ -> node_costs != NULL);
00704    
00705    for(u=0;u < this_ -> num_nodes; u++) {
00706      if (this_->node_costs[u]->getLength() == 1) {
00707        disconnect_trivialnode(this_,u); 
00708      }
00709    }
00710 }
00711 
00712 /*****************************************************************************
00713  * Normal form for PBQP 
00714  ****************************************************************************/
00715 
00716 /* simplify a cost matrix. If the matrix
00717    is independent, then simplify_matrix
00718    returns true - otherwise false. In
00719    vectors u and v the offset values of
00720    the decomposition are stored. 
00721 */
00722 
00723 static
00724 bool normalize_matrix(PBQPMatrix *m, PBQPVector *u, PBQPVector *v)
00725 {
00726   assert( m != NULL);
00727   assert( u != NULL);
00728   assert( v != NULL);
00729   assert( u->getLength() > 0);
00730   assert( v->getLength() > 0);
00731   
00732   assert(m->getRows() == u->getLength());
00733   assert(m->getCols() == v->getLength());
00734 
00735   /* determine u vector */
00736   for(unsigned r = 0; r < m->getRows(); ++r) {
00737     PBQPNum min = m->getRowMin(r);
00738     (*u)[r] += min;
00739     if (!isInf(min)) {
00740       m->subFromRow(r, min);
00741     } else {
00742       m->setRow(r, 0);
00743     }
00744   }
00745   
00746   /* determine v vector */
00747   for(unsigned c = 0; c < m->getCols(); ++c) {
00748     PBQPNum min = m->getColMin(c);
00749     (*v)[c] += min;
00750     if (!isInf(min)) {
00751       m->subFromCol(c, min);
00752     } else {
00753       m->setCol(c, 0);
00754     }
00755   }
00756   
00757   /* determine whether matrix is 
00758      independent or not. 
00759     */
00760   return m->isZero();
00761 }
00762 
00763 /* simplify single edge */
00764 static
00765 void simplify_edge(pbqp *this_,int u,int v)
00766 {
00767   PBQPMatrix *costs;
00768   bool is_zero; 
00769   
00770   assert (this_ != NULL);
00771   assert (u >= 0 && u <this_->num_nodes);
00772   assert (v >= 0 && v <this_->num_nodes);
00773   assert (u != v);
00774 
00775   /* swap u and v  if u > v in order to avoid un-necessary
00776      tranpositions of the cost matrix */
00777   
00778   if (u > v) {
00779     int swap = u;
00780     u = v;
00781     v = swap;
00782   }
00783   
00784   /* get cost matrix and simplify it */  
00785   costs = get_costmatrix_ptr(this_,u,v);
00786   is_zero=normalize_matrix(costs,this_->node_costs[u],this_->node_costs[v]);
00787 
00788   /* delete edge */
00789   if(is_zero){
00790     delete_edge(this_,u,v);
00791     this_->changed = true;
00792   }
00793 }
00794 
00795 /* normalize cost matrices and remove 
00796    edges in PBQP if they ary independent, 
00797    i.e. can be decomposed into two 
00798    cost vectors.
00799 */
00800 static
00801 void eliminate_independent_edges(pbqp *this_)
00802 {
00803   int u,v;
00804   adjnode *adj_ptr,*next;
00805   
00806   assert(this_ != NULL);
00807   assert(this_ -> adj_list != NULL);
00808 
00809   this_->changed = false;
00810   for(u=0;u < this_->num_nodes;u++) {
00811     for (adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = next) {
00812       next = adj_ptr -> succ;
00813       v = adj_ptr -> adj;
00814       assert(v >= 0 && v < this_->num_nodes);
00815       if (u < v) {
00816         simplify_edge(this_,u,v);
00817       } 
00818     }
00819   }
00820 }
00821 
00822 
00823 /*****************************************************************************
00824  * PBQP reduction rules 
00825  ****************************************************************************/
00826 
00827 /* RI reduction
00828    This reduction rule is applied for nodes 
00829    of degree one. */
00830 
00831 static
00832 void apply_RI(pbqp *this_,int x)
00833 {
00834   int y;
00835   unsigned xlen,
00836            ylen;
00837   PBQPMatrix *c_yx;
00838   PBQPVector *c_x, *delta;
00839   
00840   assert(this_ != NULL);
00841   assert(x >= 0 && x < this_->num_nodes);
00842   assert(this_ -> adj_list[x] != NULL);
00843   assert(this_ -> adj_list[x] -> succ == NULL);
00844 
00845   /* get adjacence matrix */
00846   y = this_ -> adj_list[x] -> adj;
00847   assert(y >= 0 && y < this_->num_nodes);
00848   
00849   /* determine length of cost vectors for node x and y */
00850   xlen = this_ -> node_costs[x]->getLength();
00851   ylen = this_ -> node_costs[y]->getLength();
00852 
00853   /* get cost vector c_x and matrix c_yx */
00854   c_x = this_ -> node_costs[x];
00855   c_yx = pbqp_get_costmatrix(this_,y,x); 
00856   assert (c_yx != NULL);
00857 
00858   
00859   /* allocate delta vector */
00860   delta = new PBQPVector(ylen);
00861 
00862   /* compute delta vector */
00863   for(unsigned i = 0; i < ylen; ++i) {
00864     PBQPNum min =  (*c_yx)[i][0] + (*c_x)[0];
00865     for(unsigned j = 1; j < xlen; ++j) {
00866       PBQPNum c =  (*c_yx)[i][j] + (*c_x)[j];
00867       if ( c < min )  
00868          min = c;
00869     }
00870     (*delta)[i] = min; 
00871   } 
00872 
00873   /* add delta vector */
00874   *this_ -> node_costs[y] += *delta;
00875 
00876   /* delete node x */
00877   remove_node(this_,x);
00878 
00879   /* reorder adj. nodes of node x */
00880   reorder_adjnodes(this_,x);
00881 
00882   /* push node x on stack */
00883   assert(this_ -> stack_ptr < this_ -> num_nodes);
00884   this_->stack[this_ -> stack_ptr++] = x;
00885 
00886   /* free vec/mat */
00887   delete c_yx;
00888   delete delta;
00889 
00890   /* increment counter for number statistic */
00891   this_->num_ri++;
00892 }
00893 
00894 /* RII reduction
00895    This reduction rule is applied for nodes 
00896    of degree two. */
00897 
00898 static
00899 void apply_RII(pbqp *this_,int x)
00900 {
00901   int y,z; 
00902   unsigned xlen,ylen,zlen;
00903   adjnode *adj_yz;
00904 
00905   PBQPMatrix *c_yx, *c_zx;
00906   PBQPVector *cx;
00907   PBQPMatrix *delta;
00908  
00909   assert(this_ != NULL);
00910   assert(x >= 0 && x < this_->num_nodes);
00911   assert(this_ -> adj_list[x] != NULL);
00912   assert(this_ -> adj_list[x] -> succ != NULL);
00913   assert(this_ -> adj_list[x] -> succ -> succ == NULL);
00914 
00915   /* get adjacence matrix */
00916   y = this_ -> adj_list[x] -> adj;
00917   z = this_ -> adj_list[x] -> succ -> adj;
00918   assert(y >= 0 && y < this_->num_nodes);
00919   assert(z >= 0 && z < this_->num_nodes);
00920   
00921   /* determine length of cost vectors for node x and y */
00922   xlen = this_ -> node_costs[x]->getLength();
00923   ylen = this_ -> node_costs[y]->getLength();
00924   zlen = this_ -> node_costs[z]->getLength();
00925 
00926   /* get cost vector c_x and matrix c_yx */
00927   cx = this_ -> node_costs[x];
00928   c_yx = pbqp_get_costmatrix(this_,y,x); 
00929   c_zx = pbqp_get_costmatrix(this_,z,x); 
00930   assert(c_yx != NULL);
00931   assert(c_zx != NULL);
00932 
00933   /* Colour Heuristic */
00934   if ( (adj_yz = find_adjnode(this_,y,z)) != NULL) {
00935     adj_yz->tc_valid = false;
00936     adj_yz->reverse->tc_valid = false; 
00937   }
00938 
00939   /* allocate delta matrix */
00940   delta = new PBQPMatrix(ylen, zlen);
00941 
00942   /* compute delta matrix */
00943   for(unsigned i=0;i<ylen;i++) {
00944     for(unsigned j=0;j<zlen;j++) {
00945       PBQPNum min = (*c_yx)[i][0] + (*c_zx)[j][0] + (*cx)[0];
00946       for(unsigned k=1;k<xlen;k++) {
00947         PBQPNum c = (*c_yx)[i][k] + (*c_zx)[j][k] + (*cx)[k];
00948         if ( c < min ) {
00949           min = c;
00950         }
00951       }
00952       (*delta)[i][j] = min;
00953     }
00954   }
00955 
00956   /* add delta matrix */
00957   add_pbqp_edgecosts(this_,y,z,delta);
00958 
00959   /* delete node x */
00960   remove_node(this_,x);
00961 
00962   /* simplify cost matrix c_yz */
00963   simplify_edge(this_,y,z);
00964 
00965   /* reorder adj. nodes */
00966   reorder_adjnodes(this_,x);
00967 
00968   /* push node x on stack */
00969   assert(this_ -> stack_ptr < this_ -> num_nodes);
00970   this_->stack[this_ -> stack_ptr++] = x;
00971 
00972   /* free vec/mat */
00973   delete c_yx;
00974   delete c_zx;
00975   delete delta;
00976 
00977   /* increment counter for number statistic */
00978   this_->num_rii++;
00979 
00980 }
00981 
00982 /* RN reduction */
00983 static
00984 void apply_RN(pbqp *this_,int x)
00985 {
00986   unsigned xlen;
00987 
00988   assert(this_ != NULL);
00989   assert(x >= 0 && x < this_->num_nodes);
00990   assert(this_ -> node_costs[x] != NULL);
00991 
00992   xlen = this_ -> node_costs[x] -> getLength();
00993 
00994   /* after application of RN rule no optimality
00995      can be guaranteed! */
00996   this_ -> optimal = false;
00997   
00998   /* push node x on stack */
00999   assert(this_ -> stack_ptr < this_ -> num_nodes);
01000   this_->stack[this_ -> stack_ptr++] = x;
01001 
01002   /* delete node x */ 
01003   remove_node(this_,x);
01004 
01005   /* reorder adj. nodes of node x */
01006   reorder_adjnodes(this_,x);
01007 
01008   /* increment counter for number statistic */
01009   this_->num_rn++;
01010 }
01011 
01012 
01013 static
01014 void compute_tc_info(pbqp *this_, adjnode *p)
01015 {
01016    adjnode *r;
01017    PBQPMatrix *m;
01018    int x,y;
01019    PBQPVector *c_x, *c_y;
01020    int *row_inf_counts;
01021 
01022    assert(p->reverse != NULL);
01023 
01024    /* set flags */ 
01025    r = p->reverse;
01026    p->tc_valid = true;
01027    r->tc_valid = true;
01028 
01029    /* get edge */
01030    x = r->adj;
01031    y = p->adj;
01032 
01033    /* get cost vectors */
01034    c_x = this_ -> node_costs[x];
01035    c_y = this_ -> node_costs[y];
01036 
01037    /* get cost matrix */
01038    m = pbqp_get_costmatrix(this_, x, y);
01039 
01040   
01041    /* allocate allowed set for edge (x,y) and (y,x) */
01042    if (p->tc_safe_regs == NULL) {
01043      p->tc_safe_regs = (int *) malloc(sizeof(int) * c_x->getLength());
01044    } 
01045 
01046    if (r->tc_safe_regs == NULL ) {
01047      r->tc_safe_regs = (int *) malloc(sizeof(int) * c_y->getLength());
01048    }
01049 
01050    p->tc_impact = r->tc_impact = 0;
01051 
01052    row_inf_counts = (int *) alloca(sizeof(int) * c_x->getLength());
01053 
01054    /* init arrays */
01055    p->tc_safe_regs[0] = 0;
01056    row_inf_counts[0] = 0;
01057    for(unsigned i = 1; i < c_x->getLength(); ++i){
01058      p->tc_safe_regs[i] = 1;
01059      row_inf_counts[i] = 0;
01060    }
01061 
01062    r->tc_safe_regs[0] = 0;
01063    for(unsigned j = 1; j < c_y->getLength(); ++j){
01064      r->tc_safe_regs[j] = 1;
01065    }
01066 
01067    for(unsigned j = 0; j < c_y->getLength(); ++j) {
01068       int col_inf_counts = 0;
01069       for (unsigned i = 0; i < c_x->getLength(); ++i) {
01070          if (isInf((*m)[i][j])) {
01071               ++col_inf_counts;
01072               ++row_inf_counts[i];
01073          
01074               p->tc_safe_regs[i] = 0;
01075               r->tc_safe_regs[j] = 0;
01076          }
01077       }
01078       if (col_inf_counts > p->tc_impact) {
01079            p->tc_impact = col_inf_counts;
01080       }
01081    }
01082 
01083    for(unsigned i = 0; i < c_x->getLength(); ++i){
01084      if (row_inf_counts[i] > r->tc_impact)
01085      {
01086            r->tc_impact = row_inf_counts[i];
01087      }
01088    }
01089            
01090    delete m;
01091 }
01092 
01093 /* 
01094  * Checks whether node x can be locally coloured. 
01095  */
01096 static 
01097 int is_colorable(pbqp *this_,int x)
01098 {
01099   adjnode *adj_ptr;
01100   PBQPVector *c_x;
01101   int result = 1;
01102   int *allowed;
01103   int num_allowed = 0;
01104   unsigned total_impact = 0;
01105 
01106   assert(this_ != NULL);
01107   assert(x >= 0 && x < this_->num_nodes);
01108   assert(this_ -> node_costs[x] != NULL);
01109 
01110   c_x = this_ -> node_costs[x];
01111 
01112   /* allocate allowed set */
01113   allowed = (int *)malloc(sizeof(int) * c_x->getLength());
01114   for(unsigned i = 0; i < c_x->getLength(); ++i){
01115     if (!isInf((*c_x)[i]) && i > 0) {
01116       allowed[i] = 1;
01117       ++num_allowed;
01118     } else { 
01119       allowed[i] = 0;
01120     }
01121   }
01122 
01123   /* determine local minimum */
01124   for(adj_ptr=this_->adj_list[x] ;adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
01125       if (!adj_ptr -> tc_valid) { 
01126           compute_tc_info(this_, adj_ptr);
01127       }
01128 
01129       total_impact += adj_ptr->tc_impact;
01130 
01131       if (num_allowed > 0) {
01132           for (unsigned i = 1; i < c_x->getLength(); ++i){
01133             if (allowed[i]){
01134               if (!adj_ptr->tc_safe_regs[i]){
01135                 allowed[i] = 0;
01136                 --num_allowed;
01137                 if (num_allowed == 0)
01138                     break;
01139               }
01140             }
01141           }
01142       }
01143       
01144       if ( total_impact >= c_x->getLength() - 1 && num_allowed == 0 ) {
01145          result = 0;
01146          break;
01147       }
01148   }
01149   free(allowed);
01150 
01151   return result;
01152 }
01153 
01154 /* use briggs heuristic 
01155   note: this_ is not a general heuristic. it only is useful for 
01156   interference graphs.
01157  */
01158 int pop_colorablenode(pbqp *this_)
01159 {
01160   int deg;
01161   bucketnode *min_bucket=NULL;
01162   PBQPNum min = std::numeric_limits<PBQPNum>::infinity();
01163  
01164   /* select node where the number of colors is less than the node degree */
01165   for(deg=this_->max_deg;deg > 2;deg--) {
01166     bucketnode *bucket;
01167     for(bucket=this_->bucket_list[deg];bucket!= NULL;bucket = bucket -> succ) {
01168       int u = bucket->u;
01169       if (is_colorable(this_,u)) {
01170         pbqp_remove_bucket(this_,bucket);
01171         this_->num_rn_special++;
01172         free(bucket);
01173         return u; 
01174       } 
01175     }
01176   }
01177 
01178   /* select node with minimal ratio between average node costs and degree of node */
01179   for(deg=this_->max_deg;deg >2; deg--) {
01180     bucketnode *bucket;
01181     for(bucket=this_->bucket_list[deg];bucket!= NULL;bucket = bucket -> succ) {
01182       PBQPNum h;
01183       int u;
01184  
01185       u = bucket->u;
01186       assert(u>=0 && u < this_->num_nodes);
01187       h = (*this_->node_costs[u])[0] / (PBQPNum) deg;
01188       if (h < min) {
01189         min_bucket = bucket;
01190         min = h;
01191       } 
01192     }
01193   }
01194 
01195   /* return node and free bucket */
01196   if (min_bucket != NULL) {
01197     int u;
01198 
01199     pbqp_remove_bucket(this_,min_bucket);
01200     u = min_bucket->u;
01201     free(min_bucket);
01202     return u;
01203   } else {
01204     return -1;
01205   }
01206 }
01207 
01208 
01209 /*****************************************************************************
01210  * PBQP graph parsing
01211  ****************************************************************************/
01212  
01213 /* reduce pbqp problem (first phase) */
01214 static
01215 void reduce_pbqp(pbqp *this_)
01216 {
01217   int u;
01218 
01219   assert(this_ != NULL);
01220   assert(this_->bucket_list != NULL);
01221 
01222   for(;;){
01223 
01224     if (this_->bucket_list[1] != NULL) {
01225       u = pop_node(this_,1);
01226       apply_RI(this_,u); 
01227     } else if (this_->bucket_list[2] != NULL) {
01228       u = pop_node(this_,2);
01229       apply_RII(this_,u);
01230     } else if ((u = pop_colorablenode(this_)) != -1) {
01231       apply_RN(this_,u);
01232     } else {
01233       break;
01234     }
01235   } 
01236 }
01237 
01238 /*****************************************************************************
01239  * PBQP back propagation
01240  ****************************************************************************/
01241 
01242 /* determine solution of a reduced node. Either
01243    RI or RII was applied for this_ node. */
01244 static
01245 void determine_solution(pbqp *this_,int x)
01246 {
01247   PBQPVector *v = new PBQPVector(*this_ -> node_costs[x]);
01248   adjnode *adj_ptr;
01249 
01250   assert(this_ != NULL);
01251   assert(x >= 0 && x < this_->num_nodes);
01252   assert(this_ -> adj_list != NULL);
01253   assert(this_ -> solution != NULL);
01254 
01255   for(adj_ptr=this_->adj_list[x] ;adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
01256     int y = adj_ptr -> adj;
01257     int y_sol = this_ -> solution[y];
01258 
01259     PBQPMatrix *c_yx = pbqp_get_costmatrix(this_,y,x);
01260     assert(y_sol >= 0 && y_sol < (int)this_->node_costs[y]->getLength());
01261     (*v) += c_yx->getRowAsVector(y_sol);
01262     delete c_yx;
01263   }
01264   this_ -> solution[x] = v->minIndex();
01265 
01266   delete v;
01267 }
01268 
01269 /* back popagation phase of PBQP */
01270 static
01271 void back_propagate(pbqp *this_)
01272 {
01273    int i;
01274 
01275    assert(this_ != NULL);
01276    assert(this_->stack != NULL);
01277    assert(this_->stack_ptr < this_->num_nodes);
01278 
01279    for(i=this_ -> stack_ptr-1;i>=0;i--) {
01280       int x = this_ -> stack[i];
01281       assert( x >= 0 && x < this_ -> num_nodes);
01282       reinsert_node(this_,x);
01283       determine_solution(this_,x);
01284    }
01285 }
01286 
01287 /* solve trivial nodes of degree zero */
01288 static
01289 void determine_trivialsolution(pbqp *this_)
01290 {
01291   int u;
01292   PBQPNum delta;
01293 
01294   assert( this_ != NULL);
01295   assert( this_ -> bucket_list != NULL);
01296 
01297   /* determine trivial solution */
01298   while (this_->bucket_list[0] != NULL) {
01299     u = pop_node(this_,0);
01300 
01301     assert( u >= 0 && u < this_ -> num_nodes);
01302 
01303     this_->solution[u] = this_->node_costs[u]->minIndex();
01304     delta = (*this_->node_costs[u])[this_->solution[u]];
01305     this_->min = this_->min + delta;
01306 
01307     /* increment counter for number statistic */
01308     this_->num_r0++;
01309   }
01310 }
01311 
01312 /*****************************************************************************
01313  * debug facilities
01314  ****************************************************************************/
01315 static
01316 void check_pbqp(pbqp *this_)
01317 {
01318   int u,v;
01319   PBQPMatrix *costs;
01320   adjnode *adj_ptr;
01321   
01322   assert( this_ != NULL);
01323   
01324   for(u=0;u< this_->num_nodes; u++) {
01325     assert (this_ -> node_costs[u] != NULL);
01326     for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
01327       v = adj_ptr -> adj;
01328       assert( v>= 0 && v < this_->num_nodes);
01329       if (u < v ) {
01330         costs = adj_ptr -> costs;
01331         assert( costs->getRows() == this_->node_costs[u]->getLength() &&
01332                 costs->getCols() == this_->node_costs[v]->getLength());
01333       }           
01334     }
01335   }
01336 }
01337 
01338 /*****************************************************************************
01339  * PBQP solve routines 
01340  ****************************************************************************/
01341 
01342 /* solve PBQP problem */
01343 void solve_pbqp(pbqp *this_)
01344 {
01345   assert(this_ != NULL);
01346   assert(!this_->solved); 
01347   
01348   /* check vector & matrix dimensions */
01349   check_pbqp(this_);
01350 
01351   /* simplify PBQP problem */  
01352   
01353   /* eliminate trivial nodes, i.e.
01354      nodes with cost vectors of length one.  */
01355   eliminate_trivial_nodes(this_); 
01356 
01357   /* eliminate edges with independent 
01358      cost matrices and normalize matrices */
01359   eliminate_independent_edges(this_);
01360   
01361   /* create bucket list for graph parsing */
01362   create_bucketlist(this_);
01363   
01364   /* reduce phase */
01365   reduce_pbqp(this_);
01366   
01367   /* solve trivial nodes */
01368   determine_trivialsolution(this_);
01369 
01370   /* back propagation phase */
01371   back_propagate(this_); 
01372   
01373   this_->solved = true;
01374 }
01375 
01376 /* get solution of a node */
01377 int get_pbqp_solution(pbqp *this_,int x)
01378 {
01379   assert(this_ != NULL);
01380   assert(this_->solution != NULL);
01381   assert(this_ -> solved);
01382   
01383   return this_->solution[x];
01384 }
01385 
01386 /* is solution optimal? */
01387 bool is_pbqp_optimal(pbqp *this_)
01388 {
01389   assert(this_ -> solved);
01390   return this_->optimal;
01391 }
01392 
01393 } 
01394 
01395 /* end of pbqp.c */