实验记录之划分

实验记录之划分得到特征

6月25日

nodcfeature下的数据,是PR之后的训练数据。

每行都是sink pin节点的数据。

6/25日:(已经commit:graph partitioning before)

  • 为gate设置一个字段num,表示超图中的节点编号。再设置一个字段partNo,表示划分之后的所属的partition编号。
  • 为每个gate编号,插入gate时,进行编号。
  • 设置一个map,gate name和gate num一一对应。

6/26日,已实现上面功能:

通过节点编号查找gate name:

_numToGateNames[i] ===> gatename

通过gate name查找节点编号:

_gateNamesToNum[“U462”] ==>num

std::unordered_map<int,std::string> _numToGateNames;
std::unordered_map<std::string,int> _gateNamesToNum;

计划如下工作:

  • 遍历所有net,构建超图。得到格式:

    image-20210626150541176

    net数量,gate 数量。

    要把那些pin是port的线网去掉。

    26号下午4点:超图构建完成

    在read_verilog / _verilog / _insert_gate 里面添加了

     gate.num = _gates.size();
     _numToGateNames.emplace(gate.num,gate._name);
     _gateNamesToNum.emplace(gate._name,gate.num);
    

    读入verilog文件构建超图文件的代码:

    void Timer::_build_HmetisHyperGraph(std::ostream & os) const{
      
      int net_size = 0;
      int gate_size = _gates.size(); 
      std::vector<std::vector<int>> GraphFile;
      for(const auto &[net_name,net] : _nets){
        bool flag = true;//remove nets whose pin is port
        for(const auto pin : net._pins){
          if(pin->_primary_input() || pin->_primary_output()){
            flag = false;
            break;
          }
        }
        if(flag == true){
          GraphFile.push_back(vector<int>());//fixed bug
          for(const auto pin : net._pins){
            //add a hypger edge
            GraphFile[net_size].push_back(pin->_gate->getNum());
          }
          net_size++;
        }
      }
    

    shell接口:(-o 后面接的是存放超图文件的路径)

    build_HmetisHyperGraph -o [path to save the hypergraph]
    

6月30日

6/30日进展:

在multilevel recursive bisection的情况下,假设划分npart为2的幂次方次的个数,划分后的结果的二进制就是它的划分路径!先左为0再右1。比如节点0的最后划分结果是8(二进制为1000),那么划分路径就是1000.支持的可执行文件有 shmetis/hmetis

./shmetis b11_1_mode_0_hyper.txt  4 5

7月1日

计划7/1日:将gate的字段partNo填上。


测试:

timerPr.set_pr_data(fileIndex_1,fileIndex_2,mode);
timerPr.readPartionResult(logos);

下午16:51已经实现了:将gate的字段partNo填上。

void Timer::_readPartionResult(std::istream &iss){
  std::string str;
	int count = 0;
  while(!iss.eof()){
    if (iss.bad()) {
			std::cout << "input stream corrupted" << std::endl;
			break;
		}
 
		if (iss.fail()) {
			std::cout << "bad data" << std::endl;
			iss.clear(std::istream::failbit);
			iss.ignore(256, '\n');
			continue;
		}
    std::getline(iss, str);
    if(str.length() != 0){
      count++;
      int part = std::stoi(str);
      auto gate = _numToGate.find(count);
      if(gate != _numToGate.end())
        gate->second.partNo = part; 
      else{
        OT_LOGW("_numToGate != find(count) ",count);
      }
    }
  }
} 

ps更改timer.hpp中相关数据结构:

std::unordered_map<int,Gate &> _numToGate;

将上面的接口添加到shell中,已经添加完成了。

shell接口:

read_partion_result [the path of partion result file]

在最后提取特征的时候,碰到之前留下的问题,有点模糊了。

使用布局布线之后netlist,使用线负载模型提取的spef进行的时序信息的计算,拿到的也是布局之后的label进行的训练。

所以read_spef 应该读取 线负载得到的spef。可能会有布局之后的位置信息,但是不用它就好了。

逻辑综合的时候,虽然提取了线网使得整张图不能很好的进行切割,但是在提取之前,可以事先就对网表进行超图分割,从而得到每个gate的划分结果。

  • 提取dc阶段的特征(逻辑综合的提取一一对应的线网-网表):dump_rf_feature_dc
void Net::dump_rf_feature_dc(std::ostream &os,Split el,Tran rf,int groupId,ot::Timer *prTimer) const{
              //os<<"groupId,part,pin_name,drive_load,wire_input_slew,D2M,d_x,d_y,s_x,s_y,dis,strength,sink_load,sink_pin_capacitance,elmore_delay,wire_slew,wire_delay"<<std::endl;
              const Rct*  rctree= rct(); 
              int strength = drive_strength();
               for(auto [name,rcnode]:(*rctree)._nodes)
                {
                        if(rcnode._name != rctree->_root->_name )
                        {
                            if(rcnode._pin == nullptr)
                            {
                                  continue;
                            }
                            else
                            {
                                auto itr = prTimer->_pins.find(rcnode._pin->_name);
                                assert(itr != prTimer->_pins.end());
                                const auto & pr_pin = itr->second;

                                for(auto arc: pr_pin._fanin)
                                {
                                  if(arc->_from.name() == _root->name() )
                                  {
                                       Loc sub = _root->_loc -  rcnode._pin->_loc;
                                      // double dis = sub.P2Odis();
                                      //sink_pin
                                      os<<groupId<<"," << rcnode._pin->_gate->getPart() <<"," <<rcnode._pin->_name<<","<<rctree->_root->_load[el][rf]<<","<<*_root->slew(el,rf)<<","<<\
                                      rcnode._ldelay[el][rf]<<","<<_root->_loc._x<<","<<_root->_loc._y<<","<<rcnode._pin->_loc._x<<","<<rcnode._pin->_loc._y<<","<<sub.P2Odis()<<","<<strength<<\
                                      ","<<rcnode._load[el][rf]<<","<<rcnode._pin->cap(el,rf)<<","<<rcnode.delay(el,rf)<<\
                                      "," <<*(pr_pin.slew(el,rf)) <<","<<*arc->_delay[el][rf][rf]<<std::endl;

                                  }

                                }
                            }

                        }
                        else
                        { 
                          continue;
                        }

                }
}
  • 去掉布局信息的,使用线负载模型得到逻辑综合的特征(布局阶段时候的线网)
void Net::dump_rf_feature(std::ostream &os,Split el,Tran rf,int groupId) const{
                  //os<<"groupId,part,pin_name,drive_load,wire_input_slew,D2M,d_x,d_y,s_x,s_y,dis,strength,sink_load,sink_pin_capacitance,elmore_delay,wire_slew,wire_delay"<<std::endl;
                  const Rct*  rctree= rct(); 
                  int strength = drive_strength();
                   for(auto [name,rcnode]:(*rctree)._nodes)
                    {
                            if(rcnode._name != rctree->_root->_name )
                            {
                                if(rcnode._pin == nullptr)
                                {
                                      continue;
                                }
                                else
                                {
                                    for(auto arc:rcnode._pin->_fanin)
                                    {
                                      if(arc->_from.name() == _root->name() )
                                      {
                                           Loc sub = _root->_loc -  rcnode._pin->_loc;
                                          // double dis = sub.P2Odis();
                                          //sink_pin
                                          os<<groupId<<"," << rcnode._pin->_gate->getPart() << "," <<rcnode._pin->_name<<","<<rctree->_root->_load[el][rf]<<","<<*_root->slew(el,rf)<<","<<\
                                          rcnode._ldelay[el][rf]<<","<<_root->_loc._x<<","<<_root->_loc._y<<","<<rcnode._pin->_loc._x<<","<<rcnode._pin->_loc._y<<","<<sub.P2Odis()<<","<<strength<<\
                                          ","<<rcnode._load[el][rf]<<","<<rcnode._pin->cap(el,rf)<<","<<rcnode.delay(el,rf)<<\
                                          "," <<*arc->_to.slew(el,rf) <<","<<*arc->_delay[el][rf][rf]<<std::endl;

                                      }
                                    
                                    }
                                }
                                  
                            }
                            else
                            { 
                              //root_node ��ʱ��������
                              continue;
                            }
                          
                    }
}

提取特征的脚本/代码如下:

  1. DC阶段提取的一一对应的线网,提取相应的特征,添加布局之后的label**(dump_rf_feature_dc shell接口不可用!必须用下面的代码)**
timerSyn.set_syn_data(fileIndex_1,fileIndex_2,mode);
timerSyn.prTimer = new ot::Timer();
(*timerSyn.prTimer).set_pr_data(fileIndex_1,fileIndex_2,mode);
timerSyn.dump_rf_feature_dc("./logs/DcNetDcFea/b" + fileIndex +"_mode_"+mode); 
  1. PR阶段的网表,提取去掉布局位置的特征。记住一定要添加read_spef ./logs/spef/11_1.spef
read_celllib ./data/lib/data.lib
read_multi_verilog ./data/netlist/b11_1_pr_mode_0.v
read_sdc ./data/sdc/b11/b11_1_pr.sdc
read_place ./data/DataPT/data/b11_1_mode_0
read_spef  ./logs/spef/11_1.spef
update_timing
dump_rf_feature  ./logs/prNetDcFea/b11_1_mode_0_rf.txt

为了方便调试,单独写了一个函数:set_prNetDcFea_data

void Timer::set_prNetDcFea_data(std::string fileIndex_1,std::string fileIndex_2,std::string mode){
  std::string fileIndex = fileIndex_1 + "_" + fileIndex_2;
  std::string synNetFileName = "b" + fileIndex + "_SYN.v";
  std::string prNetFileName  = "b" + fileIndex + "_pr_mode_" + mode + ".v";
  std::string synSDCfileName = "b" + fileIndex + "_syn.sdc";
  std::string prSDCfileName  = "b" + fileIndex + "_pr.sdc";
  std::string prSPEFfileName = "b" + fileIndex + "_pr_mode_" + mode + ".spef";
  std::string place = "./data/DataPT/data/b"+fileIndex + "_mode_" + mode;
  read_celllib("./data/lib/data.lib")
  .read_verilog("./data/netlist/" + prNetFileName)
  .read_place(place)
  .read_spef("./logs/spef/"+ fileIndex + "_" + mode + ".spef")
  .read_sdc("./data/sdc/b" + fileIndex_1 + "/" + prSDCfileName);
  update_timing();
}

bug的在于,有些port也作为数据集,没有gate,所以指针错误。(已解决,最终的数据里面去掉了这些port)在dump_rf_feature和dump_rf_feature_dc函数里面,不把这些port相应的特征dump出来。因为它们不属于任何gate,自然没有part结果。

已经提取完特征。

7/2日计划:批量提取所有特征,然后进行第一次模型训练。

7月2日

1、批量生成超图文件存放在logs/hypergraph文件夹下。包括b14_1。脚本hyperCreate.py如下:

import os,sys,subprocess

#os.chdir("../")
for base in range(11,15):
    for clock in range(0,5):
        for mode in range(0,4):
            place_name = "b"+str(base)+"_"+str(clock)+"_mode_"+str(mode)
            verilog_name =  "b"+str(base)+"_"+str(clock) + "_pr_mode_"+ str(mode)+".v"
            sdc_name =  "b"+str(base)+"_"+str(clock) + "_pr.sdc"
            cmd ="read_celllib ./data/lib/data.lib\n"
            cmd+="read_multi_verilog ./data/netlist/"+verilog_name+"\n"
            cmd+="read_sdc ./data/sdc/b"+str(base) +"/"+sdc_name+"\n"
            cmd+="read_place ./data/DataPT/data/"+place_name+"\n"
            cmd+="read_spef ./logs/spef/" + str(base) + "_" + str(clock) + "_" + str(mode) + ".spef" + "\n"
            cmd+="update_timing\n"
            cmd+="build_HmetisHyperGraph -o ./logs/hypergraph/"+place_name+".hgr\n" 
            try:
                data = subprocess.check_output(
                    ["./build/ot-shell"],
                    input=bytes(cmd,encoding="UTF-8"),
                )
                print(data)
            except:
                data=None
            print(cmd)

2、将所有的超图进行切割,存放在如上目录。脚本cutGraph.py如下:

import subprocess
for index1 in range(11,15):
    for index2 in range(0,5):
        for index3 in range(0,4):
            file = "b" + str(index1) + "_" + str(index2) + "_mode_"  + str(index3)+".hgr"
            cmd = "logs/partresult/shmetis logs/hypergraph/" + file +" 4" + " 5"
            print(cmd)
            subprocess.run(cmd,shell=True)

3、读入划分结果文件,批量生成特征文件。脚本injectPartion.py如下:

import os,sys,subprocess

#os.chdir("../")
for base in range(11,15):
    for clock in range(0,5):
        for mode in range(0,4):
            place_name = "b"+str(base)+"_"+str(clock)+"_mode_"+str(mode)
            verilog_name =  "b"+str(base)+"_"+str(clock) + "_pr_mode_"+ str(mode)+".v"
            sdc_name =  "b"+str(base)+"_"+str(clock) + "_pr.sdc"
            cmd ="read_celllib ./data/lib/data.lib\n"
            cmd+="read_multi_verilog ./data/netlist/"+verilog_name+"\n"
            cmd+="read_sdc ./data/sdc/b"+str(base) +"/"+sdc_name+"\n"
            cmd+="read_place ./data/DataPT/data/"+place_name+"\n"
            cmd+="read_spef ./logs/spef/" + str(base) + "_" + str(clock) + "_" + str(mode) + ".spef" + "\n"
            cmd+="update_timing\n"
            cmd+="read_partion_result ./logs/hypergraph/"+place_name+".hgr.part.4\n" 
            cmd+="dump_rf_feature ./logs/prNetDcFea/"+place_name+"\n"
            try:
                data = subprocess.check_output(
                    ["./build/ot-shell"],
                    input=bytes(cmd,encoding="UTF-8"),
                )
                print(data)
            except:
                data=None
            print(cmd)
  1. 根据节点个数来确定划分的次数。log(n) / log(2)取下整。hgr文件的第二个节点才是节点个数。

ps:遇到一个问题,那就是每次跑出来的结果都一样的。设置随机数种子的函数如下,最后添加的torch.backends.cudnn.enabled = True稳定下来了。

def set_random_seed(seed, deterministic=False):
    """Set random seed.

    Args:
        seed (int): Seed to be used.
        deterministic (bool): Whether to set the deterministic option for
            CUDNN backend, i.e., set `torch.backends.cudnn.deterministic`
            to True and `torch.backends.cudnn.benchmark` to False.
            Default: False.
    """
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    if deterministic:
        torch.backends.cudnn.deterministic = True
        torch.backends.cudnn.benchmark = False
        torch.backends.cudnn.enabled = True

由于不同update_timing,所以 逻辑综合阶段的特征会有点差别。解决这个问题的办法是,一次update timing,然后多次read_partion_result / dump_rf_feature 。

for base in range(11,15):
    for clock in range(0,5):
        for mode in range(0,4):
            place_name = "b"+str(base)+"_"+str(clock)+"_mode_"+str(mode)
            verilog_name =  "b"+str(base)+"_"+str(clock) + "_pr_mode_"+ str(mode)+".v"
            sdc_name =  "b"+str(base)+"_"+str(clock) + "_pr.sdc"
            cmd ="read_celllib ./data/lib/data.lib\n"
            cmd+="read_multi_verilog ./data/netlist/"+verilog_name+"\n"
            cmd+="read_sdc ./data/sdc/b"+str(base) +"/"+sdc_name+"\n"
            cmd+="read_place ./data/DataPT/data/"+place_name+"\n"
            cmd+="read_spef ./logs/spef/" + str(base) + "_" + str(clock) + "_" + str(mode) + ".spef" + "\n"
            cmd+="update_timing\n"
            cmd+="read_partion_result ./logs/hypergraph/"+place_name+".hgr.part.8\n" 
            cmd+="dump_rf_feature ./logs/prNetDcFea/8-way/"+place_name+"\n"
            cmd+="read_partion_result ./logs/hypergraph/"+place_name+".hgr.part.4\n" 
            cmd+="dump_rf_feature ./logs/prNetDcFea/4-way/"+place_name+"\n"
            try:
                data = subprocess.check_output(
                    ["./build/ot-shell"],
                    input=bytes(cmd,encoding="UTF-8"),
                )
                print(data)
            except:
                data=None
            print(cmd)

7月5日

根据划分的结果,取其二进制的编码。

根据最终划分粒度(不多于5个),划分的way的如下所示:

for index1 in range(11,15):
    for index2 in range(0,5):
        for index3 in range(0,4):
            file = "b" + str(index1) + "_" + str(index2) + "_mode_"  + str(index3)+".hgr"
            filepath = "logs/hypergraph/" + file
            with  open(filepath) as f:
                nodeNetstr = f.readline()
                f.close()
            listNetNode = nodeNetstr.split(" ")
            part = int(math.log2(int(listNetNode[1]) / 5))
            print(part)

二进制最高不超过10位。

为了日后可以读入划分的结果,现在需要将划分的次数进行记录到文件中。

cutGraph.py如下所示:

import subprocess
import pandas as pd
import math
name = ["file","kway"]
res_list=[]
for index1 in range(11,15):
    for index2 in range(0,5):
        for index3 in range(0,4):
            file = "b" + str(index1) + "_" + str(index2) + "_mode_"  + str(index3)+".hgr"
            filepath = "logs/hypergraph/" + file
            with  open(filepath) as f:
                nodeNetstr = f.readline()
                f.close()
            listNetNode = nodeNetstr.split(" ")
            part = int(math.log2(int(listNetNode[1]) / 5))
            print(part)
            res_list.append([file,part])
            cmd = "logs/partresult/shmetis " + filepath + " " + str(part) + " 5"
            print(cmd)
            subprocess.run(cmd,shell=True)
res_csv =pd.DataFrame(columns = name,data = res_list)
res_csv.to_csv("./logs/hypergraph/" + "filesKway.csv") 

记录文件为filesKway.csv存放在logs/hypergraph目录下。

img

所有的划分次数都大于4。

然后读入划分的结果,将特征dump_rf_feature。

injectPartion.py如下所示:

import os,sys,subprocess
import pandas as pd
#os.chdir("../")
df = pd.read_csv("./logs/hypergraph/filesKway.csv")
df.set_index(df["file"],inplace=True)
for base in range(11,15):
    for clock in range(0,5):
        for mode in range(0,4):
            place_name = "b"+str(base)+"_"+str(clock)+"_mode_"+str(mode)
            verilog_name =  "b"+str(base)+"_"+str(clock) + "_pr_mode_"+ str(mode)+".v"
            sdc_name =  "b"+str(base)+"_"+str(clock) + "_pr.sdc"
            cmd ="read_celllib ./data/lib/data.lib\n"
            cmd+="read_multi_verilog ./data/netlist/"+verilog_name+"\n"
            cmd+="read_sdc ./data/sdc/b"+str(base) +"/"+sdc_name+"\n"
            cmd+="read_place ./data/DataPT/data/"+place_name+"\n"
            cmd+="read_spef ./logs/spef/" + str(base) + "_" + str(clock) + "_" + str(mode) + ".spef" + "\n"
            cmd+="update_timing\n"
            print(str(df.loc[place_name,"kway"]))
            cmd+="read_partion_result ./logs/hypergraph/"+place_name+".hgr.part." + str(df.loc[place_name,"kway"]) +"\n" 
            cmd+="dump_rf_feature ./logs/prNetDcFea/k-way/"+place_name+"\n"
            try:
                data = subprocess.check_output(
                    ["./build/ot-shell"],
                    input=bytes(cmd,encoding="UTF-8"),
                )
                print(data)
            except:
                data=None
            print(cmd)

下面更改特征:

添加10个字段,记录了part的二进制表示。

if(rcnode._pin->_name.find(":") != std::string::npos){
                                            int part = rcnode._pin->_gate->getPart() ;   
                                            int parts[10] = {0};
                                            int tpart = part;
                                            for(int i = 9;i >=0 && tpart!=0;i --){
                                              parts[i] = tpart & 1;
                                              tpart = tpart >> 1;
                                            }
                                            os<<groupId<<"," << part << "," 
                                            << parts[0] << ","
                                            << parts[1] << ","
                                            << parts[2] << ","
                                            << parts[3] << ","
                                            << parts[4] << ","
                                            << parts[5] << ","
                                            << parts[6] << ","
                                            << parts[7] << ","
                                            << parts[8] << ","
                                            << parts[9] << ","
                                            <<rcnode._pin->_name<<","<<rctree->_root->_load[el][rf]<<","<<*_root->slew(el,rf)<<","<<\
                                            rcnode._ldelay[el][rf]<<","<<_root->_loc._x<<","<<_root->_loc._y<<","<<rcnode._pin->_loc._x<<","<<rcnode._pin->_loc._y<<","<<sub.P2Odis()<<","<<strength<<\
                                            ","<<rcnode._load[el][rf]<<","<<rcnode._pin->cap(el,rf)<<","<<rcnode.delay(el,rf)<<\
                                            "," <<*arc->_to.slew(el,rf) <<","<<*arc->_delay[el][rf][rf]<<std::endl;
                                          }

这里有个小技巧,就是再创建一个小project来进行针对性的测试,寻找bug,这样很容易发现问题、解决问题。而且很快。

img

特征生成完毕。

二话不说,进行一波训练。

现在把所有的数据放到Data/prNetDcFea_kway/data下。预测的结果放在Data/prNetDcFea_kway/predictRes下。

用cro_lg.py也就是lightgbm进行交叉验证。第一次实验如下:

先不加这10个特征,进行wire_delay的训练。

img

加入10个特征之后,进行wire_delay的训练。

img

效果反而不好了。

9:1下,没有加特征的两次的效果:

img

取上的

img

加了特征的效果:

img

差别不大。。

split_lg.py slew上加入10个特征的效果:

img

不加的效果如下:

img

不加反而效果更好。

cro_lg.py 上的 加了10个特征的wire_slew的效果。

img

不加的效果:

img

明天跟老师汇报一下,看能不能换种思路。

7月6日

特征仅使用part字段。进行第二次实验。

在wire slew上,仅加入part字段的效果如下所示,分别是交叉验证cro.lg,以及9:1split.lg的实验结果。

image-20210706151008689

image-20210706151021502

在wire delay上,仅加入part字段的效果如下所示,分别是交叉验证cro.lg,以及9:1split.lg的实验结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIcIuoYM-1653533351037)(https://i.loli.net/2021/07/14/bpQFKaSuiEBej5G.png)]

image-20210706152623018

7月7日

之前cro.rf结果跑不出来,内存不足,电脑卡住了。

下面试一下split.rf效果:文件是split_rf.py

import pickle
import random

import joblib
import numpy as np
import matplotlib.pyplot as plt
import sklearn.ensemble as se  # 集合算法模块
import pandas as pd
from torch.utils.data import Dataset, DataLoader
import torch
import config
import sklearn.metrics as sm
from sklearn.model_selection import cross_val_score
def setup_seed(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)
    torch.backends.cudnn.deterministic = True
class MyDataSetBase():
    def __init__(self,base):

        super(MyDataSetBase,self).__init__()
        self.data = pd.DataFrame()
        for clock in range(0, config.clock):
            for mode in range(0, config.mode):#b11_0_mode_0_rf.csv
                name = "b" + str(base) + "_" + str(clock) + "_mode_" + str(mode)
                drive_node_name = config.datapath + "/" + name + "_rf.csv"
                #drive_node_name = config.datapath + "/" + name + "_drive_node.csv"
                print("read name", drive_node_name)
                tmp = pd.read_csv(drive_node_name)
                self.data = self.data.append(tmp)
        #print(self.__len__())
    def __getitem__(self, item):#drive_load,wire_input_slew,D2M,d_x,d_y,s_x,s_y,dis,strength,sink_load,sink_pin_capacitance,elmore_delay
        feature = self.data[names].to_numpy()[item]
        #feature = self.data[["capacitance", "ldelay","impulse","strength"]].to_numpy()[item]
        label = self.data[[config.type]].to_numpy()[item]
        return feature,label
    def __len__(self):
        return len(self.data)

class RandomModel():
    def __init__(self):
        super(RandomModel,self).__init__()

    def load_data9to1(self):
        custom_datasets = []
        for base in range(config.train_start_id, config.train_end_id):
            if base == 16:
                continue
            subData = MyDataSetBase(base)
            custom_datasets.append(subData)
            # print(subData.__len__())

        custom_datasets_test = []

        train_dataset_feature = []
        train_dataset_label = []

        test_dataset_feature = []
        test_dataset_label = []

        dataset_feature = []
        dataset_label = []
        for custom_dataset in custom_datasets:
            train_size = int(len(custom_dataset) * 0.9)
            test_size = len(custom_dataset) - train_size
            # print(len(custom_dataset))
            train_dataset, test_dataset = torch.utils.data.random_split(custom_dataset, [train_size, test_size])
            dataset_feature.append(custom_dataset[:][0])
            dataset_label.append(custom_dataset[:][1])

            train_dataset_feature.append(train_dataset[:][0])
            train_dataset_label.append(train_dataset[:][1])
            test_dataset_feature.append(test_dataset[:][0])
            test_dataset_label.append(test_dataset[:][1])

            custom_datasets_test.append(test_dataset)
        # model train
        train_feature = train_dataset_feature[0]
        train_label = train_dataset_label[0]
        test_feature = test_dataset_feature[0]
        test_label = test_dataset_label[0]
        feature = dataset_feature[0]
        label = dataset_label[0]
        for i in range(len(train_dataset_feature)):
            if i == 0:
                continue
            train_feature = np.vstack((train_feature, train_dataset_feature[i]))
            train_label = np.vstack((train_label, train_dataset_label[i]))
            test_feature = np.vstack((test_feature, test_dataset_feature[i]))
            test_label = np.vstack((test_label, test_dataset_label[i]))
            feature =  np.vstack((feature, dataset_feature[i]))
            label = np.vstack((label, dataset_label[i]))
        # print(len(train_feature))
        # print(len(train_label))
        self.test = custom_datasets_test
        self.data = train_feature, train_label.ravel(), test_feature, test_label.ravel()
        self.total = feature,label.ravel()
        #return train_feature, train_label.ravel(), custom_datasets_test, test_feature, test_label.ravel()
    def test_RandomForestRegressor_num(self):
        '''
        测试 RandomForestRegressor 的预测性能随  n_estimators 参数的影响

        :param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、测试样本集、训练样本的值、测试样本的值
        :return: None
        '''
        X_train, y_train,X_test,y_test = self.data
        feature,label = self.total
        nums=np.arange(1,50,step=2)
        fig=plt.figure()
        ax=fig.add_subplot(1,1,1)
        testing_scores=[]
        training_scores=[]
        cross_scores = []
        for num in nums:
            regr=se.RandomForestRegressor(n_estimators=num)
            regr.fit(X_train,y_train)
            train_score = regr.score(X_train,y_train)
            test_score = regr.score(X_test,y_test)
            training_scores.append(train_score)
            testing_scores.append(test_score)
            # score_pre = cross_val_score(regr, feature, label, cv=10).mean()
            # cross_scores.append(score_pre)
            print("num " + str(num) + " ---------------")
            print("train_score " + str(train_score))
            print("test_score "+ str(test_score))
            #print("cross_score " + str(score_pre))
        test_score_max = max(testing_scores)
        print('testing_scores最大得分:{}'.format(test_score_max),
              'testing_scores子树数量为:{}'.format(testing_scores.index(test_score_max) * 2))
        train_score_max = max(training_scores)
        print('train_scores最大得分:{}'.format(train_score_max),
              'train_scores子树数量为:{}'.format(training_scores.index(train_score_max) * 2))
        # crosss_score_max = max(cross_scores)
        # print('cross_scores最大得分:{}'.format(crosss_score_max),
        #       'cross_scores子树数量为:{}'.format(cross_scores.index(crosss_score_max) * 2))

        ax.plot(nums,training_scores,label="Training Score")
        ax.plot(nums,testing_scores,label="Testing Score")
        #ax.plot(nums,cross_scores,label="Cross Score")
        ax.set_xlabel("estimator num")
        ax.set_ylabel("score")
        ax.legend(loc="lower right")
        ax.set_ylim(-1,1)
        plt.suptitle("RandomForestRegressor")
        # 设置 X 轴的网格线,风格为 点画线
        plt.grid(axis='x',linestyle='-.')
        plt.show()
    def test_RandomForestRegressor_max_depth(self,n_esimator):
        '''
        测试 RandomForestRegressor 的预测性能随  max_depth 参数的影响

        :param data:  可变参数。它是一个元组,这里要求其元素依次为:训练样本集、测试样本集、训练样本的值、测试样本的值
        :return:  None
        '''
        X_train, y_train,X_test,y_test = self.data
        feature, label = self.total
        maxdepths=range(1,30)
        fig=plt.figure()
        ax=fig.add_subplot(1,1,1)
        testing_scores=[]
        training_scores=[]
        cross_scores = []
        for max_depth in maxdepths:
            regr= se.RandomForestRegressor(max_depth=max_depth,n_estimators=n_esimator)
            regr.fit(X_train,y_train)
            train_score = regr.score(X_train, y_train)
            test_score = regr.score(X_test, y_test)
            training_scores.append(train_score)
            testing_scores.append(test_score)
            # score_pre = cross_val_score(regr, feature, label, cv=10).mean()
            # cross_scores.append(score_pre)
            print("max_depth " + str(max_depth) + " ---------------")
            print("train_score " + str(train_score))
            print("test_score " + str(test_score))
            #print("cross_score " + str(score_pre))
        test_score_max = max(testing_scores)
        print('testing_scores最大得分:{}'.format(test_score_max),
              'testing_scores  max_depth:{}'.format(testing_scores.index(test_score_max)))
        train_score_max = max(training_scores)
        print('train_scores最大得分:{}'.format(train_score_max),
              'train_scores max_depth:{}'.format(training_scores.index(train_score_max)))
        # crosss_score_max = max(cross_scores)
        # print('cross_scores最大得分:{}'.format(crosss_score_max),
        #       'cross_scores子树数量为:{}'.format(cross_scores.index(crosss_score_max) * 2))
        ax.plot(maxdepths,training_scores,label="Training Score")
        ax.plot(maxdepths,testing_scores,label="Testing Score")
        ax.plot(maxdepths, cross_scores, label="Cross Score")
        ax.set_xlabel("max_depth")
        ax.set_ylabel("score")
        ax.legend(loc="lower right")
        ax.set_ylim(0,1.05)
        plt.suptitle("RandomForestRegressor")
        # 设置 X 轴的网格线,风格为 点画线
        plt.grid(axis='x',linestyle='-.')
        plt.show()
    # def load_data(self):
    #     X_train, y_train,custom_datasets_test,X_test,y_test  = load_data9to1()
    #     self.test = custom_datasets_test
    #     self.data = X_train,y_train,X_test,y_test
    def train(self):
        train_feature,train_label,X_test,y_test = self.data
        print("RUN train")
        model = se.RandomForestRegressor(max_depth= dic[config.type]["max_depth"],n_estimators=dic[config.type]["n"], min_samples_split=2,random_state= 1, warm_start=True)
        model.fit(train_feature, train_label)
        score = model.score(X_test, y_test)
        print(score)
        joblib.dump(model, config.modelname + config.type + ".m")
    def predict(self):
        # model_test
        self.model = joblib.load(config.modelname + config.type + ".m")
        custom_datasets_test = self.test
        index = config.train_start_id
        self.lists=[]
        for test_dataset in custom_datasets_test:
            predict = self.model.predict(test_dataset[:][0])
            _cor = self.model.score(test_dataset[:][0], test_dataset[:][1].ravel())
            mse = sm.mean_squared_error(predict, test_dataset[:][1])
            _max_error = round(sm.max_error(test_dataset[:][1], predict) * 1000, 2)
            _mean_error = round(sm.mean_absolute_error(test_dataset[:][1], predict) * 1000, 2)
            if config.flag_to_net == 1:
                if index == 16:
                    index = index + 1
                data = pd.DataFrame(columns=names, data = test_dataset[:][0])
                data['label'] = test_dataset[:][1].ravel()
                data['predict'] = predict
                data['abs_error'] = abs(predict - test_dataset[:][1].ravel())
                data['abs_error/label'] = abs(predict - test_dataset[:][1].ravel()) / test_dataset[:][1].ravel()
                # data['abs_error'] = abs(predict-test_dataset)
                data.to_csv("./testPredictrf/b" + str(index) + config.type + "_test.csv", index=False, sep=',')
            self.lists.append([index,_cor, mse,_max_error,_mean_error])
            index = index + 1
colName = ["file","_cor","mse","max_error","mean_error"]
names = ["drive_load","wire_input_slew","strength","elmore_delay","sink_load","sink_pin_capacitance"]
#mode 0 dic = {"delay": {"n": 96, "max_depth": 9}, "slew": {"n": 48, "max_depth": 15}}
#dic = {"delay": {"n": 40, "max_depth": 12}, "slew": {"n": 48, "max_depth": 15}} #mode 1
#groupId,pin_name,drive_load,D2M,dis,strength,sink_load,sink_pin_capacitance,elmore_delay,sink_pin_num,output_capacitance
#names = ["drive_load","D2M","strength","elmore_delay","sink_load","sink_pin_capacitance","elmore_delay"] #slew,delay的特征
#names = ["drive_load","strength","sink_load","sink_pin_capacitance","elmore_delay","sink_pin_num"] #output load的特征
dic = {"wire_delay": {"n": 200, "max_depth": 11}, "wire_slew": {"n": 46, "max_depth": 40},"output_capacitance":{"n": 46, "max_depth": 22}}  #all mode
setup_seed(24) #delay best 24
#groupId,pin_name,drive_load,wire_input_slew,D2M,d_x,d_y,s_x,s_y,dis,strength,sink_load,sink_pin_capacitance,elmore_delay,wire_slew,wire_delay
#groupId,mode,pin_name,drive_load,wire_input_slew,D2M,d_x,d_y,s_x,s_y,dis,strength,sink_load,sink_pin_capacitance,elmore_delay,wire_slew,wire_delay

def main():
    model = RandomModel()
    model.load_data9to1()
    train(model)
    #parameter(model)
    to_csv(model)
def train(model):
    if config.train_flag == 0:
        model.train()
    model.predict()
def parameter(model):
    #model.test_RandomForestRegressor_num()
    model.test_RandomForestRegressor_max_depth(48)
def to_csv(model):
    res_csv = pd.DataFrame(columns=colName, data=model.lists)
    import time
    now = int(round(time.time() * 1000))
    now02 = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(now / 1000))
    res_csv.to_csv("./OursDC/" + config.type + "_m" + str(dic[config.type]["max_depth"]) + "_n" + str(dic[config.type]["n"]) + "_" + now02 + ".csv")
