Limbo 3.5.4
Loading...
Searching...
No Matches
FM.h
Go to the documentation of this file.
1
11
12#ifndef _LIMBO_ALGORITHMS_PARTITION_FM_H
13#define _LIMBO_ALGORITHMS_PARTITION_FM_H
14
15#include <iostream>
16#include <vector>
17#include <map>
18#include <set>
19#include <limbo/math/Math.h>
20#include <boost/array.hpp>
21#include <boost/unordered_map.hpp>
22
23using std::cout;
24using std::endl;
25using std::vector;
26using std::map;
27using std::set;
28using std::pair;
29using std::make_pair;
30using boost::array;
31using boost::unordered_map;
32
34namespace limbo
35{
37namespace algorithms
38{
40namespace partition
41{
42
46template <typename NodeType>
48{
50 typedef NodeType node_type;
51 typedef typename node_type::tie_id_type tie_id_type;
52 typedef typename node_type::weight_type node_weight_type;
54
57 static tie_id_type tie_id(node_type const& n)
58 {return n.tie_id();}
59
61 static node_weight_type weight(node_type const& n)
62 {return n.weight();}
63};
64
71template <typename NodeType, typename NetWeightType = double>
72class FM
73{
74 public:
76 typedef NodeType node_type;
77 typedef NetWeightType net_weight_type;
78 typedef typename FM_node_traits<node_type>::node_weight_type node_weight_type;
80
81 struct FM_node_type;
82 struct FM_net_type;
83
87 {
88 node_type* pNode;
89 vector<FM_net_type*> vNet;
90 bool locked;
93 node_weight_type weight;
94
97 {
98 pNode = NULL;
99 locked = false;
100 partition = -1;
101 partition_bak = -1;
102 weight = 0;
103 }
104
106 net_weight_type gain() const
107 {
108 net_weight_type g = 0;
109 for (typename vector<FM_net_type*>::const_iterator itNet = vNet.begin();
110 itNet != vNet.end(); ++itNet)
111 {
112#if 0
113 for (typename vector<FM_node_type*>::const_iterator itNode = (*itNet)->vNode.begin();
114 itNode != (*itNet)->vNode.end(); ++itNode)
115 {
116 assert((*itNode)->partition == 0 || (*itNode)->partition == 1);
117
118 if (this == *itNode) continue;
119 else if (this->partition == (*itNode)->partition) // internal node
120 g -= (*itNet)->weight;
121 else // external node
122 g += (*itNet)->weight;
123 }
124#else
125 int exclusivePartition = (*itNet)->exclusive_partition(*this);
126 if (exclusivePartition != 2)
127 {
128 // current node is in the same partition as other nodes in this net
129 if (this->partition == exclusivePartition)
130 g -= (*itNet)->weight;
131 // current node is in different partitions from other nodes in this net
132 else
133 g += (*itNet)->weight;
134 }
135#endif
136 }
137 return g;
138 }
139 };
140
143 {
144 vector<FM_node_type*> vNode;
145 net_weight_type weight;
146
149 net_weight_type cutsize() const
150 {
151 if (vNode.size() < 2) return 0;
152 for (typename vector<FM_node_type*>::const_iterator itNode = vNode.begin()+1;
153 itNode != vNode.end(); ++itNode)
154 {
155 assert((*itNode)->partition == 0 || (*itNode)->partition == 1);
156 if ((*(itNode-1))->partition != (*itNode)->partition) // has a cut
157 return weight;
158 }
159 return 0;
160 }
161
166 int exclusive_partition(FM_node_type const& fmNode) const
167 {
168 int prevPartition = -1;
169 int exclusivePartition = -1; // except current node,
170 // 0 indicates all in partition 0,
171 // 1 indicates all in partition 1,
172 // 2 indicates in both partitions
173 for (typename vector<FM_node_type*>::const_iterator itNode = vNode.begin();
174 itNode != vNode.end(); ++itNode)
175 {
176 assert((*itNode)->partition == 0 || (*itNode)->partition == 1);
177
178 if (fmNode.pNode == (*itNode)->pNode) continue;
179 else if (prevPartition < 0)
180 {
181 prevPartition = (*itNode)->partition;
182 exclusivePartition = prevPartition;
183 }
184 else if (prevPartition != (*itNode)->partition)
185 {
186 exclusivePartition = 2;
187 break;
188 }
189 }
190 return exclusivePartition;
191 }
192 };
193
194 // forward declaration
195 struct compare_type1;
196 struct compare_type2;
201 {
206 bool operator()(FM_node_type* pFMNode1, FM_node_type* pFMNode2) const
207 {
208 return pFMNode1->gain() > pFMNode2->gain();
209 }
210
214 bool operator()(net_weight_type const& g1, net_weight_type const& g2) const
215 {
216 return g1 > g2;
217 }
218#if 0
219 bool operator()(set<FM_node_type*, compare_type2> const& s1, set<FM_node_type*, compare_type2> const& s2) const
220 {
221 assert(!s1.empty() && !s2.empty());
222 return (*this)(*s1.begin(), *s2.begin());
223 }
224#endif
225 };
226
230 {
235 bool operator()(FM_node_type* pFMNode1, FM_node_type* pFMNode2) const
236 {
238 }
239 };
240
243 class gain_bucket_type : public map<net_weight_type, set<FM_node_type*, compare_type2>, compare_type1>
244 {
245 public:
247 typedef set<FM_node_type*, compare_type2> nested_type;
248 typedef map<net_weight_type, nested_type, compare_type1> base_type;
250
252 gain_bucket_type() : base_type() {}
255 gain_bucket_type(gain_bucket_type const& rhs) : base_type(rhs) {}
256
259 virtual void insert(FM_node_type* const& pFMNode)
260 {
261 net_weight_type gain = pFMNode->gain();
262 typename base_type::iterator found = this->find(gain);
263 if (found == this->end())
264 {
265 set<FM_node_type*, compare_type2> sTmp;
266 sTmp.insert(pFMNode);
267 this->base_type::insert(make_pair(gain, sTmp));
268 }
269 else
270 {
271 found->second.insert(pFMNode);
272 }
273 }
274
276 virtual void erase(FM_node_type* const& pFMNode)
277 {
278 net_weight_type gain = pFMNode->gain();
279 typename base_type::iterator found = this->find(gain);
280 if (found != this->end())
281 {
282 if (found->second.empty()) return;
283 else if (found->second.size() == 1 && found->second.count(pFMNode))
284 this->base_type::erase(found);
285 else
286 found->second.erase(pFMNode);
287 }
288 }
289
291 size_t element_size() const
292 {
293 size_t cnt = 0;
294 for (typename base_type::const_iterator it1 = this->begin();
295 it1 != this->end(); ++it1)
296 for (typename nested_type::const_iterator it2 = it1->second.begin();
297 it2 != it1->second.end(); ++it2)
298 cnt += 1;
299 return cnt;
300 }
301
302 void print() const
303 {
304 cout << "------- gain_bucket -------" << endl;
305 cout << "total # element = " << this->element_size() << endl;
306 for (typename base_type::const_iterator it1 = this->begin();
307 it1 != this->end(); ++it1)
308 {
309 cout << "gain = " << it1->first << ": ";
310 for (typename nested_type::const_iterator it2 = it1->second.begin();
311 it2 != it1->second.end(); ++it2)
312 cout << FM_node_traits<node_type>::tie_id(*((*it2)->pNode)) << " ";
313 cout << endl;
314 }
315 }
316 };
317
319 FM() {}
322 {
323 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
324 it != m_hNode.end(); ++it)
325 delete it->second;
326 for (typename vector<FM_net_type*>::const_iterator it = m_vNet.begin();
327 it != m_vNet.end(); ++it)
328 delete *it;
329 }
330
334 bool add_node(node_type* pNode, int initialPartition)
335 {
336 assert(initialPartition == 0 || initialPartition == 1);
337
338 FM_node_type* pFMNode = new FM_node_type;
339 pFMNode->pNode = pNode;
340 pFMNode->partition = initialPartition;
341 pFMNode->weight = FM_node_traits<node_type>::weight(*pNode);
342 return m_hNode.insert(make_pair(pNode, pFMNode)).second;
343 }
344
353 template <typename Iterator>
354 bool add_net(net_weight_type const& weight, Iterator first, Iterator last)
355 {
356 FM_net_type* pFMNet = new FM_net_type;
357 pFMNet->weight = weight;
358
359 for (Iterator it = first; it != last; ++it)
360 {
361 typename unordered_map<node_type*, FM_node_type*>::const_iterator found = m_hNode.find(*it);
362 // return false if failed
363 if (found == m_hNode.end())
364 {
365 delete pFMNet;
366 return false;
367 }
368 // add FM_node_type to FM_net_type
369 pFMNet->vNode.push_back(found->second);
370 }
371 // add FM_net_type to FM_node_type
372 for (typename vector<FM_node_type*>::const_iterator itNode = pFMNet->vNode.begin();
373 itNode != pFMNet->vNode.end(); ++itNode)
374 (*itNode)->vNet.push_back(pFMNet);
375 m_vNet.push_back(pFMNet);
376
377 return true;
378 }
379
380 net_weight_type cutsize() const
381 {
382 net_weight_type cs = 0;
383 for (typename vector<FM_net_type*>::const_iterator it = m_vNet.begin();
384 it != m_vNet.end(); ++it)
385 cs += (*it)->cutsize();
386 return cs;
387 }
388
392 net_weight_type operator()(double ratio1, double ratio2)
393 {
394 return this->run(ratio1, ratio2);
395 }
396
397 void print() const
398 {
399 cout << "------- partitions -------" << endl;
400 vector<typename FM_node_traits<node_type>::tie_id_type> vPartition[2];
401
402 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
403 it != m_hNode.end(); ++it)
404 {
405 FM_node_type* const& pFMNode = it->second;
406 assert(pFMNode->partition == 0 || pFMNode->partition == 1);
407 vPartition[pFMNode->partition].push_back(FM_node_traits<node_type>::tie_id(*(pFMNode->pNode)));
408 }
409 cout << "{";
410 for (typename vector<typename FM_node_traits<node_type>::tie_id_type>::const_iterator it = vPartition[0].begin();
411 it != vPartition[0].end(); ++it)
412 cout << (*it) << " ";
413 cout << "| ";
414 for (typename vector<typename FM_node_traits<node_type>::tie_id_type>::const_iterator it = vPartition[1].begin();
415 it != vPartition[1].end(); ++it)
416 cout << (*it) << " ";
417 cout << "}" << endl;
418 }
419
420 void print_connection() const
421 {
422 cout << "------- connections -------" << endl;
423 for (typename vector<FM_net_type*>::const_iterator itNet = m_vNet.begin();
424 itNet != m_vNet.end(); ++itNet)
425 {
426 FM_net_type* const& pFMNet = *itNet;
427 for (typename vector<FM_node_type*>::const_iterator itNode = pFMNet->vNode.begin();
428 itNode != pFMNet->vNode.end(); ++itNode)
429 {
430 // delimiter
431 if (itNode != pFMNet->vNode.begin())
432 cout << " - ";
433 FM_node_type* const& pFMNode = *itNode;
434 cout << FM_node_traits<node_type>::tie_id(*(pFMNode->pNode));
435 }
436 cout << endl;
437 }
438 }
439
440 void print_node() const
441 {
442 cout << "------- nodes -------" << endl;
443 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
444 it != m_hNode.end(); ++it)
445 {
446 FM_node_type* const& pFMNode = it->second;
447 assert(pFMNode->partition == 0 || pFMNode->partition == 1);
448
449 cout << FM_node_traits<node_type>::tie_id(*(pFMNode->pNode)) << ": ";
450 cout << "partition = " << pFMNode->partition << "; ";
451 cout << "partition_bak = " << pFMNode->partition_bak << "; ";
452 cout << "locked = " << pFMNode->locked << "; ";
453 cout << "weight = " << pFMNode->weight << "; ";
454 cout << "gain = " << pFMNode->gain() << "; ";
455 cout << endl;
456 }
457 }
458 protected:
463 net_weight_type run(double ratio1, double ratio2)
464 {
465 net_weight_type prev_cutsize;
466 net_weight_type cur_cutsize = this->cutsize();
467
468 unsigned int iter_cnt = 0;
469 do
470 {
471 cout << "######### iteration #" << iter_cnt++ << " #########" << endl;
472
473 prev_cutsize = cur_cutsize;
474
475 pair<net_weight_type, int> trial_pass = this->single_pass(ratio1, ratio2, -1);
476#ifdef DEBUG_FM
477 //this->print_node();
478#endif
479 pair<net_weight_type, int> actual_pass = this->single_pass(ratio1, ratio2, trial_pass.second);
480
481#ifdef DEBUG_FM
482 this->print_node();
483 assert(trial_pass == actual_pass && limbo::abs(actual_pass.first-this->cutsize()) < 1e-6);
484#endif
485
486 cur_cutsize = actual_pass.first;
487 } while (cur_cutsize < prev_cutsize);
488
489 return cur_cutsize;
490 }
491
496 pair<net_weight_type, int> single_pass(double ratio1, double ratio2, int target_cnt)
497 {
498 // trial mode, back up partition
499 if (target_cnt < 0)
500 {
501 cout << "======= trial phase =======" << endl;
502 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
503 it != m_hNode.end(); ++it)
504 {
505 FM_node_type* const& pFMNode = it->second;
506 pFMNode->partition_bak = pFMNode->partition;
507 }
508 }
509 else cout << "======= actual phase w. target_cnt = " << target_cnt << " =======" << endl;
510#ifdef DEBUG_FM
511 //this->print_node();
512#endif
513 // initialize gain_bucket
514 gain_bucket_type gain_bucket;
515 node_weight_type total_weight[2] = {0, 0};
516 net_weight_type cur_cutsize = this->cutsize();
517 net_weight_type best_cutsize = cur_cutsize;
518 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
519 it != m_hNode.end(); ++it)
520 {
521 FM_node_type* const& pFMNode = it->second;
522 assert(pFMNode->partition == 0 || pFMNode->partition == 1);
523 total_weight[pFMNode->partition] += pFMNode->weight;
524 gain_bucket.insert(pFMNode);
525 }
526
527#ifdef DEBUG_FM
528 // for Physical Design HW 2.b)
529 gain_bucket.print();
530#endif
531
532 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
533 it != m_hNode.end(); ++it)
534 {
535 FM_node_type* const& pFMNode = it->second;
536 pFMNode->locked = false;
537 }
538
539#ifdef DEBUG_FM
540 this->print();
541 cout << "initial cutsize = " << this->cutsize() << endl;
542#endif
543 // 1 trial pass, 1 real pass
544 int cur_cnt = 0;
545 int best_cnt = 0;
546 while (!gain_bucket.empty())
547 {
548 if (cur_cnt == target_cnt) break;
549#ifdef DEBUG_FM
550 //this->print_node();
551#endif
552 FM_node_type* pFMNodeBest = NULL; // candidnate node to move
553
554 for (typename gain_bucket_type::const_iterator it1 = gain_bucket.begin();
555 it1 != gain_bucket.end(); ++it1)
556 {
557 for (typename gain_bucket_type::nested_type::const_iterator it2 = it1->second.begin();
558 it2 != it1->second.end(); ++it2)
559 {
560 FM_node_type* pFMNode = *it2;
561
562 node_weight_type tmp_total_weight[2] = {
563 total_weight[0],
564 total_weight[1]
565 };
566 // move out from current partition
567 tmp_total_weight[pFMNode->partition] -= pFMNode->weight;
568 // move into the other partition
569 tmp_total_weight[!pFMNode->partition] += pFMNode->weight;
570
571 double cur_ratio = (double)total_weight[0]/total_weight[1];
572 double tmp_ratio = (double)tmp_total_weight[0]/tmp_total_weight[1];
573
574 // the ratio stays in the target range or get closer to the target range
575 if (limbo::abs(tmp_ratio-ratio1)+limbo::abs(tmp_ratio-ratio2)
576 <= limbo::abs(cur_ratio-ratio1)+limbo::abs(cur_ratio-ratio2))
577 {
578 pFMNodeBest = pFMNode;
579 break;
580 }
581 }
582 if (pFMNodeBest) break;
583 }
584 // this is not exit condition yet
585 if (!pFMNodeBest) break;
586
587#ifdef DEBUG_FM
588 //gain_bucket.print();
589#endif
590 // move pFMNodeBest
591 // move out from current partition
592 total_weight[pFMNodeBest->partition] -= pFMNodeBest->weight;
593 // move into the other partition
594 total_weight[!pFMNodeBest->partition] += pFMNodeBest->weight;
595 // remove pFMNodeBest and all its connected nodes from gain bucket
596 gain_bucket.erase(pFMNodeBest);
597 for (typename vector<FM_net_type*>::const_iterator itNet = pFMNodeBest->vNet.begin();
598 itNet != pFMNodeBest->vNet.end(); ++itNet)
599 {
600 for (typename vector<FM_node_type*>::const_iterator itNode = (*itNet)->vNode.begin();
601 itNode != (*itNet)->vNode.end(); ++itNode)
602 {
603 // skip itself and locked nodes
604 if (*itNode == pFMNodeBest || (*itNode)->locked) continue;
605#ifdef DEBUG_FM
606 //cout << "erasing " << (*itNode)->pNode->tie_id() << endl;
607#endif
608 gain_bucket.erase(*itNode);
609#ifdef DEBUG_FM
610 //gain_bucket.print();
611#endif
612 }
613 }
614#ifdef DEBUG_FM
615 //gain_bucket.print();
616#endif
617 // update current cut size
618 for (typename vector<FM_net_type*>::const_iterator itNet = pFMNodeBest->vNet.begin();
619 itNet != pFMNodeBest->vNet.end(); ++itNet)
620 {
621#if 0
622 for (typename vector<FM_node_type*>::const_iterator itNode = (*itNet)->vNode.begin();
623 itNode != (*itNet)->vNode.end(); ++itNode)
624 {
625 // skip itself
626 if (*itNode == pFMNodeBest) continue;
627 // directly update cut size
628 if (pFMNodeBest->partition == (*itNode)->partition)
629 cur_cutsize += (*itNet)->weight;
630 else
631 cur_cutsize -= (*itNet)->weight;
632 }
633#else
634 int exclusivePartition = (*itNet)->exclusive_partition(*pFMNodeBest);
635 if (exclusivePartition != 2)
636 {
637 // current node is in the same partition as other nodes in this net
638 if (pFMNodeBest->partition == exclusivePartition)
639 cur_cutsize += (*itNet)->weight;
640 // current node is in different partitions from other nodes in this net
641 else
642 cur_cutsize -= (*itNet)->weight;
643 }
644#endif
645 }
646 // update partition of pFMNodeBest
647 pFMNodeBest->partition = !pFMNodeBest->partition;
648 pFMNodeBest->locked = true;
649 // insert all its connected nodes
650 for (typename vector<FM_net_type*>::const_iterator itNet = pFMNodeBest->vNet.begin();
651 itNet != pFMNodeBest->vNet.end(); ++itNet)
652 {
653 for (typename vector<FM_node_type*>::const_iterator itNode = (*itNet)->vNode.begin();
654 itNode != (*itNet)->vNode.end(); ++itNode)
655 {
656 if (*itNode == pFMNodeBest || (*itNode)->locked) continue;
657 gain_bucket.insert(*itNode);
658 }
659 }
660
661 // record current cnt
662 ++cur_cnt;
663
664#ifdef DEBUG_FM
665 //gain_bucket.print();
666 assert(limbo::abs(cur_cutsize-this->cutsize()) < 1.0e-6);
667 this->print();
668 cout << "move cnt = " << cur_cnt << ", current cutsize = " << this->cutsize() << endl;
669#endif
670
671 if (cur_cutsize < best_cutsize)
672 {
673 best_cutsize = cur_cutsize;
674 best_cnt = cur_cnt;
675 }
676 }
677 // trial mode, recover partition
678 if (target_cnt < 0)
679 {
680 for (typename unordered_map<node_type*, FM_node_type*>::const_iterator it = m_hNode.begin();
681 it != m_hNode.end(); ++it)
682 {
683 FM_node_type* const& pFMNode = it->second;
684 pFMNode->partition = pFMNode->partition_bak;
685 }
686 }
687
688 return make_pair(best_cutsize, best_cnt);
689 }
690
691 unordered_map<node_type*, FM_node_type*> m_hNode;
692 vector<FM_net_type*> m_vNet;
694};
695
696} // namespace partition
697} // namespace algorithms
698} // namespace limbo
699
700#endif
mathematical utilities such as abs
virtual void erase(FM_node_type *const &pFMNode)
Definition FM.h:276
void print() const
print gain bucket
Definition FM.h:302
virtual void insert(FM_node_type *const &pFMNode)
Definition FM.h:259
gain_bucket_type(gain_bucket_type const &rhs)
Definition FM.h:255
void print_connection() const
print connection
Definition FM.h:420
bool add_net(net_weight_type const &weight, Iterator first, Iterator last)
add nets
Definition FM.h:354
net_weight_type operator()(double ratio1, double ratio2)
Definition FM.h:392
net_weight_type run(double ratio1, double ratio2)
kernel function to run the algorithm
Definition FM.h:463
net_weight_type cutsize() const
Definition FM.h:380
bool add_node(node_type *pNode, int initialPartition)
add node
Definition FM.h:334
void print() const
print function
Definition FM.h:397
unordered_map< node_type *, FM_node_type * > m_hNode
FM nodes.
Definition FM.h:691
vector< FM_net_type * > m_vNet
FM nets.
Definition FM.h:692
gain_bucket_type m_gain_bucket
gain buckets
Definition FM.h:693
pair< net_weight_type, int > single_pass(double ratio1, double ratio2, int target_cnt)
one pass of moving nodes
Definition FM.h:496
void print_node() const
print node
Definition FM.h:440
namespace for Limbo.Algorithms.Partition
Definition FM.h:41
namespace for Limbo.algorithms
namespace for Limbo
T abs(T const &t)
generalized api can handle both integer and floating points
Definition Math.h:21
net type for the algorithm
Definition FM.h:143
vector< FM_node_type * > vNode
nodes in the net
Definition FM.h:144
net_weight_type cutsize() const
compute cut size for the net
Definition FM.h:149
net_weight_type weight
net weight
Definition FM.h:145
int exclusive_partition(FM_node_type const &fmNode) const
partition excludes a certain node
Definition FM.h:166
node type for the algorithm
Definition FM.h:87
net_weight_type gain() const
compute gain
Definition FM.h:106
node_type * pNode
node in the graph
Definition FM.h:88
node_weight_type weight
node weight for balancing constraint, like area
Definition FM.h:93
int partition_bak
back up partition for trial pass
Definition FM.h:92
int partition
partition id: 0 or 1, -1 for uninitialized
Definition FM.h:91
vector< FM_net_type * > vNet
nets related to the node
Definition FM.h:89
bool operator()(net_weight_type const &g1, net_weight_type const &g2) const
API for comparison.
Definition FM.h:214
bool operator()(FM_node_type *pFMNode1, FM_node_type *pFMNode2) const
API for comparison.
Definition FM.h:206
bool operator()(FM_node_type *pFMNode1, FM_node_type *pFMNode2) const
API for comparison.
Definition FM.h:235
static node_weight_type weight(node_type const &n)
Definition FM.h:61
static tie_id_type tie_id(node_type const &n)
Definition FM.h:57