LLVM API Documentation
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 */