// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2016-2018, All Rights Reserved
//
// +-----------------------------------------------------------------+
// |                   C O R I O L I S                               |
// |     A n a b a t i c  -  Global Routing Toolbox                  |
// |                                                                 |
// |  Author      :                    Jean-Paul CHAPUT              |
// |  E-mail      :            Jean-Paul.Chaput@lip6.fr              |
// | =============================================================== |
// |  C++ Module  :  "./AnabaticEngine.cpp"                          |
// +-----------------------------------------------------------------+


#include <sstream>
#include <iostream>
#include "hurricane/Bug.h"
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/DataBase.h"
#include "hurricane/RegularLayer.h"
#include "hurricane/Horizontal.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/Vertical.h"
#include "hurricane/Cell.h"
#include "hurricane/NetExternalComponents.h"
#include "hurricane/DebugSession.h"
#include "hurricane/UpdateSession.h"
#include "crlcore/RoutingGauge.h"
#include "crlcore/Measures.h"
#include "crlcore/Histogram.h"
#include "anabatic/GCell.h"
#include "anabatic/AutoContactTerminal.h"
#include "anabatic/NetBuilderM2.h"
#include "anabatic/NetBuilderHV.h"
#include "anabatic/NetBuilderVH.h"
#include "anabatic/AnabaticEngine.h"


namespace {

  using namespace Hurricane;
  using namespace Anabatic;


  class SortAcByXY {
    public:
      inline bool  operator() ( AutoContactTerminal* contact1, AutoContactTerminal* contact2 );
  };


  inline bool  SortAcByXY::operator() ( AutoContactTerminal* contact1, AutoContactTerminal* contact2 )
  {
    DbU::Unit x1 = contact1->getX();
    DbU::Unit x2 = contact2->getX();

    if (x1 == x2) {
      DbU::Unit y1 = contact1->getY();
      DbU::Unit y2 = contact2->getY();

      if (y1 == y2) return false;
      return (y1 < y2);
    }
    return (x1 < x2);
  }


  void  shear ( AutoSegment* segment )
  {
    AutoContact* source    = segment->getAutoSource();
    AutoContact* target    = segment->getAutoTarget();
    bool         useSource = true;

    if (segment->isHorizontal()) {
      if (not source->isTurn() and target->isTurn()) useSource = false;
    } else {
      if (not source->isTurn() and target->isTurn()) useSource = false;
    }

    segment->makeDogleg( (useSource ? source->getGCell() : target->getGCell()) );
    Session::getDoglegs()[ Session::getDoglegs().size()-2 ]->unsetFlags( AutoSegment::SegAxisSet );

#if BAD_RESULTS
    AutoContact* source        = segment->getAutoSource();
    AutoContact* target        = segment->getAutoTarget();
    AutoSegment* perpandicular = NULL;
    bool         useSource     = true;

    if (segment->isHorizontal()) {
      if (source->isTurn()) perpandicular = source->getPerpandicular( segment );
      else {
        if (target->isTurn()) { perpandicular = target->getPerpandicular( segment ); useSource = false; }
        else {
          if (source->isHTee()) perpandicular = source->getPerpandicular( segment );
          else {
            if (target->isHTee()) { perpandicular = target->getPerpandicular( segment ); useSource = false; }
            else
              perpandicular = segment;
          }
        }
      }
    } else {
      if (source->isTurn()) perpandicular = source->getPerpandicular( segment );
      else {
        if (target->isTurn()) { perpandicular = target->getPerpandicular( segment ); useSource = false; }
        else {
          if (source->isVTee()) perpandicular = source->getPerpandicular( segment );
          else {
            if (target->isVTee()) { perpandicular = target->getPerpandicular( segment ); useSource = false; }
            else
              perpandicular = segment;
          }
        }
      }
    }

    perpandicular->makeDogleg( (useSource ? source->getGCell() : target->getGCell()) );
#endif
  }


  class NonReducedItem {
    public:
      inline              NonReducedItem ( AutoSegment* segment=NULL, uint32_t nonReduceds=0 );
      inline AutoSegment* segment        () const;
      inline uint32_t     nonReduceds    () const;
    private:
      AutoSegment* _segment;
      uint32_t     _nonReduceds;
  };


  inline NonReducedItem::NonReducedItem ( AutoSegment* segment, uint32_t nonReduceds )
    : _segment    (segment)
    , _nonReduceds(nonReduceds)
  { }

  inline AutoSegment* NonReducedItem::segment     () const { return _segment; }
  inline uint32_t     NonReducedItem::nonReduceds () const { return _nonReduceds; }

  bool  operator< ( const NonReducedItem& lhs, const NonReducedItem& rhs )
  {
    int32_t deltaReduceds = (int32_t)lhs.nonReduceds() - (int32_t)rhs.nonReduceds();
    if (deltaReduceds > 0) return true;  // Most connected first.
    if (deltaReduceds < 0) return false;
    return lhs.segment()->getId() < rhs.segment()->getId(); // Smallest Id first.
  }

}  // Anonymous namespace.


namespace Anabatic {

  using std::cerr;
  using std::cout;
  using std::endl;
  using std::multiset;
  using std::ostringstream;
  using Hurricane::Bug;
  using Hurricane::Error;
  using Hurricane::Warning;
  using Hurricane::Breakpoint;
  using Hurricane::DataBase;
  using Hurricane::RegularLayer;
  using Hurricane::Component;
  using Hurricane::Horizontal;
  using Hurricane::Vertical;
  using Hurricane::NetRoutingExtension;
  using Hurricane::NetExternalComponents;
  using Hurricane::Cell;
  using Hurricane::DebugSession;
  using Hurricane::UpdateSession;
  using CRL::RoutingGauge;
  using CRL::RoutingLayerGauge;
  using CRL::addMeasure;
  using CRL::getMeasure;
  using CRL::Histogram;


// -------------------------------------------------------------------
// Error messages.

  const char* missingAnbt =
    "%s :\n\n"
    "    Cell %s do not have any Anabatic (or not yet created).\n";

  const char* badMethod =
    "%s :\n\n"
    "    No method id %ud (Cell %s).\n";

  const char* lookupFailed =
    "Anabatic::Extension::getDatas(Segment*) :\n\n"
    "    Cannot find AutoSegment associated to %s (internal error).\n";


// -------------------------------------------------------------------
// Class  :  "Anabatic::RawGCellsUnder".

  RawGCellsUnder::RawGCellsUnder ( const AnabaticEngine* engine, Segment* segment )
  {
    cdebug_log(112,1) << "RawGCellsUnder::RawGCellsUnder(Segment*): " << segment << endl;

    commonCtor( engine, segment->getSourcePosition(), segment->getTargetPosition() );

    cdebug_tabw(112,-1);
  }


  RawGCellsUnder::RawGCellsUnder ( const AnabaticEngine* engine, Point source, Point target )
  {
    cdebug_log(112,1) << "RawGCellsUnder::RawGCellsUnder(Point,Point): s:"
                      << source << " t:" << target << endl;

    commonCtor( engine, source, target );

    cdebug_tabw(112,-1);
  }


