coriolis/knik/src/Edge.cpp

408 lines
14 KiB
C++

#include <cmath>
#include "crlcore/Utilities.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/Warning.h"
#include "knik/Edge.h"
#include "knik/Vertex.h"
#include "knik/Graph.h"
namespace Knik {
extern unsigned __congestion__;
extern unsigned __precongestion__;
extern bool __ripupMode__;
extern float __edge_cost__;
const Name Edge::_extensionName = "Knik::Edge";
Edge::Edge ( Vertex* from, Vertex* to )
// ************************************
: Inherit (from->getCell())
, _from (from)
, _nextFrom (NULL)
, _to (to)
, _nextTo (NULL)
, _connexID (-1)
, _cost (0.0)
, _capacity (0)
, _realOccupancy (0)
, _estimateOccupancy (0.0)
, _netStamp (0)
, _segments()
{
/*_cost = v1->getGCell()->getCenter().ManhattanDistance (v2->getGCell()->getCenter());*/
}
Edge::Edge ( Vertex* from, Vertex* to, unsigned capacity )
// *******************************************************
: Inherit (from->getCell())
, _boundingBox()
, _from (from)
, _nextFrom (NULL)
, _to (to)
, _nextTo (NULL)
, _connexID (-1)
, _cost (0.0)
, _capacity (capacity)
, _realOccupancy (0)
, _estimateOccupancy (0.0)
, _netStamp (0)
, _isCongested (false)
, _segments()
{
//cerr << " Edge::Edge() capacity:" << _capacity << endl;
}
void Edge::_postCreate ()
// **********************
{
Inherit::_postCreate();
_segments.reserve(_capacity);
}
Edge::~Edge()
// **********
{
}
void Edge::destroy()
// ****************
{
_preDestroy();
delete this;
}
void Edge::_preDestroy()
// ********************
{
Inherit::_preDestroy();
}
void Edge::setCapacity ( unsigned int capacity )
// *****************************************
{
_capacity = capacity;
//cerr << "Setting capacity to " << _capacity << " on " << this << endl;
}
void Edge::increaseCapacity ( int capacity )
// *****************************************
{
if ( (int)_capacity + capacity < 0 ) _capacity = 0;
else
_capacity += capacity;
//if ( _capacity < 2 ) _capacity = 0;
// cerr << "Increase Edge Capacity " << _from->getPosition()
// << " to " << _to->getPosition() << ":" << _capacity << endl;
//cerr << "Increasing capacity to " << _capacity << " on " << this << endl;
if ( _capacity == 0 )
ltrace(300) << Warning("%s has reached NULL capacity.",getString(this).c_str()) << endl;
}
void Edge::incOccupancy ()
// ***********************
{
_realOccupancy++;
if ( !_isCongested ) {
if ( _realOccupancy > _capacity ) {
_boundingBox = computeBoundingBox();
_isCongested = true;
// reste a mettre les segments traversant l'edge dans la pile ou s'ils y sont deja a les mettre a jour
}
}
}
void Edge::decOccupancy ()
// ************************
{
if ( _realOccupancy > 0 )
_realOccupancy--;
if ( _isCongested && (_realOccupancy <= _capacity) ) {
_boundingBox = computeBoundingBox();
_isCongested = false;
}
}
void Edge::removeSegment ( Segment* segment )
// ******************************************
{
assert(segment);
decOccupancy();
vector<Segment*>::iterator vsit = find(_segments.begin(),_segments.end(),segment);
if ( vsit != _segments.end() )
_segments.erase ( vsit );
else {
cerr << segment << " " << this << endl;
Breakpoint::stop(0, "Shootdown -h now");
throw Error ( "Edge::removeSegment(): I cannot believe this segment is not in _segments!" );
}
}
void Edge::addSubEstimateOccupancy ( float increment, bool add )
// *************************************************************
{
if ( add )
_estimateOccupancy += increment;
else
_estimateOccupancy -= increment;
return;
}
DbU::Unit Edge::getXTo() const
// ***************************
{
return _to->getX();
}
DbU::Unit Edge::getYTo() const
// ***************************
{
return _to->getY();
}
DbU::Unit Edge::getXFrom() const
// *****************************
{
return _from->getX();
}
DbU::Unit Edge::getYFrom() const
// *****************************
{
return _from->getY();
}
void Edge::translate ( const DbU::Unit& dx, const DbU::Unit& dy )
// **************************************************************
{
_from->translate ( dx, dy );
_to->translate ( dx, dy );
}
Cell* Edge::getCell() const
// ************************
{
return _from->getCell();
}
float Edge::getCost ( Edge* arrivalEdge )
// **************************************
{
// 20/10/2010: Check for null capacity, which may occurs after back-annotation
// by Kite.
if ( _capacity == 0.0 ) return (float)(HUGE_VAL);
//#ifdef __USE_CONGESTION__
if ( __congestion__ ) {
// definition de la fonction de cout :
// on ramene l'occupation de l'edge à un pourcentage de la capacité :
float edge_capacity = (float)1.0;
float edge_occupancy;
//float h = 9.0;
//float k = 30.0; // environ 3*h pour etre sur d'avoir cost(0) = 1 !!
//now defined as edge's attributes for ripup & reroute
if ( !__ripupMode__ ) {
//#if defined ( __USE_STATIC_PRECONGESTION__ ) || defined ( __USE_DYNAMIC_PRECONGESTION__ )
if ( __precongestion__ )
edge_occupancy = ((float)getRealOccupancy() + getEstimateOccupancy()) / (float)_capacity;
//#else
else
edge_occupancy = (float)getRealOccupancy() / (float)_capacity;
//#endif
_cost = 1.0 + (9.0 / (1.0 + exp(-30.0 * (edge_occupancy - edge_capacity)))); // plutot que 1.0 on devrait avoir un getLength renvoyant la longueur de l'arete en unités normalisées (pas de grille)
}
else {
// dans ce mode l'estimation de congestion est utilisé comme historique de congestion
edge_occupancy = (float)getRealOccupancy() / (float)_capacity;
float historicCost;
if ( edge_occupancy < 1 )
historicCost = getEstimateOccupancy() * edge_occupancy;
else
historicCost = getEstimateOccupancy() * exp(log(8)*(edge_occupancy - edge_capacity));
_cost = 1.0 + (19.0 / (1.0 + exp(-60.0 * (edge_occupancy - edge_capacity)))) + historicCost;
}
}
//#else
else
_cost = 1.0;
//#endif
// Prise en compte des vias !
if ( arrivalEdge ) {
if ( arrivalEdge->isVertical() && isHorizontal() )
_cost += __edge_cost__;
if ( arrivalEdge->isHorizontal() && isVertical() )
_cost += __edge_cost__;
}
//if ( _from->getRoutingGraph()->getRipupMode() )
// if ( _isCongested )
// _cost += 1000;
return _cost;
}
unsigned Edge::getRealOccupancy() const
// ************************************
{
// pour debug plus facile : // Attention ce n'est plus vrai lorsque l'edge gère elle même son occupation!
//assert ( _realOccupancy == _fence->getOccupancy() );
return _realOccupancy;
}
Segment* Edge::getSegmentFor ( Net* net )
// **************************************
{
for_each_segment ( segment, getCollection ( _segments ) ) {
if ( segment->getNet() == net )
return segment;
end_for;
}
return NULL;
}
bool Edge::hasInfo() const
// ***********************
{
return (_netStamp == _from->getRoutingGraph()->getNetStamp())&&(_connexID != -1);
}
// void Edge::_Draw ( View* view, BasicLayer* basicLayer, const Box& updateArea, const Transformation& transformation )
// //******************************************************************************************************************
// {
// Point fromPos = transformation.getPoint ( _from->getPosition() );
// Point toPos = transformation.getPoint ( _to->getPosition() );
// //view->DrawLine ( fromPos, toPos );
// // new version to represent occupation
// DbU::Unit halfWidth = _from->getHalfWidth() < _to->getHalfWidth() ? _from->getHalfWidth() : _to->getHalfWidth();
// DbU::Unit halfHeight = _from->getHalfHeight() < _to->getHalfHeight() ? _from->getHalfHeight() : _to->getHalfHeight();
// bool overCap = false;
// float relOccupancy = 0.0;
// if ( _realOccupancy > _capacity ) {
// overCap = true;
// relOccupancy = 1.0;
// }
// else
// relOccupancy = (float)_realOccupancy / (float)_capacity;
// if ( fromPos.getY() == toPos.getY() ) {
// DbU::Unit medFromX = fromPos.getX() + halfWidth;
// DbU::Unit medFromY = fromPos.getY() - halfHeight;
// DbU::Unit medToX = fromPos.getX() + halfWidth;
// DbU::Unit medToY = fromPos.getY() + halfHeight;
// view->DrawLine ( medFromX, medFromY, medToX, medToY );
// DbU::Unit cover = DbU::lambda ( getValue(medToY - medFromY) * relOccupancy );
// view->FillRectangle ( medFromX - 100, medFromY , medFromX + 100, medFromY + (cover/2) );
// view->FillRectangle ( medToX - 100 , medToY - (cover/2), medToX + 100 , medToY );
// if (overCap)
// view->FillRectangle ( medFromX-150, medFromY+halfHeight-150, medFromX+150, medFromY+halfHeight+150 );
// }
// else {
// DbU::Unit medFromX = fromPos.getX() - halfWidth;
// DbU::Unit medFromY = fromPos.getY() + halfHeight;
// DbU::Unit medToX = fromPos.getX() + halfWidth;
// DbU::Unit medToY = fromPos.getY() + halfHeight;
// view->DrawLine ( medFromX, medFromY, medToX, medToY );
// DbU::Unit cover = DbU::lambda ( getValue(medToX - medFromX) * relOccupancy );
// view->FillRectangle ( medFromX , medFromY - 100, medFromX + (cover/2), medFromY + 100 );
// view->FillRectangle ( medToX - (cover/2), medToY - 100 , medToX , medToY + 100 );
// if (overCap)
// view->FillRectangle ( medFromX+halfWidth-150, medFromY-150, medFromX+halfWidth+150, medFromY+150 );
// }
// // old version
// //if ( _estimateOccupancy > 0 )
// // view->DrawString ( getString(_estimateOccupancy), (fromPos.getX()+toPos.getX())/2 , (fromPos.getY()+toPos.getY())/2 );
// if ( (_netStamp == _from->getRoutingGraph()->getNetStamp()) && (_connexID != -1) ) {
// view->DrawString ( getString(_connexID), (fromPos.getX()+toPos.getX())/2 , (fromPos.getY()+toPos.getY())/2+10 );
// }
// //if ( _nextTo ) {
// // Point nextToFromPos = transformation.getPoint ( _nextTo->getFrom()->getPosition() );
// // Point nextToToPos = transformation.getPoint ( _nextTo->getTo()->getPosition() );
// // DbU::Unit origX = fromPos.getX() + (toPos.getX() - fromPos.getX())/3;
// // DbU::Unit origY = fromPos.getY() + (toPos.getY() - fromPos.getY())/3;
// // DbU::Unit destX = nextToFromPos.getX() + (nextToToPos.getX() - nextToFromPos.getX())/3;
// // DbU::Unit destY = nextToFromPos.getY() + (nextToToPos.getY() - nextToFromPos.getY())/3;
// // view->DrawLine ( origX, origY, destX, destY );
// // view->DrawCircle ( destX, destY, DbU::lambda ( 3 ) );
// //}
// //if ( _nextFrom ) {
// // Point nextFromFromPos = transformation.getPoint ( _nextFrom->getFrom()->getPosition() );
// // Point nextFromToPos = transformation.getPoint ( _nextFrom->getTo()->getPosition() );
// // DbU::Unit origX = fromPos.getX() + (toPos.getX() - fromPos.getX())*2/3;
// // DbU::Unit origY = fromPos.getY() + (toPos.getY() - fromPos.getY())*2/3;
// // DbU::Unit destX = nextFromFromPos.getX() + (nextFromToPos.getX() - nextFromFromPos.getX())*2/3;
// // DbU::Unit destY = nextFromFromPos.getY() + (nextFromToPos.getY() - nextFromFromPos.getY())*2/3;
// // view->DrawLine ( origX, origY, destX, destY );
// // view->FillCircle ( destX, destY, DbU::lambda ( 3 ) );
// //}
// }
// void Edge::_Highlight ( View* view, const Box& updateArea, const Transformation& transformation )
// // **********************************************************************************************
// {
// view->DrawLine ( transformation.getPoint ( _from->getPosition() )
// , transformation.getPoint ( _to->getPosition() ) );
// }
// bool Edge::_IsInterceptedBy ( View* view, const Point& point, const DbU::Unit& aperture ) const
// // ***************************************************************************************
// {
// Box area ( point );
// area.inflate(aperture);
// return getBoundingBox().intersect ( area );
// }
void Edge::invalidate ( bool propagateFlag )
// *****************************************
{
Inherit::invalidate ( false );
}
string Edge::_getString() const
// ****************************
{
return "<" + _TName ( "Edge" )
+ " id:" + getString( _connexID )
+ " s:" + getString( _netStamp )
+ " " + getString( _realOccupancy )
+ "/" + getString( _capacity )
+ " " + getString( _from )
+ " " + getString( _to ) + ">";
}
Record* Edge::_getRecord() const
// ***********************
{
Record* record = Inherit::_getRecord();
if ( !record )
record = new Record ( getString ( this ) );
record->add ( getSlot ( "from" , _from ) );
record->add ( getSlot ( "to" , _to ) );
record->add ( getSlot ( "nextFrom" , _nextFrom ) );
record->add ( getSlot ( "nextTo" , _nextTo ) );
record->add ( getSlot ( "connexID" , _connexID ) );
record->add ( getSlot ( "cost" , _cost ) );
record->add ( getSlot ( "netStamp" , _netStamp ) );
record->add ( getSlot ( "capacity" , _capacity ) );
record->add ( getSlot ( "occupancy", _realOccupancy ) );
record->add ( getSlot ( "estimate occupancy", _estimateOccupancy ) );
record->add ( getSlot ( "segments" , &_segments ) );
return record;
}
} // end namespace