main()

以上实验的基本特征如下:

names = [“drive_load”,“wire_input_slew”,“D2M”,“strength”,“elmore_delay”,“sink_load”,“sink_pin_capacitance”]

顺便说一句,“D2M”在随机森林里面作用不大,在lightgbm里面作用挺大。

加入part:多一个part字段

加入10个特征:多加了P10-P1(10个字段)

没有加入part的效果如下split.rf:

image-20210707154916877

加入part的效果如下split.rf:

image-20210707161258061

加入10个特征的效果如下split.rf:

image-20210707161324894

7月14日

下午,我打算把实验数据代码迁移到这个电脑上。重新整理一下。

代码迁移到hp上暂时失败

7月15日

在ubuntu上将划分的特征进行异或,作为dist特征。

int dist = _root->_gate->getPart() & rcnode._pin->_gate->getPart()

批量生成dist特征,使用scripts/injectPartion.py

特征提取完成,生成到prNetDcFea/dist-way文件夹下。

用cro.lg跑一次

明天要搞清楚dump_rf_feature的逻辑关系,否则特征提取会有问题!

7月16日

image-20210716101241073

RCTree多了一个中间节点,它是null。

  • 第一层循环:遍历RCTree的所有RCNode sink节点(除了null)。
  • 第二层循环:遍历rcNode sink的pin,回到上面的net。找fanin,也就是找出时序弧from为root,to为rcNode._pin。
  • 最后就是特征提取:节点特征从rcnode中提取,label就是从arc中提取slew/delay。

