blob: 6b2110583fe33aac0c355cb2eaff86392f4484ba [file] [log] [blame]
Evan Chengb1290a62008-10-02 18:29:27 +00001//===---------------- PBQP.cpp --------- PBQP Solver ------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Developed by: Bernhard Scholz
Evan Cheng17a82ea2008-10-03 17:11:58 +000011// The University of Sydney
Evan Chengb1290a62008-10-02 18:29:27 +000012// http://www.it.usyd.edu.au/~scholz
13//===----------------------------------------------------------------------===//
14
15
16#include <limits>
17#include <cassert>
Andrew Lenharth88ab90b2008-10-02 20:15:08 +000018#include <cstring>
Evan Chengb1290a62008-10-02 18:29:27 +000019
20#include "PBQP.h"
21
22namespace llvm {
23
24/**************************************************************************
25 * Data Structures
26 **************************************************************************/
27
28/* edge of PBQP graph */
29typedef struct adjnode {
30 struct adjnode *prev, /* doubly chained list */
31 *succ,
32 *reverse; /* reverse edge */
33 int adj; /* adj. node */
34 PBQPMatrix *costs; /* cost matrix of edge */
35
36 bool tc_valid; /* flag whether following fields are valid */
37 int *tc_safe_regs; /* safe registers */
38 int tc_impact; /* impact */
39} adjnode;
40
41/* bucket node */
42typedef struct bucketnode {
43 struct bucketnode *prev; /* doubly chained list */
44 struct bucketnode *succ;
45 int u; /* node */
46} bucketnode;
47
48/* data structure of partitioned boolean quadratic problem */
49struct pbqp {
50 int num_nodes; /* number of nodes */
51 int max_deg; /* maximal degree of a node */
52 bool solved; /* flag that indicates whether PBQP has been solved yet */
53 bool optimal; /* flag that indicates whether PBQP is optimal */
54 PBQPNum min;
55 bool changed; /* flag whether graph has changed in simplification */
56
57 /* node fields */
58 PBQPVector **node_costs; /* cost vectors of nodes */
Evan Cheng17a82ea2008-10-03 17:11:58 +000059 int *node_deg; /* node degree of nodes */
60 int *solution; /* solution for node */
Evan Chengb1290a62008-10-02 18:29:27 +000061 adjnode **adj_list; /* adj. list */
62 bucketnode **bucket_ptr; /* bucket pointer of a node */
63
64 /* node stack */
Evan Cheng17a82ea2008-10-03 17:11:58 +000065 int *stack; /* stack of nodes */
Evan Chengb1290a62008-10-02 18:29:27 +000066 int stack_ptr; /* stack pointer */
67
68 /* bucket fields */
69 bucketnode **bucket_list; /* bucket list */
70
71 int num_r0; /* counters for number statistics */
72 int num_ri;
73 int num_rii;
74 int num_rn;
75 int num_rn_special;
76};
77
78bool isInf(PBQPNum n) { return n == std::numeric_limits<PBQPNum>::infinity(); }
79
80/*****************************************************************************
81 * allocation/de-allocation of pbqp problem
82 ****************************************************************************/
83
84/* allocate new partitioned boolean quadratic program problem */
85pbqp *alloc_pbqp(int num_nodes)
86{
87 pbqp *this_;
88 int u;
89
90 assert(num_nodes > 0);
91
92 /* allocate memory for pbqp data structure */
93 this_ = (pbqp *)malloc(sizeof(pbqp));
94
95 /* Initialize pbqp fields */
96 this_->num_nodes = num_nodes;
97 this_->solved = false;
98 this_->optimal = true;
99 this_->min = 0.0;
100 this_->max_deg = 0;
101 this_->changed = false;
102 this_->num_r0 = 0;
103 this_->num_ri = 0;
104 this_->num_rii = 0;
105 this_->num_rn = 0;
106 this_->num_rn_special = 0;
107
108 /* initialize/allocate stack fields of pbqp */
109 this_->stack = (int *) malloc(sizeof(int)*num_nodes);
110 this_->stack_ptr = 0;
111
112 /* initialize/allocate node fields of pbqp */
113 this_->adj_list = (adjnode **) malloc(sizeof(adjnode *)*num_nodes);
114 this_->node_deg = (int *) malloc(sizeof(int)*num_nodes);
115 this_->solution = (int *) malloc(sizeof(int)*num_nodes);
116 this_->bucket_ptr = (bucketnode **) malloc(sizeof(bucketnode **)*num_nodes);
117 this_->node_costs = (PBQPVector**) malloc(sizeof(PBQPVector*) * num_nodes);
118 for(u=0;u<num_nodes;u++) {
119 this_->solution[u]=-1;
120 this_->adj_list[u]=NULL;
121 this_->node_deg[u]=0;
122 this_->bucket_ptr[u]=NULL;
123 this_->node_costs[u]=NULL;
124 }
125
126 /* initialize bucket list */
127 this_->bucket_list = NULL;
128
129 return this_;
130}
131
132/* free pbqp problem */
133void free_pbqp(pbqp *this_)
134{
135 int u;
136 int deg;
137 adjnode *adj_ptr,*adj_next;
138 bucketnode *bucket,*bucket_next;
139
140 assert(this_ != NULL);
141
142 /* free node cost fields */
143 for(u=0;u < this_->num_nodes;u++) {
144 delete this_->node_costs[u];
145 }
146 free(this_->node_costs);
147
148 /* free bucket list */
149 for(deg=0;deg<=this_->max_deg;deg++) {
150 for(bucket=this_->bucket_list[deg];bucket!=NULL;bucket=bucket_next) {
151 this_->bucket_ptr[bucket->u] = NULL;
152 bucket_next = bucket-> succ;
153 free(bucket);
154 }
155 }
156 free(this_->bucket_list);
157
158 /* free adj. list */
159 assert(this_->adj_list != NULL);
160 for(u=0;u < this_->num_nodes; u++) {
161 for(adj_ptr = this_->adj_list[u]; adj_ptr != NULL; adj_ptr = adj_next) {
162 adj_next = adj_ptr -> succ;
163 if (u < adj_ptr->adj) {
Evan Cheng17a82ea2008-10-03 17:11:58 +0000164 assert(adj_ptr != NULL);
165 delete adj_ptr->costs;
Evan Chengb1290a62008-10-02 18:29:27 +0000166 }
167 if (adj_ptr -> tc_safe_regs != NULL) {
168 free(adj_ptr -> tc_safe_regs);
169 }
170 free(adj_ptr);
171 }
172 }
173 free(this_->adj_list);
174
175 /* free other node fields */
176 free(this_->node_deg);
177 free(this_->solution);
178 free(this_->bucket_ptr);
179
180 /* free stack */
181 free(this_->stack);
182
183 /* free pbqp data structure itself */
184 free(this_);
185}
186
187
188/****************************************************************************
189 * adj. node routines
190 ****************************************************************************/
191
192/* find data structure of adj. node of a given node */
193static
194adjnode *find_adjnode(pbqp *this_,int u,int v)
195{
196 adjnode *adj_ptr;
197
198 assert (this_ != NULL);
199 assert (u >= 0 && u < this_->num_nodes);
200 assert (v >= 0 && v < this_->num_nodes);
201 assert(this_->adj_list != NULL);
202
203 for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
204 if (adj_ptr->adj == v) {
205 return adj_ptr;
206 }
207 }
208 return NULL;
209}
210
211/* allocate a new data structure for adj. node */
212static
213adjnode *alloc_adjnode(pbqp *this_,int u, PBQPMatrix *costs)
214{
215 adjnode *p;
216
217 assert(this_ != NULL);
218 assert(costs != NULL);
219 assert(u >= 0 && u < this_->num_nodes);
220
221 p = (adjnode *)malloc(sizeof(adjnode));
222 assert(p != NULL);
223
224 p->adj = u;
225 p->costs = costs;
226
227 p->tc_valid= false;
228 p->tc_safe_regs = NULL;
229 p->tc_impact = 0;
230
231 return p;
232}
233
234/* insert adjacence node to adj. list */
235static
236void insert_adjnode(pbqp *this_, int u, adjnode *adj_ptr)
237{
238
239 assert(this_ != NULL);
240 assert(adj_ptr != NULL);
241 assert(u >= 0 && u < this_->num_nodes);
242
243 /* if adjacency list of node is not empty -> update
244 first node of the list */
245 if (this_ -> adj_list[u] != NULL) {
246 assert(this_->adj_list[u]->prev == NULL);
247 this_->adj_list[u] -> prev = adj_ptr;
248 }
249
250 /* update doubly chained list pointers of pointers */
251 adj_ptr -> succ = this_->adj_list[u];
252 adj_ptr -> prev = NULL;
253
254 /* update adjacency list pointer of node u */
255 this_->adj_list[u] = adj_ptr;
256}
257
258/* remove entry in an adj. list */
259static
260void remove_adjnode(pbqp *this_, int u, adjnode *adj_ptr)
261{
262 assert(this_!= NULL);
263 assert(u >= 0 && u <= this_->num_nodes);
264 assert(this_->adj_list != NULL);
265 assert(adj_ptr != NULL);
266
267 if (adj_ptr -> prev == NULL) {
268 this_->adj_list[u] = adj_ptr -> succ;
269 } else {
270 adj_ptr -> prev -> succ = adj_ptr -> succ;
271 }
272
273 if (adj_ptr -> succ != NULL) {
274 adj_ptr -> succ -> prev = adj_ptr -> prev;
275 }
276
277 if(adj_ptr->reverse != NULL) {
278 adjnode *rev = adj_ptr->reverse;
279 rev->reverse = NULL;
280 }
281
282 if (adj_ptr -> tc_safe_regs != NULL) {
283 free(adj_ptr -> tc_safe_regs);
284 }
285
286 free(adj_ptr);
287}
288
289/*****************************************************************************
290 * node functions
291 ****************************************************************************/
292
293/* get degree of a node */
294static
295int get_deg(pbqp *this_,int u)
296{
297 adjnode *adj_ptr;
298 int deg = 0;
299
300 assert(this_ != NULL);
301 assert(u >= 0 && u < this_->num_nodes);
302 assert(this_->adj_list != NULL);
303
304 for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
305 deg ++;
306 }
307 return deg;
308}
309
310/* reinsert node */
311static
312void reinsert_node(pbqp *this_,int u)
313{
314 adjnode *adj_u,
315 *adj_v;
316
317 assert(this_!= NULL);
318 assert(u >= 0 && u <= this_->num_nodes);
319 assert(this_->adj_list != NULL);
320
321 for(adj_u = this_ -> adj_list[u]; adj_u != NULL; adj_u = adj_u -> succ) {
322 int v = adj_u -> adj;
323 adj_v = alloc_adjnode(this_,u,adj_u->costs);
324 insert_adjnode(this_,v,adj_v);
325 }
326}
327
328/* remove node */
329static
330void remove_node(pbqp *this_,int u)
331{
332 adjnode *adj_ptr;
333
334 assert(this_!= NULL);
335 assert(u >= 0 && u <= this_->num_nodes);
336 assert(this_->adj_list != NULL);
337
338 for(adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
339 remove_adjnode(this_,adj_ptr->adj,adj_ptr -> reverse);
340 }
341}
342
343/*****************************************************************************
344 * edge functions
345 ****************************************************************************/
346
347/* insert edge to graph */
348/* (does not check whether edge exists in graph */
349static
350void insert_edge(pbqp *this_, int u, int v, PBQPMatrix *costs)
351{
352 adjnode *adj_u,
353 *adj_v;
354
355 /* create adjanceny entry for u */
356 adj_u = alloc_adjnode(this_,v,costs);
357 insert_adjnode(this_,u,adj_u);
358
359
360 /* create adjanceny entry for v */
361 adj_v = alloc_adjnode(this_,u,costs);
362 insert_adjnode(this_,v,adj_v);
363
364 /* create link for reverse edge */
365 adj_u -> reverse = adj_v;
366 adj_v -> reverse = adj_u;
367}
368
369/* delete edge */
370static
371void delete_edge(pbqp *this_,int u,int v)
372{
373 adjnode *adj_ptr;
374 adjnode *rev;
375
376 assert(this_ != NULL);
377 assert( u >= 0 && u < this_->num_nodes);
378 assert( v >= 0 && v < this_->num_nodes);
379
380 adj_ptr=find_adjnode(this_,u,v);
381 assert(adj_ptr != NULL);
382 assert(adj_ptr->reverse != NULL);
383
384 delete adj_ptr -> costs;
385
386 rev = adj_ptr->reverse;
387 remove_adjnode(this_,u,adj_ptr);
388 remove_adjnode(this_,v,rev);
389}
390
391/*****************************************************************************
392 * cost functions
393 ****************************************************************************/
394
395/* Note: Since cost(u,v) = transpose(cost(v,u)), it would be necessary to store
396 two matrices for both edges (u,v) and (v,u). However, we only store the
397 matrix for the case u < v. For the other case we transpose the stored matrix
398 if required.
399*/
400
401/* add costs to cost vector of a node */
402void add_pbqp_nodecosts(pbqp *this_,int u, PBQPVector *costs)
403{
404 assert(this_ != NULL);
405 assert(costs != NULL);
406 assert(u >= 0 && u <= this_->num_nodes);
407
408 if (!this_->node_costs[u]) {
409 this_->node_costs[u] = new PBQPVector(*costs);
410 } else {
411 *this_->node_costs[u] += *costs;
412 }
413}
414
415/* get cost matrix ptr */
416static
417PBQPMatrix *get_costmatrix_ptr(pbqp *this_, int u, int v)
418{
419 adjnode *adj_ptr;
420 PBQPMatrix *m = NULL;
421
422 assert (this_ != NULL);
423 assert (u >= 0 && u < this_->num_nodes);
424 assert (v >= 0 && v < this_->num_nodes);
425
426 adj_ptr = find_adjnode(this_,u,v);
427
428 if (adj_ptr != NULL) {
429 m = adj_ptr -> costs;
430 }
431
432 return m;
433}
434
435/* get cost matrix ptr */
436/* Note: only the pointer is returned for
437 cost(u,v), if u < v.
438*/
439static
440PBQPMatrix *pbqp_get_costmatrix(pbqp *this_, int u, int v)
441{
442 adjnode *adj_ptr = find_adjnode(this_,u,v);
443
444 if (adj_ptr != NULL) {
445 if ( u < v) {
446 return new PBQPMatrix(*adj_ptr->costs);
447 } else {
448 return new PBQPMatrix(adj_ptr->costs->transpose());
449 }
450 } else {
451 return NULL;
452 }
453}
454
455/* add costs to cost matrix of an edge */
456void add_pbqp_edgecosts(pbqp *this_,int u,int v, PBQPMatrix *costs)
457{
458 PBQPMatrix *adj_costs;
459
460 assert(this_!= NULL);
461 assert(costs != NULL);
462 assert(u >= 0 && u <= this_->num_nodes);
463 assert(v >= 0 && v <= this_->num_nodes);
464
465 /* does the edge u-v exists ? */
466 if (u == v) {
467 PBQPVector *diag = new PBQPVector(costs->diagonalize());
468 add_pbqp_nodecosts(this_,v,diag);
469 delete diag;
470 } else if ((adj_costs = get_costmatrix_ptr(this_,u,v))!=NULL) {
471 if ( u < v) {
472 *adj_costs += *costs;
473 } else {
474 *adj_costs += costs->transpose();
475 }
476 } else {
477 adj_costs = new PBQPMatrix((u < v) ? *costs : costs->transpose());
478 insert_edge(this_,u,v,adj_costs);
479 }
480}
481
482/* remove bucket from bucket list */
483static
484void pbqp_remove_bucket(pbqp *this_, bucketnode *bucket)
485{
486 int u = bucket->u;
487
488 assert(this_ != NULL);
489 assert(u >= 0 && u < this_->num_nodes);
490 assert(this_->bucket_list != NULL);
491 assert(this_->bucket_ptr[u] != NULL);
492
493 /* update predecessor node in bucket list
494 (if no preceeding bucket exists, then
495 the bucket_list pointer needs to be
496 updated.)
497 */
498 if (bucket->prev != NULL) {
499 bucket->prev-> succ = bucket->succ;
500 } else {
501 this_->bucket_list[this_->node_deg[u]] = bucket -> succ;
502 }
503
504 /* update successor node in bucket list */
505 if (bucket->succ != NULL) {
506 bucket->succ-> prev = bucket->prev;
507 }
508}
509
510/**********************************************************************************
511 * pop functions
512 **********************************************************************************/
513
514/* pop node of given degree */
515static
516int pop_node(pbqp *this_,int deg)
517{
518 bucketnode *bucket;
519 int u;
520
521 assert(this_ != NULL);
522 assert(deg >= 0 && deg <= this_->max_deg);
523 assert(this_->bucket_list != NULL);
524
525 /* get first bucket of bucket list */
526 bucket = this_->bucket_list[deg];
527 assert(bucket != NULL);
528
529 /* remove bucket */
530 pbqp_remove_bucket(this_,bucket);
531 u = bucket->u;
532 free(bucket);
533 return u;
534}
535
536/**********************************************************************************
537 * reorder functions
538 **********************************************************************************/
539
540/* add bucket to bucketlist */
541static
542void add_to_bucketlist(pbqp *this_,bucketnode *bucket, int deg)
543{
544 bucketnode *old_head;
545
546 assert(bucket != NULL);
547 assert(this_ != NULL);
548 assert(deg >= 0 && deg <= this_->max_deg);
549 assert(this_->bucket_list != NULL);
550
551 /* store node degree (for re-ordering purposes)*/
552 this_->node_deg[bucket->u] = deg;
553
554 /* put bucket to front of doubly chained list */
555 old_head = this_->bucket_list[deg];
556 bucket -> prev = NULL;
557 bucket -> succ = old_head;
558 this_ -> bucket_list[deg] = bucket;
559 if (bucket -> succ != NULL ) {
560 assert ( old_head -> prev == NULL);
561 old_head -> prev = bucket;
562 }
563}
564
565
566/* reorder node in bucket list according to
567 current node degree */
568static
569void reorder_node(pbqp *this_, int u)
570{
571 int deg;
572
573 assert(this_ != NULL);
574 assert(u>= 0 && u < this_->num_nodes);
575 assert(this_->bucket_list != NULL);
576 assert(this_->bucket_ptr[u] != NULL);
577
578 /* get current node degree */
579 deg = get_deg(this_,u);
580
581 /* remove bucket from old bucket list only
582 if degree of node has changed. */
583 if (deg != this_->node_deg[u]) {
584 pbqp_remove_bucket(this_,this_->bucket_ptr[u]);
585 add_to_bucketlist(this_,this_->bucket_ptr[u],deg);
586 }
587}
588
589/* reorder adj. nodes of a node */
590static
591void reorder_adjnodes(pbqp *this_,int u)
592{
593 adjnode *adj_ptr;
594
595 assert(this_!= NULL);
596 assert(u >= 0 && u <= this_->num_nodes);
597 assert(this_->adj_list != NULL);
598
599 for(adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
600 reorder_node(this_,adj_ptr->adj);
601 }
602}
603
604/**********************************************************************************
605 * creation functions
606 **********************************************************************************/
607
608/* create new bucket entry */
609/* consistency of the bucket list is not checked! */
610static
611void create_bucket(pbqp *this_,int u,int deg)
612{
613 bucketnode *bucket;
614
615 assert(this_ != NULL);
616 assert(u >= 0 && u < this_->num_nodes);
617 assert(this_->bucket_list != NULL);
618
619 bucket = (bucketnode *)malloc(sizeof(bucketnode));
620 assert(bucket != NULL);
621
622 bucket -> u = u;
623 this_->bucket_ptr[u] = bucket;
624
625 add_to_bucketlist(this_,bucket,deg);
626}
627
628/* create bucket list */
629static
630void create_bucketlist(pbqp *this_)
631{
632 int u;
633 int max_deg;
634 int deg;
635
636 assert(this_ != NULL);
637 assert(this_->bucket_list == NULL);
638
639 /* determine max. degree of the nodes */
640 max_deg = 2; /* at least of degree two! */
641 for(u=0;u<this_->num_nodes;u++) {
642 deg = this_->node_deg[u] = get_deg(this_,u);
643 if (deg > max_deg) {
644 max_deg = deg;
645 }
646 }
647 this_->max_deg = max_deg;
648
649 /* allocate bucket list */
650 this_ -> bucket_list = (bucketnode **)malloc(sizeof(bucketnode *)*(max_deg + 1));
651 memset(this_->bucket_list,0,sizeof(bucketnode *)*(max_deg + 1));
652 assert(this_->bucket_list != NULL);
653
654 /* insert nodes to the list */
655 for(u=0;u<this_->num_nodes;u++) {
656 create_bucket(this_,u,this_->node_deg[u]);
657 }
658}
659
660/*****************************************************************************
661 * PBQP simplification for trivial nodes
662 ****************************************************************************/
663
664/* remove trivial node with cost vector length of one */
665static
666void disconnect_trivialnode(pbqp *this_,int u)
667{
668 int v;
669 adjnode *adj_ptr,
670 *next;
671 PBQPMatrix *c_uv;
672 PBQPVector *c_v;
673
674 assert(this_ != NULL);
675 assert(this_->node_costs != NULL);
676 assert(u >= 0 && u < this_ -> num_nodes);
677 assert(this_->node_costs[u]->getLength() == 1);
678
679 /* add edge costs to node costs of adj. nodes */
680 for(adj_ptr = this_->adj_list[u]; adj_ptr != NULL; adj_ptr = next){
681 next = adj_ptr -> succ;
682 v = adj_ptr -> adj;
683 assert(v >= 0 && v < this_ -> num_nodes);
684
685 /* convert matrix to cost vector offset for adj. node */
686 c_uv = pbqp_get_costmatrix(this_,u,v);
687 c_v = new PBQPVector(c_uv->getRowAsVector(0));
688 *this_->node_costs[v] += *c_v;
689
690 /* delete edge & free vec/mat */
691 delete c_v;
692 delete c_uv;
693 delete_edge(this_,u,v);
694 }
695}
696
697/* find all trivial nodes and disconnect them */
698static
699void eliminate_trivial_nodes(pbqp *this_)
700{
701 int u;
702
703 assert(this_ != NULL);
704 assert(this_ -> node_costs != NULL);
705
706 for(u=0;u < this_ -> num_nodes; u++) {
707 if (this_->node_costs[u]->getLength() == 1) {
708 disconnect_trivialnode(this_,u);
709 }
710 }
711}
712
713/*****************************************************************************
714 * Normal form for PBQP
715 ****************************************************************************/
716
717/* simplify a cost matrix. If the matrix
718 is independent, then simplify_matrix
719 returns true - otherwise false. In
720 vectors u and v the offset values of
721 the decomposition are stored.
722*/
723
724static
725bool normalize_matrix(PBQPMatrix *m, PBQPVector *u, PBQPVector *v)
726{
727 assert( m != NULL);
728 assert( u != NULL);
729 assert( v != NULL);
730 assert( u->getLength() > 0);
731 assert( v->getLength() > 0);
732
733 assert(m->getRows() == u->getLength());
734 assert(m->getCols() == v->getLength());
735
736 /* determine u vector */
737 for(unsigned r = 0; r < m->getRows(); ++r) {
738 PBQPNum min = m->getRowMin(r);
739 (*u)[r] += min;
740 if (!isInf(min)) {
741 m->subFromRow(r, min);
742 } else {
743 m->setRow(r, 0);
744 }
745 }
746
747 /* determine v vector */
748 for(unsigned c = 0; c < m->getCols(); ++c) {
749 PBQPNum min = m->getColMin(c);
750 (*v)[c] += min;
751 if (!isInf(min)) {
752 m->subFromCol(c, min);
753 } else {
754 m->setCol(c, 0);
755 }
756 }
757
758 /* determine whether matrix is
759 independent or not.
760 */
761 return m->isZero();
762}
763
764/* simplify single edge */
765static
766void simplify_edge(pbqp *this_,int u,int v)
767{
768 PBQPMatrix *costs;
769 bool is_zero;
770
771 assert (this_ != NULL);
772 assert (u >= 0 && u <this_->num_nodes);
773 assert (v >= 0 && v <this_->num_nodes);
774 assert (u != v);
775
776 /* swap u and v if u > v in order to avoid un-necessary
777 tranpositions of the cost matrix */
778
779 if (u > v) {
780 int swap = u;
781 u = v;
782 v = swap;
783 }
784
785 /* get cost matrix and simplify it */
786 costs = get_costmatrix_ptr(this_,u,v);
787 is_zero=normalize_matrix(costs,this_->node_costs[u],this_->node_costs[v]);
788
789 /* delete edge */
790 if(is_zero){
791 delete_edge(this_,u,v);
792 this_->changed = true;
793 }
794}
795
796/* normalize cost matrices and remove
797 edges in PBQP if they ary independent,
798 i.e. can be decomposed into two
799 cost vectors.
800*/
801static
802void eliminate_independent_edges(pbqp *this_)
803{
804 int u,v;
805 adjnode *adj_ptr,*next;
806
807 assert(this_ != NULL);
808 assert(this_ -> adj_list != NULL);
809
810 this_->changed = false;
811 for(u=0;u < this_->num_nodes;u++) {
812 for (adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = next) {
813 next = adj_ptr -> succ;
814 v = adj_ptr -> adj;
815 assert(v >= 0 && v < this_->num_nodes);
816 if (u < v) {
Evan Cheng17a82ea2008-10-03 17:11:58 +0000817 simplify_edge(this_,u,v);
Evan Chengb1290a62008-10-02 18:29:27 +0000818 }
819 }
820 }
821}
822
823
824/*****************************************************************************
825 * PBQP reduction rules
826 ****************************************************************************/
827
828/* RI reduction
829 This reduction rule is applied for nodes
830 of degree one. */
831
832static
833void apply_RI(pbqp *this_,int x)
834{
835 int y;
836 unsigned xlen,
837 ylen;
838 PBQPMatrix *c_yx;
839 PBQPVector *c_x, *delta;
840
841 assert(this_ != NULL);
842 assert(x >= 0 && x < this_->num_nodes);
843 assert(this_ -> adj_list[x] != NULL);
844 assert(this_ -> adj_list[x] -> succ == NULL);
845
846 /* get adjacence matrix */
847 y = this_ -> adj_list[x] -> adj;
848 assert(y >= 0 && y < this_->num_nodes);
849
850 /* determine length of cost vectors for node x and y */
851 xlen = this_ -> node_costs[x]->getLength();
852 ylen = this_ -> node_costs[y]->getLength();
853
854 /* get cost vector c_x and matrix c_yx */
855 c_x = this_ -> node_costs[x];
856 c_yx = pbqp_get_costmatrix(this_,y,x);
857 assert (c_yx != NULL);
858
859
860 /* allocate delta vector */
861 delta = new PBQPVector(ylen);
862
863 /* compute delta vector */
864 for(unsigned i = 0; i < ylen; ++i) {
865 PBQPNum min = (*c_yx)[i][0] + (*c_x)[0];
866 for(unsigned j = 1; j < xlen; ++j) {
867 PBQPNum c = (*c_yx)[i][j] + (*c_x)[j];
868 if ( c < min )
869 min = c;
870 }
871 (*delta)[i] = min;
872 }
873
874 /* add delta vector */
875 *this_ -> node_costs[y] += *delta;
876
877 /* delete node x */
878 remove_node(this_,x);
879
880 /* reorder adj. nodes of node x */
881 reorder_adjnodes(this_,x);
882
883 /* push node x on stack */
884 assert(this_ -> stack_ptr < this_ -> num_nodes);
885 this_->stack[this_ -> stack_ptr++] = x;
886
887 /* free vec/mat */
888 delete c_yx;
889 delete delta;
890
891 /* increment counter for number statistic */
892 this_->num_ri++;
893}
894
895/* RII reduction
896 This reduction rule is applied for nodes
897 of degree two. */
898
899static
900void apply_RII(pbqp *this_,int x)
901{
902 int y,z;
903 unsigned xlen,ylen,zlen;
904 adjnode *adj_yz;
905
906 PBQPMatrix *c_yx, *c_zx;
907 PBQPVector *cx;
908 PBQPMatrix *delta;
909
910 assert(this_ != NULL);
911 assert(x >= 0 && x < this_->num_nodes);
912 assert(this_ -> adj_list[x] != NULL);
913 assert(this_ -> adj_list[x] -> succ != NULL);
914 assert(this_ -> adj_list[x] -> succ -> succ == NULL);
915
916 /* get adjacence matrix */
917 y = this_ -> adj_list[x] -> adj;
918 z = this_ -> adj_list[x] -> succ -> adj;
919 assert(y >= 0 && y < this_->num_nodes);
920 assert(z >= 0 && z < this_->num_nodes);
921
922 /* determine length of cost vectors for node x and y */
923 xlen = this_ -> node_costs[x]->getLength();
924 ylen = this_ -> node_costs[y]->getLength();
925 zlen = this_ -> node_costs[z]->getLength();
926
927 /* get cost vector c_x and matrix c_yx */
928 cx = this_ -> node_costs[x];
929 c_yx = pbqp_get_costmatrix(this_,y,x);
930 c_zx = pbqp_get_costmatrix(this_,z,x);
931 assert(c_yx != NULL);
932 assert(c_zx != NULL);
933
934 /* Colour Heuristic */
935 if ( (adj_yz = find_adjnode(this_,y,z)) != NULL) {
936 adj_yz->tc_valid = false;
937 adj_yz->reverse->tc_valid = false;
938 }
939
940 /* allocate delta matrix */
941 delta = new PBQPMatrix(ylen, zlen);
942
943 /* compute delta matrix */
944 for(unsigned i=0;i<ylen;i++) {
945 for(unsigned j=0;j<zlen;j++) {
946 PBQPNum min = (*c_yx)[i][0] + (*c_zx)[j][0] + (*cx)[0];
947 for(unsigned k=1;k<xlen;k++) {
948 PBQPNum c = (*c_yx)[i][k] + (*c_zx)[j][k] + (*cx)[k];
949 if ( c < min ) {
950 min = c;
951 }
952 }
953 (*delta)[i][j] = min;
954 }
955 }
956
957 /* add delta matrix */
958 add_pbqp_edgecosts(this_,y,z,delta);
959
960 /* delete node x */
961 remove_node(this_,x);
962
963 /* simplify cost matrix c_yz */
964 simplify_edge(this_,y,z);
965
966 /* reorder adj. nodes */
967 reorder_adjnodes(this_,x);
968
969 /* push node x on stack */
970 assert(this_ -> stack_ptr < this_ -> num_nodes);
971 this_->stack[this_ -> stack_ptr++] = x;
972
973 /* free vec/mat */
974 delete c_yx;
975 delete c_zx;
976 delete delta;
977
978 /* increment counter for number statistic */
979 this_->num_rii++;
980
981}
982
983/* RN reduction */
984static
985void apply_RN(pbqp *this_,int x)
986{
987 unsigned xlen;
988
989 assert(this_ != NULL);
990 assert(x >= 0 && x < this_->num_nodes);
991 assert(this_ -> node_costs[x] != NULL);
992
993 xlen = this_ -> node_costs[x] -> getLength();
994
995 /* after application of RN rule no optimality
996 can be guaranteed! */
997 this_ -> optimal = false;
998
999 /* push node x on stack */
1000 assert(this_ -> stack_ptr < this_ -> num_nodes);
1001 this_->stack[this_ -> stack_ptr++] = x;
1002
1003 /* delete node x */
1004 remove_node(this_,x);
1005
1006 /* reorder adj. nodes of node x */
1007 reorder_adjnodes(this_,x);
1008
1009 /* increment counter for number statistic */
1010 this_->num_rn++;
1011}
1012
1013
1014static
1015void compute_tc_info(pbqp *this_, adjnode *p)
1016{
1017 adjnode *r;
1018 PBQPMatrix *m;
1019 int x,y;
1020 PBQPVector *c_x, *c_y;
1021 int *row_inf_counts;
1022
1023 assert(p->reverse != NULL);
1024
1025 /* set flags */
1026 r = p->reverse;
1027 p->tc_valid = true;
1028 r->tc_valid = true;
1029
1030 /* get edge */
1031 x = r->adj;
1032 y = p->adj;
1033
1034 /* get cost vectors */
1035 c_x = this_ -> node_costs[x];
1036 c_y = this_ -> node_costs[y];
1037
1038 /* get cost matrix */
1039 m = pbqp_get_costmatrix(this_, x, y);
1040
1041
1042 /* allocate allowed set for edge (x,y) and (y,x) */
1043 if (p->tc_safe_regs == NULL) {
1044 p->tc_safe_regs = (int *) malloc(sizeof(int) * c_x->getLength());
1045 }
1046
1047 if (r->tc_safe_regs == NULL ) {
1048 r->tc_safe_regs = (int *) malloc(sizeof(int) * c_y->getLength());
1049 }
1050
1051 p->tc_impact = r->tc_impact = 0;
1052
1053 row_inf_counts = (int *) alloca(sizeof(int) * c_x->getLength());
1054
1055 /* init arrays */
1056 p->tc_safe_regs[0] = 0;
1057 row_inf_counts[0] = 0;
1058 for(unsigned i = 1; i < c_x->getLength(); ++i){
1059 p->tc_safe_regs[i] = 1;
1060 row_inf_counts[i] = 0;
1061 }
1062
1063 r->tc_safe_regs[0] = 0;
1064 for(unsigned j = 1; j < c_y->getLength(); ++j){
1065 r->tc_safe_regs[j] = 1;
1066 }
1067
1068 for(unsigned j = 0; j < c_y->getLength(); ++j) {
1069 int col_inf_counts = 0;
1070 for (unsigned i = 0; i < c_x->getLength(); ++i) {
1071 if (isInf((*m)[i][j])) {
1072 ++col_inf_counts;
1073 ++row_inf_counts[i];
1074
1075 p->tc_safe_regs[i] = 0;
1076 r->tc_safe_regs[j] = 0;
1077 }
1078 }
1079 if (col_inf_counts > p->tc_impact) {
1080 p->tc_impact = col_inf_counts;
1081 }
1082 }
1083
1084 for(unsigned i = 0; i < c_x->getLength(); ++i){
1085 if (row_inf_counts[i] > r->tc_impact)
1086 {
1087 r->tc_impact = row_inf_counts[i];
1088 }
1089 }
1090
1091 delete m;
1092}
1093
1094/*
1095 * Checks whether node x can be locally coloured.
1096 */
1097static
1098int is_colorable(pbqp *this_,int x)
1099{
1100 adjnode *adj_ptr;
1101 PBQPVector *c_x;
1102 int result = 1;
1103 int *allowed;
1104 int num_allowed = 0;
1105 unsigned total_impact = 0;
1106
1107 assert(this_ != NULL);
1108 assert(x >= 0 && x < this_->num_nodes);
1109 assert(this_ -> node_costs[x] != NULL);
1110
1111 c_x = this_ -> node_costs[x];
1112
1113 /* allocate allowed set */
1114 allowed = (int *)malloc(sizeof(int) * c_x->getLength());
1115 for(unsigned i = 0; i < c_x->getLength(); ++i){
1116 if (!isInf((*c_x)[i]) && i > 0) {
1117 allowed[i] = 1;
1118 ++num_allowed;
1119 } else {
1120 allowed[i] = 0;
1121 }
1122 }
1123
1124 /* determine local minimum */
1125 for(adj_ptr=this_->adj_list[x] ;adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
1126 if (!adj_ptr -> tc_valid) {
1127 compute_tc_info(this_, adj_ptr);
1128 }
1129
1130 total_impact += adj_ptr->tc_impact;
1131
1132 if (num_allowed > 0) {
1133 for (unsigned i = 1; i < c_x->getLength(); ++i){
1134 if (allowed[i]){
1135 if (!adj_ptr->tc_safe_regs[i]){
1136 allowed[i] = 0;
1137 --num_allowed;
1138 if (num_allowed == 0)
1139 break;
1140 }
1141 }
1142 }
1143 }
1144
1145 if ( total_impact >= c_x->getLength() - 1 && num_allowed == 0 ) {
1146 result = 0;
1147 break;
1148 }
1149 }
1150 free(allowed);
1151
1152 return result;
1153}
1154
1155/* use briggs heuristic
1156 note: this_ is not a general heuristic. it only is useful for
1157 interference graphs.
1158 */
1159int pop_colorablenode(pbqp *this_)
1160{
1161 int deg;
1162 bucketnode *min_bucket=NULL;
1163 PBQPNum min = std::numeric_limits<PBQPNum>::infinity();
1164
1165 /* select node where the number of colors is less than the node degree */
1166 for(deg=this_->max_deg;deg > 2;deg--) {
1167 bucketnode *bucket;
1168 for(bucket=this_->bucket_list[deg];bucket!= NULL;bucket = bucket -> succ) {
1169 int u = bucket->u;
1170 if (is_colorable(this_,u)) {
1171 pbqp_remove_bucket(this_,bucket);
1172 this_->num_rn_special++;
1173 free(bucket);
1174 return u;
1175 }
1176 }
1177 }
1178
1179 /* select node with minimal ratio between average node costs and degree of node */
1180 for(deg=this_->max_deg;deg >2; deg--) {
1181 bucketnode *bucket;
1182 for(bucket=this_->bucket_list[deg];bucket!= NULL;bucket = bucket -> succ) {
1183 PBQPNum h;
1184 int u;
1185
1186 u = bucket->u;
1187 assert(u>=0 && u < this_->num_nodes);
1188 h = (*this_->node_costs[u])[0] / (PBQPNum) deg;
1189 if (h < min) {
1190 min_bucket = bucket;
1191 min = h;
1192 }
1193 }
1194 }
1195
1196 /* return node and free bucket */
1197 if (min_bucket != NULL) {
1198 int u;
1199
1200 pbqp_remove_bucket(this_,min_bucket);
1201 u = min_bucket->u;
1202 free(min_bucket);
1203 return u;
1204 } else {
1205 return -1;
1206 }
1207}
1208
1209
1210/*****************************************************************************
1211 * PBQP graph parsing
1212 ****************************************************************************/
1213
1214/* reduce pbqp problem (first phase) */
1215static
1216void reduce_pbqp(pbqp *this_)
1217{
1218 int u;
1219
1220 assert(this_ != NULL);
1221 assert(this_->bucket_list != NULL);
1222
1223 for(;;){
1224
1225 if (this_->bucket_list[1] != NULL) {
1226 u = pop_node(this_,1);
1227 apply_RI(this_,u);
1228 } else if (this_->bucket_list[2] != NULL) {
1229 u = pop_node(this_,2);
1230 apply_RII(this_,u);
1231 } else if ((u = pop_colorablenode(this_)) != -1) {
1232 apply_RN(this_,u);
1233 } else {
1234 break;
1235 }
1236 }
1237}
1238
1239/*****************************************************************************
1240 * PBQP back propagation
1241 ****************************************************************************/
1242
1243/* determine solution of a reduced node. Either
1244 RI or RII was applied for this_ node. */
1245static
1246void determine_solution(pbqp *this_,int x)
1247{
1248 PBQPVector *v = new PBQPVector(*this_ -> node_costs[x]);
1249 adjnode *adj_ptr;
1250
1251 assert(this_ != NULL);
1252 assert(x >= 0 && x < this_->num_nodes);
1253 assert(this_ -> adj_list != NULL);
1254 assert(this_ -> solution != NULL);
1255
1256 for(adj_ptr=this_->adj_list[x] ;adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
1257 int y = adj_ptr -> adj;
1258 int y_sol = this_ -> solution[y];
1259
1260 PBQPMatrix *c_yx = pbqp_get_costmatrix(this_,y,x);
1261 assert(y_sol >= 0 && y_sol < (int)this_->node_costs[y]->getLength());
1262 (*v) += c_yx->getRowAsVector(y_sol);
1263 delete c_yx;
1264 }
1265 this_ -> solution[x] = v->minIndex();
1266
1267 delete v;
1268}
1269
1270/* back popagation phase of PBQP */
1271static
1272void back_propagate(pbqp *this_)
1273{
1274 int i;
1275
1276 assert(this_ != NULL);
1277 assert(this_->stack != NULL);
1278 assert(this_->stack_ptr < this_->num_nodes);
1279
1280 for(i=this_ -> stack_ptr-1;i>=0;i--) {
1281 int x = this_ -> stack[i];
1282 assert( x >= 0 && x < this_ -> num_nodes);
1283 reinsert_node(this_,x);
1284 determine_solution(this_,x);
1285 }
1286}
1287
1288/* solve trivial nodes of degree zero */
1289static
1290void determine_trivialsolution(pbqp *this_)
1291{
1292 int u;
1293 PBQPNum delta;
1294
1295 assert( this_ != NULL);
1296 assert( this_ -> bucket_list != NULL);
1297
1298 /* determine trivial solution */
1299 while (this_->bucket_list[0] != NULL) {
1300 u = pop_node(this_,0);
1301
1302 assert( u >= 0 && u < this_ -> num_nodes);
1303
1304 this_->solution[u] = this_->node_costs[u]->minIndex();
1305 delta = (*this_->node_costs[u])[this_->solution[u]];
1306 this_->min = this_->min + delta;
1307
1308 /* increment counter for number statistic */
1309 this_->num_r0++;
1310 }
1311}
1312
1313/*****************************************************************************
1314 * debug facilities
1315 ****************************************************************************/
1316static
1317void check_pbqp(pbqp *this_)
1318{
1319 int u,v;
1320 PBQPMatrix *costs;
1321 adjnode *adj_ptr;
1322
1323 assert( this_ != NULL);
1324
1325 for(u=0;u< this_->num_nodes; u++) {
1326 assert (this_ -> node_costs[u] != NULL);
1327 for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) {
1328 v = adj_ptr -> adj;
1329 assert( v>= 0 && v < this_->num_nodes);
1330 if (u < v ) {
Evan Cheng17a82ea2008-10-03 17:11:58 +00001331 costs = adj_ptr -> costs;
1332 assert( costs->getRows() == this_->node_costs[u]->getLength() &&
1333 costs->getCols() == this_->node_costs[v]->getLength());
Evan Chengb1290a62008-10-02 18:29:27 +00001334 }
1335 }
1336 }
1337}
1338
1339/*****************************************************************************
1340 * PBQP solve routines
1341 ****************************************************************************/
1342
1343/* solve PBQP problem */
1344void solve_pbqp(pbqp *this_)
1345{
1346 assert(this_ != NULL);
1347 assert(!this_->solved);
1348
1349 /* check vector & matrix dimensions */
1350 check_pbqp(this_);
1351
1352 /* simplify PBQP problem */
1353
1354 /* eliminate trivial nodes, i.e.
1355 nodes with cost vectors of length one. */
1356 eliminate_trivial_nodes(this_);
1357
1358 /* eliminate edges with independent
1359 cost matrices and normalize matrices */
1360 eliminate_independent_edges(this_);
1361
1362 /* create bucket list for graph parsing */
1363 create_bucketlist(this_);
1364
1365 /* reduce phase */
1366 reduce_pbqp(this_);
1367
1368 /* solve trivial nodes */
1369 determine_trivialsolution(this_);
1370
1371 /* back propagation phase */
1372 back_propagate(this_);
1373
1374 this_->solved = true;
1375}
1376
1377/* get solution of a node */
1378int get_pbqp_solution(pbqp *this_,int x)
1379{
1380 assert(this_ != NULL);
1381 assert(this_->solution != NULL);
1382 assert(this_ -> solved);
1383
1384 return this_->solution[x];
1385}
1386
1387/* is solution optimal? */
1388bool is_pbqp_optimal(pbqp *this_)
1389{
1390 assert(this_ -> solved);
1391 return this_->optimal;
1392}
1393
1394}
1395
1396/* end of pbqp.c */