├── .DS_Store ├── .gitattributes ├── .gitignore ├── BenchmarkGenerator ├── .DS_Store ├── AStarSearchSolver.py ├── BenchmarkGenerator.py ├── GridGraph.py ├── Initializer.py ├── MST.py ├── Router.py └── TwoPinRouterASearch.py ├── Images ├── CapPlot.png ├── CapPlot32.png ├── SolPlot.png └── edgePlotwithCapacity5number8.png ├── LICENSE ├── Main.py ├── README.md ├── environment.yml └── readme.txt /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haiguanl/GlobalRoutingProblemGenerator/8e5907852bf02b5801e44708122b84c1af3adbb5/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore these files for GIT, they are generated by the tool and should 2 | # not be checked in. 3 | 4 | # Byte-compiled code 5 | __pycache__/ 6 | *.py[cod] 7 | 8 | # Tool output files 9 | benchmark/ 10 | benchmark_reduced/ 11 | capacityPlot_A*/ 12 | capacityPlot_A*_reduced/ 13 | solutionsA*/ 14 | solutionsA*_reduced/ 15 | -------------------------------------------------------------------------------- /BenchmarkGenerator/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haiguanl/GlobalRoutingProblemGenerator/8e5907852bf02b5801e44708122b84c1af3adbb5/BenchmarkGenerator/.DS_Store -------------------------------------------------------------------------------- /BenchmarkGenerator/AStarSearchSolver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Feb 20 14:07:32 2019 5 | 6 | @author: liaohaiguang 7 | """ 8 | # This part of code implement A*Search router to solve problems, dump solutions and plots 9 | 10 | import os 11 | import operator 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | import Initializer as init 16 | import GridGraph as graph 17 | import TwoPinRouterASearch as twoPinASearch 18 | import MST as tree 19 | 20 | # The following function solve benchmarks with A* Search Algorithm 21 | # and return edge traffic information 22 | def solve(benchmarkfile,solution_savepath): 23 | # Getting Net Info 24 | grid_info = init.read(benchmarkfile) 25 | gridParameters = init.gridParameters(grid_info) 26 | capacity = graph.GridGraph(init.gridParameters(grid_info)).generate_capacity() 27 | gridX,gridY,gridZ = graph.GridGraph(init.gridParameters(grid_info)).generate_grid() 28 | gridGraph = twoPinASearch.AStarSearchGraph(gridParameters, capacity) 29 | # Sort net 30 | halfWireLength = init.VisualGraph(init.gridParameters(grid_info)).bounding_length() 31 | sortedHalfWireLength = sorted(halfWireLength.items(),key=operator.itemgetter(1),reverse=True) # Large2Small 32 | netSort = [] 33 | for i in range(len(sortedHalfWireLength)): 34 | netSort.append(int(sortedHalfWireLength[i][0])) 35 | 36 | routeListMerged = [] 37 | routeListNotMerged = [] 38 | routeListMergedCap = [] 39 | twoPinListPlot = [] 40 | for i in range(len(init.gridParameters(grid_info)['netInfo'])): 41 | netNum = netSort[i] 42 | # # Remove pins that are in the same grid: 43 | netPinList = [] 44 | netPinCoord = [] 45 | for j in range(0, gridParameters['netInfo'][netNum]['numPins']): 46 | pin = tuple([int((gridParameters['netInfo'][netNum][str(j+1)][0]-gridParameters['Origin'][0])/gridParameters['tileWidth']), 47 | int((gridParameters['netInfo'][netNum][str(j+1)][1]-gridParameters['Origin'][1])/gridParameters['tileHeight']), 48 | int(gridParameters['netInfo'][netNum][str(j+1)][2]), 49 | int(gridParameters['netInfo'][netNum][str(j+1)][0]), 50 | int(gridParameters['netInfo'][netNum][str(j+1)][1])]) 51 | if pin[0:3] in netPinCoord: 52 | continue 53 | else: 54 | netPinList.append(pin) 55 | netPinCoord.append(pin[0:3]) 56 | twoPinList = [] 57 | for i in range(len(netPinList)-1): 58 | pinStart = netPinList[i] 59 | pinEnd = netPinList[i+1] 60 | twoPinList.append([pinStart,pinEnd]) 61 | # Insert Tree method to decompose two pin problems here 62 | twoPinList = tree.generateMST(twoPinList) 63 | # Remove pin pairs that are in the same grid again 64 | nullPairList = [] 65 | for i in range(len(twoPinList)): 66 | if twoPinList[i][0][:3] == twoPinList[i][1][:3]: 67 | nullPairList.append(twoPinList[i]) 68 | 69 | for i in range(len(nullPairList)): 70 | twoPinList.reomove(nullPairList[i]) 71 | i = 1 72 | twoPinListPlot.append(twoPinList) 73 | routeListSingleNet = [] 74 | routeListSingleNetPlot = [] 75 | for twoPinPair in twoPinList: 76 | pinStart = twoPinPair[0]; pinEnd = twoPinPair[1] 77 | route, cost = twoPinASearch.AStarSearchRouter(pinStart, pinEnd, gridGraph) 78 | routeListSingleNet.append([route]) 79 | routeListSingleNetPlot.append(route) 80 | i += 1 81 | mergedrouteListSingleNet = [] 82 | mergedrouteListSingleNetCap = [] 83 | 84 | for twoPinRoute in routeListSingleNet: 85 | for twoPinRouteSpecific in twoPinRoute: 86 | # if loc not in mergedrouteListSingleNet: 87 | mergedrouteListSingleNet.append(twoPinRouteSpecific) 88 | for i in range(len(twoPinRouteSpecific)): 89 | mergedrouteListSingleNetCap.append(twoPinRouteSpecific[i]) 90 | routeListMerged.append(mergedrouteListSingleNet) 91 | routeListMergedCap.append(mergedrouteListSingleNetCap) 92 | 93 | routeListNotMerged.append(routeListSingleNetPlot) 94 | # Update capacity and grid graph after routing one pin pair 95 | capacity = graph.updateCapacity(capacity, mergedrouteListSingleNetCap) 96 | twoPinListPlotRavel = [] 97 | for i in range(len(twoPinListPlot)): 98 | for j in range(len(twoPinListPlot[i])): 99 | twoPinListPlotRavel.append(twoPinListPlot[i][j][0]) 100 | twoPinListPlotRavel.append(twoPinListPlot[i][j][1]) 101 | 102 | # Visualize results on 3D 103 | fig = plt.figure() 104 | ax = fig.add_subplot(111, projection='3d') 105 | # # Hide grid lines 106 | # ax.grid(False) 107 | # # Hide axes ticks 108 | ax.set_xticks([]) 109 | ax.set_yticks([]) 110 | ax.set_zticks([]) 111 | # plt.axis('off') 112 | # plt.grid(b=None) 113 | ax.set_zlim(0.75,2.25) 114 | plt.axis('off') 115 | # 116 | x_meshP = np.linspace(0,gridParameters['gridSize'][0]-1,200) 117 | y_meshP = np.linspace(0,gridParameters['gridSize'][1]-1,200) 118 | z_meshP = np.linspace(1,2,200) 119 | x_mesh,y_mesh = np.meshgrid(x_meshP,y_meshP) 120 | z_mesh = np.ones_like(x_mesh) 121 | ax.plot_surface(x_mesh,y_mesh,z_mesh,alpha=0.3,color='r') 122 | ax.plot_surface(x_mesh,y_mesh,2*z_mesh,alpha=0.3,color='r') 123 | 124 | for routeList in routeListNotMerged: 125 | for route in routeList: 126 | x = [coord[3] for coord in route] 127 | y = [coord[4] for coord in route] 128 | z = [coord[2] for coord in route] 129 | ax.plot(x,y,z,linewidth=2.5) 130 | 131 | plt.xlim([0, gridParameters['gridSize'][0]-1]) 132 | plt.ylim([0, gridParameters['gridSize'][1]-1]) 133 | plt.savefig('{path}RoutingVisualize_{benchmark}.jpg'.format(path=solution_savepath,\ 134 | benchmark=benchmarkfile)) 135 | # plt.show() 136 | plt.close() 137 | 138 | # dump solution for Astar 139 | f = open('{solution_savepath}{benchmark}Astar_solution'.format(\ 140 | solution_savepath=solution_savepath,benchmark=benchmarkfile),'w+') 141 | 142 | for i in range(gridParameters['numNet']): 143 | singleNetRouteCache = [] 144 | indicator = i 145 | # netNum = int(sortedHalfWireLength[i][0]) 146 | netNum = netSort[i] 147 | i = netNum 148 | 149 | value = '{netName} {netID} {cost}\n'.format(netName=gridParameters['netInfo'][i]['netName'], 150 | netID = gridParameters['netInfo'][i]['netID'], 151 | cost = max(0,len(routeListMerged[indicator])-1)) 152 | f.write(value) 153 | for j in range(len(routeListMerged[indicator])): 154 | # In generating the route in length coordinate system, the first pin (corresponding to griParameters['netInfo'][i]['1']) 155 | # is used as reference point 156 | for k in range(len(routeListMerged[indicator][j])-1): 157 | a = routeListMerged[indicator][j][k] 158 | b = routeListMerged[indicator][j][k+1] 159 | 160 | if (a[3],a[4],a[2],b[3],b[4],b[2]) not in singleNetRouteCache: 161 | singleNetRouteCache.append((a[3],a[4],a[2],b[3],b[4],b[2])) 162 | singleNetRouteCache.append((b[3],b[4],b[2],a[3],a[4],a[2])) 163 | 164 | diff = [abs(a[2]-b[2]),abs(a[3]-b[3]),abs(a[4]-b[4])] 165 | if diff[1] > 2 or diff[2] > 2: 166 | continue 167 | elif diff[1] == 2 or diff[2] == 2: 168 | # print('Alert') 169 | continue 170 | elif diff[0] == 0 and diff[1] == 0 and diff[2] == 0: 171 | continue 172 | elif diff[0] + diff[1] + diff[2] >= 2: 173 | continue 174 | else: 175 | value = '({},{},{})-({},{},{})\n'.format(a[0],a[1],a[2],b[0],b[1],b[2]) 176 | f.write(value) 177 | f.write('!\n') 178 | f.close() 179 | return routeListMergedCap 180 | 181 | if __name__ == "__main__": 182 | 183 | # get edge traffic (data structure: gridSize*gridSize*2) 184 | # edge_traffic = 185 | os.chdir("benchmark/") 186 | benchmarkfile = "test_benchmark_5.gr" 187 | 188 | 189 | solution_savepath = '../solutionsForBenchmark/' 190 | os.mkdir(solution_savepath) 191 | 192 | solve(benchmarkfile,solution_savepath) 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /BenchmarkGenerator/BenchmarkGenerator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Wed Feb 20 10:14:16 2019 5 | 6 | @author: liaohaiguang 7 | """ 8 | 9 | import numpy as np 10 | import os 11 | import argparse 12 | import matplotlib.pyplot as plt 13 | import collections as col 14 | 15 | import AStarSearchSolver as solver 16 | 17 | np.random.seed(1) 18 | 19 | # Input parameters: 20 | # Default setting: minWidth = 1, minSpacing = 0, 21 | # tileLength = 10, tileHeight = 10 22 | 23 | # 1. Grid Size: for 8-by-8 benchmark, grid size is 8 24 | # 2. vCap and hCap represents vertical capacity for layer2, 25 | # and horizontal capacity for layer 1; unspecified capacity are 26 | # by default 0 27 | # 3. maxPinNum: maximum number of pins of one net 28 | # 4. capReduce: number of capacity reduction specification, by default = 0 29 | 30 | def generator(benchmark_name,gridSize,netNum,vCap,hCap,maxPinNum,savepath): 31 | 32 | file = open('%s' % benchmark_name, 'w+') 33 | 34 | # Write general information 35 | file.write('grid {gridSize} {gridSize} 2\n'.format(gridSize=gridSize)) 36 | file.write('vertical capacity 0 {vCap}\n'.format(vCap=vCap)) 37 | file.write('horizontal capacity {hCap} 0\n'.format(hCap=hCap)) 38 | file.write('minimum width 1 1\n') 39 | file.write('minimum spacing 0 0\n') 40 | file.write('via spacing 0 0\n') 41 | file.write('0 0 10 10\n') 42 | file.write('num net {netNum}\n'.format(netNum=netNum)) 43 | # Write nets information 44 | pinNum = np.random.randint(2,maxPinNum+1,netNum) # Generate Pin Number randomly 45 | for i in range(netNum): 46 | specificPinNum = pinNum[i] 47 | file.write('A{netInd} 0{netInd} {pin} 1\n'.format(netInd=i+1,pin=specificPinNum)) 48 | xCoordArray = np.random.randint(1,10*gridSize,specificPinNum) 49 | yCoordArray = np.random.randint(1,10*gridSize,specificPinNum) 50 | for j in range(specificPinNum): 51 | file.write('{x} {y} 1\n'.format(x=xCoordArray[j],y=yCoordArray[j])) 52 | # Write capacity information 53 | file.write('{capReduce}'.format(capReduce=0)) 54 | file.close() 55 | return 56 | 57 | def generator_reducedCapacity(benchmark_name,gridSize,netNum,vCap,hCap,maxPinNum,\ 58 | savepath,reducedCapNum,connection_statistical_array): 59 | # generate benchmarks with reduced capacity 60 | file = open('%s' % benchmark_name, 'w+') 61 | 62 | # Write general information 63 | file.write('grid {gridSize} {gridSize} 2\n'.format(gridSize=gridSize)) 64 | file.write('vertical capacity 0 {vCap}\n'.format(vCap=vCap)) 65 | file.write('horizontal capacity {hCap} 0\n'.format(hCap=hCap)) 66 | file.write('minimum width 1 1\n') 67 | file.write('minimum spacing 0 0\n') 68 | file.write('via spacing 0 0\n') 69 | file.write('0 0 10 10\n') 70 | file.write('num net {netNum}\n'.format(netNum=netNum)) 71 | # Write nets information 72 | pinNum = np.random.randint(2,maxPinNum+1,netNum) # Generate Pin Number randomly 73 | for i in range(netNum): 74 | specificPinNum = pinNum[i] 75 | file.write('A{netInd} 0{netInd} {pin} 1\n'.format(netInd=i+1,pin=specificPinNum)) 76 | xCoordArray = np.random.randint(1,10*gridSize,specificPinNum) 77 | yCoordArray = np.random.randint(1,10*gridSize,specificPinNum) 78 | for j in range(specificPinNum): 79 | file.write('{x} {y} 1\n'.format(x=xCoordArray[j],y=yCoordArray[j])) 80 | # Write capacity information 81 | file.write('{capReduce}\n'.format(capReduce=reducedCapNum)) 82 | for i in range(reducedCapNum): 83 | obstaclei = connection_statistical_array[-(i+1),0:6] 84 | file.write('{a} {b} {c} {d} {e} {f} 0\n'.format(a=int(obstaclei[0]),b=int(obstaclei[1]),c=int(obstaclei[2]),\ 85 | d=int(obstaclei[3]),e=int(obstaclei[4]),f=int(obstaclei[5]))) 86 | file.close() 87 | return 88 | 89 | # edge_traffic_stat get statiscal information of edge traffic by solving problems 90 | # with A* search 91 | def edge_traffic_stat(edge_traffic,gridSize): 92 | via_capacity = np.zeros((gridSize,gridSize)) 93 | hoz_capacity = np.zeros((gridSize,gridSize-1)) # Only for Layer 1 94 | vet_capacity = np.zeros((gridSize-1,gridSize)) # Only for Layer 2 95 | for i in range(edge_traffic.shape[0]): 96 | connection = edge_traffic[i,:].astype(int) 97 | # print(connection) 98 | diff = (connection[3]-connection[0],\ 99 | connection[4]-connection[1],\ 100 | connection[5]-connection[2]) 101 | if diff[0] == 1: 102 | hoz_capacity[connection[1],connection[0]] \ 103 | = hoz_capacity[connection[1],connection[0]] + 1 104 | elif diff[0] == -1: 105 | hoz_capacity[connection[1],int(connection[0])-1] \ 106 | = hoz_capacity[connection[1],int(connection[0])-1] + 1 107 | elif diff[1] == 1: 108 | vet_capacity[connection[1],connection[0]] \ 109 | = vet_capacity[connection[1],connection[0]] + 1 110 | elif diff[1] == -1: 111 | vet_capacity[int(connection[1])-1,connection[0]] \ 112 | = vet_capacity[int(connection[1])-1,connection[0]] + 1 113 | elif abs(diff[2]) == 1: 114 | via_capacity[connection[0],connection[1]] \ 115 | = via_capacity[connection[0],connection[1]] + 1 116 | else: 117 | continue 118 | return via_capacity, hoz_capacity, vet_capacity 119 | 120 | def connection_statistical(edge_traffic,gridSize,benchmarkNumber): 121 | # get connection statistcal in vertical and horizontal direction, 122 | # ignoring the via capacity since they tends to be large (set as 10 in simulated env) 123 | # cleaned edge traffic as input 124 | connection_cleaned = np.empty((0,6)) 125 | for i in range(edge_traffic.shape[0]): 126 | connection = edge_traffic[i,:] 127 | if connection[3]1): 111 | netParameters[str(pinNum)] = [int(grid_info[lineNum+pinNum][0]),int(grid_info[lineNum+pinNum][1]), 112 | int(grid_info[lineNum+pinNum][2])] 113 | pinNum += 1 114 | 115 | gridParameters['reducedCapacity'] = grid_info[lineNum+pinNum] 116 | pinEnumerator = pinNum 117 | lineEnumerator = lineNum + pinNum + 1 118 | netParametersStore.append(netParameters) 119 | if ('n' in grid_info[lineNum][0]) and (grid_info[lineNum][0] != 'num'): 120 | netParameters = {} 121 | netParameters['netName'] = grid_info[lineNum][0] 122 | netParameters['netID'] = int(grid_info[lineNum][1]) 123 | netParameters['numPins'] = int(grid_info[lineNum][2]) 124 | netParameters['minWidth'] = float(grid_info[lineNum][3]) 125 | pinNum = 1 126 | while ('n' not in grid_info[lineNum+pinNum][0]) and (len(grid_info[lineNum+pinNum])>1): 127 | netParameters[str(pinNum)] = [int(grid_info[lineNum+pinNum][0]),int(grid_info[lineNum+pinNum][1]), 128 | int(grid_info[lineNum+pinNum][2])] 129 | pinNum += 1 130 | 131 | gridParameters['reducedCapacity'] = grid_info[lineNum+pinNum] 132 | pinEnumerator = pinNum 133 | lineEnumerator = lineNum + pinNum + 1 134 | netParametersStore.append(netParameters) 135 | gridParameters['netInfo'] = netParametersStore 136 | # Parsing adjustments depicting reduced capacity (override layer specification) 137 | i = 1 138 | for lineNum in range(lineEnumerator, len(grid_info)): 139 | reducedEdge = [int(grid_info[lineNum][0]),int(grid_info[lineNum][1]),int(grid_info[lineNum][2]), 140 | int(grid_info[lineNum][3]),int(grid_info[lineNum][4]),int(grid_info[lineNum][5]), 141 | int(grid_info[lineNum][6])] 142 | gridParameters['reducedCapacitySpecify'][str(i)] = reducedEdge 143 | i += 1 144 | return gridParameters 145 | -------------------------------------------------------------------------------- /BenchmarkGenerator/MST.py: -------------------------------------------------------------------------------- 1 | # Ref Source: https://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.sparse.csgraph.minimum_spanning_tree.html 2 | # Using Krusal Algo 3 | 4 | import numpy as np 5 | 6 | from scipy.sparse import csr_matrix 7 | from scipy.sparse.csgraph import minimum_spanning_tree 8 | 9 | def generateMST(twoPinList): 10 | # Two pin list: [[(0,0,0),(2,0,0)],[(2,0,0),(2,0,1)],[(2,0,1),(2,2,0)]] 11 | # Generate sorted two pin list based on tree approach 12 | 13 | # print('Original Two pin list: ', twoPinList) 14 | pinList = [] 15 | for i in range(len(twoPinList)): 16 | pinList.append(twoPinList[i][0]) 17 | pinList.append(twoPinList[i][1]) 18 | 19 | pinList = list(set(pinList)) 20 | # print(pinList) 21 | 22 | # Set Manhattan distance as weights of tree 23 | recDist = np.zeros((len(pinList),len(pinList))) 24 | for i in range(len(pinList)): 25 | for j in range(len(pinList)): 26 | recDist[i,j] = int(np.abs(pinList[i][0]-pinList[j][0])+ np.abs(pinList[i][1]-pinList[j][1])\ 27 | +np.abs(pinList[i][2] - pinList[j][2])) 28 | 29 | X = csr_matrix(recDist) 30 | Tcsr = minimum_spanning_tree(X) 31 | Tree = Tcsr.toarray().astype(int) 32 | # print(Tree) 33 | 34 | twoPinListSorted = [] 35 | for i in range(Tree.shape[0]): 36 | for j in range(Tree.shape[1]): 37 | if Tree[i,j] != 0: 38 | twoPinListSorted.append([pinList[i],pinList[j]]) 39 | # print ('Sorted Two pin list: ',twoPinListSorted) 40 | return twoPinListSorted 41 | 42 | 43 | if __name__ == '__main__': 44 | 45 | # X = csr_matrix([[0, 8, 0, 3], 46 | # [0, 0, 2, 5], 47 | # [0, 0, 0, 6], 48 | # [0, 0, 0, 0]]) 49 | # 50 | # Tcsr = minimum_spanning_tree(X) 51 | # print(Tcsr.toarray().astype(int)) 52 | 53 | 54 | # Test Generate MST 55 | twoPinList = [[(0,0,0),(2,0,0)],[(2,0,0),(2,0,1)],[(2,0,1),(2,2,0)],[(2,2,0),(0,0,1)]] 56 | MST = generateMST(twoPinList) 57 | -------------------------------------------------------------------------------- /BenchmarkGenerator/Router.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import matplotlib 3 | matplotlib.use('TkAgg') 4 | 5 | import matplotlib.pyplot as plt 6 | 7 | import Initializer as init 8 | import GridGraph as graph 9 | import TwoPinRouterASearch as twoPinASearch 10 | import MST as tree 11 | 12 | import matplotlib.patches as patches 13 | import numpy as np 14 | import pandas as pd 15 | import operator 16 | from matplotlib import cm 17 | from mpl_toolkits.mplot3d import Axes3D 18 | 19 | def getGridCoord(pinInGrid): 20 | # pin = (gridx,gridz,layer,actualx,actualy) 21 | return 22 | 23 | 24 | if __name__ == "__main__": 25 | # filename = '3d.txt' 26 | # filename = '8by8small.gr' 27 | # filename = '8by8simplee.gr' 28 | # filename = '32by32simple.gr' 29 | # filename = '4by4simple.gr' 30 | # filename = '4by4simple_val2.gr' # 3-by-3 nets toy sample 31 | # filename = 'adaptec1.capo70.2d.35.50.90.gr' 32 | filename = 'test_benchmark.gr' 33 | 34 | # # Getting Net Info 35 | grid_info = init.read(filename) 36 | # print(grid_info) 37 | # # print(init.gridParameters(grid_info)['netInfo']) 38 | # for item in init.gridParameters(grid_info).items(): 39 | # print(item) 40 | gridParameters = init.gridParameters(grid_info) 41 | # # for net in init.gridParameters(grid_info)['netInfo']: 42 | # init.GridGraph(init.gridParameters(grid_info)).show_grid() 43 | # init.GridGraph(init.gridParameters(grid_info)).pin_density_plot() 44 | 45 | # # GridGraph 46 | capacity = graph.GridGraph(init.gridParameters(grid_info)).generate_capacity() 47 | # print(capacity[:,:,0,0]) 48 | 49 | gridX,gridY,gridZ = graph.GridGraph(init.gridParameters(grid_info)).generate_grid() 50 | # print(gridX[1,1,0]) 51 | # print(gridY[1,1,0]) 52 | # print(gridZ[1,1,0]) 53 | 54 | # Real Router for Multiple Net 55 | # Note: pinCoord input as absolute length coordinates 56 | gridGraph = twoPinASearch.AStarSearchGraph(gridParameters, capacity) 57 | 58 | # Sort net 59 | halfWireLength = init.VisualGraph(init.gridParameters(grid_info)).bounding_length() 60 | # print('Half Wire Length:',halfWireLength) 61 | 62 | sortedHalfWireLength = sorted(halfWireLength.items(),key=operator.itemgetter(1),reverse=True) # Large2Small 63 | # sortedHalfWireLength = sorted(halfWireLength.items(),key=operator.itemgetter(1),reverse=False) # Small2Large 64 | 65 | # print('Sorted Half Wire Length:',sortedHalfWireLength) 66 | 67 | # Following plot is foe half wire length distribution 68 | # plt.figure() 69 | # plt.hist([i[1] for i in sortedHalfWireLength],bins=20) 70 | # plt.show() 71 | 72 | routeListMerged = [] 73 | routeListNotMerged = [] 74 | 75 | # For testing first part nets 76 | 77 | # for i in range(1): 78 | for i in range(len(init.gridParameters(grid_info)['netInfo'])): 79 | 80 | # Determine nets to wire based on sorted nets (stored in list sortedHalfWireLength) 81 | # print('*********************') 82 | # print('Routing net No.',init.gridParameters(grid_info)['netInfo'][int(sortedHalfWireLength[i][0])]['netName']) 83 | # (above output is to get actual netName) 84 | # print('Routing net No.',sortedHalfWireLength[i][0]) 85 | 86 | netNum = int(sortedHalfWireLength[i][0]) 87 | 88 | # Sort the pins by a heuristic such as Min Spanning Tree or Rectilinear Steiner Tree 89 | 90 | # # Remove pins that are in the same grid: 91 | netPinList = [] 92 | netPinCoord = [] 93 | for j in range(0, gridParameters['netInfo'][netNum]['numPins']): 94 | pin = tuple([int((gridParameters['netInfo'][netNum][str(j+1)][0]-gridParameters['Origin'][0])/gridParameters['tileWidth']), 95 | int((gridParameters['netInfo'][netNum][str(j+1)][1]-gridParameters['Origin'][1])/gridParameters['tileHeight']), 96 | int(gridParameters['netInfo'][netNum][str(j+1)][2]), 97 | int(gridParameters['netInfo'][netNum][str(j+1)][0]), 98 | int(gridParameters['netInfo'][netNum][str(j+1)][1])]) 99 | if pin[0:3] in netPinCoord: 100 | continue 101 | else: 102 | netPinList.append(pin) 103 | netPinCoord.append(pin[0:3]) 104 | 105 | twoPinList = [] 106 | for i in range(len(netPinList)-1): 107 | pinStart = netPinList[i] 108 | pinEnd = netPinList[i+1] 109 | twoPinList.append([pinStart,pinEnd]) 110 | # Sort 111 | # 112 | # for i in range(len(netPinList)): 113 | # for j in range(i+1,len(netPinList)): 114 | # redundancy = (0,0,0,0,0) 115 | # if netPinList[i][:3] == netPinList[j][:3]: 116 | # redundancy = netPinList[i] 117 | # netPinList.remove(redundancy) 118 | 119 | 120 | 121 | # for j in range(1,gridParameters['netInfo'][netNum]['numPins']): 122 | # # print(gridParameters['netInfo'][i][str(j)][0]) 123 | # 124 | # # Here, pin representation is converted from length coordinates to grid coordinates, 125 | # # while length coordinates is stored at last two positons 126 | # pinStart = tuple([int((gridParameters['netInfo'][netNum][str(j)][0]-gridParameters['Origin'][0])/gridParameters['tileWidth']), 127 | # int((gridParameters['netInfo'][netNum][str(j)][1]-gridParameters['Origin'][1])/gridParameters['tileHeight']), 128 | # int(gridParameters['netInfo'][netNum][str(j)][2]), 129 | # int(gridParameters['netInfo'][netNum][str(j)][0]), 130 | # int(gridParameters['netInfo'][netNum][str(j)][1])]) 131 | # pinEnd = tuple([int((gridParameters['netInfo'][netNum][str(j+1)][0]-gridParameters['Origin'][0])/gridParameters['tileWidth']), 132 | # int((gridParameters['netInfo'][netNum][str(j+1)][1]-gridParameters['Origin'][1])/gridParameters['tileHeight']), 133 | # int(gridParameters['netInfo'][netNum][str(j+1)][2]), 134 | # int(gridParameters['netInfo'][netNum][str(j+1)][0]), 135 | # int(gridParameters['netInfo'][netNum][str(j+1)][1])]) 136 | # 137 | # # Remove pin pairs that are in the same grid 138 | # if pinStart[:3] == pinEnd[:3]: 139 | # continue 140 | # else: 141 | # twoPinList.append([pinStart,pinEnd]) 142 | 143 | # print('Two pin list:',twoPinList,'\n') 144 | 145 | # Insert Tree method to decompose two pin problems here 146 | twoPinList = tree.generateMST(twoPinList) 147 | # print('Two pin list after:', twoPinList, '\n') 148 | 149 | # Remove pin pairs that are in the same grid again 150 | nullPairList = [] 151 | for i in range(len(twoPinList)): 152 | if twoPinList[i][0][:3] == twoPinList[i][1][:3]: 153 | nullPairList.append(twoPinList[i]) 154 | 155 | for i in range(len(nullPairList)): 156 | twoPinList.reomove(nullPairList[i]) 157 | 158 | i = 1 159 | routeListSingleNet = [] 160 | for twoPinPair in twoPinList: 161 | pinStart = twoPinPair[0]; pinEnd = twoPinPair[1] 162 | # print('Routing pin pair No.',i) 163 | # print('Pin start ',pinStart) 164 | route, cost = twoPinASearch.AStarSearchRouter(pinStart, pinEnd, gridGraph) 165 | # print('Route:',route) 166 | # print('Cost:',cost) 167 | routeListSingleNet.append(route) 168 | i += 1 169 | 170 | 171 | # print('Route List Single Net:',routeListSingleNet,'\n') 172 | mergedrouteListSingleNet = [] 173 | 174 | for list in routeListSingleNet: 175 | # if len(routeListSingleNet[0]) == 2: 176 | # mergedrouteListSingleNet.append(list[0]) 177 | # mergedrouteListSingleNet.append(list[1]) 178 | # else: 179 | for loc in list: 180 | # if loc not in mergedrouteListSingleNet: 181 | mergedrouteListSingleNet.append(loc) 182 | # print('Merged Route List Single Net',mergedrouteListSingleNet,'\n') 183 | routeListMerged.append(mergedrouteListSingleNet) 184 | routeListNotMerged.append(routeListSingleNet) 185 | 186 | # Update capacity and grid graph after routing one pin pair 187 | # # WARNING: capacity update could lead to failure since capacity could go to negative (possible bug) 188 | # # # print(route) 189 | capacity = graph.updateCapacity(capacity, mergedrouteListSingleNet) 190 | # gridGraph = twoPinASearch.AStarSearchGraph(gridParameters, capacity) 191 | 192 | # Plot of routing for multilple net 193 | # print('\nRoute List Merged:',routeListMerged) 194 | 195 | fig = plt.figure() 196 | ax = fig.add_subplot(111, projection='3d') 197 | ax.set_zlim(0.5,2.0) 198 | # 199 | for routeList in routeListNotMerged: 200 | for route in routeList: 201 | x = [coord[3] for coord in route] 202 | y = [coord[4] for coord in route] 203 | z = [coord[2] for coord in route] 204 | ax.plot(x,y,z) 205 | 206 | 207 | plt.xlim([0, gridParameters['gridSize'][0]-1]) 208 | plt.ylim([0, gridParameters['gridSize'][1]-1]) 209 | # plt. 210 | plt.savefig('RoutingVisualize.jpg') 211 | fig.tight_layout() 212 | plt.show() 213 | 214 | # for i in range(len(routeListMerged)): 215 | # print(i) 216 | # print(routeListMerged[i]) 217 | 218 | #Generate output file 219 | # print('routeListMerged',routeListMerged) 220 | f = open('%s.solutiontesting' % filename, 'w+') 221 | 222 | # For testing first part nets 223 | 224 | # for i in range(1): 225 | for i in range(gridParameters['numNet']): 226 | indicator = i 227 | netNum = int(sortedHalfWireLength[i][0]) 228 | i = netNum 229 | 230 | value = '{netName} {netID} {cost}\n'.format(netName=gridParameters['netInfo'][i]['netName'], 231 | netID = gridParameters['netInfo'][i]['netID'], 232 | cost = max(0,len(routeListMerged[indicator])-1)) 233 | f.write(value) 234 | for j in range(len(routeListMerged[indicator])-1): 235 | # In generating the route in length coordinate system, the first pin (corresponding to griParameters['netInfo'][i]['1']) 236 | # is used as reference point 237 | a = routeListMerged[indicator][j] 238 | b = routeListMerged[indicator][j+1] 239 | diff = [abs(a[2]-b[2]),abs(a[3]-b[3]),abs(a[4]-b[4])] 240 | if diff[1] > 2 or diff[2] > 2: 241 | continue 242 | elif diff[1] == 2 or diff[2] == 2: 243 | # print('Alert') 244 | continue 245 | elif diff[0] == 0 and diff[1] == 0 and diff[2] == 0: 246 | continue 247 | elif diff[0] + diff[1] + diff[2] >= 2: 248 | continue 249 | else: 250 | value = '({},{},{})-({},{},{})\n'.format(a[0],a[1],a[2],b[0],b[1],b[2]) 251 | f.write(value) 252 | f.write('!\n') 253 | f.close() 254 | -------------------------------------------------------------------------------- /BenchmarkGenerator/TwoPinRouterASearch.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import matplotlib 3 | matplotlib.use('TkAgg') 4 | import matplotlib.pyplot as plt 5 | 6 | import Initializer as init 7 | import GridGraph as gridgraph 8 | 9 | import matplotlib.patches as patches 10 | import numpy as np 11 | import pandas as pd 12 | from matplotlib import cm 13 | from mpl_toolkits.mplot3d import Axes3D 14 | 15 | class AStarSearchGraph(object): 16 | def __init__(self,gridParameters,capacity): 17 | self.capacity = capacity 18 | self.gridParameters = gridParameters 19 | 20 | def heuristic(self,currentGrid,goalGrid): 21 | # Using Manhattan Distance as heuristic distance 22 | # currentGrid and goalGrid: [x,y,z] 23 | distX = abs(currentGrid[0] - goalGrid[0]) 24 | distY = abs(currentGrid[1] - goalGrid[1]) 25 | distZ = abs(currentGrid[2] - goalGrid[2]) 26 | dist = distX + distY + distZ 27 | return dist 28 | 29 | def get_grid_neighbors(self,currentGrid,pinStart,pinEnd): 30 | 31 | # Key grid are grids containing pinStart or pinEnd 32 | keyGrid = [(pinStart[0], pinStart[1], pinStart[2]), (pinEnd[0], pinEnd[1], pinEnd[2])] 33 | 34 | # Store allowable neighbor positions in a list 35 | neighbor = [] 36 | curX = currentGrid[0];curY = currentGrid[1];curZ = currentGrid[2] 37 | curLengthX = currentGrid[3]; curLengthY = currentGrid[4] 38 | 39 | possible_neighborGrid = [(curX-1,curY,curZ),(curX+1,curY,curZ), 40 | (curX,curY-1,curZ),(curX,curY+1,curZ), 41 | (curX, curY, curZ+1),(curX,curY,curZ-1)] 42 | for n in possible_neighborGrid: 43 | if n[0] < 0 or n[0] >= self.gridParameters['gridSize'][0] or\ 44 | n[1] < 0 or n[1] >= self.gridParameters['gridSize'][1] or\ 45 | n[2] <= 0 or n[2] > self.gridParameters['gridSize'][2]: 46 | continue 47 | elif n == keyGrid[0]: 48 | n = pinStart 49 | elif n == keyGrid[1]: 50 | n = pinEnd 51 | else: 52 | neighborX = self.gridParameters['Origin'][0] + n[0]*self.gridParameters['tileWidth'] 53 | neighborY = self.gridParameters['Origin'][1] + n[1]*self.gridParameters['tileHeight'] 54 | n = n + (int(neighborX),int(neighborY)) 55 | neighbor.append(n) 56 | 57 | # Output during search 58 | # print('Current Position', currentGrid) 59 | # print('Neighbor Position',neighbor) 60 | return neighbor 61 | 62 | def get_move_cost(self,state,action): 63 | if self.capacity[state[0],state[1],state[2]-1,action] <= 0: 64 | return 1000 # Very high cost for Overflow 65 | return 1 # Normal action cost 66 | 67 | def AStarSearchRouter(pinStart, pinEnd, graph): 68 | # pin = (xGrid, yGrid, layer, xLength, yLength) 69 | 70 | # Key grid are grids containing pinStart or pinEnd 71 | keyGrid = [(pinStart[0],pinStart[1],pinStart[2]),(pinEnd[0],pinEnd[1],pinEnd[2])] 72 | 73 | G = {} # Actual Movement cost to each position from the start position 74 | F = {} # Estimated movement cost of start to end going via this position 75 | 76 | # Initializing starting value 77 | G[pinStart] = 0 78 | F[pinStart] = graph.heuristic(pinStart,pinEnd) 79 | 80 | closedVertices = set() 81 | openVertices = set([pinStart]) 82 | cameFrom = {} 83 | 84 | # print('graph.capacity\n',graph.capacity[0,0,0,0]) 85 | # Update capacity 86 | # graph.capacity = gridgraph.updateCapacityRL(graph.capacity,(0,0,1,5,5),0) 87 | 88 | 89 | while len(openVertices) > 0: 90 | # Get the vertex in the open list with lowest F score 91 | current = None 92 | currentFscore = None 93 | for pos in openVertices: 94 | if current is None or F[pos] < currentFscore: 95 | currentFscore = F[pos] 96 | current = pos 97 | # if current is None: 98 | # current = pos 99 | # if currentFscore is None: 100 | # currentFscore = graph.heuristic(current,pinEnd) 101 | 102 | # if F[pos] < currentFscore: 103 | # currentFscore = F[pos] 104 | 105 | # action = 0 106 | # delta = [pos[0]-current[0],pos[1]-current[1],pos[2]-current[2]] 107 | # if delta[2] == 1: 108 | # action = 4 109 | # elif delta[2] == -1: 110 | # action = 5 111 | # elif delta[1] == 1: 112 | # action = 2 113 | # elif delta[1] == -1: 114 | # action = 3 115 | # elif delta[0] == 1: 116 | # action = 0 117 | # elif delta[0] == -1: 118 | # action = 1 119 | # oldcurrent = current 120 | 121 | # current = pos 122 | # # Update capacity 123 | 124 | # graph.capacity = gridgraph.updateCapacityRL(graph.capacity,oldcurrent,action) 125 | 126 | 127 | # Check if pinEnd is reached 128 | if current == pinEnd: 129 | # Retrace route backward 130 | path = [(current[3],current[4],current[2],current[0],current[1])] 131 | while current in cameFrom: 132 | current = cameFrom[current] 133 | path.append((current[3],current[4],current[2],current[0],current[1])) 134 | path.reverse() 135 | return path, F[pinEnd] # Routing accomplished 136 | 137 | # Mark the current vertex as closed 138 | openVertices.remove(current) 139 | closedVertices.add(current) 140 | 141 | # Update scores for vertices near the current position 142 | for neighbor in graph.get_grid_neighbors(current,pinStart,pinEnd): 143 | if neighbor in closedVertices: 144 | continue # We have already processed this node exhaustively 145 | # Get action based on current and neighbour 146 | delta = [neighbor[0]-current[0],neighbor[1]-current[1],neighbor[2]-current[2]] 147 | # such as (0,0,1) means moving +z 148 | action = 0 149 | if delta == [0,0,1]: 150 | action = 4 151 | elif delta == [0,0,-1]: 152 | action = 5 153 | elif delta == [0,1,0]: 154 | action = 2 155 | elif delta == [0,-1,0]: 156 | action = 3 157 | elif delta == [1,0,0]: 158 | action = 0 159 | elif delta == [-1,0,0]: 160 | action = 1 161 | 162 | candidateG = G[current] + graph.get_move_cost(current,action) 163 | if neighbor not in openVertices: 164 | openVertices.add(neighbor) # Discovered a new vertex 165 | elif candidateG >= G[neighbor]: 166 | continue # This G score is worse than previously found 167 | 168 | 169 | # Adopt this G score 170 | cameFrom[neighbor] = current 171 | G[neighbor] = candidateG 172 | H = graph.heuristic(neighbor,pinEnd) 173 | F[neighbor] = G[neighbor] + H 174 | 175 | # update capacity 176 | # capacity = gridgraph.updateCapacityRL(capacity,state,action) 177 | 178 | raise RuntimeError("A* failed to find a solution") 179 | 180 | if __name__ == "__main__": 181 | filename = 'small.gr' 182 | # filename = 'adaptec1.capo70.2d.35.50.90.gr' 183 | # filename = 'sampleBenchmark' 184 | 185 | # # Getting Net Info 186 | grid_info = init.read(filename) 187 | # print(grid_info) 188 | # # print(init.gridParameters(grid_info)['netInfo']) 189 | for item in init.gridParameters(grid_info).items(): 190 | print(item) 191 | gridParameters = init.gridParameters(grid_info) 192 | # # for net in init.gridParameters(grid_info)['netInfo']: 193 | # init.GridGraph(init.gridParameters(grid_info)).show_grid() 194 | # init.GridGraph(init.gridParameters(grid_info)).pin_density_plot() 195 | 196 | # # GridGraph 197 | capacity = gridgraph.GridGraph(init.gridParameters(grid_info)).generate_capacity() 198 | # print(capacity[:,:,0,0]) 199 | gridX,gridY,gridZ = gridgraph.GridGraph(init.gridParameters(grid_info)).generate_grid() 200 | # print(gridX[1,1,0]) 201 | # print(gridY[1,1,0]) 202 | # print(gridZ[1,1,0]) 203 | 204 | # # Test: get grid neighbors 205 | # pinStart = (0,0,0,5,5); pinEnd = (2,0,0,25,5) 206 | # neighbor = AStarSearchGraph(gridParameters,capacity).get_grid_neighbors([1,1,0,15,15],pinStart,pinEnd) 207 | # print('Neighbor Test: ', neighbor) 208 | 209 | # Test: get move cost 210 | # state = (1,0,0); action = 1 211 | # cost = AStarSearchGraph(gridParameters,capacity).get_move_cost(state,action) 212 | # print(cost) 213 | 214 | 215 | # Test: A* router 216 | gridGraph = AStarSearchGraph(gridParameters,capacity) 217 | pinStart = (0,0,1,5,5); pinEnd = (2,0,1,25,5) 218 | route, cost = AStarSearchRouter(pinStart, pinEnd, gridGraph) 219 | print('Route',route) 220 | print('Cost',cost) 221 | 222 | 223 | # coord_L1 = []; coord_L0 = [] 224 | # for coord in route: 225 | # if coord[2] == 1: 226 | # coord_L1.append(coord) 227 | # else: 228 | # coord_L0.append(coord) 229 | # plt.plot([coord[0] for coord in coord_L0],[coord[1] for coord in coord_L0],label='Layer 0',color='r') 230 | # plt.plot([coord[0] for coord in coord_L1],[coord[1] for coord in coord_L1],label='Layer 1',color='b') 231 | # plt.plot([coord[0] for coord in route],[coord[1] for coord in route],) 232 | 233 | # Possible bug: diagnol plot found in plots 234 | fig = plt.figure() 235 | ax = fig.add_subplot(111,projection='3d') 236 | # ax.plot(route[0],route[1],route[2]) 237 | x = [coord[0] for coord in route] 238 | y = [coord[1] for coord in route] 239 | z = [coord[2] for coord in route] 240 | ax.plot(x,y,z,'r',linewidth=2) 241 | 242 | # plt.xlim([0,324]) 243 | # plt.ylim([0,324]) 244 | # plt.legend() 245 | # plt.xlim([-1, gridParameters['gridSize'][0]]) 246 | # plt.ylim([-1, gridParameters['gridSize'][1]]) 247 | plt.show() -------------------------------------------------------------------------------- /Images/CapPlot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haiguanl/GlobalRoutingProblemGenerator/8e5907852bf02b5801e44708122b84c1af3adbb5/Images/CapPlot.png -------------------------------------------------------------------------------- /Images/CapPlot32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haiguanl/GlobalRoutingProblemGenerator/8e5907852bf02b5801e44708122b84c1af3adbb5/Images/CapPlot32.png -------------------------------------------------------------------------------- /Images/SolPlot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haiguanl/GlobalRoutingProblemGenerator/8e5907852bf02b5801e44708122b84c1af3adbb5/Images/SolPlot.png -------------------------------------------------------------------------------- /Images/edgePlotwithCapacity5number8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haiguanl/GlobalRoutingProblemGenerator/8e5907852bf02b5801e44708122b84c1af3adbb5/Images/edgePlotwithCapacity5number8.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Haiguang Liao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import sys 4 | 5 | def parse_arguments(): 6 | parser = argparse.ArgumentParser('Benchmark Generator Parser') 7 | parser.add_argument('--benchNumber',type=int,\ 8 | dest='benchmarkNumber',default=20) 9 | parser.add_argument('--gridSize',type=int,dest='gridSize',default=16) 10 | parser.add_argument('--netNum',type=int,dest='netNum',default=5) 11 | parser.add_argument('--capacity',type=int,dest='cap',default=4) 12 | parser.add_argument('--maxPinNum',type=int,dest='maxPinNum',default=5) 13 | parser.add_argument('--reducedCapNum',type=int,dest='reducedCapNum',default=1) 14 | 15 | return parser.parse_args() 16 | 17 | 18 | if __name__ == '__main__': 19 | # Remember to copy results to other directory when running new parameters 20 | 21 | filename = None 22 | args = parse_arguments() 23 | benNum = args.benchmarkNumber 24 | gridSize = args.gridSize; netNum = args.netNum 25 | cap = args.cap; maxPinNum = args.maxPinNum 26 | reducedCapNum = args.reducedCapNum 27 | 28 | # Generating problems module (A*) 29 | # Make sure previous benchmark files: "benchmark","capacityplot", 30 | # and 'solution' are removed 31 | sys.setrecursionlimit(100000) 32 | os.system('rm -r benchmark') 33 | os.system('rm -r capacityplot_A*') 34 | os.system('rm -r solutionsA*') 35 | os.system('rm -r solutionsDRL') 36 | os.chdir('BenchmarkGenerator') 37 | # os.chdir('..') 38 | print('**************') 39 | print('Problem Generating Module') 40 | print('**************') 41 | os.system('python BenchmarkGenerator.py --benchNumber {benNum} --gridSize {gridSize}\ 42 | --netNum {netNum} --capacity {cap} --maxPinNum {maxPinNum} --reducedCapNum {reducedCapNum}'\ 43 | .format(benNum=benNum,gridSize=gridSize,\ 44 | netNum=netNum,cap=cap,maxPinNum=maxPinNum,reducedCapNum=reducedCapNum)) 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Global Routing Problem Generator V1.0 2 | This repository functions as an automatic problem generator for global routing problems. Benchmarks (or problem sets) are generated and then solved with A\*Search so that a baseline solution is provided and a rough estimate of congestion can be obtained. 3 | Congestion is described by heatmaps representing traffic on edges of different directions (horizontal, vertical,via) and edge utilization count plot. 4 |
There are two types of generated problems: the first type problems only have specified global capacity (stored in folder "**benchmark**"); the second type problems have both specified global capacity and reduced capacity (stored in folder "**benchmark_reduced**"). The reduced capacity blocked edges in descending orders of edge utilization based on A\* solution .i.e. blocking edges with highest edge utilization in A\* solution. 5 |
The generated problem sets will faciliate development of machine-learning-based global routing algorithms that relies on large amount of training datasets to make it generalizable. 6 |
Some details of the code are as follows: 7 | #### 1. Python Version: Python3.6 8 | #### 2. Packages: 9 | os, operator, matplotlib, numpy, argparse, collections, scipy, sys, mpl_toolkits. To install them: 10 | ``` 11 | pip install 12 | ``` 13 | You might need to install some extra packages in your environment to run the generator. 14 | 15 | Alternatively, to setup your environment, use the conda environment specified in environment.yml by simply doing the following with a recent version of conda in Linux/Bash (https://conda.io/projects/conda/en/latest/user-guide/install/index.html): 16 | ``` 17 | cd GlobalRoutingProblemGenerator 18 | conda env create 19 | source activate GlobalRoutingProblemGenerator 20 | ``` 21 | 22 | 23 | #### 3. Parameters to be specified include: 24 | - number of generated problems (benchNumber) 25 | - gridSize, number of nets in each problem (netNum) 26 | - global capacity (capacity), maximum number of pins for each net (maxPinNum) 27 | - reducedCapNum (number of edges with reduced capacity). 28 | In existing version of code, reduced capacity edges are set with zero capacity, i.e. fully blocked. 29 | #### 4. To run the generator, specify problem parameters as follows: 30 | ``` 31 | python Main.py --benchNumber 10 --gridSize 8 --netNum 50 --capacity 5 --maxPinNum 2 --reducedCapNum 3 32 | ``` 33 | #### 5. Output: 34 | - benchmark: generated problems with only global capacity specification 35 | - benchmark_reduced: generated problems with global capacity specification and reduced capacity specification 36 | - capacityPlot_A*: capacity plot of edge utilizations for problems in "benchmark" folder in different directions (horizontal, vertical) for individual problems (with number) and averaged over all problems (without number); edge utilization count plot 37 |