Pin类里面写一个成员函数,然后使用Net*,找出其它sink节点driver异或。

14:31 先取均值

float Pin::getContextMean(){
  auto pins = (*_net).getAllPin();
  auto root_pin = (*_net).rootPin();
  float sum = 0;
  int count = 0;
  for(auto pin : pins){
    if(pin != root_pin && pin->name() != name() && pin->_name.find(":") != std::string::npos){
      sum += pin->_gate->getPart() & root_pin->_gate->getPart();
      count++;
    }
  }
  return count !=0 ? sum / count : 0;
}

bug: return count !=0 ? sum / count : 0;有些线网就一个pin,那么其它sink pin的与驱动dist就是0.这里出现-nan,是因为有除以count0的存在。

image-20210716152914843

将数据迁移到hp电脑上了!!!

OSError: [Errno 22] Invalid argument已解决(to_csv()时遇到以时间为文件名)

吓一跳,应该是将中文换成英文后,路径出现变化,桌面上图标就不见了。

PyCharm也能正常跑模型代码。

现在将特征数据提取到pycharm中,进行模型训练。

void Net::dump_rf_feature(std::ostream &os,Split el,Tran rf,int groupId) const{
                  //os<<"groupId,part,pin_name,drive_load,wire_input_slew,D2M,d_x,d_y,s_x,s_y,dis,strength,sink_load,sink_pin_capacitance,elmore_delay,wire_slew,wire_delay"<<std::endl;
                  const Rct*  rctree= rct(); 
                  // Loc rootLoc = _root->_loc;

                  int strength = drive_strength();
                  //_root������ǿ�� (Net��)
                  //_sink_pin��root_pin�ľ��루sink_pin�
                  //net ��context_dis����???����
                   for(auto [name,rcnode]:(*rctree)._nodes)
                    {
                            if(rcnode._name != rctree->_root->_name )
                            {
                                if(rcnode._pin == nullptr)
                                {
                                      //rc_node ��ʱ��������
                                      continue;
                                }
                                else
                                {
                                    for(auto arc:rcnode._pin->_fanin)
                                    {
                                      if(arc->_from.name() == _root->name())
                                      {
                                           Loc sub = _root->_loc -  rcnode._pin->_loc;
                                           
                                          // double dis = sub.P2Odis();
                                          //sink_pin
                                          //std::cout << rcnode._pin->_name <<std::endl;
                                          if(rcnode._pin->_name.find(":") != std::string::npos && _root->gate() != nullptr){
                                            int dist = _root->gate()->getPart() & rcnode._pin->_gate->getPart();
                                            int part = rcnode._pin->_gate->getPart() ;   
                                            int parts[10] = {0};
                                            int tpart = part;
                                            for(int i = 9;i >=0 && tpart!=0;i --){
                                              parts[i] = tpart & 1;
                                              tpart = tpart >> 1;
                                            }
                                            os
                                            <<  groupId << "," 
                                            <<  part    << "," 
                                            <<  dist    << ","
                                            << rcnode._pin->getContextMean() << ","
                                            << parts[0] << ","
                                            << parts[1] << ","
                                            << parts[2] << ","
                                            << parts[3] << ","
                                            << parts[4] << ","
                                            << parts[5] << ","
                                            << parts[6] << ","
                                            << parts[7] << ","
                                            << parts[8] << ","
                                            << parts[9] << ","
                                            <<rcnode._pin->_name<<","<<rctree->_root->_load[el][rf]<<","<<*_root->slew(el,rf)<<","<<\
                                            rcnode._ldelay[el][rf]<<","<<_root->_loc._x<<","<<_root->_loc._y<<","<<rcnode._pin->_loc._x<<","<<rcnode._pin->_loc._y<<","<<sub.P2Odis()<<","<<strength<<\
                                            ","<<rcnode._load[el][rf]<<","<<rcnode._pin->cap(el,rf)<<","<<rcnode.delay(el,rf)<<\
                                            "," <<*arc->_to.slew(el,rf) <<","<<*arc->_delay[el][rf][rf]<<std::endl;
                                          }
                                      }
                                    
                                    }
                                }
                                  
                            }
                            else
                            { 
                              //root_node ��ʱ��������
                              continue;
                            }
                          
                    }
}