  void  RawGCellsUnder::commonCtor ( const AnabaticEngine* engine, Point source, Point target )
  {
    cdebug_log(112,1) << "RawGCellsUnder::commontCtor(): s:" << source << " t:" << target << endl;

    Box        gcellsArea = engine->getCell()->getAbutmentBox();
    DbU::Unit  axis       = 0;
    Flags      side       = Flags::NoFlags;

    if (source.getY() == target.getY()) {
      side = Flags::EastSide;
      axis = source.getY();
      if (source.getX() > target.getX()) std::swap( source, target );
    }
    if (source.getX() == target.getX()) {
      side = Flags::NorthSide;
      axis = source.getX();
      if (source.getY() > target.getY()) std::swap( source, target );
    }

    if (side == Flags::NoFlags) {
      cerr << Error( "RawGCellsUnder::commonCtor(): Points are neither horizontally nor vertically aligneds (ignored)."
                   ) << endl;
      cdebug_tabw(112,-1);
      DebugSession::close();
      return;
    }

    if (  (source.getX() >  gcellsArea.getXMax())
       or (source.getY() >  gcellsArea.getYMax())
       or (target.getX() <= gcellsArea.getXMin())
       or (target.getY() <= gcellsArea.getYMin()) ) {
      cerr << Error( "RawGCellsUnder::commonCtor(): Area is completly outside the GCells area (ignored)."
                   ) << endl;
      cdebug_tabw(112,-1);
      DebugSession::close();
      return;
    }

    DbU::Unit xsource = std::max( source.getX(), gcellsArea.getXMin() );
    DbU::Unit ysource = std::max( source.getY(), gcellsArea.getYMin() );
    DbU::Unit xtarget = std::min( target.getX(), gcellsArea.getXMax() );
    DbU::Unit ytarget = std::min( target.getY(), gcellsArea.getYMax() );

    if (xtarget == gcellsArea.getXMax()) --xtarget;
    if (ytarget == gcellsArea.getYMax()) --ytarget;

    GCell* gsource = engine->getGCellUnder( xsource, ysource );
    GCell* gtarget = engine->getGCellUnder( xtarget, ytarget );

    if (not gsource) {
      cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): Source not under a GCell (ignored)."
                 ) << endl;
      cdebug_tabw(112,-1);
      DebugSession::close();
      return;
    }
    if (not gtarget) {
      cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): Target not under a GCell (ignored)."
                 ) << endl;
      cdebug_tabw(112,-1);
      DebugSession::close();
      return;
    }

    if (gsource == gtarget) {
      _elements.push_back( Element(gsource,NULL) );
      cdebug_tabw(112,-1);
      DebugSession::close();
      return;
    }

    cdebug_log(112,0) << "flags:" << side << " axis:" << DbU::getValueString(axis) << endl;

    Edge* edge = gsource->getEdgeAt( side, axis );
    while ( edge ) {
      _elements.push_back( Element(edge->getSource(),edge) );
      cdebug_log(112,0) << "| push:" << edge->getSource() << " from " << edge << endl;

      if (edge->getTarget() == gtarget) break;
      edge = edge->getTarget()->getEdgeAt( side, axis );
    } 
    _elements.push_back( Element(gtarget,NULL) );
    cdebug_log(112,0) << "| push:" << gtarget << " last/target" << endl;

    cdebug_tabw(112,-1);
  }


// -------------------------------------------------------------------
// Class  :  "Anabatic::NetData".

  NetData::NetData ( Net* net, AnabaticEngine* anabatic )
    : _net       (net)
    , _state     (NetRoutingExtension::get(net))
    , _searchArea()
    , _rpCount   (0)
    , _diodeCount(0)
    , _sparsity  (0)
    , _flags     ()
    , _noMoveUp  ()
  {
    if (_state and _state->isMixedPreRoute()) return;

    Cell* diodeCell = anabatic->getDiodeCell();
    for ( RoutingPad* rp : _net->getRoutingPads() ) {
      _searchArea.merge( rp->getBoundingBox() );
      ++_rpCount;

      if (diodeCell) {
        Plug* plug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
        if (plug and (plug->getInstance()->getMasterCell() == diodeCell))
          ++_diodeCount;
      }
    }
    _update();
  }


