Compare commits
No commits in common. "20315a484a7bf33f4d7143f8ee13bdf37f664bbc" and "29b01461e64064204436dea76cbfde7cb48dd7fe" have entirely different histories.
20315a484a
...
29b01461e6
83
README.md
83
README.md
@ -1,70 +1,7 @@
|
||||
## MaskPlace: Fast Chip Placement via Reinforced Visual Representation Learning
|
||||
|
||||
A new chip placement method based on visual representation learning.
|
||||
A new chip placement method based on visual representation learning.
|
||||
|
||||
### Publication
|
||||
Lai, Yao, Yao Mu, and Ping Luo. "Maskplace: Fast chip placement via reinforced visual representation learning." Advances in Neural Information Processing Systems 35 (2022): 24019-24030. (NeurIPS 2022, **spotlight**)
|
||||
|
||||
[paper](https://arxiv.org/pdf/2211.13382.pdf)
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
You can start easily by using the following script.
|
||||
|
||||
```
|
||||
cd maskplace
|
||||
python PPO2.py
|
||||
```
|
||||
|
||||
### Parameter
|
||||
|
||||
- **gamma** Decay factor.
|
||||
- **seed** Random seed.
|
||||
- **disable_tqdm** Whether to disable the progress bar.
|
||||
- **lr** Learning rate.
|
||||
- **log-interval** Interval between training status logs.
|
||||
- **pnm** Number of place modules for each placement trajectory.
|
||||
- **benchmark** Circuit benchmark.
|
||||
- **soft_coefficient** Whether to constriant the actions based on the wiremask.
|
||||
- **batch_size** Batch size.
|
||||
- **is_test** Testing mode based on the trained agent.
|
||||
- **save_fig** Whether to save placement figures.
|
||||
|
||||
|
||||
### Benchmark
|
||||
The repo has provided the benchmark *adaptec1* and *ariane*. For other benchmarks, you can download them by the following the link:
|
||||
|
||||
http://www.cerc.utexas.edu/~zixuan/ispd2005dp.tar.xz
|
||||
|
||||
|
||||
### Dependency
|
||||
- [Python](https://www.python.org/) >= 3.9
|
||||
|
||||
- [Pytorch](https://pytorch.org/) >= 1.10
|
||||
|
||||
- Other versions may also work, but not tested
|
||||
|
||||
- [gym](https://www.gymlibrary.dev/index.html) >= 0.21.0
|
||||
- [matplotlib](https://matplotlib.org/) >= 3.7.1
|
||||
- [tqdm](https://tqdm.github.io/)
|
||||
- [protobuf](https://pypi.org/project/protobuf/) (for benchmark *ariane*)
|
||||
|
||||
### Citation
|
||||
If you find our paper/code useful in your research, please cite
|
||||
|
||||
```
|
||||
@article{lai2022maskplace,
|
||||
title={Maskplace: Fast chip placement via reinforced visual representation learning},
|
||||
author={Lai, Yao and Mu, Yao and Luo, Ping},
|
||||
journal={Advances in Neural Information Processing Systems},
|
||||
volume={35},
|
||||
pages={24019--24030},
|
||||
year={2022}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### The placement process animation
|
||||
|
||||
Benchmark: Bigblue3
|
||||
@ -77,14 +14,6 @@ Benchmark: Bigblue3
|
||||
|<img src="imgs/view_img.gif" width=250>|<img src="imgs/pos_img_next.gif" width=250> | <img src="imgs/net_img_next.gif" width=250>|
|
||||
|
||||
|
||||
### Standard Cell Placement
|
||||
|
||||
Fix macros and use DREAMPlace (classic optimization-based method) to place standard cells.
|
||||
|
||||
|<center>adaptec2</center>| <center>adaptec4 </center>| <center> bigblue3 </center>|
|
||||
|---|---|---|
|
||||
|<img src="imgs/stdcell_a2.gif" width="250">|<img src="imgs/stdcell_a4.gif" width="250">|<img src="imgs/stdcell_b3.gif" width="250">|
|
||||
|
||||
### Full Benchmark demonstration
|
||||
|
||||
|
||||
@ -93,31 +22,21 @@ Fix macros and use DREAMPlace (classic optimization-based method) to place stand
|
||||
|adaptec1|<img src="imgs/dreamplace/adaptec1.png" width="160">|<img src="imgs/graph/adaptec1.png" width="160">|<img src="imgs/deeppr/adaptec1.png" width="160">|<img src="imgs/maskplace/adaptec1.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|17.94|26.05|21.36|<strong>6.57</strong>|
|
||||
|Wirel (10<sup>5</sup>)|19.24|28.54|25.64|<strong>7.36</strong>|
|
||||
|Overlap|0.34%|1.89%|32.03%|<strong>0</strong>|
|
||||
|adaptec2|<img src="imgs/dreamplace/adaptec2.png" width="160">|<img src="imgs/graph/adaptec2.png" width="160"> | <img src="imgs/deeppr/adaptec2.png" width="160">|<img src="imgs/maskplace/adaptec2.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|135.32|359.35|197.13|<strong>79.98</strong>|
|
||||
|Wirel (10<sup>5</sup>)|140.91|381.64|205.78|<strong>83.59</strong>|
|
||||
|Overlap|0.16%|1.54%|49.10%|<strong>0</strong>|
|
||||
|adaptec3|<img src="imgs/dreamplace/adaptec3.png" width="160">|<img src="imgs/graph/adaptec3.png" width="160"> | <img src="imgs/deeppr/adaptec3.png" width="160">|<img src="imgs/maskplace/adaptec3.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|112.28|392.66|340.29|<strong>79.33</strong>|
|
||||
|Wirel (10<sup>5</sup>)|119.23|409.37|372.02|<strong>85.28</strong>|
|
||||
|Overlap|<strong>0</strong>|1.26%|29.10%|<strong>0</strong>|
|
||||
|adaptec4|<img src="imgs/dreamplace/adaptec4.png" width="160">|<img src="imgs/graph/adaptec4.png" width="160"> | <img src="imgs/deeppr/adaptec4.png" width="160">|<img src="imgs/maskplace/adaptec4.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|<strong>37.77</strong>|152.89|243.12|75.75|
|
||||
|Wirel (10<sup>5</sup>)|<strong>47.90</strong>|179.43|290.14|88.87|
|
||||
|Overlap|<strong>0</strong>|7.43%|19.29%|<strong>0</strong>|
|
||||
|bigblue1|<img src="imgs/dreamplace/bigblue1.png" width="160">|<img src="imgs/graph/bigblue1.png" width="160"> | <img src="imgs/deeppr/bigblue1.png" width="160">|<img src="imgs/maskplace/bigblue1.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|2.50|8.32|20.49|<strong>2.42</strong>|
|
||||
|Wirel (10<sup>5</sup>)|3.41|10.00|25.68|<strong>3.14</strong>|
|
||||
|Overlap|<strong>0</strong>|2.48%|9.33%|<strong>0</strong>|
|
||||
|bigblue3|<img src="imgs/dreamplace/bigblue3.png" width="160">|<img src="imgs/graph/bigblue3.png" width="160"> | <img src="imgs/deeppr/bigblue3.png" width="160">|<img src="imgs/maskplace/bigblue3.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|104.05|345.49|439.09|<strong>82.61</strong>|
|
||||
|Wirel (10<sup>5</sup>)|107.58|373.33|517.86|<strong>88.51</strong>|
|
||||
|Overlap|8.06%|0.80%|85.23%|<strong>0</strong>|
|
||||
|ariane|<img src="imgs/dreamplace/ariane.png" width="160">|<img src="imgs/graph/ariane.png" width="160"> | <img src="imgs/deeppr/ariane.png" width="160">|<img src="imgs/maskplace/ariane.png" width="160">|
|
||||
|HPWL (10<sup>5</sup>)|20.30|16.83|51.43|<strong>14.86</strong>|
|
||||
|Wirel (10<sup>5</sup>)|21.72|18.48|55.85|<strong>15.80</strong>|
|
||||
|Overlap|<strong>0.78%</strong>|3.72%|38.91%|1.94%|
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 212 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.0 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 MiB |
@ -1,412 +0,0 @@
|
||||
import argparse
|
||||
import pickle
|
||||
from collections import namedtuple
|
||||
|
||||
import os
|
||||
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
import gym
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
import torch.optim as optim
|
||||
from torch.distributions import Normal
|
||||
from torch.distributions import Categorical
|
||||
from torch.utils.data.sampler import BatchSampler, SubsetRandomSampler
|
||||
|
||||
import place_env
|
||||
import torchvision
|
||||
from place_db import PlaceDB
|
||||
import time
|
||||
from tqdm import tqdm
|
||||
import random
|
||||
from comp_res import comp_res
|
||||
from torch.utils.tensorboard import SummaryWriter
|
||||
|
||||
# set device to cpu or cuda
|
||||
device = torch.device('cuda')
|
||||
|
||||
if(torch.cuda.is_available()):
|
||||
device = torch.device('cuda:0')
|
||||
torch.cuda.empty_cache()
|
||||
print("Device set to : " + str(torch.cuda.get_device_name(device)))
|
||||
else:
|
||||
print("Device set to : cpu")
|
||||
|
||||
# Parameters
|
||||
parser = argparse.ArgumentParser(description='Solve the Pendulum-v0 with PPO')
|
||||
parser.add_argument(
|
||||
'--gamma', type=float, default=0.95, metavar='G', help='discount factor (default: 0.9)')
|
||||
parser.add_argument('--seed', type=int, default=42, metavar='N', help='random seed (default: 0)')
|
||||
parser.add_argument('--disable_tqdm', type=int, default=1)
|
||||
parser.add_argument('--lr', type=float, default=2.5e-3)
|
||||
parser.add_argument(
|
||||
'--log-interval',
|
||||
type=int,
|
||||
default=10,
|
||||
metavar='N',
|
||||
help='interval between training status logs (default: 10)')
|
||||
parser.add_argument('--pnm', type=int, default=128)
|
||||
parser.add_argument('--benchmark', type=str, default='adaptec1')
|
||||
parser.add_argument('--soft_coefficient', type=float, default = 1)
|
||||
parser.add_argument('--batch_size', type=int, default=64)
|
||||
parser.add_argument('--is_test', action='store_true', default=False)
|
||||
parser.add_argument('--save_fig', action='store_true', default=False)
|
||||
args = parser.parse_args()
|
||||
writer = SummaryWriter('./tb_log')
|
||||
|
||||
benchmark = args.benchmark
|
||||
placedb = PlaceDB(benchmark)
|
||||
grid = 224
|
||||
placed_num_macro = args.pnm
|
||||
if args.pnm > placedb.node_cnt:
|
||||
placed_num_macro = placedb.node_cnt
|
||||
args.pnm = placed_num_macro
|
||||
env = gym.make('place_env-v0', placedb = placedb, placed_num_macro = placed_num_macro, grid = grid).unwrapped
|
||||
|
||||
num_emb_state = 64 + 2 + 1
|
||||
num_state = 1 + grid*grid*5 + 2
|
||||
|
||||
def seed_torch(seed=0):
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
os.environ['PYTHONHASHSEED'] = str(seed)
|
||||
torch.manual_seed(seed)
|
||||
torch.cuda.manual_seed(seed)
|
||||
torch.manual_seed(seed)
|
||||
env.seed(seed)
|
||||
torch.backends.cudnn.deterministic = True
|
||||
torch.backends.cudnn.benchmark = False
|
||||
|
||||
num_action = env.action_space.shape
|
||||
seed_torch(args.seed)
|
||||
|
||||
Transition = namedtuple('Transition',['state', 'action', 'reward', 'a_log_prob', 'next_state', 'reward_intrinsic'])
|
||||
TrainingRecord = namedtuple('TrainRecord',['episode', 'reward'])
|
||||
print("seed = {}".format(args.seed))
|
||||
print("lr = {}".format(args.lr))
|
||||
print("placed_num_macro = {}".format(args.pnm))
|
||||
|
||||
|
||||
class MyCNN(nn.Module):
|
||||
def __init__(self):
|
||||
super(MyCNN, self).__init__()
|
||||
self.cnn = nn.Sequential(
|
||||
nn.Conv2d(4, 8, 1),
|
||||
nn.ReLU(),
|
||||
nn.Conv2d(8, 8, 1),
|
||||
nn.ReLU(),
|
||||
nn.Conv2d(8, 1, 1),
|
||||
)
|
||||
def forward(self, x):
|
||||
return self.cnn(x)
|
||||
|
||||
|
||||
class MyCNNCoarse(nn.Module):
|
||||
def __init__(self, res_net):
|
||||
super(MyCNNCoarse, self).__init__()
|
||||
self.cnn = res_net.to(device)
|
||||
self.cnn.fc = torch.nn.Linear(512, 16*7*7)
|
||||
self.deconv = nn.Sequential(
|
||||
nn.ConvTranspose2d(16, 8, 3, stride=2, padding=1, output_padding = 1), #14
|
||||
nn.ReLU(),
|
||||
nn.ConvTranspose2d(8, 4, 3, stride=2, padding=1, output_padding = 1), #28
|
||||
nn.ReLU(),
|
||||
nn.ConvTranspose2d(4, 2, 3, stride=2, padding=1, output_padding = 1), #56
|
||||
nn.ReLU(),
|
||||
nn.ConvTranspose2d(2, 1, 3, stride=2, padding=1, output_padding = 1), #112
|
||||
nn.ReLU(),
|
||||
nn.ConvTranspose2d(1, 1, 3, stride=2, padding=1, output_padding = 1), #224
|
||||
)
|
||||
def forward(self, x):
|
||||
x = self.cnn(x).reshape(-1, 16, 7, 7)
|
||||
return self.deconv(x)
|
||||
|
||||
|
||||
class Actor(nn.Module):
|
||||
def __init__(self, cnn, gcn, cnn_coarse):
|
||||
super(Actor, self).__init__()
|
||||
self.fc1 = nn.Linear(num_emb_state, 512)
|
||||
self.fc2 = nn.Linear(512, 64)
|
||||
self.fc3 = nn.Linear(64, grid * grid)
|
||||
self.cnn = cnn
|
||||
self.cnn_coarse = cnn_coarse
|
||||
self.gcn = None
|
||||
self.softmax = nn.Softmax(dim=-1)
|
||||
self.merge = nn.Conv2d(2, 1, 1)
|
||||
|
||||
def forward(self, x, graph = None, cnn_res = None, gcn_res = None, graph_node = None):
|
||||
if not cnn_res:
|
||||
cnn_input = x[:, 1+grid*grid*1: 1+grid*grid*5].reshape(-1, 4, grid, grid)
|
||||
mask = x[:, 1+grid*grid*2: 1+grid*grid*3].reshape(-1, grid, grid)
|
||||
mask = mask.flatten(start_dim=1, end_dim=2)
|
||||
cnn_res = self.cnn(cnn_input)
|
||||
coarse_input = torch.cat((x[:, 1: 1+grid*grid*2].reshape(-1, 2, grid, grid),
|
||||
x[:, 1+grid*grid*3: 1+grid*grid*4].reshape(-1, 1, grid, grid)
|
||||
),dim= 1).reshape(-1, 3, grid, grid)
|
||||
cnn_coarse_res = self.cnn_coarse(coarse_input)
|
||||
cnn_res = self.merge(torch.cat((cnn_res, cnn_coarse_res), dim=1))
|
||||
net_img = x[:, 1+grid*grid: 1+grid*grid*2]
|
||||
net_img = net_img + x[:, 1+grid*grid*2: 1+grid*grid*3] * 10
|
||||
net_img_min = net_img.min() + args.soft_coefficient
|
||||
mask2 = net_img.le(net_img_min).logical_not().float()
|
||||
|
||||
x = cnn_res
|
||||
x = x.reshape(-1, grid * grid)
|
||||
x = torch.where(mask + mask2 >=1.0, -1.0e10, x.double())
|
||||
x = self.softmax(x)
|
||||
|
||||
return x, cnn_res, gcn_res
|
||||
|
||||
|
||||
class Critic(nn.Module):
|
||||
def __init__(self, cnn, gcn, cnn_coarse, res_net):
|
||||
super(Critic, self).__init__()
|
||||
self.fc1 = nn.Linear(64, 64)
|
||||
self.fc2 = nn.Linear(64, 64)
|
||||
self.state_value = nn.Linear(64, 1)
|
||||
self.pos_emb = nn.Embedding(1400, 64)
|
||||
self.cnn = cnn
|
||||
self.gcn = gcn
|
||||
def forward(self, x, graph = None, cnn_res = None, gcn_res = None, graph_node = None):
|
||||
x1 = F.relu(self.fc1(self.pos_emb(x[:, 0].long())))
|
||||
x2 = F.relu(self.fc2(x1))
|
||||
value = self.state_value(x2)
|
||||
return value
|
||||
|
||||
|
||||
class PPO():
|
||||
clip_param = 0.2
|
||||
max_grad_norm = 0.5
|
||||
ppo_epoch = 10
|
||||
if placed_num_macro:
|
||||
buffer_capacity = 10 * (placed_num_macro)
|
||||
else:
|
||||
buffer_capacity = 5120
|
||||
batch_size = args.batch_size
|
||||
print("batch_size = {}".format(batch_size))
|
||||
|
||||
def __init__(self):
|
||||
super(PPO, self).__init__()
|
||||
self.gcn = None
|
||||
self.resnet = torchvision.models.resnet18(pretrained=True)
|
||||
self.cnn = MyCNN().to(device)
|
||||
self.cnn_coarse = MyCNNCoarse(self.resnet).to(device)
|
||||
self.actor_net = Actor(cnn = self.cnn, gcn = self.gcn, cnn_coarse = self.cnn_coarse).float().to(device)
|
||||
self.critic_net = Critic(cnn = self.cnn, gcn = self.gcn, cnn_coarse = None, res_net = self.resnet).float().to(device)
|
||||
self.buffer = []
|
||||
self.counter = 0
|
||||
self.training_step = 0
|
||||
self.actor_optimizer = optim.Adam(self.actor_net.parameters(), args.lr)
|
||||
self.critic_net_optimizer = optim.Adam(self.critic_net.parameters(), args.lr)
|
||||
|
||||
def load_param(self, path):
|
||||
checkpoint = torch.load(path, map_location=torch.device(device))
|
||||
self.actor_net.load_state_dict(checkpoint['actor_net_dict'])
|
||||
self.critic_net.load_state_dict(checkpoint['critic_net_dict'])
|
||||
|
||||
def select_action(self, state):
|
||||
state = torch.from_numpy(state).float().to(device).unsqueeze(0)
|
||||
with torch.no_grad():
|
||||
action_probs, _, _ = self.actor_net(state)
|
||||
dist = Categorical(action_probs)
|
||||
action = dist.sample()
|
||||
action_log_prob = dist.log_prob(action)
|
||||
return action.item(), action_log_prob.item()
|
||||
|
||||
def get_value(self, state):
|
||||
state = torch.from_numpy(state)
|
||||
with torch.no_grad():
|
||||
value = self.critic_net(state)
|
||||
return value.item()
|
||||
|
||||
def save_param(self, running_reward):
|
||||
strftime = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
if not os.path.exists("save_models"):
|
||||
os.mkdir("save_models")
|
||||
torch.save({"actor_net_dict": self.actor_net.state_dict(),
|
||||
"critic_net_dict": self.critic_net.state_dict()},
|
||||
"./save_models/net_dict-{}-{}-".format(benchmark, placed_num_macro)+strftime+"{}".format(int(running_reward))+".pkl")
|
||||
|
||||
def store_transition(self, transition):
|
||||
self.buffer.append(transition)
|
||||
self.counter+=1
|
||||
return self.counter % self.buffer_capacity == 0
|
||||
|
||||
def update(self):
|
||||
state = torch.tensor(np.array([t.state for t in self.buffer]), dtype=torch.float)
|
||||
action = torch.tensor(np.array([t.action for t in self.buffer]), dtype=torch.float).view(-1, 1).to(device)
|
||||
reward = torch.tensor(np.array([t.reward for t in self.buffer]), dtype=torch.float).view(-1, 1).to(device)
|
||||
old_action_log_prob = torch.tensor(np.array([t.a_log_prob for t in self.buffer]), dtype=torch.float).view(-1, 1).to(device)
|
||||
del self.buffer[:]
|
||||
target_list = []
|
||||
target = 0
|
||||
for i in range(reward.shape[0]-1, -1, -1):
|
||||
if state[i, 0] >= placed_num_macro - 1:
|
||||
target = 0
|
||||
r = reward[i, 0].item()
|
||||
target = r + args.gamma * target
|
||||
target_list.append(target)
|
||||
target_list.reverse()
|
||||
target_v_all = torch.tensor(np.array([t for t in target_list]), dtype=torch.float).view(-1, 1).to(device)
|
||||
|
||||
for _ in range(self.ppo_epoch): # iteration ppo_epoch
|
||||
for index in tqdm(BatchSampler(SubsetRandomSampler(range(self.buffer_capacity)), self.batch_size, True),
|
||||
disable = args.disable_tqdm):
|
||||
self.training_step +=1
|
||||
|
||||
action_probs, _, _ = self.actor_net(state[index].to(device))
|
||||
dist = Categorical(action_probs)
|
||||
action_log_prob = dist.log_prob(action[index].squeeze())
|
||||
ratio = torch.exp(action_log_prob - old_action_log_prob[index].squeeze())
|
||||
target_v = target_v_all[index]
|
||||
critic_net_output = self.critic_net(state[index].to(device))
|
||||
advantage = (target_v - critic_net_output).detach()
|
||||
|
||||
L1 = ratio * advantage.squeeze()
|
||||
L2 = torch.clamp(ratio, 1-self.clip_param, 1+self.clip_param) * advantage.squeeze()
|
||||
action_loss = -torch.min(L1, L2).mean() # MAX->MIN desent
|
||||
|
||||
self.actor_optimizer.zero_grad()
|
||||
action_loss.backward()
|
||||
nn.utils.clip_grad_norm_(self.actor_net.parameters(), self.max_grad_norm)
|
||||
self.actor_optimizer.step()
|
||||
|
||||
value_loss = F.smooth_l1_loss(self.critic_net(state[index].to(device)), target_v)
|
||||
self.critic_net_optimizer.zero_grad()
|
||||
value_loss.backward()
|
||||
nn.utils.clip_grad_norm_(self.critic_net.parameters(), self.max_grad_norm)
|
||||
self.critic_net_optimizer.step()
|
||||
|
||||
writer.add_scalar('action_loss', action_loss, self.training_step)
|
||||
writer.add_scalar('value_loss', value_loss, self.training_step)
|
||||
|
||||
|
||||
def save_placement(file_path, node_pos, ratio):
|
||||
fwrite = open(file_path, 'w')
|
||||
node_place = {}
|
||||
for node_name in node_pos:
|
||||
|
||||
x, y,_ , _ = node_pos[node_name]
|
||||
x = round(x * ratio + ratio)
|
||||
y = round(y * ratio + ratio)
|
||||
node_place[node_name] = (x, y)
|
||||
print("len node_place", len(node_place))
|
||||
for node_name in placedb.node_info:
|
||||
if node_name not in node_place:
|
||||
continue
|
||||
x, y = node_place[node_name]
|
||||
fwrite.write('{}\t{}\t{}\t:\tN /FIXED\n'.format(node_name, x, y))
|
||||
print(".pl has been saved to {}.".format(file_path))
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
agent = PPO()
|
||||
strftime = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
|
||||
training_records = []
|
||||
running_reward = -1000000
|
||||
|
||||
|
||||
log_file_name = "logs/log_"+ benchmark + "_" + strftime + "_seed_"+ str(args.seed) + "_pnm_" + str(args.pnm) + ".csv"
|
||||
if not os.path.exists("logs"):
|
||||
os.mkdir("logs")
|
||||
fwrite = open(log_file_name, "w")
|
||||
load_model_path = None
|
||||
|
||||
if load_model_path:
|
||||
agent.load_param(load_model_path)
|
||||
|
||||
best_reward = running_reward
|
||||
if args.is_test:
|
||||
torch.inference_mode()
|
||||
|
||||
for i_epoch in range(100000):
|
||||
score = 0
|
||||
raw_score = 0
|
||||
start = time.time()
|
||||
state = env.reset()
|
||||
|
||||
done = False
|
||||
while done is False:
|
||||
state_tmp = state.copy()
|
||||
action, action_log_prob = agent.select_action(state)
|
||||
|
||||
next_state, reward, done, info = env.step(action)
|
||||
assert next_state.shape == (num_state, )
|
||||
reward_intrinsic = 0
|
||||
if not args.is_test:
|
||||
trans = Transition(state_tmp, action, reward / 200.0, action_log_prob, next_state, reward_intrinsic)
|
||||
if not args.is_test and agent.store_transition(trans):
|
||||
assert done == True
|
||||
agent.update()
|
||||
score += reward
|
||||
raw_score += info["raw_reward"]
|
||||
state = next_state
|
||||
end = time.time()
|
||||
|
||||
if i_epoch == 0:
|
||||
running_reward = score
|
||||
running_reward = running_reward * 0.9 + score * 0.1
|
||||
print("score = {}, raw_score = {}".format(score, raw_score))
|
||||
|
||||
if running_reward > best_reward * 0.975:
|
||||
best_reward = running_reward
|
||||
if i_epoch >= 10:
|
||||
agent.save_param(running_reward)
|
||||
if args.save_fig:
|
||||
strftime_now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
if not os.path.exists("figures"):
|
||||
os.mkdir("figures")
|
||||
env.save_fig("./figures/{}{}.png".format(strftime_now,int(raw_score)))
|
||||
print("save_figure: figures/{}{}.png".format(strftime_now,int(raw_score)))
|
||||
try:
|
||||
print("start try")
|
||||
# cost is the routing estimation based on the MST algorithm
|
||||
hpwl, cost = comp_res(placedb, env.node_pos, env.ratio)
|
||||
print("hpwl = {:.2f}\tcost = {:.2f}".format(hpwl, cost))
|
||||
except:
|
||||
assert False
|
||||
|
||||
if args.is_test:
|
||||
print("save node_pos")
|
||||
hpwl, cost = comp_res(placedb, env.node_pos, env.ratio)
|
||||
print("hpwl = {:.2f}\tcost = {:.2f}".format(hpwl, cost))
|
||||
print("time = {}s".format(end-start))
|
||||
pl_file_path = "{}-{}-{}.pl".format(benchmark, int(hpwl), time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) )
|
||||
save_placement(pl_file_path, env.node_pos, env.ratio)
|
||||
strftime_now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
pl_path = 'gg_place_new/{}-{}-{}-{}.pl'.format(benchmark, strftime_now, int(hpwl), int(cost))
|
||||
fwrite_pl = open(pl_path, 'w')
|
||||
for node_name in env.node_pos:
|
||||
if node_name == "V":
|
||||
continue
|
||||
x, y, size_x, size_y = env.node_pos[node_name]
|
||||
x = x * env.ratio + placedb.node_info[node_name]['x'] /2.0
|
||||
y = y * env.ratio + placedb.node_info[node_name]['y'] /2.0
|
||||
fwrite_pl.write("{}\t{:.4f}\t{:.4f}\n".format(node_name, x, y))
|
||||
fwrite_pl.close()
|
||||
strftime_now = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
|
||||
env.save_fig("./figures/{}-{}-{}-{}.png".format(benchmark, strftime_now, int(hpwl), int(cost)))
|
||||
|
||||
training_records.append(TrainingRecord(i_epoch, running_reward))
|
||||
if i_epoch % 1 ==0:
|
||||
print("Epoch {}, Moving average score is: {:.2f} ".format(i_epoch, running_reward))
|
||||
fwrite.write("{},{},{:.2f},{}\n".format(i_epoch, score, running_reward, agent.training_step))
|
||||
fwrite.flush()
|
||||
writer.add_scalar('reward', running_reward, i_epoch)
|
||||
if running_reward > -100:
|
||||
print("Solved! Moving average score is now {}!".format(running_reward))
|
||||
env.close()
|
||||
agent.save_param()
|
||||
break
|
||||
if i_epoch % 100 == 0:
|
||||
if placed_num_macro is None:
|
||||
env.write_gl_file("./gl/{}{}.gl".format(strftime, int(score)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@ -1 +0,0 @@
|
||||
RowBasedPlacement : adaptec1.nodes adaptec1.nets adaptec1.wts adaptec1.pl adaptec1.scl
|
||||
1165202
maskplace/adaptec1/adaptec1.nets
1165202
maskplace/adaptec1/adaptec1.nets
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +0,0 @@
|
||||
UCLA wts 1.0
|
||||
# Created : Jan 6 2005
|
||||
# User : Gi-Joon Nam & Mehmet Yildiz at IBM Austin Research({gnam, mcan}@us.ibm.com)
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package tensorflow;
|
||||
|
||||
// import "tensorflow/core/framework/function.proto";
|
||||
// import "tensorflow/core/framework/node_def.proto";
|
||||
// import "tensorflow/core/framework/versions.proto";
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option java_outer_classname = "GraphProtos";
|
||||
option java_multiple_files = true;
|
||||
option java_package = "org.tensorflow.framework";
|
||||
option go_package = "github.com/tensorflow/tensorflow/tensorflow/go/core/framework/graph_go_proto";
|
||||
|
||||
// Represents the graph of operations
|
||||
message GraphDef {
|
||||
repeated NodeDef node = 1;
|
||||
|
||||
// Compatibility versions of the graph. See core/public/version.h for version
|
||||
// history. The GraphDef version is distinct from the TensorFlow version, and
|
||||
// each release of TensorFlow will support a range of GraphDef versions.
|
||||
VersionDef versions = 4;
|
||||
|
||||
// Deprecated single version field; use versions above instead. Since all
|
||||
// GraphDef changes before "versions" was introduced were forward
|
||||
// compatible, this field is entirely ignored.
|
||||
int32 version = 3 [deprecated = true];
|
||||
|
||||
// "library" provides user-defined functions.
|
||||
//
|
||||
// Naming:
|
||||
// * library.function.name are in a flat namespace.
|
||||
// NOTE: We may need to change it to be hierarchical to support
|
||||
// different orgs. E.g.,
|
||||
// { "/google/nn", { ... }},
|
||||
// { "/google/vision", { ... }}
|
||||
// { "/org_foo/module_bar", { ... }}
|
||||
// map<string, FunctionDefLib> named_lib;
|
||||
// * If node[i].op is the name of one function in "library",
|
||||
// node[i] is deemed as a function call. Otherwise, node[i].op
|
||||
// must be a primitive operation supported by the runtime.
|
||||
//
|
||||
//
|
||||
// Function call semantics:
|
||||
//
|
||||
// * The callee may start execution as soon as some of its inputs
|
||||
// are ready. The caller may want to use Tuple() mechanism to
|
||||
// ensure all inputs are ready in the same time.
|
||||
//
|
||||
// * The consumer of return values may start executing as soon as
|
||||
// the return values the consumer depends on are ready. The
|
||||
// consumer may want to use Tuple() mechanism to ensure the
|
||||
// consumer does not start until all return values of the callee
|
||||
// function are ready.
|
||||
FunctionDefLibrary library = 2;
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message AttrValue {
|
||||
// LINT.IfChange
|
||||
message ListValue {
|
||||
repeated bytes s = 2; // "list(string)"
|
||||
repeated int64 i = 3 [packed = true]; // "list(int)"
|
||||
repeated float f = 4 [packed = true]; // "list(float)"
|
||||
repeated bool b = 5 [packed = true]; // "list(bool)"
|
||||
// repeated DataType type = 6 [packed = true]; // "list(type)"
|
||||
// repeated TensorShapeProto shape = 7; // "list(shape)"
|
||||
// repeated TensorProto tensor = 8; // "list(tensor)"
|
||||
repeated NameAttrList func = 9; // "list(attr)"
|
||||
}
|
||||
// LINT.ThenChange(https://www.tensorflow.org/code/tensorflow/c/c_api.cc)
|
||||
|
||||
oneof value {
|
||||
bytes s = 2; // "string"
|
||||
int64 i = 3; // "int"
|
||||
float f = 4; // "float"
|
||||
bool b = 5; // "bool"
|
||||
DataType type = 6; // "type"
|
||||
// TensorShapeProto shape = 7; // "shape"
|
||||
// TensorProto tensor = 8; // "tensor"
|
||||
// ListValue list = 1; // any "list(...)"
|
||||
|
||||
// "func" represents a function. func.name is a function's name or
|
||||
// a primitive op's name. func.attr.first is the name of an attr
|
||||
// defined for that function. func.attr.second is the value for
|
||||
// that attr in the instantiation.
|
||||
NameAttrList func = 10;
|
||||
|
||||
// This is a placeholder only used in nodes defined inside a
|
||||
// function. It indicates the attr value will be supplied when
|
||||
// the function is instantiated. For example, let us suppose a
|
||||
// node "N" in function "FN". "N" has an attr "A" with value
|
||||
// placeholder = "foo". When FN is instantiated with attr "foo"
|
||||
// set to "bar", the instantiated node N's attr A will have been
|
||||
// given the value "bar".
|
||||
string placeholder = 9;
|
||||
}
|
||||
}
|
||||
|
||||
// A list of attr names and their values. The whole list is attached
|
||||
// with a string name. E.g., MatMul[T=float].
|
||||
message NameAttrList {
|
||||
string name = 1;
|
||||
map<string, AttrValue> attr = 2;
|
||||
}
|
||||
message NodeDef {
|
||||
string name = 1;
|
||||
repeated string input = 2;
|
||||
map<string, AttrValue> attr = 5;
|
||||
}
|
||||
message GraphDef {
|
||||
repeated NodeDef node = 1;
|
||||
}
|
||||
@ -1,434 +0,0 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: laiyao.proto
|
||||
|
||||
import sys
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='laiyao.proto',
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=None,
|
||||
serialized_pb=_b('\n\x0claiyao.proto\"\xe0\x01\n\tAttrValue\x12\x0b\n\x01s\x18\x02 \x01(\x0cH\x00\x12\x0b\n\x01i\x18\x03 \x01(\x03H\x00\x12\x0b\n\x01\x66\x18\x04 \x01(\x02H\x00\x12\x0b\n\x01\x62\x18\x05 \x01(\x08H\x00\x12\x1d\n\x04\x66unc\x18\n \x01(\x0b\x32\r.NameAttrListH\x00\x12\x15\n\x0bplaceholder\x18\t \x01(\tH\x00\x1a`\n\tListValue\x12\t\n\x01s\x18\x02 \x03(\x0c\x12\r\n\x01i\x18\x03 \x03(\x03\x42\x02\x10\x01\x12\r\n\x01\x66\x18\x04 \x03(\x02\x42\x02\x10\x01\x12\r\n\x01\x62\x18\x05 \x03(\x08\x42\x02\x10\x01\x12\x1b\n\x04\x66unc\x18\t \x03(\x0b\x32\r.NameAttrListB\x07\n\x05value\"|\n\x0cNameAttrList\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x04\x61ttr\x18\x02 \x03(\x0b\x32\x17.NameAttrList.AttrEntry\x1a\x37\n\tAttrEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.AttrValue:\x02\x38\x01\"\x81\x01\n\x07NodeDef\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05input\x18\x02 \x03(\t\x12 \n\x04\x61ttr\x18\x05 \x03(\x0b\x32\x12.NodeDef.AttrEntry\x1a\x37\n\tAttrEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.AttrValue:\x02\x38\x01\"\"\n\x08GraphDef\x12\x16\n\x04node\x18\x01 \x03(\x0b\x32\x08.NodeDefb\x06proto3')
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
_ATTRVALUE_LISTVALUE = _descriptor.Descriptor(
|
||||
name='ListValue',
|
||||
full_name='AttrValue.ListValue',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='s', full_name='AttrValue.ListValue.s', index=0,
|
||||
number=2, type=12, cpp_type=9, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='i', full_name='AttrValue.ListValue.i', index=1,
|
||||
number=3, type=3, cpp_type=2, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=_b('\020\001'), file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='f', full_name='AttrValue.ListValue.f', index=2,
|
||||
number=4, type=2, cpp_type=6, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=_b('\020\001'), file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='b', full_name='AttrValue.ListValue.b', index=3,
|
||||
number=5, type=8, cpp_type=7, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=_b('\020\001'), file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='func', full_name='AttrValue.ListValue.func', index=4,
|
||||
number=9, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=136,
|
||||
serialized_end=232,
|
||||
)
|
||||
|
||||
_ATTRVALUE = _descriptor.Descriptor(
|
||||
name='AttrValue',
|
||||
full_name='AttrValue',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='s', full_name='AttrValue.s', index=0,
|
||||
number=2, type=12, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b(""),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='i', full_name='AttrValue.i', index=1,
|
||||
number=3, type=3, cpp_type=2, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='f', full_name='AttrValue.f', index=2,
|
||||
number=4, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=float(0),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='b', full_name='AttrValue.b', index=3,
|
||||
number=5, type=8, cpp_type=7, label=1,
|
||||
has_default_value=False, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='func', full_name='AttrValue.func', index=4,
|
||||
number=10, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='placeholder', full_name='AttrValue.placeholder', index=5,
|
||||
number=9, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[_ATTRVALUE_LISTVALUE, ],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
_descriptor.OneofDescriptor(
|
||||
name='value', full_name='AttrValue.value',
|
||||
index=0, containing_type=None, fields=[]),
|
||||
],
|
||||
serialized_start=17,
|
||||
serialized_end=241,
|
||||
)
|
||||
|
||||
|
||||
_NAMEATTRLIST_ATTRENTRY = _descriptor.Descriptor(
|
||||
name='AttrEntry',
|
||||
full_name='NameAttrList.AttrEntry',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='key', full_name='NameAttrList.AttrEntry.key', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='NameAttrList.AttrEntry.value', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=_b('8\001'),
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=312,
|
||||
serialized_end=367,
|
||||
)
|
||||
|
||||
_NAMEATTRLIST = _descriptor.Descriptor(
|
||||
name='NameAttrList',
|
||||
full_name='NameAttrList',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='name', full_name='NameAttrList.name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='attr', full_name='NameAttrList.attr', index=1,
|
||||
number=2, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[_NAMEATTRLIST_ATTRENTRY, ],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=243,
|
||||
serialized_end=367,
|
||||
)
|
||||
|
||||
|
||||
_NODEDEF_ATTRENTRY = _descriptor.Descriptor(
|
||||
name='AttrEntry',
|
||||
full_name='NodeDef.AttrEntry',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='key', full_name='NodeDef.AttrEntry.key', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='NodeDef.AttrEntry.value', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=_b('8\001'),
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=312,
|
||||
serialized_end=367,
|
||||
)
|
||||
|
||||
_NODEDEF = _descriptor.Descriptor(
|
||||
name='NodeDef',
|
||||
full_name='NodeDef',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='name', full_name='NodeDef.name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='input', full_name='NodeDef.input', index=1,
|
||||
number=2, type=9, cpp_type=9, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='attr', full_name='NodeDef.attr', index=2,
|
||||
number=5, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[_NODEDEF_ATTRENTRY, ],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=370,
|
||||
serialized_end=499,
|
||||
)
|
||||
|
||||
|
||||
_GRAPHDEF = _descriptor.Descriptor(
|
||||
name='GraphDef',
|
||||
full_name='GraphDef',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='node', full_name='GraphDef.node', index=0,
|
||||
number=1, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=501,
|
||||
serialized_end=535,
|
||||
)
|
||||
|
||||
_ATTRVALUE_LISTVALUE.fields_by_name['func'].message_type = _NAMEATTRLIST
|
||||
_ATTRVALUE_LISTVALUE.containing_type = _ATTRVALUE
|
||||
_ATTRVALUE.fields_by_name['func'].message_type = _NAMEATTRLIST
|
||||
_ATTRVALUE.oneofs_by_name['value'].fields.append(
|
||||
_ATTRVALUE.fields_by_name['s'])
|
||||
_ATTRVALUE.fields_by_name['s'].containing_oneof = _ATTRVALUE.oneofs_by_name['value']
|
||||
_ATTRVALUE.oneofs_by_name['value'].fields.append(
|
||||
_ATTRVALUE.fields_by_name['i'])
|
||||
_ATTRVALUE.fields_by_name['i'].containing_oneof = _ATTRVALUE.oneofs_by_name['value']
|
||||
_ATTRVALUE.oneofs_by_name['value'].fields.append(
|
||||
_ATTRVALUE.fields_by_name['f'])
|
||||
_ATTRVALUE.fields_by_name['f'].containing_oneof = _ATTRVALUE.oneofs_by_name['value']
|
||||
_ATTRVALUE.oneofs_by_name['value'].fields.append(
|
||||
_ATTRVALUE.fields_by_name['b'])
|
||||
_ATTRVALUE.fields_by_name['b'].containing_oneof = _ATTRVALUE.oneofs_by_name['value']
|
||||
_ATTRVALUE.oneofs_by_name['value'].fields.append(
|
||||
_ATTRVALUE.fields_by_name['func'])
|
||||
_ATTRVALUE.fields_by_name['func'].containing_oneof = _ATTRVALUE.oneofs_by_name['value']
|
||||
_ATTRVALUE.oneofs_by_name['value'].fields.append(
|
||||
_ATTRVALUE.fields_by_name['placeholder'])
|
||||
_ATTRVALUE.fields_by_name['placeholder'].containing_oneof = _ATTRVALUE.oneofs_by_name['value']
|
||||
_NAMEATTRLIST_ATTRENTRY.fields_by_name['value'].message_type = _ATTRVALUE
|
||||
_NAMEATTRLIST_ATTRENTRY.containing_type = _NAMEATTRLIST
|
||||
_NAMEATTRLIST.fields_by_name['attr'].message_type = _NAMEATTRLIST_ATTRENTRY
|
||||
_NODEDEF_ATTRENTRY.fields_by_name['value'].message_type = _ATTRVALUE
|
||||
_NODEDEF_ATTRENTRY.containing_type = _NODEDEF
|
||||
_NODEDEF.fields_by_name['attr'].message_type = _NODEDEF_ATTRENTRY
|
||||
_GRAPHDEF.fields_by_name['node'].message_type = _NODEDEF
|
||||
DESCRIPTOR.message_types_by_name['AttrValue'] = _ATTRVALUE
|
||||
DESCRIPTOR.message_types_by_name['NameAttrList'] = _NAMEATTRLIST
|
||||
DESCRIPTOR.message_types_by_name['NodeDef'] = _NODEDEF
|
||||
DESCRIPTOR.message_types_by_name['GraphDef'] = _GRAPHDEF
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
AttrValue = _reflection.GeneratedProtocolMessageType('AttrValue', (_message.Message,), dict(
|
||||
|
||||
ListValue = _reflection.GeneratedProtocolMessageType('ListValue', (_message.Message,), dict(
|
||||
DESCRIPTOR = _ATTRVALUE_LISTVALUE,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:AttrValue.ListValue)
|
||||
))
|
||||
,
|
||||
DESCRIPTOR = _ATTRVALUE,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:AttrValue)
|
||||
))
|
||||
_sym_db.RegisterMessage(AttrValue)
|
||||
_sym_db.RegisterMessage(AttrValue.ListValue)
|
||||
|
||||
NameAttrList = _reflection.GeneratedProtocolMessageType('NameAttrList', (_message.Message,), dict(
|
||||
|
||||
AttrEntry = _reflection.GeneratedProtocolMessageType('AttrEntry', (_message.Message,), dict(
|
||||
DESCRIPTOR = _NAMEATTRLIST_ATTRENTRY,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:NameAttrList.AttrEntry)
|
||||
))
|
||||
,
|
||||
DESCRIPTOR = _NAMEATTRLIST,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:NameAttrList)
|
||||
))
|
||||
_sym_db.RegisterMessage(NameAttrList)
|
||||
_sym_db.RegisterMessage(NameAttrList.AttrEntry)
|
||||
|
||||
NodeDef = _reflection.GeneratedProtocolMessageType('NodeDef', (_message.Message,), dict(
|
||||
|
||||
AttrEntry = _reflection.GeneratedProtocolMessageType('AttrEntry', (_message.Message,), dict(
|
||||
DESCRIPTOR = _NODEDEF_ATTRENTRY,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:NodeDef.AttrEntry)
|
||||
))
|
||||
,
|
||||
DESCRIPTOR = _NODEDEF,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:NodeDef)
|
||||
))
|
||||
_sym_db.RegisterMessage(NodeDef)
|
||||
_sym_db.RegisterMessage(NodeDef.AttrEntry)
|
||||
|
||||
GraphDef = _reflection.GeneratedProtocolMessageType('GraphDef', (_message.Message,), dict(
|
||||
DESCRIPTOR = _GRAPHDEF,
|
||||
__module__ = 'laiyao_pb2'
|
||||
# @@protoc_insertion_point(class_scope:GraphDef)
|
||||
))
|
||||
_sym_db.RegisterMessage(GraphDef)
|
||||
|
||||
|
||||
_ATTRVALUE_LISTVALUE.fields_by_name['i']._options = None
|
||||
_ATTRVALUE_LISTVALUE.fields_by_name['f']._options = None
|
||||
_ATTRVALUE_LISTVALUE.fields_by_name['b']._options = None
|
||||
_NAMEATTRLIST_ATTRENTRY._options = None
|
||||
_NODEDEF_ATTRENTRY._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
||||
# import tensorflow as tf
|
||||
|
||||
from google.protobuf import text_format
|
||||
|
||||
import laiyao_pb2
|
||||
|
||||
|
||||
def load_pbtxt_file(path):
|
||||
"""Read .pbtxt file.
|
||||
|
||||
Args:
|
||||
path: Path to StringIntLabelMap proto text file (.pbtxt file).
|
||||
|
||||
Returns:
|
||||
A StringIntLabelMapProto.
|
||||
|
||||
Raises:
|
||||
ValueError: If path is not exist.
|
||||
"""
|
||||
# if not tf.gfile.Exists(path):
|
||||
# raise ValueError('`path` is not exist.')
|
||||
|
||||
# with tf.gfile.GFile(path, 'r') as fid:
|
||||
# pbtxt_string = fid.read()
|
||||
# pbtxt = laiyao_pb2.StudentInfo()
|
||||
# try:
|
||||
# text_format.Merge(pbtxt_string, pbtxt)
|
||||
# except text_format.ParseError:
|
||||
# pbtxt.ParseFromString(pbtxt_string)
|
||||
fid = open(path, 'r')
|
||||
pbtxt_string = fid.read()
|
||||
pbtxt = laiyao_pb2.GraphDef()
|
||||
try:
|
||||
text_format.Merge(pbtxt_string, pbtxt)
|
||||
except text_format.ParseError:
|
||||
pbtxt.ParseFromString(pbtxt_string)
|
||||
return pbtxt
|
||||
|
||||
|
||||
def get_netlist_info_dict(path):
|
||||
"""Reads a .pbtxt file and returns a dictionary.
|
||||
|
||||
Args:
|
||||
path: Path to StringIntLabelMap proto text file.
|
||||
|
||||
Returns:
|
||||
A dictionary mapping class names to indices.
|
||||
"""
|
||||
pbtxt = load_pbtxt_file(path)
|
||||
|
||||
# result_dict = {}
|
||||
# for node in pbtxt.node:
|
||||
# print("node_name: {}".format(node.name))
|
||||
return pbtxt
|
||||
|
||||
|
||||
def main():
|
||||
get_netlist_info_dict('netlist.pb.txt')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,51 +0,0 @@
|
||||
from place_db import PlaceDB
|
||||
from prim import prim_real
|
||||
import pickle
|
||||
|
||||
def comp_res(placedb, node_pos, ratio):
|
||||
|
||||
hpwl = 0.0
|
||||
cost = 0.0
|
||||
for net_name in placedb.net_info:
|
||||
max_x = 0.0
|
||||
min_x = placedb.max_height * 1.1
|
||||
max_y = 0.0
|
||||
min_y = placedb.max_height * 1.1
|
||||
for node_name in placedb.net_info[net_name]["nodes"]:
|
||||
if node_name not in node_pos:
|
||||
continue
|
||||
h = placedb.node_info[node_name]['x']
|
||||
w = placedb.node_info[node_name]['y']
|
||||
pin_x = node_pos[node_name][0] * ratio + h / 2.0 + placedb.net_info[net_name]["nodes"][node_name]["x_offset"]
|
||||
pin_y = node_pos[node_name][1] * ratio + w / 2.0 + placedb.net_info[net_name]["nodes"][node_name]["y_offset"]
|
||||
max_x = max(pin_x, max_x)
|
||||
min_x = min(pin_x, min_x)
|
||||
max_y = max(pin_y, max_y)
|
||||
min_y = min(pin_y, min_y)
|
||||
for port_name in placedb.net_info[net_name]["ports"]:
|
||||
h = placedb.port_info[port_name]['x']
|
||||
w = placedb.port_info[port_name]['y']
|
||||
pin_x = h
|
||||
pin_y = w
|
||||
max_x = max(pin_x, max_x)
|
||||
min_x = min(pin_x, min_x)
|
||||
max_y = max(pin_y, max_y)
|
||||
min_y = min(pin_y, min_y)
|
||||
if min_x <= placedb.max_height:
|
||||
hpwl_tmp = (max_x - min_x) + (max_y - min_y)
|
||||
else:
|
||||
hpwl_tmp = 0
|
||||
if "weight" in placedb.net_info[net_name]:
|
||||
hpwl_tmp *= placedb.net_info[net_name]["weight"]
|
||||
hpwl += hpwl_tmp
|
||||
net_node_set = set.union(set(placedb.net_info[net_name]["nodes"]),
|
||||
set(placedb.net_info[net_name]["ports"]))
|
||||
for net_node in list(net_node_set):
|
||||
if net_node not in node_pos and net_node not in placedb.port_info:
|
||||
net_node_set.discard(net_node)
|
||||
prim_cost = prim_real(net_node_set, node_pos, placedb.net_info[net_name]["nodes"], ratio, placedb.node_info, placedb.port_info)
|
||||
if "weight" in placedb.net_info[net_name]:
|
||||
prim_cost *= placedb.net_info[net_name]["weight"]
|
||||
assert hpwl_tmp <= prim_cost +1e-5
|
||||
cost += prim_cost
|
||||
return hpwl, cost
|
||||
Binary file not shown.
@ -1,257 +0,0 @@
|
||||
import numpy as np
|
||||
import os
|
||||
import random
|
||||
from operator import itemgetter
|
||||
from itertools import combinations
|
||||
from place_db_proto import get_node_info
|
||||
from place_db_proto import get_net_info
|
||||
import sys
|
||||
import pickle
|
||||
sys.path.append('ariane')
|
||||
from ariane.read_info import get_netlist_info_dict
|
||||
# Macro dict (macro id -> name, x, y)
|
||||
|
||||
def read_node_file(fopen, benchmark):
|
||||
node_info = {}
|
||||
node_info_raw_id_name ={}
|
||||
node_cnt = 0
|
||||
for line in fopen.readlines():
|
||||
if not line.startswith("\t"):
|
||||
continue
|
||||
line = line.strip().split()
|
||||
if line[-1] != "terminal":
|
||||
continue
|
||||
node_name = line[0]
|
||||
x = int(line[1])
|
||||
y = int(line[2])
|
||||
node_info[node_name] = {"id": node_cnt, "x": x , "y": y }
|
||||
node_info_raw_id_name[node_cnt] = node_name
|
||||
node_cnt += 1
|
||||
print("len node_info", len(node_info))
|
||||
return node_info, node_info_raw_id_name
|
||||
|
||||
|
||||
def read_net_file(fopen, node_info):
|
||||
net_info = {}
|
||||
net_name = None
|
||||
net_cnt = 0
|
||||
for line in fopen.readlines():
|
||||
if not line.startswith("\t") and not line.startswith("NetDegree"):
|
||||
continue
|
||||
line = line.strip().split()
|
||||
if line[0] == "NetDegree":
|
||||
net_name = line[-1]
|
||||
else:
|
||||
node_name = line[0]
|
||||
if node_name in node_info:
|
||||
if not net_name in net_info:
|
||||
net_info[net_name] = {}
|
||||
net_info[net_name]["nodes"] = {}
|
||||
net_info[net_name]["ports"] = {}
|
||||
if not node_name in net_info[net_name]["nodes"]:
|
||||
x_offset = float(line[-2])
|
||||
y_offset = float(line[-1])
|
||||
net_info[net_name]["nodes"][node_name] = {}
|
||||
net_info[net_name]["nodes"][node_name] = {"x_offset": x_offset, "y_offset": y_offset}
|
||||
for net_name in list(net_info.keys()):
|
||||
if len(net_info[net_name]["nodes"]) <= 1:
|
||||
net_info.pop(net_name)
|
||||
for net_name in net_info:
|
||||
net_info[net_name]['id'] = net_cnt
|
||||
net_cnt += 1
|
||||
print("adjust net size = {}".format(len(net_info)))
|
||||
return net_info
|
||||
|
||||
|
||||
def get_comp_hpwl_dict(node_info, net_info):
|
||||
comp_hpwl_dict = {}
|
||||
for net_name in net_info:
|
||||
max_idx = 0
|
||||
for node_name in net_info[net_name]["nodes"]:
|
||||
max_idx = max(max_idx, node_info[node_name]["id"])
|
||||
if not max_idx in comp_hpwl_dict:
|
||||
comp_hpwl_dict[max_idx] = []
|
||||
comp_hpwl_dict[max_idx].append(net_name)
|
||||
return comp_hpwl_dict
|
||||
|
||||
|
||||
def get_node_to_net_dict(node_info, net_info):
|
||||
node_to_net_dict = {}
|
||||
for node_name in node_info:
|
||||
node_to_net_dict[node_name] = set()
|
||||
for net_name in net_info:
|
||||
for node_name in net_info[net_name]["nodes"]:
|
||||
node_to_net_dict[node_name].add(net_name)
|
||||
return node_to_net_dict
|
||||
|
||||
|
||||
def get_port_to_net_dict(port_info, net_info):
|
||||
port_to_net_dict = {}
|
||||
for port_name in port_info:
|
||||
port_to_net_dict[port_name] = set()
|
||||
for net_name in net_info:
|
||||
for port_name in net_info[net_name]["ports"]:
|
||||
port_to_net_dict[port_name].add(net_name)
|
||||
return port_to_net_dict
|
||||
|
||||
def read_pl_file(fopen, node_info):
|
||||
max_height = 0
|
||||
max_width = 0
|
||||
for line in fopen.readlines():
|
||||
if not line.startswith('o'):
|
||||
continue
|
||||
line = line.strip().split()
|
||||
node_name = line[0]
|
||||
if not node_name in node_info:
|
||||
continue
|
||||
place_x = int(line[1])
|
||||
place_y = int(line[2])
|
||||
max_height = max(max_height, node_info[node_name]["x"] + place_x)
|
||||
max_width = max(max_width, node_info[node_name]["y"] + place_y)
|
||||
node_info[node_name]["raw_x"] = place_x
|
||||
node_info[node_name]["raw_y"] = place_y
|
||||
return max(max_height, max_width), max(max_height, max_width)
|
||||
|
||||
|
||||
def get_node_id_to_name(node_info, node_to_net_dict):
|
||||
node_name_and_num = []
|
||||
for node_name in node_info:
|
||||
node_name_and_num.append((node_name, len(node_to_net_dict[node_name])))
|
||||
node_name_and_num = sorted(node_name_and_num, key=itemgetter(1), reverse = True)
|
||||
print("node_name_and_num", node_name_and_num)
|
||||
node_id_to_name = [node_name for node_name, _ in node_name_and_num]
|
||||
for i, node_name in enumerate(node_id_to_name):
|
||||
node_info[node_name]["id"] = i
|
||||
return node_id_to_name
|
||||
|
||||
|
||||
def get_node_id_to_name_topology(node_info, node_to_net_dict, net_info, benchmark):
|
||||
node_id_to_name = []
|
||||
adjacency = {}
|
||||
for net_name in net_info:
|
||||
for node_name_1, node_name_2 in list(combinations(net_info[net_name]['nodes'],2)):
|
||||
if node_name_1 not in adjacency:
|
||||
adjacency[node_name_1] = set()
|
||||
if node_name_2 not in adjacency:
|
||||
adjacency[node_name_2] = set()
|
||||
adjacency[node_name_1].add(node_name_2)
|
||||
adjacency[node_name_2].add(node_name_1)
|
||||
|
||||
visited_node = set()
|
||||
|
||||
node_net_num = {}
|
||||
for node_name in node_info:
|
||||
node_net_num[node_name] = len(node_to_net_dict[node_name])
|
||||
|
||||
node_net_num_fea= {}
|
||||
node_net_num_max = max(node_net_num.values())
|
||||
print("node_net_num_max", node_net_num_max)
|
||||
for node_name in node_info:
|
||||
node_net_num_fea[node_name] = node_net_num[node_name]/node_net_num_max
|
||||
|
||||
node_area_fea = {}
|
||||
node_area_max_node = max(node_info, key = lambda x : node_info[x]['x'] * node_info[x]['y'])
|
||||
node_area_max = node_info[node_area_max_node]['x'] * node_info[node_area_max_node]['y']
|
||||
print("node_area_max = {}".format(node_area_max))
|
||||
for node_name in node_info:
|
||||
node_area_fea[node_name] = node_info[node_name]['x'] * node_info[node_name]['y'] / node_area_max
|
||||
|
||||
if "V" in node_info:
|
||||
add_node = "V"
|
||||
visited_node.add(add_node)
|
||||
node_id_to_name.append((add_node, node_net_num[add_node]))
|
||||
node_net_num.pop(add_node)
|
||||
|
||||
add_node = max(node_net_num, key = lambda v: node_net_num[v])
|
||||
visited_node.add(add_node)
|
||||
node_id_to_name.append((add_node, node_net_num[add_node]))
|
||||
node_net_num.pop(add_node)
|
||||
|
||||
while len(node_id_to_name) < len(node_info):
|
||||
candidates = {}
|
||||
for node_name in visited_node:
|
||||
if node_name not in adjacency:
|
||||
continue
|
||||
for node_name_2 in adjacency[node_name]:
|
||||
if node_name_2 in visited_node:
|
||||
continue
|
||||
if node_name_2 not in candidates:
|
||||
candidates[node_name_2] = 0
|
||||
candidates[node_name_2] += 1
|
||||
for node_name in node_info:
|
||||
if node_name not in candidates and node_name not in visited_node:
|
||||
candidates[node_name] = 0
|
||||
if len(candidates) > 0:
|
||||
if benchmark != 'ariane':
|
||||
if benchmark == "bigblue3":
|
||||
add_node = max(candidates, key = lambda v: candidates[v]*1 + node_net_num[v]*100000 +\
|
||||
node_info[v]['x']*node_info[v]['y'] * 1 +int(hash(v)%10000)*1e-6)
|
||||
else:
|
||||
add_node = max(candidates, key = lambda v: candidates[v]*1 + node_net_num[v]*1000 +\
|
||||
node_info[v]['x']*node_info[v]['y'] * 1 +int(hash(v)%10000)*1e-6)
|
||||
else:
|
||||
add_node = max(candidates, key = lambda v: candidates[v]*30000 + node_net_num[v]*1000 +\
|
||||
node_info[v]['x']*node_info[v]['y']*1 +int(hash(v)%10000)*1e-6)
|
||||
else:
|
||||
if benchmark != 'ariane':
|
||||
if benchmark == "bigblue3":
|
||||
add_node = max(node_net_num, key = lambda v: node_net_num[v]*100000 + node_info[v]['x']*node_info[v]['y']*1)
|
||||
else:
|
||||
add_node = max(node_net_num, key = lambda v: node_net_num[v]*1000 + node_info[v]['x']*node_info[v]['y']*1)
|
||||
else:
|
||||
add_node = max(node_net_num, key = lambda v: node_net_num[v]*1000 + node_info[v]['x']*node_info[v]['y']*1)
|
||||
|
||||
visited_node.add(add_node)
|
||||
node_id_to_name.append((add_node, node_net_num[add_node]))
|
||||
node_net_num.pop(add_node)
|
||||
for i, (node_name, _) in enumerate(node_id_to_name):
|
||||
node_info[node_name]["id"] = i
|
||||
# print("node_id_to_name")
|
||||
# print(node_id_to_name)
|
||||
node_id_to_name_res = [x for x, _ in node_id_to_name]
|
||||
return node_id_to_name_res
|
||||
|
||||
|
||||
class PlaceDB():
|
||||
|
||||
def __init__(self, benchmark = "adaptec1"):
|
||||
self.benchmark = benchmark
|
||||
if benchmark == "ariane" or benchmark == "sample_clustered":
|
||||
path = benchmark + '/netlist.pb.txt'
|
||||
pbtxt = get_netlist_info_dict(path)
|
||||
self.node_info, self.node_info_raw_id_name = get_node_info(pbtxt)
|
||||
self.node_cnt = len(self.node_info)
|
||||
self.net_info, self.port_info = get_net_info(pbtxt)
|
||||
self.net_cnt = len(self.net_info)
|
||||
self.max_height, self.max_width = 357, 357
|
||||
self.port_to_net_dict = get_port_to_net_dict(self.port_info, self.net_info)
|
||||
else:
|
||||
assert os.path.exists(benchmark)
|
||||
node_file = open(os.path.join(benchmark, benchmark+".nodes"), "r")
|
||||
self.node_info, self.node_info_raw_id_name = read_node_file(node_file, benchmark)
|
||||
pl_file = open(os.path.join(benchmark, benchmark+".pl"), "r")
|
||||
self.port_info = {}
|
||||
self.node_cnt = len(self.node_info)
|
||||
node_file.close()
|
||||
net_file = open(os.path.join(benchmark, benchmark+".nets"), "r")
|
||||
self.net_info = read_net_file(net_file, self.node_info)
|
||||
self.net_cnt = len(self.net_info)
|
||||
net_file.close()
|
||||
pl_file = open(os.path.join(benchmark, benchmark+".pl"), "r")
|
||||
self.max_height, self.max_width = read_pl_file(pl_file, self.node_info)
|
||||
pl_file.close()
|
||||
self.port_to_net_dict = {}
|
||||
self.node_to_net_dict = get_node_to_net_dict(self.node_info, self.net_info)
|
||||
self.node_id_to_name = get_node_id_to_name_topology(self.node_info, self.node_to_net_dict, self.net_info, self.benchmark)
|
||||
|
||||
def debug_str(self):
|
||||
print("node_cnt = {}".format(len(self.node_info)))
|
||||
print("net_cnt = {}".format(len(self.net_info)))
|
||||
print("max_height = {}".format(self.max_height))
|
||||
print("max_width = {}".format(self.max_width))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
placedb = PlaceDB("ariane")
|
||||
placedb.debug_str()
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
import sys
|
||||
sys.path.append('ariane')
|
||||
from ariane.read_info import get_netlist_info_dict
|
||||
from tqdm import tqdm
|
||||
|
||||
def get_node_info(pbtxt):
|
||||
node_info = {}
|
||||
node_info_raw_id_name = {}
|
||||
node_cnt = 0
|
||||
area_sum = 0.0
|
||||
|
||||
for node in pbtxt.node:
|
||||
if node.attr['type'].placeholder.upper() != "MACRO":
|
||||
continue
|
||||
node_name = node.name
|
||||
x = float(node.attr['width'].f)
|
||||
y = float(node.attr['height'].f)
|
||||
node_info[node_name] = {"id": node_cnt, "x": x, "y": y}
|
||||
area_sum += x * y
|
||||
if node.attr['type'].placeholder == "MACRO":
|
||||
node_info[node_name]["is_hard"] = 1
|
||||
else:
|
||||
node_info[node_name]["is_hard"] = 0
|
||||
node_info_raw_id_name[node_cnt] = node_name
|
||||
node_cnt += 1
|
||||
print("area_sum = {}".format(area_sum))
|
||||
return node_info, node_info_raw_id_name
|
||||
|
||||
|
||||
def get_net_info(pbtxt):
|
||||
net_info = {}
|
||||
net_name = None
|
||||
net_cnt = 0
|
||||
pin_cnt = 0
|
||||
pin_info = {}
|
||||
port_info = {}
|
||||
for node in pbtxt.node:
|
||||
if node.attr['type'].placeholder.upper() == "MACRO":
|
||||
continue
|
||||
pin_name = node.name
|
||||
if node.attr['type'].placeholder.upper() == "PORT":
|
||||
x = float(node.attr['x'].f)
|
||||
y = float(node.attr['y'].f)
|
||||
port_info[pin_name] = {"x": x, "y": y}
|
||||
elif node.attr['type'].placeholder.upper() == "MACRO_PIN":
|
||||
macro_name = node.attr['macro_name'].placeholder
|
||||
x_offset = float(node.attr['x_offset'].f)
|
||||
y_offset = float(node.attr['y_offset'].f)
|
||||
pin_info[pin_name] = {"node_name": macro_name, "x_offset": x_offset, "y_offset": y_offset}
|
||||
pin_cnt += 1
|
||||
print("pin_cnt = {}".format(pin_cnt))
|
||||
for node in pbtxt.node:
|
||||
net_name = node.name
|
||||
if node.attr['type'].placeholder.upper() == "MACRO":
|
||||
continue
|
||||
net_info[net_name] = {}
|
||||
net_info[net_name]["nodes"] = {}
|
||||
net_info[net_name]["ports"] = {}
|
||||
if 'weight' in node.attr:
|
||||
net_info[net_name]["weight"] = float(node.attr['weight'].f)
|
||||
else:
|
||||
net_info[net_name]["weight"] = 1.0
|
||||
for pin_name in node.input:
|
||||
if pin_name in port_info:
|
||||
assert pin_name not in net_info[net_name]["ports"]
|
||||
net_info[net_name]["ports"][pin_name] = {}
|
||||
net_info[net_name]["ports"][pin_name]["x"] = port_info[pin_name]["x"]
|
||||
net_info[net_name]["ports"][pin_name]["y"] = port_info[pin_name]["y"]
|
||||
elif pin_name in pin_info:
|
||||
node_name = pin_info[pin_name]["node_name"]
|
||||
if node_name in net_info[net_name]["nodes"]:
|
||||
if "x_offsets" not in net_info[net_name]["nodes"][node_name]:
|
||||
net_info[net_name]["nodes"][node_name]["x_offsets"] = [net_info[net_name]["nodes"][node_name]["x_offset"]]
|
||||
net_info[net_name]["nodes"][node_name]["y_offsets"] = [net_info[net_name]["nodes"][node_name]["y_offset"]]
|
||||
net_info[net_name]["nodes"][node_name]["x_offsets"].append(pin_info[pin_name]["x_offset"])
|
||||
net_info[net_name]["nodes"][node_name]["y_offsets"].append(pin_info[pin_name]["y_offset"])
|
||||
net_info[net_name]["nodes"][node_name] = {}
|
||||
net_info[net_name]["nodes"][node_name]["x_offset"] = pin_info[pin_name]["x_offset"]
|
||||
net_info[net_name]["nodes"][node_name]["y_offset"] = pin_info[pin_name]["y_offset"]
|
||||
else:
|
||||
assert False
|
||||
out_pin_name = net_name
|
||||
if out_pin_name in port_info:
|
||||
assert out_pin_name not in net_info[net_name]["ports"]
|
||||
net_info[net_name]["ports"][out_pin_name] = {}
|
||||
net_info[net_name]["ports"][out_pin_name]["x"] = port_info[out_pin_name]["x"]
|
||||
net_info[net_name]["ports"][out_pin_name]["y"] = port_info[out_pin_name]["y"]
|
||||
elif out_pin_name in pin_info:
|
||||
node_name = pin_info[out_pin_name]["node_name"]
|
||||
assert node_name not in net_info[net_name]["nodes"]
|
||||
net_info[net_name]["nodes"][node_name] = {}
|
||||
net_info[net_name]["nodes"][node_name]["x_offset"] = pin_info[out_pin_name]["x_offset"]
|
||||
net_info[net_name]["nodes"][node_name]["y_offset"] = pin_info[out_pin_name]["y_offset"]
|
||||
else:
|
||||
print("out_pin_name = {}".format(out_pin_name))
|
||||
assert False
|
||||
|
||||
for net_name in list(net_info.keys()):
|
||||
if len(net_info[net_name]["nodes"]) + \
|
||||
len(net_info[net_name]["ports"]) <= 1:
|
||||
net_info.pop(net_name)
|
||||
for net_name in net_info:
|
||||
net_info[net_name]['id'] = net_cnt
|
||||
net_cnt += 1
|
||||
print("adjust net size = {}".format(len(net_info)))
|
||||
return net_info, port_info
|
||||
|
||||
|
||||
def main():
|
||||
path = 'ariane/netlist.pb.txt'
|
||||
pbtxt = get_netlist_info_dict(path)
|
||||
node_info = get_node_info(pbtxt)
|
||||
net_info, port_info = get_net_info(pbtxt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,6 +0,0 @@
|
||||
from gym.envs.registration import register
|
||||
|
||||
register(
|
||||
id = 'place_env-v0',
|
||||
entry_point = 'place_env.place_env:PlaceEnv'
|
||||
)
|
||||
@ -1,301 +0,0 @@
|
||||
import math
|
||||
import gym
|
||||
from gym import spaces
|
||||
import numpy as np
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from place_db import PlaceDB
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as patches
|
||||
import time
|
||||
|
||||
class PlaceEnv(gym.Env):
|
||||
|
||||
def __init__(self, placedb, placed_num_macro = None, grid = 224):
|
||||
|
||||
# need to get GCN vector and CNN
|
||||
print("grid * grid", grid * grid)
|
||||
print("placedb.node_cnt", placedb.node_cnt)
|
||||
print("placedb.net_cnt", placedb.net_cnt)
|
||||
assert grid * grid >= placedb.node_cnt
|
||||
self.grid = grid
|
||||
self.max_height = placedb.max_height
|
||||
self.max_width = placedb.max_width
|
||||
self.placedb = placedb
|
||||
self.num_macro = placedb.node_cnt
|
||||
self.placed_num_macro = placed_num_macro
|
||||
self.num_net = placedb.net_cnt
|
||||
self.node_name_list = placedb.node_id_to_name
|
||||
self.action_space = spaces.Discrete(self.grid * self.grid)
|
||||
self.state = None
|
||||
self.net_min_max_ord = {}
|
||||
self.node_pos = {}
|
||||
self.net_placed_set = {}
|
||||
self.last_reward = 0
|
||||
self.num_macro_placed = 0
|
||||
self.node_x_max = 0
|
||||
self.node_x_min = self.grid
|
||||
self.node_y_max = 0
|
||||
self.node_y_min = self.grid
|
||||
self.ratio = self.placedb.max_height / self.grid
|
||||
print("self.ratio = {:.2f}".format(self.ratio))
|
||||
|
||||
def reset(self):
|
||||
self.num_macro_placed = 0
|
||||
num_macro = self.num_macro
|
||||
canvas = np.zeros((self.grid, self.grid))
|
||||
self.node_pos = {}
|
||||
self.net_min_max_ord = {}
|
||||
self.net_fea = np.zeros((self.num_net, 4))
|
||||
self.net_fea[:, 0] = 0
|
||||
self.net_fea[:, 1] = 1.0
|
||||
self.net_fea[:, 2] = 0
|
||||
self.net_fea[:, 3] = 1.0
|
||||
self.rudy = np.zeros((self.grid, self.grid))
|
||||
for port_name in self.placedb.port_to_net_dict:
|
||||
for net_name in self.placedb.port_to_net_dict[port_name]:
|
||||
pin_x = round(self.placedb.port_info[port_name]['x'] / self.ratio)
|
||||
pin_y = round(self.placedb.port_info[port_name]['y'] / self.ratio)
|
||||
if net_name in self.net_min_max_ord:
|
||||
if pin_x > self.net_min_max_ord[net_name]['max_x']:
|
||||
self.net_min_max_ord[net_name]['max_x'] = pin_x
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][1] = pin_x / self.grid
|
||||
elif pin_x < self.net_min_max_ord[net_name]['min_x']:
|
||||
self.net_min_max_ord[net_name]['max_y'] = pin_y
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][0] = pin_x / self.grid
|
||||
if pin_y > self.net_min_max_ord[net_name]['max_y']:
|
||||
self.net_min_max_ord[net_name]['max_y'] = pin_y
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][3] = pin_y / self.grid
|
||||
elif pin_y < self.net_min_max_ord[net_name]['min_y']:
|
||||
self.net_min_max_ord[net_name]['min_y'] = pin_y
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][2] = pin_y / self.grid
|
||||
else:
|
||||
self.net_min_max_ord[net_name] = {}
|
||||
self.net_min_max_ord[net_name]['max_x'] = pin_x
|
||||
self.net_min_max_ord[net_name]['min_x'] = pin_x
|
||||
self.net_min_max_ord[net_name]['max_y'] = pin_y
|
||||
self.net_min_max_ord[net_name]['min_y'] = pin_y
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][1] = pin_x / self.grid
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][0] = pin_x / self.grid
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][3] = pin_y / self.grid
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][2] = pin_y / self.grid
|
||||
self.net_placed_set = {}
|
||||
self.num_macro_placed = 0
|
||||
|
||||
net_img = np.zeros((self.grid, self.grid))
|
||||
net_img_2 = np.zeros((self.grid, self.grid))
|
||||
|
||||
next_x = math.ceil(max(1, self.placedb.node_info[self.node_name_list[self.num_macro_placed]]['x'] / self.ratio))
|
||||
next_y = math.ceil(max(1, self.placedb.node_info[self.node_name_list[self.num_macro_placed]]['y'] / self.ratio))
|
||||
mask = self.get_mask(canvas, next_x, next_y)
|
||||
next_x_2 = math.ceil(max(1, self.placedb.node_info[self.node_name_list[self.num_macro_placed+1]]['x'] / self.ratio))
|
||||
next_y_2 = math.ceil(max(1, self.placedb.node_info[self.node_name_list[self.num_macro_placed+1]]['y'] / self.ratio))
|
||||
mask_2 = self.get_mask(canvas, next_x_2, next_y_2)
|
||||
for net_name in self.placedb.net_info:
|
||||
self.net_placed_set[net_name] = set()
|
||||
self.state = np.concatenate((np.array([self.num_macro_placed]), canvas.flatten(),
|
||||
net_img.flatten(), mask.flatten(), net_img_2.flatten(), mask_2.flatten(),
|
||||
np.array([next_x/self.grid, next_y/self.grid])), axis = 0)
|
||||
self.node_x_max = 0
|
||||
self.node_x_min = self.grid
|
||||
self.node_y_max = 0
|
||||
self.node_y_min = self.grid
|
||||
|
||||
return self.state
|
||||
|
||||
def save_fig(self, file_path):
|
||||
fig1 = plt.figure()
|
||||
ax1 = fig1.add_subplot(111, aspect='equal')
|
||||
ax1.axes.xaxis.set_visible(False)
|
||||
ax1.axes.yaxis.set_visible(False)
|
||||
for node_name in self.node_pos:
|
||||
x, y, size_x, size_y = self.node_pos[node_name]
|
||||
ax1.add_patch(
|
||||
patches.Rectangle(
|
||||
(x/self.grid, y/self.grid), # (x,y)
|
||||
size_x/self.grid, # width
|
||||
size_y/self.grid, linewidth=1, edgecolor='k',
|
||||
)
|
||||
)
|
||||
fig1.savefig(file_path, dpi=90, bbox_inches='tight')
|
||||
plt.close()
|
||||
# WireMask
|
||||
def get_net_img(self, is_next_next = False):
|
||||
net_img = np.zeros((self.grid, self.grid))
|
||||
if not is_next_next:
|
||||
next_node_name = self.placedb.node_id_to_name[self.num_macro_placed]
|
||||
elif self.num_macro_placed + 1 < len(self.placedb.node_id_to_name):
|
||||
next_node_name = self.placedb.node_id_to_name[self.num_macro_placed + 1]
|
||||
else:
|
||||
return net_img
|
||||
|
||||
for net_name in self.placedb.node_to_net_dict[next_node_name]:
|
||||
if net_name in self.net_min_max_ord:
|
||||
delta_pin_x = round((self.placedb.node_info[next_node_name]['x']/2 + \
|
||||
self.placedb.net_info[net_name]["nodes"][next_node_name]["x_offset"])/self.ratio)
|
||||
delta_pin_y = round((self.placedb.node_info[next_node_name]['y']/2 + \
|
||||
self.placedb.net_info[net_name]["nodes"][next_node_name]["y_offset"])/self.ratio)
|
||||
start_x = self.net_min_max_ord[net_name]['min_x'] - delta_pin_x
|
||||
end_x = self.net_min_max_ord[net_name]['max_x'] - delta_pin_x
|
||||
start_y = self.net_min_max_ord[net_name]['min_y'] - delta_pin_y
|
||||
end_y = self.net_min_max_ord[net_name]['max_y'] - delta_pin_y
|
||||
start_x = min(start_x, self.grid)
|
||||
start_y = min(start_y, self.grid)
|
||||
if not 'weight' in self.placedb.net_info[net_name]:
|
||||
weight = 1.0
|
||||
else:
|
||||
weight = self.placedb.net_info[net_name]['weight']
|
||||
for i in range(0, start_x):
|
||||
net_img[i, :] += (start_x - i) * weight
|
||||
for i in range(end_x+1, self.grid):
|
||||
net_img[i, :] += (i- end_x) * weight
|
||||
for j in range(0, start_y):
|
||||
net_img[:, j] += (start_y - j) * weight
|
||||
for j in range(end_y+1, self.grid):
|
||||
net_img[:, j] += (j - start_y) * weight
|
||||
return net_img
|
||||
|
||||
def step(self, action):
|
||||
err_msg = f"{action!r} ({type(action)}) invalid"
|
||||
assert self.action_space.contains(action), err_msg
|
||||
|
||||
canvas = self.state[1: 1+self.grid*self.grid].reshape(self.grid, self.grid)
|
||||
mask = self.state[1+self.grid*self.grid*2: 1+self.grid*self.grid*3].reshape(self.grid, self.grid)
|
||||
reward = 0
|
||||
x = round(action // self.grid)
|
||||
y = round(action % self.grid)
|
||||
|
||||
if mask[x][y] == 1:
|
||||
reward += -200000
|
||||
|
||||
node_name = self.placedb.node_id_to_name[self.num_macro_placed]
|
||||
size_x = math.ceil(max(1, self.placedb.node_info[node_name]['x']/self.ratio))
|
||||
size_y = math.ceil(max(1, self.placedb.node_info[node_name]['y']/self.ratio))
|
||||
|
||||
assert abs(size_x - self.state[-2]*self.grid) < 1e-5
|
||||
assert abs(size_y - self.state[-1]*self.grid) < 1e-5
|
||||
|
||||
canvas[x : x+size_x, y : y+size_y] = 1.0
|
||||
canvas[x : x + size_x, y] = 0.5
|
||||
if y + size_y -1 < self.grid:
|
||||
canvas[x : x + size_x, max(0, y + size_y -1)] = 0.5
|
||||
canvas[x, y: y + size_y] = 0.5
|
||||
if x + size_x - 1 < self.grid:
|
||||
canvas[max(0, x+size_x-1), y: y + size_y] = 0.5
|
||||
self.node_pos[self.node_name_list[self.num_macro_placed]] = (x, y, size_x, size_y)
|
||||
|
||||
for net_name in self.placedb.node_to_net_dict[node_name]:
|
||||
self.net_placed_set[net_name].add(node_name)
|
||||
pin_x = round((x * self.ratio + self.placedb.node_info[node_name]['x']/2 + \
|
||||
self.placedb.net_info[net_name]["nodes"][node_name]["x_offset"])/self.ratio)
|
||||
pin_y = round((y * self.ratio + self.placedb.node_info[node_name]['y']/2 + \
|
||||
self.placedb.net_info[net_name]["nodes"][node_name]["y_offset"])/self.ratio)
|
||||
if net_name in self.net_min_max_ord:
|
||||
start_x = self.net_min_max_ord[net_name]['min_x']
|
||||
end_x = self.net_min_max_ord[net_name]['max_x']
|
||||
start_y = self.net_min_max_ord[net_name]['min_y']
|
||||
end_y = self.net_min_max_ord[net_name]['max_y']
|
||||
delta_x = end_x - start_x
|
||||
delta_y = end_y - start_y
|
||||
if delta_x > 0 or delta_y > 0:
|
||||
self.rudy[start_x : end_x +1, start_y: end_y +1] -= 1/(delta_x+1) + 1/(delta_y+1)
|
||||
weight = 1.0
|
||||
if 'weight' in self.placedb.net_info[net_name]:
|
||||
weight = self.placedb.net_info[net_name]['weight']
|
||||
|
||||
if pin_x > self.net_min_max_ord[net_name]['max_x']:
|
||||
reward += weight * (self.net_min_max_ord[net_name]['max_x'] - pin_x)
|
||||
self.net_min_max_ord[net_name]['max_x'] = pin_x
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][1] = pin_x / self.grid
|
||||
elif pin_x < self.net_min_max_ord[net_name]['min_x']:
|
||||
reward += weight * (pin_x - self.net_min_max_ord[net_name]['min_x'])
|
||||
self.net_min_max_ord[net_name]['min_x'] = pin_x
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][0] = pin_x / self.grid
|
||||
if pin_y > self.net_min_max_ord[net_name]['max_y']:
|
||||
reward += weight * (self.net_min_max_ord[net_name]['max_y'] - pin_y)
|
||||
self.net_min_max_ord[net_name]['max_y'] = pin_y
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][3] = pin_y / self.grid
|
||||
elif pin_y < self.net_min_max_ord[net_name]['min_y']:
|
||||
reward += weight * (pin_y - self.net_min_max_ord[net_name]['min_y'])
|
||||
self.net_min_max_ord[net_name]['min_y'] = pin_y
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][2] = pin_y / self.grid
|
||||
start_x = self.net_min_max_ord[net_name]['min_x']
|
||||
end_x = self.net_min_max_ord[net_name]['max_x']
|
||||
start_y = self.net_min_max_ord[net_name]['min_y']
|
||||
end_y = self.net_min_max_ord[net_name]['max_y']
|
||||
delta_x = end_x - start_x
|
||||
delta_y = end_y - start_y
|
||||
self.rudy[start_x : end_x +1, start_y: end_y +1] += 1/(delta_x+1) + 1/(delta_y+1)
|
||||
else:
|
||||
self.net_min_max_ord[net_name] = {}
|
||||
self.net_min_max_ord[net_name]['max_x'] = pin_x
|
||||
self.net_min_max_ord[net_name]['min_x'] = pin_x
|
||||
self.net_min_max_ord[net_name]['max_y'] = pin_y
|
||||
self.net_min_max_ord[net_name]['min_y'] = pin_y
|
||||
start_x = self.net_min_max_ord[net_name]['min_x']
|
||||
end_x = self.net_min_max_ord[net_name]['max_x']
|
||||
start_y = self.net_min_max_ord[net_name]['min_y']
|
||||
end_y = self.net_min_max_ord[net_name]['max_y']
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][1] = pin_x / self.grid
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][0] = pin_x / self.grid
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][3] = pin_y / self.grid
|
||||
self.net_fea[self.placedb.net_info[net_name]['id']][2] = pin_y / self.grid
|
||||
reward += 0
|
||||
|
||||
self.num_macro_placed += 1
|
||||
net_img = np.zeros((self.grid, self.grid))
|
||||
net_img_2 = np.zeros((self.grid, self.grid))
|
||||
|
||||
if self.num_macro_placed < self.placed_num_macro:
|
||||
net_img = self.get_net_img()
|
||||
net_img_2 = self.get_net_img(is_next_next= True)
|
||||
if net_img.max() >0 or net_img_2.max()>0:
|
||||
net_img /= max(net_img.max(), net_img_2.max())
|
||||
net_img_2 /= max(net_img.max(), net_img_2.max())
|
||||
|
||||
if self.node_x_max < x:
|
||||
self.node_x_max = x
|
||||
if self.node_x_min > x:
|
||||
self.node_x_min = x
|
||||
if self.node_y_max < y:
|
||||
self.node_y_max = y
|
||||
if self.node_y_min > y:
|
||||
self.node_y_min = y
|
||||
|
||||
if self.num_macro_placed == self.num_macro or \
|
||||
(self.placed_num_macro is not None and self.num_macro_placed == self.placed_num_macro):
|
||||
done = True
|
||||
else:
|
||||
done = False
|
||||
mask = np.ones((self.grid, self.grid))
|
||||
mask_2 = np.ones((self.grid, self.grid))
|
||||
if not done: # get next macro size and pre-mask the solution
|
||||
next_x = math.ceil(max(1, self.placedb.node_info[self.placedb.node_id_to_name[self.num_macro_placed]]['x']/self.ratio))
|
||||
next_y = math.ceil(max(1, self.placedb.node_info[self.placedb.node_id_to_name[self.num_macro_placed]]['y']/self.ratio))
|
||||
mask = self.get_mask(canvas, next_x, next_y)
|
||||
if self.num_macro_placed + 1 < self.placed_num_macro:
|
||||
next_x_2 = math.ceil(max(1, self.placedb.node_info[self.placedb.node_id_to_name[self.num_macro_placed+1]]['x']/self.ratio))
|
||||
next_y_2 = math.ceil(max(1, self.placedb.node_info[self.placedb.node_id_to_name[self.num_macro_placed+1]]['y']/self.ratio))
|
||||
mask_2 = self.get_mask(canvas, next_x_2, next_y_2)
|
||||
else:
|
||||
next_x = 0
|
||||
next_y = 0
|
||||
self.state = np.concatenate((np.array([self.num_macro_placed]), canvas.flatten(),
|
||||
net_img.flatten(), mask.flatten(), net_img_2.flatten(), mask_2.flatten(),
|
||||
np.array([next_x/self.grid, next_y/self.grid])), axis = 0)
|
||||
return self.state, reward, done, {"raw_reward": reward, "net_img": net_img, "mask": mask}
|
||||
|
||||
# PositionMask
|
||||
def get_mask(self, canvas, next_x, next_y):
|
||||
mask = np.zeros((self.grid, self.grid))
|
||||
for node_name in self.node_pos:
|
||||
startx = max(0, self.node_pos[node_name][0] - next_x + 1)
|
||||
starty = max(0, self.node_pos[node_name][1] - next_y + 1)
|
||||
endx = min(self.node_pos[node_name][0] + self.node_pos[node_name][2] - 1, self.grid - 1)
|
||||
endy = min(self.node_pos[node_name][1] + self.node_pos[node_name][3] - 1, self.grid - 1)
|
||||
mask[startx: endx + 1, starty : endy + 1] = 1
|
||||
mask[self.grid - next_x + 1:,:] = 1
|
||||
mask[:, self.grid - next_y + 1:] = 1
|
||||
return mask
|
||||
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
from itertools import combinations
|
||||
from heapq import *
|
||||
|
||||
def prim_real(vertexs_tmp, node_pos, net_info, ratio, node_info, port_info):# vertexs, edges,start='D'):
|
||||
vertexs = list(vertexs_tmp)
|
||||
if len(vertexs)<=1:
|
||||
return 0
|
||||
adjacent_dict = {}
|
||||
for node in vertexs:
|
||||
adjacent_dict[node] = []
|
||||
for node1, node2 in list(combinations(vertexs, 2)):
|
||||
if node1 in node_pos:
|
||||
pin_x_1 = node_pos[node1][0] * ratio + node_info[node1]["x"] / 2 + net_info[node1]["x_offset"] # )//ratio
|
||||
pin_y_1 = node_pos[node1][1] * ratio + node_info[node1]["y"] / 2 + net_info[node1]["y_offset"] # )//ratio
|
||||
else:
|
||||
pin_x_1 = port_info[node1]['x']
|
||||
pin_y_1 = port_info[node1]['y']
|
||||
if node2 in node_pos:
|
||||
pin_x_2 = node_pos[node2][0] * ratio + node_info[node2]["x"] / 2 + net_info[node2]["x_offset"] # )//ratio
|
||||
pin_y_2 = node_pos[node2][1] * ratio + node_info[node2]["y"] / 2 + net_info[node2]["y_offset"] # )//ratio
|
||||
else:
|
||||
pin_x_2 = port_info[node2]['x']
|
||||
pin_y_2 = port_info[node2]['y']
|
||||
weight = abs(pin_x_1-pin_x_2) + \
|
||||
abs(pin_y_1-pin_y_2)
|
||||
adjacent_dict[node1].append((weight, node1, node2))
|
||||
adjacent_dict[node2].append((weight, node2, node1))
|
||||
|
||||
start = vertexs[0]
|
||||
minu_tree = []
|
||||
visited = set()
|
||||
visited.add(start)
|
||||
adjacent_vertexs_edges = adjacent_dict[start]
|
||||
heapify(adjacent_vertexs_edges)
|
||||
cost = 0
|
||||
cnt = 0
|
||||
while cnt < len(vertexs)-1:
|
||||
weight, v1, v2 = heappop(adjacent_vertexs_edges)
|
||||
if v2 not in visited:
|
||||
visited.add(v2)
|
||||
minu_tree.append((weight, v1, v2))
|
||||
cost += weight
|
||||
cnt += 1
|
||||
for next_edge in adjacent_dict[v2]:
|
||||
if next_edge[2] not in visited:
|
||||
heappush(adjacent_vertexs_edges, next_edge)
|
||||
return cost
|
||||
Loading…
Reference in New Issue
Block a user