Compare commits

..

No commits in common. "20315a484a7bf33f4d7143f8ee13bdf37f664bbc" and "29b01461e64064204436dea76cbfde7cb48dd7fe" have entirely different histories.

25 changed files with 1 additions and 2595333 deletions

View File

@ -1,70 +1,7 @@
## MaskPlace: Fast Chip Placement via Reinforced Visual Representation Learning ## 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 ### The placement process animation
Benchmark: Bigblue3 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>| |<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 ### 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">| |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>| |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>| |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">| |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>| |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>| |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">| |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>| |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>| |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">| |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| |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| |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">| |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>| |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>| |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">| |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>| |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>| |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">| |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>| |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>| |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

View File

@ -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()

View File

@ -1 +0,0 @@
RowBasedPlacement : adaptec1.nodes adaptec1.nets adaptec1.wts adaptec1.pl adaptec1.scl

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

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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()

View File

@ -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.

View File

@ -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()

View File

@ -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()

View File

@ -1,6 +0,0 @@
from gym.envs.registration import register
register(
id = 'place_env-v0',
entry_point = 'place_env.place_env:PlaceEnv'
)

View File

@ -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

View File

@ -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