// -------------------------------------------------------------------
// Class  :  "Anabatic::AnabaticEngine".

  Name  AnabaticEngine::_toolName = "Anabatic";


  AnabaticEngine* AnabaticEngine::get ( const Cell* cell )
  { return static_cast<AnabaticEngine*>(ToolEngine::get(cell,staticGetName())); }


  const Name& AnabaticEngine::staticGetName ()
  { return _toolName; }


  const Name& AnabaticEngine::getName () const
  { return _toolName; }


  AnabaticEngine::AnabaticEngine ( Cell* cell )
    : Super(cell)
    , _configuration    (new Configuration())
    , _chipTools        (cell)
    , _state            (EngineCreation)
    , _matrix           ()
    , _gcells           ()
    , _ovEdges          ()
    , _netOrdering      ()
    , _netDatas         ()
    , _viewer           (NULL)
    , _flags            (Flags::DestroyBaseContact)
    , _stamp            (-1)
    , _densityMode      (MaxDensity)
    , _autoSegmentLut   ()
    , _autoContactLut   ()
    , _edgeCapacitiesLut()
    , _blockageNet      (cell->getNet("blockagenet"))
    , _diodeCell        (NULL)
  {
    _matrix.setCell( cell, _configuration->getSliceHeight() );
    Edge::unity = _configuration->getSliceHeight();

    if (not _blockageNet) {
      _blockageNet = Net::create( cell, "blockagenet" );
      _blockageNet->setType( Net::Type::BLOCKAGE );
    }
  }


  void  AnabaticEngine::_postCreate ()
  {
    Super::_postCreate();

    _diodeCell = DataBase::getDB()->getCell( getConfiguration()->getDiodeName() );;
    if (not _diodeCell) {
      cerr << Warning( "AnabaticEngine::_postCreate() Unable to find \"%s\" diode cell."
                     , getConfiguration()->getDiodeName().c_str()
                     ) << endl;
    }

    UpdateSession::open();
    GCell::create( this );
    UpdateSession::close();
    checkPlacement();
  }


  AnabaticEngine* AnabaticEngine::create ( Cell* cell )
  {
    if (not cell) throw Error( "AnabaticEngine::create(): NULL cell argument." );
    if (cell->getAbutmentBox().isEmpty())
      throw Error( "AnabaticEngine::create(): %s has no abutment box." , getString(cell).c_str() );
    
    AnabaticEngine* engine = new AnabaticEngine ( cell );
    engine->_postCreate();
    return engine;
  }


  AnabaticEngine::~AnabaticEngine ()
  {
    delete _configuration;
    for ( pair<unsigned int,NetData*> data : _netDatas ) delete data.second;
  }


  void  AnabaticEngine::_preDestroy ()
  {
    cdebug_log(145,1) << "Anabatic::_preDestroy ()" << endl;

    if (getState() < EngineGutted)
      setState( EnginePreDestroying );

    _gutAnabatic();
    _state = EngineGutted;

    cdebug_log(145,0) << "About to delete base class ToolEngine." << endl;
    Super::_preDestroy();

  //cmess2 << "     - GCells        := " << GCell::getAllocateds() << endl;
    cmess2 << "     - AutoContacts  := " << AutoContact::getAllocateds() << endl;
    cmess2 << "     - AutoSegments  := " << AutoSegment::getAllocateds() << endl;

    cdebug_log(145,0) << "Exiting Anabatic::_preDestroy()." << endl;
    cdebug_tabw(145,-1);
  }


  void  AnabaticEngine::_gutAnabatic ()
  {
  //DebugSession::open( 159, 160 );
    openSession();

    _flags.reset( Flags::DestroyBaseContact|Flags::DestroyBaseSegment );

    if (_state == EngineDriving) {
      cdebug_log(145,1) << "Saving AutoContacts/AutoSegments." << endl;

      vector<NonReducedItem> reduceds;
      size_t fixedSegments    = 0;
      size_t sameLayerDoglegs = 0;
      size_t bloatedStraps    = 0;
      for ( auto isegment : _autoSegmentLut ) {
        if (isegment.second->isFixed()) ++fixedSegments;
        if (isegment.second->canReduce( Flags::NullLength )) {
        //cerr << "push_back() " << (void*)isegment.second << ":" << isegment.second << endl;
          reduceds.push_back( NonReducedItem( isegment.second
                                            , isegment.second->getNonReduceds( Flags::NoFlags ) ));
        } else {
          if (isegment.second->reduceDoglegLayer()) ++sameLayerDoglegs;
        }
      //if (isegment.second->bloatStackedStrap()) ++bloatedStraps;
      }
      sort( reduceds.begin(), reduceds.end() );
      // cerr << "Reduced segment queue:" << endl;
      // for ( size_t i=0 ; i<reduceds.size() ; ++i ) {
      //   cerr << "| " << setw(3) << i
      //        << " " << reduceds[i].nonReduceds()
      //        << " " << reduceds[i].segment() << endl;
      // }
      for ( auto& item : reduceds ) {
        item.segment()->reduce( Flags::NoFlags );
        if (item.segment()->reduceDoglegLayer()) ++sameLayerDoglegs;
      }

      cmess1 << "  o  Driving Hurricane data-base." << endl;
      cmess1 << Dots::asSizet("     - Active AutoSegments"       ,AutoSegment::getAllocateds()-fixedSegments) << endl;
      cmess1 << Dots::asSizet("     - Active AutoContacts"       ,AutoContact::getAllocateds()-fixedSegments*2) << endl;
      cmess1 << Dots::asSizet("     - AutoSegments"              ,AutoSegment::getAllocateds()) << endl;
      cmess1 << Dots::asSizet("     - AutoContacts"              ,AutoContact::getAllocateds()) << endl;
      cmess1 << Dots::asSizet("     - Same Layer doglegs"        ,sameLayerDoglegs) << endl;
      cmess1 << Dots::asSizet("     - Bloated straps (< minArea)",bloatedStraps   ) << endl;

    //for ( Net* net : _cell->getNets() ) _saveNet( net );

      cdebug_tabw(145,-1);
    }

    if (_state < EngineGutted ) {
      cdebug_log(145,0) << "Gutting Anabatic." << endl;
      _state = EngineGutted;
      _flags |= Flags::DestroyBaseContact;

      _destroyAutoSegments();
      _destroyAutoContacts();

      _flags |= Flags::DestroyGCell;

      for ( GCell* gcell : _gcells ) gcell->_destroyEdges();
      for ( GCell* gcell : _gcells ) gcell->destroy();
      _gcells.clear();
      _ovEdges.clear();
    }

    exportExternalNets();
    Session::close();
  //DebugSession::close();
  }


  void  AnabaticEngine::exportExternalNets ()
  {
    for ( Net* net : getCell()->getNets() ) {
      if (not net->isExternal()) continue;
      if (net->isSupply()) continue;

      for ( Segment* segment : net->getSegments() ) {
        NetExternalComponents::setExternal( segment );
      }
    }
  }
  

  Configuration* AnabaticEngine::getConfiguration ()
  { return _configuration; }


  const Configuration* AnabaticEngine::getConfiguration () const
  { return _configuration; }


  Interval  AnabaticEngine::getUSide ( Flags direction ) const
  {
    Interval side;
    Box      bBox ( getCell()->getBoundingBox() );

    if      (direction & Flags::Horizontal) side = Interval( bBox.getXMin(), bBox.getXMax() );
    else if (direction & Flags::Vertical  ) side = Interval( bBox.getYMin(), bBox.getYMax() );
    else {
      cerr << Error( "AnabaticEngine::getUSide(): Unknown direction flag \"%i\""
                   , getString(direction).c_str() ) << endl;
    }
    return side;
  }


  int  AnabaticEngine::getCapacity ( Interval span, Flags flags ) const
  {
    int           capacity = 0;
    Box           ab       = getCell()->getAbutmentBox();
    RoutingGauge* rg       = _configuration->getRoutingGauge();

    span.inflate( 0, -1 );
    if (span.isEmpty()) return 0;

    const vector<RoutingLayerGauge*>& layerGauges = rg->getLayerGauges();
    for ( size_t depth=0 ; depth <= _configuration->getAllowedDepth() ; ++depth ) {
      if (layerGauges[depth]->getType() != Constant::Default) continue;

      if (flags & Flags::Horizontal) {
        if (layerGauges[depth]->getDirection() != Constant::Horizontal) continue;
        capacity += layerGauges[depth]->getTrackNumber( span.getVMin() - ab.getYMin()
                                                      , span.getVMax() - ab.getYMin() );
      //cdebug_log(110,0) << "Horizontal edge capacity:" << capacity << endl;
      }

      if (flags & Flags::Vertical) {
        if (layerGauges[depth]->getDirection() != Constant::Vertical) continue;
        capacity += layerGauges[depth]->getTrackNumber( span.getVMin() - ab.getXMin()
                                                      , span.getVMax() - ab.getXMin() );
      //cdebug_log(110,0) << "Vertical edge capacity:" << capacity << endl;
      }
    }

    return capacity;
  }


  bool  AnabaticEngine::checkPlacement () const
  {
    bool valid  = true;
    Box  cellAb = getCell()->getAbutmentBox();
    
    for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences() ) {
      Instance* instance     = static_cast<Instance*>(occurrence.getEntity());
      Cell*     masterCell   = instance->getMasterCell();
      string    instanceName = occurrence.getCompactString();

      instanceName.erase( 0, 1 );
      instanceName.erase( instanceName.size()-1 );

      Box instanceAb = masterCell->getAbutmentBox();

      Transformation instanceTransf = instance->getTransformation();
      occurrence.getPath().getTransformation().applyOn( instanceTransf );
      instanceTransf.applyOn( instanceAb );

      if (not cellAb.contains(instanceAb)) {
        valid = false;
        cerr << Error( "AnabaticEngine::checkPlacement(): Instance %s is outside top cell abutment box, routing will be incomplete.\n"
                       "        (cell:%s vs instance:%s)"
                     , instanceName.c_str()
                     , getString(cellAb    ).c_str()
                     , getString(instanceAb).c_str()
                     ) << endl;
      }
    }

    size_t        errorCount = 0;
    ostringstream errors;
    errors << "AnabaticEngine::checkPlacement():\n";

    for ( Net* net: getCell()->getNets() ) {
      for ( RoutingPad* rp : net->getRoutingPads() ) {
        Pin* pin = dynamic_cast<Pin*>( rp->getOccurrence().getEntity() );
        if (not pin) continue;

        ostringstream pinError;

        Point pinCenter = rp->getCenter();
        if (  (pin->getAccessDirection() == Pin::AccessDirection::NORTH)
           or (pin->getAccessDirection() == Pin::AccessDirection::SOUTH) ) {
          if (pin->getLayer() != getConfiguration()->getDVerticalLayer()) {
            pinError << "    Should be in vertical routing layer, "
                     << "pin:"      << pin->getLayer()->getName()
                     << " vs gauge:" << getConfiguration()->getDVerticalLayer()->getName()
                     << "\n";
            valid = false;
            ++errorCount;
          }
          if ((pinCenter.getX() - getCell()->getAbutmentBox().getXMin()
                                - getConfiguration()->getDVerticalOffset())
              % getConfiguration()->getDVerticalPitch()) {
            pinError << "    Misaligned, "
                     << "pin:" << DbU::getValueString(pinCenter.getX())
                     << " vs gauge, pitch:" << DbU::getValueString(getConfiguration()->getDVerticalPitch ())
                     << ", offset:"         << DbU::getValueString(getConfiguration()->getDVerticalOffset())
                     << "\n";
            valid = false;
            ++errorCount;
          }
        } 

        if (  (pin->getAccessDirection() == Pin::AccessDirection::EAST)
           or (pin->getAccessDirection() == Pin::AccessDirection::WEST) ) {
          if (pin->getLayer() != getConfiguration()->getDHorizontalLayer()) {
            pinError << "    Should be in horizontal routing layer, "
                     << "pin:"      << pin->getLayer()->getName()
                     << " vs gauge:" << getConfiguration()->getDHorizontalLayer()->getName()
                     << "\n";
            valid = false;
            ++errorCount;
          }
          if ((pinCenter.getY() - getCell()->getAbutmentBox().getYMin()
                                - getConfiguration()->getDHorizontalOffset())
              % getConfiguration()->getDHorizontalPitch()) {
            pinError << "    Misaligned, "
                     << "pin:" << DbU::getValueString(pinCenter.getY())
                     << " vs gauge, pitch:" << DbU::getValueString(getConfiguration()->getDHorizontalPitch ())
                     << ", offset:"         << DbU::getValueString(getConfiguration()->getDHorizontalOffset())
                     << "\n";
            valid = false;
            ++errorCount;
          }
        } 

        if (not pinError.str().empty()) {
          errors << "On " << pin << "\n" << pinError.str();
        }
      }
    }
    if (errorCount) throw Error( errors.str() );
    
    return valid;
  }


  void  AnabaticEngine::openSession ()
  { Session::_open(this); }


  void  AnabaticEngine::reset ()
  {
    _gutAnabatic();
    _flags.reset( Flags::DestroyMask );
    _state = EngineCreation;

    UpdateSession::open();
    GCell::create( this );
    UpdateSession::close();
  }


  void  AnabaticEngine::setupNetDatas ()
  {
    Histogram  netHistogram ( 0.0, 1.0, 1 );
    netHistogram.setTitle ( "RoutingPads", 0 );
    netHistogram.setColor ( "green"      , 0 );
    netHistogram.setIndent( "       "    , 0 );
    
    size_t  oindex = _netOrdering.size();
    for ( Net* net : _cell->getNets() ) {
      if (_netDatas.find(net->getId()) != _netDatas.end()) continue;
      NetData* data = new NetData( net, this );
      _netOrdering.push_back( data );

      netHistogram.addSample( (float)(data->getRpCount() - data->getDiodeRpCount()), 0 );
    }

    for ( ; oindex < _netOrdering.size() ; ++oindex ) {
      _netDatas.insert( make_pair( _netOrdering[oindex]->getNet()->getId()
                                 , _netOrdering[oindex] ) );
    }

    sort( _netOrdering.begin(), _netOrdering.end(), SparsityOrder() );

    cmess2 << "  o  Nets Histogram." << endl;
    cmess2 << netHistogram.toString(0) << endl;
  }


  void  AnabaticEngine::exclude ( const Name& netName )
  {
    Net* net = _cell->getNet( netName );
    if (not net) return;

    exclude( net );
  }


  void  AnabaticEngine::exclude ( Net* net )
  {
    NetDatas::iterator inet =_netDatas.find( net->getId() );
    if (inet == _netDatas.end()) return;

    (*inet).second->setExcluded( true );
  }


  void AnabaticEngine::updateMatrix()
  {
    _matrix.setCell( getCell(), Session::getSliceHeight() );
    for ( GCell* gcell : _gcells ) _updateLookup( gcell );
  }


  size_t  AnabaticEngine::getNetsFromEdge ( const Edge* edge, NetSet& nets )
  {
    size_t  count  = 0;
    GCell*  source = edge->getSource();
    GCell*  target = edge->getTarget();
    const vector<Contact*>& contacts = source->getGContacts();

    for ( Contact* contact : contacts ) {
      for ( Component* component : contact->getSlaveComponents() ) {
        if (edge->isHorizontal()) {
          Horizontal* horizontal = dynamic_cast<Horizontal*>( component );
          if (horizontal
             and (horizontal->getSource() == contact)
             and (target->hasGContact(dynamic_cast<Contact*>(horizontal->getTarget())))) {
            nets.insert( horizontal->getNet() );
            ++count;
          }
        }
        if (edge->isVertical()) {
          Vertical* vertical = dynamic_cast<Vertical*>( component );
          if (vertical
             and (vertical->getSource() == contact)
             and (target->hasGContact(dynamic_cast<Contact*>(vertical->getTarget())))) {
            nets.insert( vertical->getNet() );
            ++count;
          }
        }
      }
    }
    return count;
  }


  NetData* AnabaticEngine::getNetData ( Net* net, Flags flags )
  {
    NetData*            data = NULL;
    NetDatas::iterator idata = _netDatas.find( net->getId() );
    if (idata == _netDatas.end()) {
      data = new NetData( net, this );
      _netDatas.insert( make_pair(net->getId(),data) );
      _netOrdering.push_back( data );
      // cerr << Bug( "AnabaticEngine::getNetData() - %s is missing in NetDatas table."
      //            , getString(net->getName()).c_str()
      //            ) << endl;
      // return NULL;
    } else
      data = idata->second;

    if ((flags & Flags::Create) and not data->getNetRoutingState()) {
      data->setNetRoutingState( NetRoutingExtension::create(net) );
    }

    return data;
  }


  Contact* AnabaticEngine::breakAt ( Segment* segment, GCell* breakGCell )
  {
    size_t       i       = 0;
    GCellsUnder  gcells  ( new RawGCellsUnder(this,segment) );
    for ( ; i<gcells->size() ; ++i ) {
      if (gcells->gcellAt(i) == breakGCell) break;
    }

    Contact* breakContact = breakGCell->getGContact( segment->getNet() );

    if (i == gcells->size()) {
      cerr << Error( "AnabaticEngine::breakAt(): %s is *not* over %s."
                   , getString(segment).c_str()
                   , getString(breakGCell).c_str()
                   ) << endl;
      return breakContact;
    }

    Component* targetContact = segment->getTarget();
    segment->getTargetHook()->detach();
    segment->getTargetHook()->attach( breakContact->getBodyHook() );

    Segment*    splitted   = NULL;
    Horizontal* horizontal = dynamic_cast<Horizontal*>(segment);
    if (horizontal) {
      splitted = Horizontal::create( breakContact
                                   , targetContact
                                   , getConfiguration()->getGHorizontalLayer()
                                   , horizontal->getY()
                                   , DbU::fromLambda(2.0)
                                   );
    } else {
      Vertical* vertical = dynamic_cast<Vertical*>(segment);
      if (vertical) {
        splitted = Vertical::create( breakContact
                                   , targetContact
                                   , getConfiguration()->getGVerticalLayer()
                                   , vertical->getX()
                                   , DbU::fromLambda(2.0)
                                   );
      } else
        return breakContact;
    }

    NetData* netData = getNetData( segment->getNet() );
    if (netData and netData->isNoMoveUp(segment))
      netData->setNoMoveUp( splitted );
    for ( ; i<gcells->size()-1 ; ++i ) gcells->edgeAt(i)->replace( segment, splitted );

    return breakContact;
  }


  bool  AnabaticEngine::unify ( Contact* contact )
  {
    size_t      hCount     = 0;
    size_t      vCount     = 0;
    Horizontal* horizontals[2];
    Vertical*   verticals  [2];

    cdebug_log(112,1) << "AnabaticEngine::unify(): " << (void*)contact << endl;
    cdebug_log(112,0) << contact << endl;

    for ( Hook* hook : contact->getBodyHook()->getHooks() ) {
      RoutingPad* rp = dynamic_cast<RoutingPad*>( hook->getComponent() );
      if (rp) {
        cdebug_log(112,0) << "Cannot unify, there is a RoutingPad in this GCell." << endl;
        cdebug_tabw(112,-1);
        return false;
      }
    }

    for ( Component* slave : contact->getSlaveComponents() ) {
      Horizontal* h = dynamic_cast<Horizontal*>( slave );
      if (h) {
        if (vCount or (hCount > 1)) return false;
        horizontals[hCount++] = h;
      } else {
        Vertical* v = dynamic_cast<Vertical*>( slave );
        if (v) {
          if (hCount or (vCount > 1)) return false;
          verticals[vCount++] = v;
        } else {
        // Something else depends on this contact.
          cdebug_log(112,0) << "Cannot unify, still have slave components." << endl;
          cdebug_tabw(112,-1);
          return false;
        }
      }
    }

    if (hCount == 2) {
      if (horizontals[0]->getTarget() != contact) std::swap( horizontals[0], horizontals[1] );
      Interval    constraints ( false );
      GCellsUnder gcells0     = getGCellsUnder( horizontals[0] );
      if (not gcells0->empty()) {
        for ( size_t i=0 ; i<gcells0->size() ; ++i )
          constraints.intersection( gcells0->gcellAt(i)->getSide(Flags::Vertical) );
      }

      GCellsUnder gcells1 = getGCellsUnder( horizontals[1] );
      if (not gcells1->empty()) {
        for ( size_t i=0 ; i<gcells1->size() ; ++i ) {
          constraints.intersection( gcells1->gcellAt(i)->getSide(Flags::Vertical) );
          if (constraints.isEmpty()) {
            cdebug_tabw(112,-1);
            return false;
          }
        }
      }

      if (not gcells1->empty()) {
        for ( size_t i=0 ; i<gcells1->size()-1 ; ++i )
          gcells1->edgeAt(i)->replace( horizontals[1], horizontals[0] );
      }

      Component* target = horizontals[1]->getTarget();
      horizontals[1]->destroy();
      horizontals[0]->getTargetHook()->detach();
      horizontals[0]->getTargetHook()->attach( target->getBodyHook() );
      horizontals[0]->setY( constraints.getCenter() );
    } 

    if (vCount == 2) {
      cdebug_log(112,0) << "Vertical unify of: " << contact << endl;
      
      if (verticals[0]->getTarget() != contact) std::swap( verticals[0], verticals[1] );
      Interval    constraints ( false );
      GCellsUnder gcells0     = getGCellsUnder( verticals[0] );
      if (not gcells0->empty()) {
        for ( size_t i=0 ; i<gcells0->size() ; ++i )
          constraints.intersection( gcells0->gcellAt(i)->getSide(Flags::Horizontal) );
      }

      GCellsUnder gcells1 = getGCellsUnder( verticals[1] );
      if (not gcells1->empty()) {
        for ( size_t i=0 ; i<gcells1->size() ; ++i ) {
          constraints.intersection( gcells1->gcellAt(i)->getSide(Flags::Horizontal) );
          if (constraints.isEmpty()) {
            cdebug_log(112,0) << "Cannot unify, shearing constraints." << endl;
            cdebug_tabw(112,-1);
            return false;
          }
        }
      }

      if (not gcells1->empty()) {
        for ( size_t i=0 ; i<gcells1->size()-1 ; ++i )
          gcells1->edgeAt(i)->replace( verticals[1], verticals[0] );
      }

      Component* target = verticals[1]->getTarget();
      verticals[1]->destroy();
      verticals[0]->getTargetHook()->detach();
      verticals[0]->getTargetHook()->attach( target->getBodyHook() );
      verticals[0]->setX( constraints.getCenter() );
    } 

    getGCellUnder( contact->getPosition() )->unrefContact( contact );

    cdebug_tabw(112,-1);
    return true;
  }


  void  AnabaticEngine::ripup ( Segment* seed, Flags flags )
  {
    Net* net = seed->getNet();

    DebugSession::open( net, 112, 120 );
    cdebug_log(112,1) << "AnabaticEngine::ripup(): " << seed << endl;

    Contact* end0 = NULL;
    Contact* end1 = NULL;

    set<Segment*,Entity::CompareById> ripups;
    ripups.insert( seed );

    vector< pair<Segment*,Component*> > stack;
    if (flags & Flags::Propagate) {
      stack.push_back( make_pair(seed,seed->getSource()) );
      stack.push_back( make_pair(seed,seed->getTarget()) );
    }

    while ( not stack.empty() ) {
      Contact* contact = dynamic_cast<Contact*>( stack.back().second );
      Segment* from    = stack.back().first;
      stack.pop_back();
      if (not contact) continue;

      Segment* connected  = NULL;
      size_t   slaveCount = 0;
      for ( Hook* hook : contact->getBodyHook()->getHooks() ) {
        Component* linked = hook->getComponent();
        if ((linked == contact) or (linked == from)) continue;

        if (dynamic_cast<RoutingPad*>(linked)) { ++slaveCount; continue; }

        connected = dynamic_cast<Segment*>( linked );
        if (connected) ++slaveCount; 
      }

      if ((slaveCount == 1) and (connected)) {
        if (not ripups.count(connected)) {
          stack .push_back( make_pair(connected,connected->getOppositeAnchor(contact)) );
          ripups.insert( connected );
        }
      } else {
        if (not end0) {
          end0 = contact;
          cdebug_log(112,0) << "end0:" << contact << endl;
        } else {
          if (contact != end0) {
            end1 = contact;
            cdebug_log(112,0) << "end1:" << contact << endl;
          }
        }
      }
    }

    for ( Segment* segment : ripups ) {
      cdebug_log(112,1) << "| Destroy:" << segment << endl;

      GCellsUnder gcells = getGCellsUnder( segment );
      if (not gcells->empty()) {
        for ( size_t i=0 ; i<gcells->size()-1 ; ++i ) {
          cdebug_log(112,0) << "| " << gcells->gcellAt(i) << endl;
          cdebug_log(112,0) << "| " << gcells->edgeAt(i) << endl;
          gcells->edgeAt(i)->remove( segment );
        }
      } else {
        cdebug_log(112,0) << "No GCells under segment." << endl;
      }

      Contact* source = dynamic_cast<Contact*>( segment->getSource() );
      Contact* target = dynamic_cast<Contact*>( segment->getTarget() );
      segment->getSourceHook()->detach();
      segment->getTargetHook()->detach();
      segment->destroy();
      bool deletedSource = gcells->gcellAt( 0                )->unrefContact( source );
      bool deletedTarget = gcells->gcellAt( gcells->size()-1 )->unrefContact( target );

      if (deletedSource) {
        if (source == end0) end0 = NULL;
        if (source == end1) end1 = NULL;
      }
      if (deletedTarget) {
        if (target == end0) end0 = NULL;
        if (target == end1) end1 = NULL;
      }

      cdebug_tabw(112,-1);
    }

    if (end0) unify( end0 );
    if (end1) unify( end1 );

    getNetData( net )->setGlobalRouted( false );

    cdebug_tabw(112,-1);
    DebugSession::close();
  }


  void  AnabaticEngine::cleanupGlobal ()
  {
    UpdateSession::open();
    for ( GCell* gcell : _gcells ) gcell->cleanupGlobal();
    UpdateSession::close();

    for ( Net* net : getCell()->getNets() ) {
      for ( Component* component : net->getComponents() ) {
        if (getConfiguration()->isGLayer(component->getLayer())) {
          cerr << Error( "AnabaticEngine::cleanupGlobal(): Remaining global routing,\n"
                         "        %s"
                       , getString(component).c_str()
                       ) << endl;
        }
      }
    }
  }


  void  AnabaticEngine::loadGlobalRouting ( uint32_t method )
  {
    if (_state < EngineGlobalLoaded)
      throw Error ("AnabaticEngine::loadGlobalRouting() : global routing not present yet.");

    if (_state > EngineGlobalLoaded)
      throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded.");

    antennaProtect();

    if (method == EngineLoadGrByNet ) { _loadGrByNet(); }
    else {
      throw Error( badMethod, "Anabatic::loadGlobalRouting()", method, getString(_cell).c_str() );
    }
    cleanupGlobal();

    if (not getConfiguration()->isTwoMetals()) relaxOverConstraineds();

    _state = EngineActive;
  }


  void  AnabaticEngine::relaxOverConstraineds ()
  {
    openSession();

  //DbU::Unit           pitch3 = Session::getPitch( 2 );
    AutoSegment::IdSet  constraineds;
    AutoSegment::IdSet  processeds;
    
    for ( GCell* gcell : _gcells ) {
      multiset<AutoContactTerminal*,SortAcByXY>  acTerminals;
      for ( AutoContact* contact : gcell->getContacts() ) {
        if (contact->isTerminal() and (Session::getViaDepth(contact->getLayer()) == 0) )
          acTerminals.insert( dynamic_cast<AutoContactTerminal*>(contact) );
      }

      AutoContactTerminal* south = NULL;
      for ( AutoContactTerminal* north : acTerminals ) {
        if (south) {
          if (   south->canDrag()
             and north->canDrag()
             and (south->getNet() != north->getNet())
             and (south->getX  () == north->getX  ()) ) {
            Interval constraints ( gcell->getYMin(), north->getCBYMin() /*- pitch3*/ );
            AutoSegment* terminal = south->getSegment();
            AutoContact* opposite = terminal->getOppositeAnchor( south );

            for ( AutoSegment* segment : AutoSegments_OnContact(terminal,opposite->base()) ) {
              segment->mergeUserConstraints( constraints );
              constraineds.insert( segment );
            }

            constraints = Interval( south->getCBYMax() /*+ pitch3*/, gcell->getYMax() );
            terminal    = north->getSegment();
            opposite    = terminal->getOppositeAnchor( north );

            for ( AutoSegment* segment : AutoSegments_OnContact(terminal,opposite->base()) ) {
              segment->mergeUserConstraints( constraints );
              constraineds.insert( segment );
            }
          }
        }
        south = north;
      }
    }

    Session::revalidate();

    for ( AutoSegment* constrained : constraineds ) {
      if (processeds.find(constrained) != processeds.end()) continue;
      processeds.insert( constrained );
      
      Interval              userConstraints ( false );
      vector<AutoSegment*>  aligneds;

      aligneds.push_back( constrained );

      for ( AutoSegment* aligned : constrained->getAligneds() ) {
        aligneds.push_back( aligned );
        processeds.insert( aligned );
      }

      sort( aligneds.begin(), aligneds.end(), AutoSegment::CompareBySourceU() );

    //AutoSegment* previous = NULL;
      for ( AutoSegment* aligned : aligneds ) {
        Interval constraints = userConstraints.getIntersection( aligned->getUserConstraints() );

        if (constraints.getSize() < Session::getPitch(1)) {
        //if (not previous) {
        //  cerr << Warning( "protectAlignedAccesses(): Shearing constraints between S/T on\n"
        //                   "          %s\n"
        //                   "          S:%s\n"
        //                   "          T:%s\n"
        //                   "          Combined user constraints are too tight [%s : %s]."
        //                 , getString(aligned ).c_str()
        //                 , getString(aligned->getAutoSource()->getConstraintBox()).c_str()
        //                 , getString(aligned->getAutoTarget()->getConstraintBox()).c_str()
        //                 , DbU::getValueString(constraints.getVMin()).c_str()
        //                 , DbU::getValueString(constraints.getVMax()).c_str()
        //                 ) << endl;
        //} else {
        //  cerr << Warning( "protectAlignedAccesses(): Shearing constraints between\n"
        //                   "          %s\n"
        //                   "          %s\n"
        //                   "          Combined user constraints are too tight [%s : %s]."
        //                 , getString(previous).c_str()
        //                 , getString(aligned ).c_str()
        //                 , DbU::getValueString(constraints.getVMin()).c_str()
        //                 , DbU::getValueString(constraints.getVMax()).c_str()
        //                 ) << endl;
        //}
        //if (previous) {
        //  if (previous->getAutoTarget() == aligned->getAutoSource()) {
        //    cerr << "Found a shared contact: " << aligned->getAutoSource() << endl;
              shear( aligned );
        //  }
        //}
          
          userConstraints = aligned->getUserConstraints();
        } else {
          userConstraints = constraints;
        }

      //previous = aligned;
      }
    }

    Session::close();
  }


  void  AnabaticEngine::_loadGrByNet ()
  {
    cmess1 << "  o  Building detailed routing from global. " << endl;

    size_t shortNets = 0;

    startMeasures();
    openSession();

    int gaugeKind = 3;
    if (getConfiguration()->isTwoMetals()) gaugeKind = 0;
    if (getConfiguration()->isHV       ()) gaugeKind = 1;
    if (getConfiguration()->isVH       ()) gaugeKind = 2;

    if (gaugeKind < 3) {
      for ( Net* net : getCell()->getNets() ) {
        if (NetRoutingExtension::isShortNet(net)) {
        //AutoSegment::setShortNetMode( true );
          ++shortNets;
        }
        if (NetRoutingExtension::isManualDetailRoute(net))
          continue;
        if (  NetRoutingExtension::isManualGlobalRoute(net)
           or NetRoutingExtension::isAutomaticGlobalRoute(net)) {
          DebugSession::open( net, 145, 150 );
          AutoSegment::setAnalogMode( NetRoutingExtension::isAnalog(net) );

          switch ( gaugeKind ) {
            case 0: NetBuilder::load<NetBuilderM2>( this, net ); break;
            case 1: NetBuilder::load<NetBuilderHV>( this, net ); break;
            case 2: NetBuilder::load<NetBuilderVH>( this, net ); break;
          }

          Session::revalidate();
          DebugSession::close();
        }
        AutoSegment::setAnalogMode  ( false );
        AutoSegment::setShortNetMode( false );
      }
    }

#if defined(CHECK_DATABASE)
    _check ( "after Anabatic loading" );
#endif

    Session::close();
    stopMeasures();

    cmess2 << Dots::asSizet("     - Short nets",shortNets) << endl;

    if (gaugeKind > 2) {
      throw Error( "AnabaticEngine::_loadGrByNet(): Unsupported kind of routing gauge \"%s\"."
                 , getString(getConfiguration()->getRoutingGauge()->getName()).c_str() );
    }
    
    printMeasures( "load" );

    addMeasure<size_t>( "Globals", AutoSegment::getGlobalsCount() );
    addMeasure<size_t>( "Edges"  , AutoSegment::getAllocateds() );
  }


  void  AnabaticEngine::updateNetTopology ( Net* net )
  {
    DebugSession::open( net, 145, 150 );

    cdebug_log(149,0) << "Anabatic::updateNetTopology( " << net << " )" << endl;
    cdebug_tabw(145,1);

    vector<AutoContact*>  contacts;
    for ( Component* component : net->getComponents() ) {
      Contact* contact = dynamic_cast<Contact*>( component );
      if (contact) {
        AutoContact* autoContact = Session::lookup( contact );
        if (autoContact and autoContact->isInvalidatedCache()) 
          contacts.push_back( autoContact );
      }
    }

    for ( size_t i=0 ; i<contacts.size() ; ++i )
      contacts[i]->updateTopology();

    cdebug_tabw(145,-1);
    DebugSession::close();
  }


  void  AnabaticEngine::finalizeLayout ()
  {
    cdebug_log(145,0) << "Anabatic::finalizeLayout()" << endl;
    if (_state > EngineDriving) return;

    _state = EngineDriving;

    startMeasures();
    _gutAnabatic();
    stopMeasures ();
    printMeasures( "fin" );

    _state = EngineGutted;
  }


  void  AnabaticEngine::_alignate ( Net* net )
  {
    DebugSession::open( net, 145, 150 );

    cdebug_log(149,0) << "Anabatic::_alignate( " << net << " )" << endl;
    cdebug_tabw(145,1);

  //cmess2 << "     - " << getString(net) << endl;

    set<Segment*>        exploredSegments;
    vector<AutoSegment*> unexploreds;
    vector<AutoSegment*> aligneds;

    for ( Component* component : net->getComponents() ) {
      Segment* segment = dynamic_cast<Segment*>(component);
      if (segment) {
        AutoSegment* seedSegment = Session::lookup( segment );
        if (seedSegment) unexploreds.push_back( seedSegment );
      }
    }
    sort( unexploreds.begin(), unexploreds.end(), AutoSegment::CompareId() );

    for ( size_t i=0 ; i<unexploreds.size() ; i++ ) {
      AutoSegment* seedSegment = unexploreds[i];

      if (exploredSegments.find(seedSegment->base()) == exploredSegments.end()) {
        cdebug_log(145,0) << "New chunk from: " << seedSegment << endl;
        aligneds.push_back( seedSegment );

        for ( AutoSegment* collapsed : seedSegment->getAligneds() ) {
          cdebug_log(145,0) << "Aligned: " << collapsed << endl;
          aligneds.push_back( collapsed );
          exploredSegments.insert( collapsed->base() );
        }

        cdebug_tabw(145,1);
        sort( aligneds.begin(), aligneds.end(), AutoSegment::CompareId() );

        cdebug_log(145,0) << "Seed: " << (void*)aligneds[0]->base() << " " << aligneds[0] << endl;
        for ( size_t j=1 ; j<aligneds.size() ; j++ ) {
          cdebug_log(145,0) << "Secondary: " << (void*)(aligneds[j]->base()) << " " << aligneds[j] << endl;
        }

        cdebug_log(149,0) << "Align on " << aligneds[0]
                    << " " << DbU::getValueString(aligneds[0]->getAxis()) << endl;
        aligneds[0]->setAxis( aligneds[0]->getAxis(), Flags::Realignate );
        aligneds.clear();

        cdebug_tabw(145,-1);
      }
    }

    cdebug_tabw(145,-1);

    DebugSession::close();
  }


  void  AnabaticEngine::_computeNetTerminals ( Net* net )
  {
    DebugSession::open( net, 145, 150 );

    cdebug_log(149,0) << "Anabatic::_computeNetTerminals( " << net << " )" << endl;
    cdebug_tabw(145,1);

    for ( Segment* segment : net->getSegments() ) {
      AutoSegment* autoSegment = Session::lookup( segment );
      if (autoSegment == NULL) continue;
      if (autoSegment->isInvalidated()) autoSegment->computeTerminal();
    }

    cdebug_tabw(145,-1);

    DebugSession::close();
  }


  void  AnabaticEngine::_saveNet ( Net* net )
  {
    DebugSession::open( net, 145, 150 );

    cdebug_log(145,0) << "Anabatic::_saveNet() " << net << endl;
    cdebug_tabw(145,1);

#if 0
    cdebug_log(145,0) << "Deleting zero-length segments." << endl;

    vector<Segment*>   nullSegments;
    set<const Layer*>  connectedLayers;

    forEach ( Segment*, segment, net->getSegments() ) {
      if (segment->getAnchoredLength()) {
        if (net->isExternal()) {
          NetExternalComponents::setExternal( *segment );
        }
        continue;
      }
    
      if (Session::lookup(*segment) == NULL) {
        cdebug_log(145,0) << "* Not associated to an AutoSegment: " << *segment << endl;
        continue;
      }

      if (not isTopAndBottomConnected(*segment,connectedLayers)) {
        nullSegments.push_back( *segment );
        cdebug_log(145,0) << "* Null Length: " << *segment << endl;
      }
    }
    
    setFlags( EngineDestroyBaseSegment );
    for ( size_t i = 0 ; i < nullSegments.size() ; i++ ) {
      Contact* source = dynamic_cast<Contact*>(nullSegments[i]->getSource());
      Contact* target = dynamic_cast<Contact*>(nullSegments[i]->getTarget());

      if ( (source == NULL) or (target == NULL) ) {
        cerr << Error("Unconnected source/target on %s.",getString(nullSegments[i]).c_str()) << endl;
        continue;
      }

      if (source->getAnchor()) {
        if (target->getAnchor()) {
          continue;
        //cerr << Bug("Both source & target are anchored while deleting zero-length segment:\n"
        //            "       %s.",getString(nullSegments[i]).c_str()) << endl;
        } else
          swap( source, target );
      }

      cdebug_log(145,0) << "Deleting: " << nullSegments[i] << endl;
      if (isTopAndBottomConnected(nullSegments[i],connectedLayers)) {
        cdebug_log(145,0) << "Deletion cancelled, no longer top or bottom connected." << endl;
        continue;
      }

      cdebug_log(145,0) << "* Source: " << (void*)source << " " << source << endl;
      cdebug_log(145,0) << "* Target: " << (void*)target << " " << target << endl;

      const Layer* layer = DataBase::getDB()->getTechnology()
        ->getViaBetween( *connectedLayers.begin(), *connectedLayers.rbegin() );

      cdebug_log(145,0) << *connectedLayers.begin() << " + " << *connectedLayers.rbegin() << endl;
      cdebug_log(145,0) << "* Shrink layer: " << layer << endl;
      if ( !layer ) {
        cerr << Error("NULL contact layer while deleting %s."
                     ,getString(nullSegments[i]).c_str()) << endl;
        continue;
      }

      Session::lookup( nullSegments[i] )->destroy ();

      vector<Hook*>  slaveHooks;
      Hook*          masterHook = source->getBodyHook()->getPreviousMasterHook();

      while ( masterHook->getNextHook() != source->getBodyHook() ) {
        slaveHooks.push_back( masterHook->getNextHook() );
        cdebug_log(145,0) << "* detach: "
                   << (void*)masterHook->getNextHook()->getComponent()
                   << " " << masterHook->getNextHook()->getComponent() << endl;
        masterHook->getNextHook()->detach();
      }
      source->destroy();

      masterHook = target->getBodyHook();
      for ( size_t j=0 ; j < slaveHooks.size() ; j++ ) {
        slaveHooks[j]->attach( masterHook );
      }

      cdebug_log(145,0) << (void*)target << " " << target << " setLayer: " << layer << endl;
      target->setLayer( layer );
    }
    unsetFlags( EngineDestroyBaseSegment );
#endif

    cdebug_tabw(145,-1);
    DebugSession::close();
  }


  void  AnabaticEngine::invalidateRoutingPads ()
  {
  // This a flaw in the Hurricane Session update mechanism
  // and needs to be fixed in the future.
    for ( Net* net : getCell()->getNets() ) {
      for ( RoutingPad* rp : net->getRoutingPads() ) {
        rp->invalidate( false );
      }
    }
  }


  void  AnabaticEngine::updateDensity ()
  { for ( GCell* gcell : _gcells ) gcell->updateDensity(); } 


  size_t  AnabaticEngine::checkGCellDensities ()
  {
    size_t saturateds = 0;
    for ( GCell* gcell : _gcells ) saturateds += gcell->checkDensity();
    return saturateds;
  } 


  AutoSegment* AnabaticEngine::_lookup ( Segment* segment ) const
  {
    AutoSegmentLut::const_iterator it = _autoSegmentLut.find( segment );
    if (it == _autoSegmentLut.end()) return NULL;

    return (*it).second;
  }


  void  AnabaticEngine::_link ( AutoSegment* autoSegment )
  {
    if (_state > EngineActive) return;
    _autoSegmentLut[ autoSegment->base() ] = autoSegment;
  }


  void  AnabaticEngine::_unlink ( AutoSegment* autoSegment )
  {
    if (_state > EngineDriving) return;

    AutoSegmentLut::iterator it = _autoSegmentLut.find( autoSegment->base() );
    if (it != _autoSegmentLut.end())
      _autoSegmentLut.erase( it );
  }


  AutoContact* AnabaticEngine::_lookup ( Contact* contact ) const
  {
    AutoContactLut::const_iterator it = _autoContactLut.find( contact );
    if (it == _autoContactLut.end()) {
      return NULL;
    }
    return (*it).second;
  }


  void  AnabaticEngine::_link ( AutoContact* autoContact )
  {
    if (_state > EngineActive) return;
    _autoContactLut [ autoContact->base() ] = autoContact;
  }


  void  AnabaticEngine::_unlink ( AutoContact* autoContact )
  {
    if ( _state > EngineActive ) return;

    AutoContactLut::iterator it = _autoContactLut.find( autoContact->base() );
    if (it != _autoContactLut.end())
      _autoContactLut.erase( it );
  }


  void  AnabaticEngine::_destroyAutoSegments ()
  {
    cdebug_log(145,0) << "Anabatic::_destroyAutoSegments ()" << endl;

    size_t expandeds = 0;
    for ( auto sasp : _autoSegmentLut ) {
      expandeds++;
      sasp.second->destroy();
    }
    if (_state == EngineDriving)
      cmess2 << "     - Expandeds     := " << expandeds << endl;

    _autoSegmentLut.clear();
  }


  void  AnabaticEngine::_destroyAutoContacts ()
  {
    cdebug_log(145,0) << "Anabatic::_destroyAutoContacts ()" << endl;

    for ( auto cacp : _autoContactLut ) cacp.second->destroy();
    _autoContactLut.clear();
  }


  EdgeCapacity* AnabaticEngine::_createCapacity ( Flags flags, Interval span )
  {
    size_t        depth        = getConfiguration()->getAllowedDepth();
    EdgeCapacity* edgeCapacity = NULL;

    flags &= Flags::EdgeCapacityMask;
    EdgeCapacity  key ( this, flags, span, depth );

    auto icap = _edgeCapacitiesLut.find( &key );
    if (icap != _edgeCapacitiesLut.end()) {
      edgeCapacity = *icap;
    } else {
      edgeCapacity = new EdgeCapacity ( this, flags, span, depth );
      _edgeCapacitiesLut.insert( edgeCapacity );
    }

    edgeCapacity->incref();
    return edgeCapacity;
  }

  
  size_t  AnabaticEngine::_unrefCapacity ( EdgeCapacity* capacity )
  {
    if (capacity->getref() < 2) _edgeCapacitiesLut.erase( capacity );
    return capacity->decref();
  }
  

  void  AnabaticEngine::computeEdgeCapacities ( int maxHCap, int maxVCap, int termSatThreshold, int maxTermSat )
  {
          vector<RoutingPad*> rps;
          vector<GCell*>      saturateds;
    const vector<NetData*>&   netDatas = getNetOrdering();

    for ( NetData* netData : netDatas ) {
      for ( Component* component : netData->getNet()->getComponents() ) {
        RoutingPad* rp = dynamic_cast<RoutingPad*>( component );
        if (rp) rps.push_back( rp ); 
      }
    }

    UpdateSession::open();
    
    for ( auto rp : rps ) {
      if (not getConfiguration()->selectRpComponent(rp))
        cerr << Warning( "AnabaticEngine::computeEdgeCapacities(): %s has no components on grid.", getString(rp).c_str() ) << endl;

      Point  center = rp->getBoundingBox().getCenter();
      GCell* gcell  = getGCellUnder( center );
      
      if (not gcell) {
        cerr << Error( "AnabaticEngine::computeEdgeCapacities(): %s\n"
                       "        @%s of %s is not under any GCell.\n"
                       "        It will be ignored so the edge capacity estimate may be wrong."
                     , getString(rp).c_str()
                     , getString(center).c_str()
                     , getString(rp->getNet()).c_str()
                     ) << endl;
        continue;
      }

      gcell->incRpCount( 1 );
      if (gcell->getRpCount() == termSatThreshold) saturateds.push_back( gcell );
    }

    for ( GCell* gcell : getGCells() ) {
      if (not gcell->isMatrix()) continue;

      for ( Edge* edge : gcell->getEdges(Flags::EastSide|Flags::NorthSide) ) {
        GCell* opposite    = edge->getOpposite( gcell );
        int    maxReserved = maxHCap;
        int    reserved    = std::max( gcell->getRpCount(), opposite->getRpCount() );

        if (edge->isVertical()) maxReserved = maxVCap;
        edge->reserveCapacity( std::min( maxReserved, reserved ) );
      }
    }

    for ( GCell* gcell : saturateds ) {
      GCell* neighbor = gcell;
      for ( size_t i=0 ; i<2; ++i ) {
        Edge* edge = neighbor->getWestEdge();
        if (not edge) break;

        if (edge->getReservedCapacity() < (uint32_t)maxTermSat)
          edge->reserveCapacity( maxTermSat - edge->getReservedCapacity() );
        neighbor = neighbor->getWest();
      }
      neighbor = gcell;
      for ( size_t i=0 ; i<2; ++i ) {
        Edge* edge = neighbor->getEastEdge();
        if (not edge) break;

        if (edge->getReservedCapacity() < (uint32_t)maxTermSat)
          edge->reserveCapacity( maxTermSat - edge->getReservedCapacity() );
        neighbor = neighbor->getEast();
      }
    }

    UpdateSession::close();

  //Breakpoint::stop( 1, "Edge capacities computeds." );
  }
  

  void  AnabaticEngine::_check ( Net* net ) const
  {
    cdebug_log(149,1) << "Checking " << net << endl;
    for ( Segment* segment : net->getComponents().getSubSet<Segment*>() ) {
      AutoSegment* autoSegment = _lookup( segment );
      cdebug_log(149,0) << autoSegment << endl;
      if (autoSegment) {
        AutoContact* autoContact = autoSegment->getAutoSource();
        cdebug_log(149,0) << autoContact << endl;
        if (autoContact) autoContact->checkTopology();

        autoContact = autoSegment->getAutoTarget();
        cdebug_log(149,0) << autoContact << endl;
        if (autoContact) autoContact->checkTopology();
      }
    }
    cdebug_tabw(149,-1);
  }


  bool  AnabaticEngine::_check ( const char* message ) const
  {
    bool coherency = true;
    if (message)
      cerr << "     o  checking Anabatic DB (" << message << ")." << endl;

    for ( auto element : _autoSegmentLut )
      coherency = element.second->_check() and coherency;

    for ( GCell* gcell : _gcells ) {
      for ( AutoContact* contact : gcell->getContacts() )
        contact->checkTopology();
    }

    if (message) cerr << "        - completed." << endl;

    return coherency;
  }


  void  AnabaticEngine::printMeasures ( const string& tag ) const
  {
    Super::printMeasures();

    // if (not tag.empty()) {
    //   addMeasure<double>( getCell(), tag+"T",  getTimer().getCombTime  () );
    //   addMeasure<size_t>( getCell(), tag+"S", (getTimer().getMemorySize() >> 20) );
    // }
  }


  string  AnabaticEngine::_getTypeName () const
  { return getString(_toolName); }


  string  AnabaticEngine::_getString () const
  {
    ostringstream os;
    os << "<" << _toolName << " " << _cell->getName() << ">";
    return os.str();
  }


  Record* AnabaticEngine::_getRecord () const
  {
    Record* record = Super::_getRecord();
    record->add( getSlot("_configuration"    ,  _configuration     ) );
    record->add( getSlot("_gcells"           , &_gcells            ) );
    record->add( getSlot("_matrix"           , &_matrix            ) );
    record->add( getSlot("_flags"            , &_flags             ) );
    record->add( getSlot("_autoSegmentLut"   , &_autoSegmentLut    ) );
    record->add( getSlot("_autoContactLut"   , &_autoContactLut    ) );
    record->add( getSlot("_edgeCapacitiesLut", &_edgeCapacitiesLut ) );
    return record;
  }


}  // Anabatic namespace.