38 | drawing 39 |

40 | 41 | - capacityPlot_A*_reduced: capacity plot of edge utilizations for problems in "benchmark_reduced" folder in different directions (horizontal, vertical) for individual problems (with number) and averaged over all problems (without number); edge utilization count plot 42 | - solutionsA*: solution files for problems in "benchmark" folder given by A*Search router together with plot for solutions 43 |

44 | drawing 45 |

46 | 47 | - solutionsA*_reduced: solution files for problems in "benchmark_reduced" folder given by A*Search router together with plot for solutions 48 | #### 6. Warning: 49 | when executed again, previously generated problems, solutions and plots will be removed. 50 | 51 | #### Appendix: capacity plot of a 32*32 size problem 52 |

53 | drawing 54 |

55 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: GlobalRoutingProblemGenerator 2 | 3 | dependencies: 4 | - python=3.6 5 | - matplotlib 6 | - numpy 7 | - scipy 8 | - basemap 9 | - pandas 10 | - pillow 11 | 12 | 13 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | Global Routing Problem Generator V1.0 2 | 3 | 1. Python Version: Python3.6 4 | 2. Packages: os, operator, matplotlib, numpy, argparse, collections, spicy, sys, mpl_toolkits. To install them: $ pip install . You might need to install some extra packages in your environment to run the generator. 5 | 3. Parameters to be specified includes: number of generated problems (benchNumber),gridSize, number of nets in each problem (netNum), global capacity (capacity), maximum number of pins for each net (maxPinNum), reducedCapNum (number of edges with reduced capacity). In existing version of code, reduced capacity edges are set with zero capacity, i.e. fully blocked. 6 | 4. To run the generator, specify problem parameters as follows: $ python Main.py --benchNumber 10 --gridSize 8 --netNum 50 --capacity 5 --maxPinNum 2 --reducedCapNum 3 7 | 5. Output: 8 | (1) benchmark: generated problems with only global capacity specification 9 | (2) benchmark_reduced: generated problems with global capacity specification and reduced capacity specification 10 | (3) capacityPlot_A*: capacity plot of edge utilizations for problems in "benchmark" folder in different directions (horizontal, vertical) for individual problems (with number) and averaged over all problems (without number); edge utilization count plot 11 | (4) capacityPlot_A*_reduced: capacity plot of edge utilizations for problems in "benchmark_reduced" folder in different directions (horizontal, vertical) for individual problems (with number) and averaged over all problems (without number); edge utilization count plot 12 | (5) solutionsA*: solution files for problems in "benchmark" folder given by A*Search router together with plot for solutions 13 | (6) solutionsA*_reduced: solution files for problems in "benchmark_reduced" folder given by A*Search router together with plot for solutions 14 | 15 | 6. Warning: when executed again, previously generated problems, solutions and plots will be removed. 16 | --------------------------------------------------------------------------------