coriolis/deprecated/cumulus/src/plugins/cts/rsmt.py

364 lines
11 KiB
Python

# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2014-2021, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/clocktree/rsmt.py" |
# +-----------------------------------------------------------------+
import sys
import Cfg
import Hurricane
from Hurricane import DbU
from Hurricane import Box
from Hurricane import Path
from Hurricane import Occurrence
from Hurricane import UpdateSession
from Hurricane import Breakpoint
from Hurricane import Net
from Hurricane import RoutingPad
from Hurricane import Contact
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Instance
import Viewer
import CRL
from CRL import RoutingLayerGauge
import helpers
from helpers import trace
from helpers.io import ErrorMessage
import plugins
def manhattanDistance ( node1, node2 ):
return abs(node1.x - node2.x) + abs(node1.y - node2.y)
class Node ( object ):
GraphPoint = 0x0001
SteinerPoint = 0x0002
KeepPoint = 0x0004
@staticmethod
def showNodes ( level, nodes ):
for node in nodes:
trace( level, node )
return
def __init__ ( self, component, x, y, flags=0 ):
self._component = component
self._edges = [ ]
self._x = x
self._y = y
self._realY = y
self._back = None
self._distance = DbU.fromLambda(1000.0)
self._flags = flags
if component: self._flags = self._flags|Node.GraphPoint|Node.KeepPoint
else: self._flags = self._flags|Node.SteinerPoint
return
def __cmp__ ( self, other ):
return self.distance - other.distance
def __str__ ( self ):
return '<Node P:%d,%d (realY:%d) d:%d %s>' % ( DbU.toLambda(self.x)
, DbU.toLambda(self.y)
, DbU.toLambda(self.realY)
, DbU.toLambda(self.distance)
, str(self.component)
)
@property
def component ( self ): return self._component
@property
def x ( self ): return self._x
@property
def y ( self ): return self._y
@property
def realX ( self ): return self._x
@property
def realY ( self ): return self._realY
@property
def back ( self ): return self._back
@property
def distance ( self ): return self._distance
@property
def flags ( self ): return self._flags
@property
def edges ( self ): return self._edges
@property
def degree ( self ): return len(self._edges)
@component.setter
def component ( self, component ): self._component = component
@realY.setter
def realY ( self, y ): self._realY = y
def setFlags ( self, flags ): self._flags = self._flags | flags
def unsetFlags ( self, flags ): self._flags = self._flags & ~flags
def addEdge ( self, edge ): self._edges.append( edge )
def delEdge ( self, edge ):
for i in range(len(self._edges)):
if self._edges[i] == edge:
del self._edges[i]
return
def isSame ( self, other ): return id(self) == id(other)
def update ( self, node ):
distance = manhattanDistance( self, node )
if distance < self.distance:
self._distance = distance
self._back = node
return True
return False
class Edge ( object ):
def __init__ ( self, source, target ):
self._source = source
self._target = target
self._length = manhattanDistance( self._source, self._target )
self._source.addEdge( self )
self._target.addEdge( self )
return
def __del__ ( self ):
self._source.delEdge( self )
self._target.delEdge( self )
return
def __str__ ( self ):
return '<Edge S:%d,%d T:%d,%d len:%d>' % ( DbU.toLambda(self.source.x)
, DbU.toLambda(self.source.y)
, DbU.toLambda(self.target.x)
, DbU.toLambda(self.target.y)
, DbU.toLambda(self.length)
)
@property
def source ( self ): return self._source
@property
def target ( self ): return self._target
@property
def length ( self ): return self._length
def isHorizontal ( self ): return self.source.y == self.target.y
def isVertical ( self ): return self.source.x == self.target.x
class Graph ( object ):
def __init__ ( self, name ):
self._nodes = [ ]
self._edges = [ ]
self._length = 0
self._name = name
return
def __len__ ( self ): return self._length
@property
def name ( self ): return self._name
@property
def length ( self ): return self._length
@property
def nodes ( self ): return self._nodes
@property
def edges ( self ): return self._edges
def addNode ( self, component, x, y ):
self._nodes.append( Node( component, x, y ) )
return self._nodes[-1]
def copyNode ( self, node ):
self.addNode( node.component, node.x, node.y )
self._nodes[-1].realY = node.realY
def setNodes ( self, nodes ):
self.__init__( self.name )
for node in nodes:
self.copyNode( node )
return
def showNodes ( self, level ):
trace( level, '+,+', '\tGraph Nodes:\n' )
for node in self._nodes:
trace( level, node )
trace(level, '--')
return
def showEdges ( self, level ):
trace( level, '+,+', '\tGraph Edges:\n' )
for edge in self._edges:
trace( level, edge )
trace(level, '--')
return
class RMST ( Graph ):
def __init__ ( self, name ):
Graph.__init__( self, name )
return
def runPrim ( self ):
self._edges = [ ]
self._length = 0
if len(self._nodes) < 2: return
if len(self._nodes) == 2:
self._edges.append( Edge( self._nodes[0], self._nodes[1] ) )
self._length = self._edges[0].length
return
trace(500, '+')
toReach = [ ]
self._nodes[0]._distance = 0
for node in self._nodes[1:]:
node.update( self._nodes[0] )
toReach.append( node )
toReach.sort()
trace( 500, '+' , '\tPrim (initial stack)\n' )
trace( 500, '+,+', '\tS %s\n' % self._nodes[0] )
Node.showNodes( 500, toReach )
trace( 500, '---' )
while len(toReach):
nearest = toReach.pop(0)
self._edges.append( Edge( nearest, nearest.back ) )
trace( 500, '++,--', '\tAdding %s\n' % self._edges[-1] )
for node in toReach:
node.update( nearest )
toReach.sort()
trace( 500, '+' , '\tPrim (current stack)\n' )
trace( 500, '+,+', '\tS %s\n' % self._nodes[0] )
Node.showNodes( 500, toReach )
trace( 500, '---' )
for edge in self._edges:
self._length += edge.length
trace( 500, '-' )
return
class RSMT ( Graph ):
def __init__ ( self, name ):
Graph.__init__( self, name )
self._hananNodes = [ ]
return
def _computeHanan ( self ):
xs = [ ]
ys = [ ]
realYs = { }
for node in self._nodes:
if not node.x in xs: xs.append( node.x )
if not node.y in xs:
ys.append( node.y )
realYs[ node.y ] = node.component.getY()
xs.sort()
ys.sort()
trace( 550, '+,+', '\tHanan matrix: %ix%i' % (len(xs),len(ys)) )
self._hananNodes = [ ]
for x in xs:
trace( 550, '\n' )
trace( 550, '\t' )
for y in ys:
isNode = False
for node in self._nodes:
if node.x == x and node.y == y: isNode = True
if isNode:
trace( 550, ' -:%04.2d,%04.2d' % (DbU.toLambda(x),DbU.toLambda(y)) )
continue
trace( 550, ' H:%04.2d,%04.2d' % (DbU.toLambda(x),DbU.toLambda(y)) )
self._hananNodes.append( Node( None, x, y ) )
self._hananNodes[-1].realY = realYs[ y ]
trace( 550, ',--', "\n" )
return
def addNode ( self, component, x, y ):
node = Graph.addNode( self, component, x, y )
trace( 550, '\t New Node: %s\n' % node )
return
def runI1S ( self ):
self._edges = [ ]
self._length = 0
if len(self._nodes) < 2: return
if len(self._nodes) == 2:
self._edges.append( Edge( self._nodes[0], self._nodes[1] ) )
self._length = self._edges[0].length
return
self._computeHanan()
count = 0
trace( 550, '++' )
minMST = RMST( 'MST[%i]' % count )
minMST.setNodes( self._nodes )
minMST.runPrim()
trace( 550, '-,+', '\tInitial %s length %d\n' % (minMST.name,DbU.toLambda(len(minMST))) )
minMST.showEdges( 550 )
trace( 550, '-' )
addedSteiner = True
while addedSteiner:
addedSteiner = False
for steinerNode in self._hananNodes:
count += 1
trace( 550, '\tTrying with Steiner point H:%d,%d\n' \
% (DbU.toLambda(steinerNode.x),DbU.toLambda(steinerNode.y)) )
mst = RMST( 'MST[%i]' % count )
mst.setNodes( self._nodes )
mst.copyNode( steinerNode )
mst.runPrim()
trace( 550, '\tCurrent %s length %d\n' % (mst.name,DbU.toLambda(len(mst))) )
mst.showEdges( 550 )
if len(mst) < len(minMST):
trace( 550, '\tAccept min RST.\n' )
minMST = mst
addedSteiner = True
if addedSteiner:
self.copyNode( minMST.nodes[-1] )
self.nodes[-1].setFlags( Node.KeepPoint )
i = 0
while i < len(self._edges):
if self._nodes[i].flags & Node.SteinerPoint \
and self._nodes[i].degree < 3:
trace( 550, 'Deleting unused Steiner point H:%d,%d' \
% (DbU.toLambda(self._nodes[i].x),DbU.toLambda(self._nodes[i].y)) )
del self._nodes[i]
else:
i += 1
self._nodes = minMST.nodes
self._edges = minMST.edges
self._length = minMST.length
trace( 550, '-' )
return