7月18日

修改小论文,pycharm 全部文件搜索关键词(全局文件搜索) - 博二爷 - 博客园 (cnblogs.com)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-id1Yr4zk-1653533351040)(https://i.loli.net/2021/07/18/Yh1B9OASKePtJUs.png)]

如何用sklearn对随机森林调参? - 知乎 (zhihu.com)

“DC Ours" 采用最大深度25,子树数量46.

"Ours"采用最大深度为22,子树数量为46.

image-20210723095814864

7月30日

上回说道:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yj62faDy-1653533351042)(https://i.loli.net/2021/07/30/DkN3q4vaLpcKEbT.png)]

目前已经将driver-sink之间的part异或作为dist特征

​ 还有其余sink的part(与driver异或)得到均值。如下图所示:

image-20210730105738123

下面对它们进行训练。

随机森林训练效果演示

  • 用cro.rf 在不加划分特征的情况下,进行训练。特征:[“drive_load”,“wire_input_slew”,“D2M”,“strength”,“elmore_delay”,“sink_load”,“sink_pin_capacitance”]

image-20210730114341772

  • 加入[“drive_load”,“dist”,“meanvalue”,“wire_input_slew”,“D2M”,“strength”,“elmore_delay”,“sink_load”,“sink_pin_capacitance”] dist和meanvalue进行训练image-20210730153909250

  • 下面使用meanvalue进行训练,[“drive_load”,“meanvalue”,“wire_input_slew”,“D2M”,“strength”,“elmore_delay”,“sink_load”,“sink_pin_capacitance”]

9月15日

问题:我们使用的是delay/slew是用布局布线后通过PT跑出来的时序结果,将它们作为label进行训练和预测。之后就是算时序路径的slack,同一个逻辑综合的netlist,会有多个布局布线的模式,那么选择哪个模式作为标准答案进行对比呢?怎么判断算出来的时序路径(时序违例)是否正确呢?定性分析(时序违例判断是否正确)还要定量分析(slack差值大不大)

方案:根据《Net2》论文中提出的方案:PR只用一种策略。也就是在我们之后的模型训练和预测、以及最后slack的比较中,只参考一种PR方式。

image-20210915195147105

明日计划:只使用一种PR的数据进行模型的训练和预测。重新跑一下数据。之前我们都是使用了几种PR,混在一起进行模型的训练和预测的。接下来我会只使用一种PR来做实验。

每个Design有5种逻辑综合的策略,对应的又有4种PR的策略。

image-20210915200959193

image-20210915201154725

9月16日

解决多模块问题

  • 利用线负载模型生成逻辑综合SPEF

debug调试 spef.cpp 是用来debug 利用线负载模型生成逻辑综合阶段下的SPEF文件

spef.cpp如下:

#include <ot/timer/timer.hpp>
#include <sstream>
#include <fstream>
#include <iomanip>
int main(int argc, char* argv[]) {
  
  ot::Timer timerSyn;
  std::string filepath = argv[1];// 输出spef文件路径
  std::string fileIndex_1 = argv[2];//哪种desgin
  std::string fileIndex_2 = argv[3];//design之下哪种synthesis 
  std::string fileIndex = fileIndex_1 + "_" + fileIndex_2;
  
  std::ofstream logofs(filepath + "/" + fileIndex + ".spef");
  std::ostream &logos = logofs.good()?logofs:std::cout;
  // Builder
  //   - read cell library for both early/late mode (nullopt)
  //   - read the verilog
  //   - read the parasitics
  //   - read the design constraints
  std::string synNetFileName = "b" + fileIndex + "_SYN.v";
  std::string prNetFileName  = "b" + fileIndex + "_pr_mode_0.v";//默认使用第一种PR策略
  std::string synSDCfileName = "b" + fileIndex + "_syn.sdc";
  std::string prSDCfileName  = "b" + fileIndex + "_pr.sdc";
  std::string prSPEFfileName = "b" + fileIndex + "_pr_mode_0.spef";//默认使用第一种PR策略
  //读取celllib
  timerSyn.read_celllib("./data/lib/data.lib")
        //读取 多模块的逻辑综合netlist
       .read_multi_verilog("./data/netlist/" + synNetFileName)
       //读取  逻辑综合的sdc约束文件
       .read_sdc("./data/sdc/b" + fileIndex_1 + "/" + synSDCfileName);
  timerSyn.update_timing();
  timerSyn.write_spef(logos);
  //timerSyn.dump_verilog(logos,fileIndex+"_"+mode);
  return 0;
}

尝试生成b20_0 多模块下的spef如下图所示:

image-20210916165758979

  • 读取多模块的netlist以及相应生成的SPEF

    multimodule.cpp如下:

/*
    这个文件用来debug 多模块读取
    date: 2021/9/16 下午17:07
*/
#include <ot/timer/timer.hpp>
#include <sstream>
#include <fstream>
#include <iomanip>
int main(int argc, char* argv[]) {
  
  ot::Timer timerSyn;
  
  std::string fileIndex_1 = argv[2];//哪个design
  std::string fileIndex_2 = argv[3];//逻辑综合的第n个策略
  std::string fileIndex = fileIndex_1 + "_" + fileIndex_2;//

  std::string synNetFileName = "b" + fileIndex + "_SYN.v";
  std::string prNetFileName  = "b" + fileIndex + "_pr_mode_0.v";//默认使用第一种PR策略
  std::string synSDCfileName = "b" + fileIndex + "_syn.sdc";
  std::string prSDCfileName  = "b" + fileIndex + "_pr.sdc";
  std::string prSPEFfileName = "b" + fileIndex + "_pr_mode_0.spef";//默认使用第一种PR策略
  
  //读取celllib
  timerSyn.read_celllib("./data/lib/data.lib")
        //读取 多模块的逻辑综合netlist
       .read_multi_verilog("./data/netlist/" + synNetFileName)
       //读取线负载模型下生成的逻辑综合的spef 
       .read_spef("./logs/spef2/"+fileIndex +".spef")
       //读取  逻辑综合的sdc约束文件
       .read_sdc("./data/sdc/b" + fileIndex_1 + "/" + synSDCfileName);
  timerSyn.update_timing();
  return 0;
}

从下图来看,spef读取成功了。

image-20210916171550101

  • 尝试读取PT时序报告
/*
    这个文件用来debug 多模块读取
    date: 2021/9/16 下午17:07
*/
#include <ot/timer/timer.hpp>
#include <sstream>
#include <fstream>
#include <iomanip>
int main(int argc, char* argv[]) {
  
  ot::Timer timerSyn;
  
  std::string fileIndex_1 = argv[2];//哪个design
  std::string fileIndex_2 = argv[3];//逻辑综合的第n个策略

  std::string fileIndex = fileIndex_1 + "_" + fileIndex_2;//


  std::string synNetFileName = "b" + fileIndex + "_SYN.v";
  std::string prNetFileName  = "b" + fileIndex + "_pr_mode_0.v";//默认使用第一种PR策略
  std::string synSDCfileName = "b" + fileIndex + "_syn.sdc";
  std::string prSDCfileName  = "b" + fileIndex + "_pr.sdc";
  std::string prSPEFfileName = "b" + fileIndex + "_pr_mode_0.spef";//默认使用第一种PR策略
  


  //读取celllib
  timerSyn.read_celllib("./data/lib/data.lib")
        //读取 多模块的逻辑综合netlist
       .read_multi_verilog("./data/netlist/" + synNetFileName)
       //读取 逻辑综合之下的PT时序报告
       .read_place("./data/DataDPT/data/b"+fileIndex)
       //读取线负载模型下生成的逻辑综合的spef 
       .read_spef("./logs/spef2/"+fileIndex +".spef")
       //读取  逻辑综合的sdc约束文件
       .read_sdc("./data/sdc/b" + fileIndex_1 + "/" + synSDCfileName);
  timerSyn.update_timing();
  return 0;
}

时序报告里面的格式:每个instance的各个pin

image-20210916172513155

  • 生成多模块下的特征文件,一种PR策略。提取一一对应的线网。

10月13日

看师兄的专利。

特征和时延,也要看信号的跳变。分情况,例如Gate Delay的输入引脚信号是上升沿,输出引脚信号是下降沿,此时对应的特征和时延,作为模型的样本。其它情况对应的跳变情况也要考虑。

10月14日

from math import sqrt

points = []
graph = []

def findSmallest(key, mstSet): 
  
        min = float("inf")
        
        for v in range(len(graph)): 
            if key[v] < min and mstSet[v] == False: 
                min = key[v] 
                min_index = v 
  
        return min_index

    
def getMSTWeight(parent):
    global graph
    weight = 0
    for i in range(1, len(graph)):
        weight = weight + graph[i][parent[i]]
        
    return weight


def primMST(): 
    global graph
    key = [float("+inf")] * len(graph)
    parent = [None] * len(graph)
    key[0] = 0 
    mstSet = [False] * len(graph)

    parent[0] = -1  

    for cout in range(len(graph)): 

        u = findSmallest(key, mstSet) 

        mstSet[u] = True

        for v in range(len(graph)): 

            if graph[u][v] > 0 and mstSet[v] == False and key[v] > graph[u][v]: 
                    key[v] = graph[u][v] 
                    parent[v] = u 

    return getMSTWeight(parent) 

def findLeftMostPoint(points):
    return sorted(points)[0]
    
def findRightMostPoint(points):
    return sorted(points)[-1]

def findTopMostPoint(points):
    return sorted(points, key = lambda x : x[1])[-1]

def findBottomMostPoint(points):
    return sorted(points, key = lambda x : x[1])[0]

def findTopLeftPoint(topPoint, leftPoint):
    return [leftPoint[0], topPoint[1]]

def findTopRightPoint(topPoint, rightPoint):
    return [rightPoint[0], topPoint[1]]

def findBottomLeftPoint(bottomPoint, leftPoint):
    return [leftPoint[0], bottomPoint[1]]

def findDist(point1, point2):
    x1, y1 = point1
    x2, y2 = point2
    
    return abs(x2 - x1) + abs(y2 - y1)

def HPWL(points):
    
    leftPoint = findLeftMostPoint(points)
    topPoint = findTopMostPoint(points)
    bottomPoint = findBottomMostPoint(points)
    rightPoint = findRightMostPoint(points)

    rectTopLeftPoint = findTopLeftPoint(topPoint, leftPoint)
    rectBottomLeftPoint = findBottomLeftPoint(bottomPoint, leftPoint)
    rectTopRightPoint = findTopRightPoint(topPoint, rightPoint)

    rectLength = findDist(rectTopLeftPoint, rectBottomLeftPoint)
    rectBreadth = findDist(rectTopLeftPoint, rectTopRightPoint)

    return rectLength + rectBreadth

def getSteinerPoints(points):

    steinerPoints = []

    for pt1 in points:
        for pt2 in points:
            if pt1 == pt2:
                continue
            
            x1, y1 = pt1
            x2, y2 = pt2

            steiner_pt1 = [x1, y2]
            steiner_pt2 = [x2, y1]
            if steiner_pt1 not in points + steinerPoints:
                steinerPoints.append(steiner_pt1)

            if steiner_pt2 not in points + steinerPoints:
                steinerPoints.append(steiner_pt2)

    return steinerPoints
            

def computeMST(points):
    global graph
    adjMatrix = []

    for point1 in points:
        adjMatrix.append([])
        for point2 in points:
            adjMatrix[-1].append(findDist(point1, point2))

    graph = adjMatrix
    return primMST()
    

with open("net7", "r") as file:
    lines = file.read().split("\n")

    for line in lines:
        line = line.strip()
        if len(line) == 0:
            continue
        
        nums = line.split(" ")
        points.append([int(nums[0]), int(nums[1])])
print ("# Points: " + str(len(points)))
print ("HPWL: " + str(HPWL(points)))
currentMST_weight = computeMST(points)
print ("MST: " + str(currentMST_weight))
while True:

    bestMST = currentMST_weight + 1
    bestSteinerPoint = []
    steinerPoint = getSteinerPoints(points)

    for s_pt in steinerPoint:
        MSTwt = computeMST(points + [s_pt])
        if MSTwt < bestMST:
            bestMST = MSTwt
            bestSteinerPoint = s_pt

    if bestMST < currentMST_weight:
        currentMST_weight = bestMST
        points = points + [bestSteinerPoint]
    else:
        break

print("Steiner tree: " + str(currentMST_weight))

image-20211014172147762

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛歌依旧fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值