diff --git a/pkgs/abstract-machine/default.nix b/pkgs/abstract-machine/default.nix new file mode 100644 index 0000000..fce6c82 --- /dev/null +++ b/pkgs/abstract-machine/default.nix @@ -0,0 +1,42 @@ +{ lib +, stdenvNoCC +, fetchFromGitHub +, pkgsCross +, gnumake +, isa ? "riscv32e" +, platform ? "nemu" +}: + +let + isa_mapping = { + riscv32e = "riscv64"; + }; +in stdenvNoCC.mkDerivation rec { + pname = "abstract-machine"; + version = "2023-08-29"; + + src = fetchFromGitHub { + owner = "NJU-ProjectN"; + repo = "abstract-machine"; + rev = "3348db971fd860be5cb28e21c18f9d0e65d0c96a"; + hash = "sha256-jZVivawwHXw5WCrHm5vOb9nDBqK6BFVer8Zec0/oZvc="; + }; + + nativeBuildInputs = [ + gnumake + pkgsCross.${isa_mapping.${isa}}.gcc + ]; + + SRCS = src; + AM_HOME = src; + ARCH = "${isa}-${platform}"; + MAKECMDGOALS = "image"; + + meta = with lib; { + description = "A minimal, modularized, and machine-independent hardware abstraction layer"; + homepage = "https://github.com/NJU-ProjectN/abstract-machine.git"; + license = licenses.mit; + maintainers = with maintainers; [ ]; + broken = true; + }; +} diff --git a/pkgs/ieda/default.nix b/pkgs/ieda/default.nix new file mode 100644 index 0000000..044576b --- /dev/null +++ b/pkgs/ieda/default.nix @@ -0,0 +1,77 @@ +{ stdenvNoCC +, lib +, cargo +, fetchgit +, pkgsStatic +, gcc11 +, cmake +, ninja +, flex +, bison +, zlib +, tcl +, gflags +, glog +, boost180 +, eigen +, yaml-cpp +, libunwind +, metis +, gmp +, python3 +}: + +stdenvNoCC.mkDerivation rec { + name = "iEDA"; + version = "0.3"; + # src = fetchFromGitHub { + # owner = "OSCC-Project"; + # repo = "iEDA"; + # rev = "a7df35fb4667cc099ab76d10da113f09060ac0ea"; + # hash = "sha256-ShMZ20EoFM34JUjmBh2enHTarM0qQbYb5A5eoC9D/VA="; + # }; + src = fetchgit { + url = "https://gitee.com/oscc-project/iEDA.git"; + name = "iEDA"; + rev = "4de9f6c2dc602852fc1b668a866ffee0d96e2dcb"; + hash = "sha256-BBVLVa2vuKdhz0Eb5aRrlkAMXlLcrTKWW63G3L3XgyE="; + }; + patches = [ ./fixtcl.patch ./fix_header.patch ]; + + nativeBuildInputs = [ + gcc11 + cargo + cmake + ninja + flex + bison + zlib + ]; + + buildInputs = [ + tcl + pkgsStatic.gtest + gflags + glog + boost180 + eigen + yaml-cpp + libunwind + metis + gmp + python3 + ]; + + cmakeFlags = [ + "-DBUILD_STATIC_LIB=off" + ]; + + CXXFLAGS = "-fpermissive"; + meta = with lib; { + description = "An open-source EDA infracstrucutre and tools from netlist to GDS for ASIC design."; + homepage = "https://gitee.com/oscc-project/iEDA"; + license = licenses.mulan-psl2; + maintainers = with maintainers; [ ]; + broken = true; + }; +} diff --git a/pkgs/ieda/fix_header.patch b/pkgs/ieda/fix_header.patch new file mode 100644 index 0000000..8afb206 --- /dev/null +++ b/pkgs/ieda/fix_header.patch @@ -0,0 +1,12 @@ +diff --git a/src/operation/iCTS/api/CTSAPI.hh b/src/operation/iCTS/api/CTSAPI.hh +index 86ff3565..bef443a0 100644 +--- a/src/operation/iCTS/api/CTSAPI.hh ++++ b/src/operation/iCTS/api/CTSAPI.hh +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include "../../../database/interaction/ids.hpp" + diff --git a/pkgs/ieda/fixtcl.patch b/pkgs/ieda/fixtcl.patch new file mode 100644 index 0000000..e830834 --- /dev/null +++ b/pkgs/ieda/fixtcl.patch @@ -0,0 +1,13 @@ +diff --git a/src/utility/tcl/ScriptEngine.hh b/src/utility/tcl/ScriptEngine.hh +index 522e9878..cdee8af9 100644 +--- a/src/utility/tcl/ScriptEngine.hh ++++ b/src/utility/tcl/ScriptEngine.hh +@@ -24,7 +24,7 @@ + + #pragma once + +-#include ++#include + + #include + #include diff --git a/pkgs/ieda/remove_format.patch b/pkgs/ieda/remove_format.patch new file mode 100644 index 0000000..f97fa13 --- /dev/null +++ b/pkgs/ieda/remove_format.patch @@ -0,0 +1,3077 @@ +diff --git a/src/third_party/salt/CHANGELOG.md b/src/third_party/salt/CHANGELOG.md +index 5408be85..33992341 100644 +--- a/src/third_party/salt/CHANGELOG.md ++++ b/src/third_party/salt/CHANGELOG.md +@@ -149,8 +149,4 @@ diff -r ./base/net.h {ORIGIN REPOSITORY}/src/salt/base/net.h + > void Write(const string& prefix, bool withNetInfo = true) const; + > + > friend ostream& operator<<(ostream& os, const Net& net) { net.Write(os); return os; } +-``` +- +-### Rename variable +- +-Changing some variable names and function names for the uniform naming convention does not change the code logic +\ No newline at end of file ++``` +\ No newline at end of file +diff --git a/src/third_party/salt/base/eval.cpp b/src/third_party/salt/base/eval.cpp +index 1cf554b4..b1f8cc5e 100644 +--- a/src/third_party/salt/base/eval.cpp ++++ b/src/third_party/salt/base/eval.cpp +@@ -7,7 +7,7 @@ namespace salt { + + void WireLengthEvalBase::Update(const Tree& tree) { + wireLength = 0; +- tree.postOrder([&](const shared_ptr& node) { ++ tree.PostOrder([&](const shared_ptr& node) { + if (node->parent) { + wireLength += node->WireToParent(); + } +@@ -60,7 +60,7 @@ void ElmoreDelayEval::Update(double rd, Tree& tree, bool normalize) { + maxDelay = avgDelay = maxNorDelay = avgNorDelay = 0; + + auto delay = GetDelay(rd, tree, numNodes); // delay for all tree nodes +- tree.preOrder([&](const shared_ptr& node) { ++ tree.PreOrder([&](const shared_ptr& node) { + if (!node->pin || node == tree.source) return; + maxDelay = max(maxDelay, delay[node->id]); + avgDelay += delay[node->id]; +@@ -70,7 +70,7 @@ void ElmoreDelayEval::Update(double rd, Tree& tree, bool normalize) { + if (!normalize) return; + + auto lb = GetDelayLB(rd, tree); // delay lb for all pins, 0 is source +- // tree.preOrder([&](const shared_ptr& node){ ++ // tree.PreOrder([&](const shared_ptr& node){ + // if(!node->pin || node == tree.source) return; + // double norDelay = delay[node->id] / lb[node->id]; + // maxNorDelay = max(maxNorDelay, norDelay); +@@ -85,7 +85,7 @@ void ElmoreDelayEval::Update(double rd, Tree& tree, bool normalize) { + vector ElmoreDelayEval::GetDelay(double rd, const Tree& tree, int numNode) { + // get node cap by post-order traversal + vector cap(numNode, 0); +- tree.postOrder([&](const shared_ptr& node) { ++ tree.PostOrder([&](const shared_ptr& node) { + if (node->pin && node != tree.source) cap[node->id] = node->pin->cap; + for (auto c : node->children) { + cap[node->id] += cap[c->id]; +@@ -95,7 +95,7 @@ vector ElmoreDelayEval::GetDelay(double rd, const Tree& tree, int numNod + + // get delay by post-order traversal + vector delay(numNode, 0); +- tree.preOrder([&](const shared_ptr& node) { ++ tree.PreOrder([&](const shared_ptr& node) { + if (node == tree.source) + delay[node->id] = rd * cap[node->id]; + else { +diff --git a/src/third_party/salt/base/flute.cpp b/src/third_party/salt/base/flute.cpp +index 31672f46..f83f637f 100644 +--- a/src/third_party/salt/base/flute.cpp ++++ b/src/third_party/salt/base/flute.cpp +@@ -14,8 +14,8 @@ void salt::FluteBuilder::Run(const salt::Net& net, salt::Tree& saltTree) { + } + + // Obtain flute tree +- Flute::Tree flute_tree; +- flute_tree.branch = nullptr; ++ Flute::Tree fluteTree; ++ fluteTree.branch = nullptr; + int d = net.pins.size(); + assert(d <= MAXD); + int x[MAXD], y[MAXD]; +@@ -23,17 +23,17 @@ void salt::FluteBuilder::Run(const salt::Net& net, salt::Tree& saltTree) { + x[i] = net.pins[i]->loc.x; + y[i] = net.pins[i]->loc.y; + } +- if (flute_tree.branch) free(flute_tree.branch); // is it complete for mem leak? +- flute_tree = Flute::flute(d, x, y, FLUTE_ACCURACY); ++ if (fluteTree.branch) free(fluteTree.branch); // is it complete for mem leak? ++ fluteTree = Flute::flute(d, x, y, FLUTE_ACCURACY); + + // Build adjacency list + unordered_map, shared_ptr, boost::hash>> key2node; + for (auto p : net.pins) { + key2node[{p->loc.x, p->loc.y}] = make_shared(p); + } +- auto& t = flute_tree; ++ auto& t = fluteTree; + +- auto find_or_create = [&](DTYPE x, DTYPE y) { ++ auto FindOrCreate = [&](DTYPE x, DTYPE y) { + auto it = key2node.find({x, y}); + if (it == key2node.end()) { + shared_ptr node = make_shared(x, y); +@@ -47,8 +47,8 @@ void salt::FluteBuilder::Run(const salt::Net& net, salt::Tree& saltTree) { + int j = t.branch[i].n; + if (t.branch[i].x == t.branch[j].x && t.branch[i].y == t.branch[j].y) continue; + // any more duplicate? +- shared_ptr n1 = find_or_create(t.branch[i].x, t.branch[i].y); +- shared_ptr n2 = find_or_create(t.branch[j].x, t.branch[j].y); ++ shared_ptr n1 = FindOrCreate(t.branch[i].x, t.branch[i].y); ++ shared_ptr n2 = FindOrCreate(t.branch[j].x, t.branch[j].y); + // printlog(LOG_INFO, "%d - %d\n", n1->pin?n1->pin->id:-1, n2->pin?n2->pin->id:-1); + n1->children.push_back(n2); + n2->children.push_back(n1); +@@ -59,5 +59,5 @@ void salt::FluteBuilder::Run(const salt::Net& net, salt::Tree& saltTree) { + saltTree.SetParentFromUndirectedAdjList(); + saltTree.net = &net; + +- free(flute_tree.branch); ++ free(fluteTree.branch); + } +\ No newline at end of file +diff --git a/src/third_party/salt/base/mst.cpp b/src/third_party/salt/base/mst.cpp +index 8a2ac098..48fe9352 100644 +--- a/src/third_party/salt/base/mst.cpp ++++ b/src/third_party/salt/base/mst.cpp +@@ -68,7 +68,7 @@ void MstBuilder::RunPrimAlg(const Net& net, const vector>& adjLists, + } + for (int i = 0; i < numPins; ++i) { + if (prefixes[i] >= 0) { +- TreeNode::setParent(nodes[i], nodes[prefixes[i]]); ++ TreeNode::SetParent(nodes[i], nodes[prefixes[i]]); + } + } + tree.source = nodes[0]; +diff --git a/src/third_party/salt/base/net.cpp b/src/third_party/salt/base/net.cpp +index ce852e22..246d2f23 100644 +--- a/src/third_party/salt/base/net.cpp ++++ b/src/third_party/salt/base/net.cpp +@@ -39,7 +39,7 @@ bool Net::Read(istream& is) { + istringstream iss(buf); + iss >> id >> name >> numPin >> option; + assert(numPin > 0); +- with_cap = (option == "-cap"); ++ withCap = (option == "-cap"); + + // pins + int i; +@@ -48,7 +48,7 @@ bool Net::Read(istream& is) { + pins.resize(numPin); + for (auto& pin : pins) { + is >> i >> x >> y; +- if (with_cap) is >> c; ++ if (withCap) is >> c; + pin = make_shared(x, y, i, c); + } + +@@ -67,7 +67,7 @@ void Net::Read(const string& fileName) { + string Net::GetHeader() const { + string header = to_string(id) + " " + name + " " + to_string(pins.size()); + // string header = name + " " + to_string(pins.size()); +- if (with_cap) header += " -cap"; ++ if (withCap) header += " -cap"; + return header; + } + +@@ -78,7 +78,7 @@ void Net::Write(ostream& os) const { + // pins + for (const auto& pin : pins) { + os << pin->id << " " << pin->loc.x << " " << pin->loc.y; +- if (with_cap) os << " " << pin->cap; ++ if (withCap) os << " " << pin->cap; + os << endl; + } + } +diff --git a/src/third_party/salt/base/net.h b/src/third_party/salt/base/net.h +index 3869359e..968eb8e2 100644 +--- a/src/third_party/salt/base/net.h ++++ b/src/third_party/salt/base/net.h +@@ -6,19 +6,21 @@ + + #include "salt/utils/utils.h" + ++using namespace std; ++ + // #define DTYPE int // same as flute.h, will overwrite it + typedef int DTYPE; + + namespace salt { +-using namespace std; ++ + using Point = utils::PointT; + using Box = utils::BoxT; + + class Pin + { + public: +- Point loc; + int id; // 0 for source, should be in range [0, pin_num) for a net ++ Point loc; + double cap; + + Pin(const Point& l, int i = -1, double c = 0.0) : loc(l), id(i), cap(c) {} +@@ -33,7 +35,7 @@ class Net + public: + int id; + string name; +- bool with_cap = false; ++ bool withCap = false; + + vector> pins; // source is always the first one + +@@ -42,7 +44,7 @@ class Net + this->id = id; + this->name = name; + this->pins = pins; +- this->with_cap = true; ++ this->withCap = true; + } + + void RanInit(int i, int numPin, DTYPE width = 100, DTYPE height = 100); // random initialization +diff --git a/src/third_party/salt/base/rsa.cpp b/src/third_party/salt/base/rsa.cpp +index 8461cbbe..b76f4345 100644 +--- a/src/third_party/salt/base/rsa.cpp ++++ b/src/third_party/salt/base/rsa.cpp +@@ -5,255 +5,227 @@ + + namespace salt { + +-constexpr double kPI = 3.14159265358979323846; /* pi */ +- +-void RSABase::ReplaceRootChildren(Tree& tree) +-{ +- const Net* old_net = tree.net; +- +- // create tmp_net and fake_pins +- Net tmp_net = *old_net; +- tmp_net.pins.clear(); +- unordered_map, shared_ptr> pin_to_old_node; +- tmp_net.pins.push_back(tree.source->pin); +- unordered_set> fake_pins; +- pin_to_old_node[tree.source->pin] = tree.source; +- for (auto c : tree.source->children) { // only contains the direct children of tree.source +- shared_ptr pin = c->pin; +- if (!pin) { +- pin = make_shared(c->loc); +- fake_pins.insert(pin); +- } +- tmp_net.pins.push_back(pin); +- pin_to_old_node[pin] = c; +- } +- tree.source->children.clear(); // free them... +- +- // get rsa and graft the old subtrees to it +- Run(tmp_net, tree); +- tree.postOrder([&](const shared_ptr& node) { +- if (node->pin) { +- auto old_node = pin_to_old_node[node->pin]; +- if (fake_pins.find(node->pin) != fake_pins.end()) +- node->pin = nullptr; +- if (node->parent) +- for (auto c : old_node->children) +- TreeNode::setParent(c, node); ++constexpr double PI_VALUE = 3.14159265358979323846; /* pi */ ++ ++void RsaBase::ReplaceRootChildren(Tree& tree) { ++ const Net* oldNet = tree.net; ++ ++ // create tmpNet and fakePins ++ Net tmpNet = *oldNet; ++ tmpNet.pins.clear(); ++ unordered_map, shared_ptr> pinToOldNode; ++ tmpNet.pins.push_back(tree.source->pin); ++ unordered_set> fakePins; ++ pinToOldNode[tree.source->pin] = tree.source; ++ for (auto c : tree.source->children) { // only contains the direct children of tree.source ++ shared_ptr pin = c->pin; ++ if (!pin) { ++ pin = make_shared(c->loc); ++ fakePins.insert(pin); ++ } ++ tmpNet.pins.push_back(pin); ++ pinToOldNode[pin] = c; + } +- }); +- tree.net = old_net; +- tree.RemoveTopoRedundantSteiner(); ++ tree.source->children.clear(); // free them... ++ ++ // get rsa and graft the old subtrees to it ++ Run(tmpNet, tree); ++ tree.PostOrder([&](const shared_ptr& node) { ++ if (node->pin) { ++ auto oldNode = pinToOldNode[node->pin]; ++ if (fakePins.find(node->pin) != fakePins.end()) node->pin = nullptr; ++ if (node->parent) ++ for (auto c : oldNode->children) TreeNode::SetParent(c, node); ++ } ++ }); ++ tree.net = oldNet; ++ tree.RemoveTopoRedundantSteiner(); + } + +-DTYPE RSABase::MaxOvlp(DTYPE z1, DTYPE z2) +-{ +- if (z1 >= 0 && z2 >= 0) +- return min(z1, z2); +- else if (z1 <= 0 && z2 <= 0) +- return max(z1, z2); +- else +- return 0; ++DTYPE RsaBase::MaxOvlp(DTYPE z1, DTYPE z2) { ++ if (z1 >= 0 && z2 >= 0) ++ return min(z1, z2); ++ else if (z1 <= 0 && z2 <= 0) ++ return max(z1, z2); ++ else ++ return 0; + } + +-void RsaBuilder::Run(const Net& net, Tree& tree) +-{ +- // Shift all pins to make source (0,0) +- auto ori_src_loc = net.source()->loc; +- for (auto& p : net.pins) +- p->loc -= ori_src_loc; +- +- // Init inner_nodes with all sinks +- for (auto p : net.pins) +- if (p->IsSink()) +- inner_nodes.insert(new InnerNode(make_shared(p))); +- +- // Process a inner node in each iteration +- while (!inner_nodes.empty()) { +- if ((*inner_nodes.begin())->dist == 0) +- break; // TODO: clear +- shared_ptr node = (*inner_nodes.begin())->tn; +- auto for_delete = *inner_nodes.begin(); +- inner_nodes.erase(inner_nodes.begin()); +- if (!node->pin) { // steiner node +- assert(node->children.size() == 2); +- if (node->children[0]) +- RemoveAnOuterNode(node->children[0], true, false); +- if (node->children[1]) +- RemoveAnOuterNode(node->children[1], false, true); +- node->children[0]->parent = node; +- node->children[1]->parent = node; +- } else { // pin node +- TryDominating(node); ++void RsaBuilder::Run(const Net& net, Tree& tree) { ++ // Shift all pins to make source (0,0) ++ auto oriSrcLoc = net.source()->loc; ++ for (auto& p : net.pins) p->loc -= oriSrcLoc; ++ ++ // Init innerNodes with all sinks ++ for (auto p : net.pins) ++ if (p->IsSink()) innerNodes.insert(new InnerNode(make_shared(p))); ++ ++ // Process a inner node in each iteration ++ while (!innerNodes.empty()) { ++ if ((*innerNodes.begin())->dist == 0) break; // TODO: clear ++ shared_ptr node = (*innerNodes.begin())->tn; ++ auto forDelete = *innerNodes.begin(); ++ innerNodes.erase(innerNodes.begin()); ++ if (!node->pin) { // steiner node ++ assert(node->children.size() == 2); ++ if (node->children[0]) RemoveAnOuterNode(node->children[0], true, false); ++ if (node->children[1]) RemoveAnOuterNode(node->children[1], false, true); ++ node->children[0]->parent = node; ++ node->children[1]->parent = node; ++ } else { // pin node ++ TryDominating(node); ++ } ++ delete forDelete; ++ AddAnOuterNode(node); + } +- delete for_delete; +- AddAnOuterNode(node); +- } + +- // connet the remaining outer_nodes to the source +- tree.source = make_shared(net.source()); +- for (const auto& on : outer_nodes) +- TreeNode::setParent(on.second.cur, tree.source); +- tree.net = &net; ++ // connet the remaining outerNodes to the source ++ tree.source = make_shared(net.source()); ++ for (const auto& on : outerNodes) TreeNode::SetParent(on.second.cur, tree.source); ++ tree.net = &net; + +- // shift all pins back +- for (auto& p : net.pins) +- p->loc += ori_src_loc; +- tree.preOrder([&](const shared_ptr& node) { node->loc += ori_src_loc; }); ++ // shift all pins back ++ for (auto& p : net.pins) p->loc += oriSrcLoc; ++ tree.PreOrder([&](const shared_ptr& node) { node->loc += oriSrcLoc; }); + +- // clear +- for (auto in : inner_nodes) +- delete in; +- inner_nodes.clear(); +- outer_nodes.clear(); ++ // clear ++ for (auto in : innerNodes) delete in; ++ innerNodes.clear(); ++ outerNodes.clear(); + } + +-map::iterator RsaBuilder::NextOuterNode(const map::iterator& it) +-{ +- auto res = next(it); +- if (res != outer_nodes.end()) +- return res; +- else +- return outer_nodes.begin(); ++map::iterator RsaBuilder::NextOuterNode(const map::iterator& it) { ++ auto res = next(it); ++ if (res != outerNodes.end()) ++ return res; ++ else ++ return outerNodes.begin(); + } + +-map::iterator RsaBuilder::PrevOuterNode(const map::iterator& it) +-{ +- if (it != outer_nodes.begin()) +- return prev(it); +- else +- return prev(outer_nodes.end()); ++map::iterator RsaBuilder::PrevOuterNode(const map::iterator& it) { ++ if (it != outerNodes.begin()) ++ return prev(it); ++ else ++ return prev(outerNodes.end()); + } + +-bool RsaBuilder::TryMaxOvlpSteinerNode(OuterNode& left, OuterNode& right) +-{ +- double rl_ang = atan2(right.cur->loc.y, right.cur->loc.x) - atan2(left.cur->loc.y, left.cur->loc.x); +- // if (rl_ang>-kPI && rl_ang<0) return false; // there is smaller arc +- DTYPE new_x, new_y; +- if ((rl_ang > -kPI && rl_ang < 0) || rl_ang > kPI) { // large arc +- new_x = 0; +- new_y = 0; +- } else { +- new_x = MaxOvlp(left.cur->loc.x, right.cur->loc.x); +- new_y = MaxOvlp(left.cur->loc.y, right.cur->loc.y); +- } +- // if (new_x==0 && new_y==0) return false; // non-neighboring quadrant +- auto tn = make_shared(new_x, new_y); +- tn->children = {left.cur, right.cur}; +- auto in = new InnerNode(tn); +- left.right_parent = in; +- right.left_parent = in; +- inner_nodes.insert(in); +- // cout << "add a tmp steiner point" << endl; +- // tn->Print(0,true); +- return true; ++bool RsaBuilder::TryMaxOvlpSteinerNode(OuterNode& left, OuterNode& right) { ++ double rlAng = atan2(right.cur->loc.y, right.cur->loc.x) - atan2(left.cur->loc.y, left.cur->loc.x); ++ // if (rlAng>-PI_VALUE && rlAng<0) return false; // there is smaller arc ++ DTYPE newX, newY; ++ if ((rlAng > -PI_VALUE && rlAng < 0) || rlAng > PI_VALUE) { // large arc ++ newX = 0; ++ newY = 0; ++ } else { ++ newX = MaxOvlp(left.cur->loc.x, right.cur->loc.x); ++ newY = MaxOvlp(left.cur->loc.y, right.cur->loc.y); ++ } ++ // if (newX==0 && newY==0) return false; // non-neighboring quadrant ++ auto tn = make_shared(newX, newY); ++ tn->children = {left.cur, right.cur}; ++ auto in = new InnerNode(tn); ++ left.rightP = in; ++ right.leftP = in; ++ innerNodes.insert(in); ++ // cout << "add a tmp steiner point" << endl; ++ // tn->Print(0,true); ++ return true; + } + +-void RsaBuilder::RemoveAnOuterNode(const shared_ptr& node, bool del_left, bool del_right) +-{ +- auto outer_cur = outer_nodes.find(OuterNodeKey(node)); +- assert(outer_cur != outer_nodes.end()); +- InnerNode *inner_left = outer_cur->second.left_parent, *inner_right = outer_cur->second.right_parent; +- auto outer_left = outer_nodes.end(), outer_right = outer_nodes.end(); +- if (inner_left != nullptr) { +- outer_left = PrevOuterNode(outer_cur); +- assert(outer_left->second.cur == inner_left->tn->children[0]); +- assert(outer_cur->second.cur == inner_left->tn->children[1]); +- inner_nodes.erase(inner_left); +- if (del_left) +- delete inner_left; // inner parent become invalid now +- outer_left->second.right_parent = nullptr; +- } +- if (inner_right != nullptr) { +- outer_right = NextOuterNode(outer_cur); +- assert(outer_cur->second.cur == inner_right->tn->children[0]); +- assert(outer_right->second.cur == inner_right->tn->children[1]); +- inner_nodes.erase(inner_right); +- if (del_right) +- delete inner_right; // inner parent become invalid now +- outer_right->second.left_parent = nullptr; +- } +- // delete outer_cur->second.first; // outer child should be kept +- outer_nodes.erase(outer_cur); +- if (del_left && del_right && outer_right != outer_nodes.end() && outer_left != outer_nodes.end() && outer_left != outer_right) { +- TryMaxOvlpSteinerNode(outer_left->second, outer_right->second); +- } ++void RsaBuilder::RemoveAnOuterNode(const shared_ptr& node, bool delL, bool delR) { ++ auto outerCur = outerNodes.find(OuterNodeKey(node)); ++ assert(outerCur != outerNodes.end()); ++ InnerNode *innerL = outerCur->second.leftP, *innerR = outerCur->second.rightP; ++ auto outerL = outerNodes.end(), outerR = outerNodes.end(); ++ if (innerL != nullptr) { ++ outerL = PrevOuterNode(outerCur); ++ assert(outerL->second.cur == innerL->tn->children[0]); ++ assert(outerCur->second.cur == innerL->tn->children[1]); ++ innerNodes.erase(innerL); ++ if (delL) delete innerL; // inner parent become invalid now ++ outerL->second.rightP = nullptr; ++ } ++ if (innerR != nullptr) { ++ outerR = NextOuterNode(outerCur); ++ assert(outerCur->second.cur == innerR->tn->children[0]); ++ assert(outerR->second.cur == innerR->tn->children[1]); ++ innerNodes.erase(innerR); ++ if (delR) delete innerR; // inner parent become invalid now ++ outerR->second.leftP = nullptr; ++ } ++ // delete outerCur->second.first; // outer child should be kept ++ outerNodes.erase(outerCur); ++ if (delL && delR && outerR != outerNodes.end() && outerL != outerNodes.end() && outerL != outerR) { ++ TryMaxOvlpSteinerNode(outerL->second, outerR->second); ++ } + } + + // p dominates c +-inline bool Dominate(const Point& p, const Point& c) +-{ +- return ((p.x >= 0 && c.x >= 0 && p.x <= c.x) || (p.x <= 0 && c.x <= 0 && p.x >= c.x)) // x +- && ((p.y >= 0 && c.y >= 0 && p.y <= c.y) || (p.y <= 0 && c.y <= 0 && p.y >= c.y)); // y ++inline bool Dominate(const Point& p, const Point& c) { ++ return ((p.x >= 0 && c.x >= 0 && p.x <= c.x) || (p.x <= 0 && c.x <= 0 && p.x >= c.x)) // x ++ && ((p.y >= 0 && c.y >= 0 && p.y <= c.y) || (p.y <= 0 && c.y <= 0 && p.y >= c.y)); // y + } + +-bool RsaBuilder::TryDominatingOneSide(OuterNode& p, OuterNode& c) +-{ +- if (!Dominate(p.cur->loc, c.cur->loc)) +- return false; +- TreeNode::setParent(c.cur, p.cur); +- RemoveAnOuterNode(c.cur); +- return true; ++bool RsaBuilder::TryDominatingOneSide(OuterNode& p, OuterNode& c) { ++ if (!Dominate(p.cur->loc, c.cur->loc)) return false; ++ TreeNode::SetParent(c.cur, p.cur); ++ RemoveAnOuterNode(c.cur); ++ return true; + } + +-void RsaBuilder::TryDominating(const shared_ptr& node) +-{ +- OuterNode outer_cur(node); +- if (outer_nodes.empty()) +- return; +- else if (outer_nodes.size() == 1) { +- TryDominatingOneSide(outer_cur, outer_nodes.begin()->second); +- return; +- } +- // get outer_right & outer_left +- auto outer_right = outer_nodes.upper_bound(OuterNodeKey(node)); +- if (outer_right == outer_nodes.end()) +- outer_right = outer_nodes.begin(); +- auto outer_left = PrevOuterNode(outer_right); +- assert(outer_left != outer_nodes.end() && outer_right != outer_nodes.end()); +- assert(outer_left->second.right_parent == outer_right->second.left_parent); +- // try dominating twice +- TryDominatingOneSide(outer_cur, outer_left->second); +- TryDominatingOneSide(outer_cur, outer_right->second); ++void RsaBuilder::TryDominating(const shared_ptr& node) { ++ OuterNode outerCur(node); ++ if (outerNodes.empty()) ++ return; ++ else if (outerNodes.size() == 1) { ++ TryDominatingOneSide(outerCur, outerNodes.begin()->second); ++ return; ++ } ++ // get outerR & outerL ++ auto outerR = outerNodes.upper_bound(OuterNodeKey(node)); ++ if (outerR == outerNodes.end()) outerR = outerNodes.begin(); ++ auto outerL = PrevOuterNode(outerR); ++ assert(outerL != outerNodes.end() && outerR != outerNodes.end()); ++ assert(outerL->second.rightP == outerR->second.leftP); ++ // try dominating twice ++ TryDominatingOneSide(outerCur, outerL->second); ++ TryDominatingOneSide(outerCur, outerR->second); + } + + // suppose no case of [node = min(node, an outer node)] +-void RsaBuilder::AddAnOuterNode(const shared_ptr& node) +-{ +- OuterNode outer_cur(node); +- if (!outer_nodes.empty()) { +- // get outer_right & outer_left +- auto outer_right = outer_nodes.upper_bound(OuterNodeKey(node)); +- if (outer_right == outer_nodes.end()) +- outer_right = outer_nodes.begin(); +- auto outer_left = PrevOuterNode(outer_right); +- assert(outer_left != outer_nodes.end() && outer_right != outer_nodes.end()); +- assert(outer_left->second.right_parent == outer_right->second.left_parent); +- // delete parent(outer_right, outer_left) +- if (outer_left->second.right_parent) { +- inner_nodes.erase(outer_left->second.right_parent); +- delete outer_left->second.right_parent; // inner parent become invalid now ++void RsaBuilder::AddAnOuterNode(const shared_ptr& node) { ++ OuterNode outerCur(node); ++ if (!outerNodes.empty()) { ++ // get outerR & outerL ++ auto outerR = outerNodes.upper_bound(OuterNodeKey(node)); ++ if (outerR == outerNodes.end()) outerR = outerNodes.begin(); ++ auto outerL = PrevOuterNode(outerR); ++ assert(outerL != outerNodes.end() && outerR != outerNodes.end()); ++ assert(outerL->second.rightP == outerR->second.leftP); ++ // delete parent(outerR, outerL) ++ if (outerL->second.rightP) { ++ innerNodes.erase(outerL->second.rightP); ++ delete outerL->second.rightP; // inner parent become invalid now ++ } ++ // add two parents ++ TryMaxOvlpSteinerNode(outerL->second, outerCur); ++ TryMaxOvlpSteinerNode(outerCur, outerR->second); + } +- // add two parents +- TryMaxOvlpSteinerNode(outer_left->second, outer_cur); +- TryMaxOvlpSteinerNode(outer_cur, outer_right->second); +- } +- outer_nodes.insert({OuterNodeKey(node), outer_cur}); ++ outerNodes.insert({OuterNodeKey(node), outerCur}); + } + +-void RsaBuilder::PrintInnerNodes() +-{ +- cout << "Inner nodes (# = " << inner_nodes.size() << ")" << endl; +- for (auto in : inner_nodes) { +- cout << in->tn; +- } ++void RsaBuilder::PrintInnerNodes() { ++ cout << "Inner nodes (# = " << innerNodes.size() << ")" << endl; ++ for (auto in : innerNodes) { ++ cout << in->tn; ++ } + } + +-void RsaBuilder::PrintOuterNodes() +-{ +- cout << "Outer nodes (# = " << outer_nodes.size() << ")" << endl; +- for (auto on : outer_nodes) { +- cout << on.second.cur; +- } ++void RsaBuilder::PrintOuterNodes() { ++ cout << "Outer nodes (# = " << outerNodes.size() << ")" << endl; ++ for (auto on : outerNodes) { ++ cout << on.second.cur; ++ } + } + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/base/rsa.h b/src/third_party/salt/base/rsa.h +index 172829fa..2266ae0a 100644 +--- a/src/third_party/salt/base/rsa.h ++++ b/src/third_party/salt/base/rsa.h +@@ -1,91 +1,85 @@ + #pragma once + ++#include "tree.h" ++ + #include + #include + #include + +-#include "tree.h" +- + namespace salt { + +-class RSABase +-{ +- public: +- void ReplaceRootChildren(Tree& tree); +- virtual void Run(const Net& net, Tree& tree) = 0; ++class RsaBase { ++public: ++ void ReplaceRootChildren(Tree& tree); ++ virtual void Run(const Net& net, Tree& tree) = 0; + +- protected: +- DTYPE MaxOvlp(DTYPE z1, DTYPE z2); ++protected: ++ DTYPE MaxOvlp(DTYPE z1, DTYPE z2); + }; + + // Inner Node: an inner node alway has two child (outer) nodes + // tn->children[0]: smaller angle, clockwise, left + // tn->children[1]: larger angle, counter clockwise, right +-class InnerNode +-{ +- public: +- unsigned id; +- shared_ptr tn; +- DTYPE dist; +- double angle; // [-pi, pi] +- InnerNode(const shared_ptr& treeNode) : tn(treeNode), dist(abs(tn->loc.x) + abs(tn->loc.y)), angle(atan2(tn->loc.y, tn->loc.x)) +- { +- static unsigned gid = 0; +- id = gid++; +- } // use id instead of pointer to make it deterministic ++class InnerNode { ++public: ++ unsigned id; ++ shared_ptr tn; ++ DTYPE dist; ++ double angle; // [-pi, pi] ++ InnerNode(const shared_ptr& treeNode) ++ : tn(treeNode), dist(abs(tn->loc.x) + abs(tn->loc.y)), angle(atan2(tn->loc.y, tn->loc.x)) { ++ static unsigned gid = 0; ++ id = gid++; ++ } // use id instead of pointer to make it deterministic + }; +-class CompInnerNode +-{ +- public: +- bool operator()(const InnerNode* a, const InnerNode* b) +- { +- return a->dist > b->dist || // prefer fathest one +- (a->dist == b->dist +- && (a->angle > b->angle || // prefer single direction +- (a->angle == b->angle && a->id > b->id))); // distinguish two nodes with same loc (not touched normally) +- } ++class CompInnerNode { ++public: ++ bool operator()(const InnerNode* a, const InnerNode* b) { ++ return a->dist > b->dist || // prefer fathest one ++ (a->dist == b->dist && (a->angle > b->angle || // prefer single direction ++ (a->angle == b->angle && ++ a->id > b->id))); // distinguish two nodes with same loc (not touched normally) ++ } + }; + + // Outer Node: an outer node has one or two parent (inner) nodes +-class OuterNode +-{ +- public: +- shared_ptr cur; // itself +- InnerNode *left_parent, *right_parent; // left parent, right parent +- OuterNode(const shared_ptr& c, InnerNode* l = nullptr, InnerNode* r = nullptr) : cur(c), left_parent(l), right_parent(r) {} ++class OuterNode { ++public: ++ shared_ptr cur; // itself ++ InnerNode *leftP, *rightP; // left parent, right parent ++ OuterNode(const shared_ptr& c, InnerNode* l = nullptr, InnerNode* r = nullptr) : cur(c), leftP(l), rightP(r) {} + }; + + // RSA Builder +-class RsaBuilder : public RSABase +-{ +- public: +- void Run(const Net& net, Tree& tree); ++class RsaBuilder : public RsaBase { ++public: ++ void Run(const Net& net, Tree& tree); + +- private: +- // inner nodes +- set inner_nodes; ++private: ++ // inner nodes ++ set innerNodes; + +- // outer nodes +- map outer_nodes; +- // the unique key is always guaranteed, better for query/find by key +- inline double OuterNodeKey(const shared_ptr& tn) { return atan2(tn->loc.y, tn->loc.x); } +- // larger angle, counter clockwise, right +- map::iterator NextOuterNode(const map::iterator& it); +- // smaller angle, clockwise, left +- map::iterator PrevOuterNode(const map::iterator& it); ++ // outer nodes ++ map outerNodes; ++ // the unique key is always guaranteed, better for query/find by key ++ inline double OuterNodeKey(const shared_ptr& tn) { return atan2(tn->loc.y, tn->loc.x); } ++ // larger angle, counter clockwise, right ++ map::iterator NextOuterNode(const map::iterator& it); ++ // smaller angle, clockwise, left ++ map::iterator PrevOuterNode(const map::iterator& it); + +- // remove an outer node +- bool TryMaxOvlpSteinerNode(OuterNode& left, OuterNode& right); // maximize the overlapping +- void RemoveAnOuterNode(const shared_ptr& node, bool del_left = true, bool del_right = true); ++ // remove an outer node ++ bool TryMaxOvlpSteinerNode(OuterNode& left, OuterNode& right); // maximize the overlapping ++ void RemoveAnOuterNode(const shared_ptr& node, bool delL = true, bool delR = true); + +- // add an outer node +- bool TryDominatingOneSide(OuterNode& p, OuterNode& c); +- void TryDominating(const shared_ptr& node); +- void AddAnOuterNode(const shared_ptr& node); ++ // add an outer node ++ bool TryDominatingOneSide(OuterNode& p, OuterNode& c); ++ void TryDominating(const shared_ptr& node); ++ void AddAnOuterNode(const shared_ptr& node); + +- // for debug +- void PrintInnerNodes(); +- void PrintOuterNodes(); ++ // for debug ++ void PrintInnerNodes(); ++ void PrintOuterNodes(); + }; + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/base/tree.cpp b/src/third_party/salt/base/tree.cpp +index a8648297..0fa5f8a3 100644 +--- a/src/third_party/salt/base/tree.cpp ++++ b/src/third_party/salt/base/tree.cpp +@@ -6,349 +6,310 @@ + + namespace salt { + +-void TreeNode::PrintSingle(ostream& os) const +-{ +- os << "Node " << id << ": " << loc << (pin ? ", pin" : "") << ", " << children.size() << " children"; ++void TreeNode::PrintSingle(ostream& os) const { ++ os << "Node " << id << ": " << loc << (pin ? ", pin" : "") << ", " << children.size() << " children"; + } + +-void TreeNode::PrintRecursiveHelp(ostream& os, vector& prefix) const +-{ +- for (auto pre : prefix) +- os << (pre ? " |" : " "); +- if (!prefix.empty()) +- os << "-> "; +- PrintSingle(os); +- os << endl; +- if (children.size() > 0) { +- prefix.push_back(true); +- for (size_t i = 0; i < children.size() - 1; ++i) { +- if (children[i]) +- children[i]->PrintRecursiveHelp(os, prefix); +- else +- os << "" << endl; ++void TreeNode::PrintRecursiveHelp(ostream& os, vector& prefix) const { ++ for (auto pre : prefix) os << (pre ? " |" : " "); ++ if (!prefix.empty()) os << "-> "; ++ PrintSingle(os); ++ os << endl; ++ if (children.size() > 0) { ++ prefix.push_back(true); ++ for (size_t i = 0; i < children.size() - 1; ++i) { ++ if (children[i]) ++ children[i]->PrintRecursiveHelp(os, prefix); ++ else ++ os << "" << endl; ++ } ++ prefix.back() = false; ++ children.back()->PrintRecursiveHelp(os, prefix); ++ prefix.pop_back(); + } +- prefix.back() = false; +- children.back()->PrintRecursiveHelp(os, prefix); +- prefix.pop_back(); +- } + } + +-void TreeNode::PrintRecursive(ostream& os) const +-{ +- vector prefix; // prefix indicates whether an ancestor is a last child or not +- PrintRecursiveHelp(os, prefix); ++void TreeNode::PrintRecursive(ostream& os) const { ++ vector prefix; // prefix indicates whether an ancestor is a last child or not ++ PrintRecursiveHelp(os, prefix); + } + +-void TreeNode::setParent(const shared_ptr& childNode, const shared_ptr& parentNode) +-{ +- childNode->parent = parentNode; +- parentNode->children.push_back(childNode); ++void TreeNode::SetParent(const shared_ptr& childNode, const shared_ptr& parentNode) { ++ childNode->parent = parentNode; ++ parentNode->children.push_back(childNode); + } + +-void TreeNode::resetParent(const shared_ptr& node) +-{ +- assert(node->parent); ++void TreeNode::ResetParent(const shared_ptr& node) { ++ assert(node->parent); + +- auto& n = node->parent->children; +- auto it = find(n.begin(), n.end(), node); +- assert(it != n.end()); +- *it = n.back(); +- n.pop_back(); ++ auto& n = node->parent->children; ++ auto it = find(n.begin(), n.end(), node); ++ assert(it != n.end()); ++ *it = n.back(); ++ n.pop_back(); + +- node->parent.reset(); ++ node->parent.reset(); + } + +-void TreeNode::reroot(const shared_ptr& node) +-{ +- if (node->parent) { +- reroot(node->parent); +- auto old_parent = node->parent; +- TreeNode::resetParent(node); +- TreeNode::setParent(old_parent, node); +- } ++void TreeNode::Reroot(const shared_ptr& node) { ++ if (node->parent) { ++ Reroot(node->parent); ++ auto oldParent = node->parent; ++ TreeNode::ResetParent(node); ++ TreeNode::SetParent(oldParent, node); ++ } + } + +-bool TreeNode::isAncestor(const shared_ptr& ancestor, const shared_ptr& descendant) +-{ +- auto tmp = descendant; +- do { +- if (tmp == ancestor) { +- return true; +- } +- tmp = tmp->parent; +- } while (tmp); +- return false; ++bool TreeNode::IsAncestor(const shared_ptr& ancestor, const shared_ptr& descendant) { ++ auto tmp = descendant; ++ do { ++ if (tmp == ancestor) { ++ return true; ++ } ++ tmp = tmp->parent; ++ } while (tmp); ++ return false; + } + +-void TreeNode::preOrder(const shared_ptr& node, const function&)>& visit) +-{ +- visit(node); +- for (auto c : node->children) +- preOrder(c, visit); ++void TreeNode::PreOrder(const shared_ptr& node, const function&)>& visit) { ++ visit(node); ++ for (auto c : node->children) PreOrder(c, visit); + } + +-void TreeNode::postOrder(const shared_ptr& node, const function&)>& visit) +-{ +- for (auto c : node->children) +- postOrder(c, visit); +- visit(node); ++void TreeNode::PostOrder(const shared_ptr& node, const function&)>& visit) { ++ for (auto c : node->children) PostOrder(c, visit); ++ visit(node); + } + +-void TreeNode::postOrderCopy(const shared_ptr& node, const function&)>& visit) +-{ +- auto tmp = node->children; +- for (auto c : tmp) +- postOrderCopy(c, visit); +- visit(node); ++void TreeNode::PostOrderCopy(const shared_ptr& node, const function&)>& visit) { ++ auto tmp = node->children; ++ for (auto c : tmp) PostOrderCopy(c, visit); ++ visit(node); + } + +-void Tree::Reset(bool freeTreeNodes) +-{ +- if (freeTreeNodes) { +- postOrder([](const shared_ptr& node) { node->children.clear(); }); +- } +- source.reset(); +- net = nullptr; ++void Tree::Reset(bool freeTreeNodes) { ++ if (freeTreeNodes) { ++ PostOrder([](const shared_ptr& node) { node->children.clear(); }); ++ } ++ source.reset(); ++ net = nullptr; + } + +-void Tree::Read(istream& is) +-{ +- Net* p_net = new Net; +- +- // header +- string buf, option; +- int num_pin = 0; +- while (is >> buf && buf != "Tree") +- ; +- assert(buf == "Tree"); +- getline(is, buf); +- istringstream iss(buf); +- iss >> p_net->id >> p_net->name >> num_pin >> option; +- assert(num_pin > 0); +- p_net->with_cap = (option == "-cap"); +- +- // pins +- int i, parent_idx; +- DTYPE x, y; +- double c = 0.0; +- p_net->pins.resize(num_pin); +- vector parent_idxs; +- vector> tree_nodes; +- for (auto& pin : p_net->pins) { +- is >> i >> x >> y >> parent_idx; +- assert(i == tree_nodes.size()); +- if (p_net->with_cap) +- is >> c; +- pin = make_shared(x, y, i, c); +- tree_nodes.push_back(make_shared(x, y, pin, i)); +- parent_idxs.push_back(parent_idx); +- } +- assert(tree_nodes.size() == num_pin); +- +- // non-pin nodes +- getline(is, buf); // consume eol +- streampos pos; +- while (true) { +- pos = is.tellg(); ++void Tree::Read(istream& is) { ++ Net* pNet = new Net; ++ ++ // header ++ string buf, option; ++ int numPin = 0; ++ while (is >> buf && buf != "Tree") ++ ; ++ assert(buf == "Tree"); + getline(is, buf); +- istringstream iss2(buf); +- iss2 >> i >> x >> y >> parent_idx; +- if (iss2.fail()) +- break; +- assert(i == tree_nodes.size()); +- tree_nodes.push_back(make_shared(x, y, nullptr, i)); +- parent_idxs.push_back(parent_idx); +- } +- is.seekg(pos); // go back +- +- // parents +- for (unsigned i = 0; i < tree_nodes.size(); ++i) { +- parent_idx = parent_idxs[i]; +- if (parent_idx >= 0) { +- assert(parent_idx < tree_nodes.size()); +- salt::TreeNode::setParent(tree_nodes[i], tree_nodes[parent_idx]); +- } else { +- assert(parent_idx == -1); +- source = tree_nodes[i]; ++ istringstream iss(buf); ++ iss >> pNet->id >> pNet->name >> numPin >> option; ++ assert(numPin > 0); ++ pNet->withCap = (option == "-cap"); ++ ++ // pins ++ int i, parentIdx; ++ DTYPE x, y; ++ double c = 0.0; ++ pNet->pins.resize(numPin); ++ vector parentIdxs; ++ vector> treeNodes; ++ for (auto& pin : pNet->pins) { ++ is >> i >> x >> y >> parentIdx; ++ assert(i == treeNodes.size()); ++ if (pNet->withCap) is >> c; ++ pin = make_shared(x, y, i, c); ++ treeNodes.push_back(make_shared(x, y, pin, i)); ++ parentIdxs.push_back(parentIdx); ++ } ++ assert(treeNodes.size() == numPin); ++ ++ // non-pin nodes ++ getline(is, buf); // consume eol ++ streampos pos; ++ while (true) { ++ pos = is.tellg(); ++ getline(is, buf); ++ istringstream iss2(buf); ++ iss2 >> i >> x >> y >> parentIdx; ++ if (iss2.fail()) break; ++ assert(i == treeNodes.size()); ++ treeNodes.push_back(make_shared(x, y, nullptr, i)); ++ parentIdxs.push_back(parentIdx); ++ } ++ is.seekg(pos); // go back ++ ++ // parents ++ for (unsigned i = 0; i < treeNodes.size(); ++i) { ++ parentIdx = parentIdxs[i]; ++ if (parentIdx >= 0) { ++ assert(parentIdx < treeNodes.size()); ++ salt::TreeNode::SetParent(treeNodes[i], treeNodes[parentIdx]); ++ } else { ++ assert(parentIdx == -1); ++ source = treeNodes[i]; ++ } + } +- } + +- net = p_net; +- // TODO: check dangling nodes ++ net = pNet; ++ // TODO: check dangling nodes + } + +-void Tree::Read(const string& file_name) +-{ +- ifstream is(file_name); +- if (is.fail()) { +- cout << "ERROR: Cannot open file " << file_name << endl; +- exit(1); +- } +- Read(is); ++void Tree::Read(const string& fileName) { ++ ifstream is(fileName); ++ if (is.fail()) { ++ cout << "ERROR: Cannot open file " << fileName << endl; ++ exit(1); ++ } ++ Read(is); + } + +-void Tree::Write(ostream& os) +-{ +- // header +- os << "Tree " << net->GetHeader() << endl; +- +- // nodes +- // Note: source pin may not be covered in some intermediate state +- int num_nodes = UpdateId(); +- auto nodes = ObtainNodes(); +- vector> sorted_nodes(num_nodes, nullptr); // bucket sort +- for (auto node : nodes) { +- sorted_nodes[node->id] = node; +- } +- for (auto node : sorted_nodes) { +- if (!node) +- continue; +- int parentId = node->parent ? node->parent->id : -1; +- os << node->id << " " << node->loc.x << " " << node->loc.y << " " << parentId; +- if (net->with_cap && node->pin) +- os << " " << node->pin->cap; +- os << endl; +- } ++void Tree::Write(ostream& os) { ++ // header ++ os << "Tree " << net->GetHeader() << endl; ++ ++ // nodes ++ // Note: source pin may not be covered in some intermediate state ++ int numNodes = UpdateId(); ++ auto nodes = ObtainNodes(); ++ vector> sortedNodes(numNodes, nullptr); // bucket sort ++ for (auto node : nodes) { ++ sortedNodes[node->id] = node; ++ } ++ for (auto node : sortedNodes) { ++ if (!node) continue; ++ int parentId = node->parent ? node->parent->id : -1; ++ os << node->id << " " << node->loc.x << " " << node->loc.y << " " << parentId; ++ if (net->withCap && node->pin) os << " " << node->pin->cap; ++ os << endl; ++ } + } + +-void Tree::Write(const string& prefix, bool with_net_info) +-{ +- ofstream ofs(prefix + (with_net_info ? ("_" + net->name) : "") + ".tree"); +- Write(ofs); +- ofs.close(); ++void Tree::Write(const string& prefix, bool withNetInfo) { ++ ofstream ofs(prefix + (withNetInfo ? ("_" + net->name) : "") + ".tree"); ++ Write(ofs); ++ ofs.close(); + } + +-void Tree::Print(ostream& os) const +-{ +- os << "Tree "; +- if (net) +- os << net->id << ": #pins=" << net->pins.size() << endl; +- else +- os << "" << endl; +- if (source) +- source->PrintRecursive(os); +- else +- os << "" << endl; ++void Tree::Print(ostream& os) const { ++ os << "Tree "; ++ if (net) ++ os << net->id << ": #pins=" << net->pins.size() << endl; ++ else ++ os << "" << endl; ++ if (source) ++ source->PrintRecursive(os); ++ else ++ os << "" << endl; + } + +-int Tree::UpdateId() +-{ +- int num_node = net->pins.size(); +- preOrder([&](const shared_ptr& node) { +- if (node->pin) { +- assert(node->pin->id < net->pins.size()); +- node->id = node->pin->id; +- } else +- node->id = num_node++; +- }); +- return num_node; ++int Tree::UpdateId() { ++ int numNode = net->pins.size(); ++ PreOrder([&](const shared_ptr& node) { ++ if (node->pin) { ++ assert(node->pin->id < net->pins.size()); ++ node->id = node->pin->id; ++ } else ++ node->id = numNode++; ++ }); ++ return numNode; + } + +-vector> Tree::ObtainNodes() const +-{ +- vector> nodes; +- preOrder([&](const shared_ptr& node) { nodes.push_back(node); }); +- return nodes; ++vector> Tree::ObtainNodes() const { ++ vector> nodes; ++ PreOrder([&](const shared_ptr& node) { nodes.push_back(node); }); ++ return nodes; + } + +-void Tree::SetParentFromChildren() +-{ +- preOrder([](const shared_ptr& node) { +- for (auto& c : node->children) { +- c->parent = node; +- } +- }); ++void Tree::SetParentFromChildren() { ++ PreOrder([](const shared_ptr& node) { ++ for (auto& c : node->children) { ++ c->parent = node; ++ } ++ }); + } + +-void Tree::SetParentFromUndirectedAdjList() +-{ +- preOrder([](const shared_ptr& node) { +- for (auto& c : node->children) { +- auto& n = c->children; +- auto it = find(n.begin(), n.end(), node); +- assert(it != n.end()); +- *it = n.back(); +- n.pop_back(); +- c->parent = node; +- } +- }); ++void Tree::SetParentFromUndirectedAdjList() { ++ PreOrder([](const shared_ptr& node) { ++ for (auto& c : node->children) { ++ auto& n = c->children; ++ auto it = find(n.begin(), n.end(), node); ++ assert(it != n.end()); ++ *it = n.back(); ++ n.pop_back(); ++ c->parent = node; ++ } ++ }); + } + +-void Tree::reroot() +-{ +- TreeNode::reroot(source); ++void Tree::Reroot() { ++ TreeNode::Reroot(source); + } + +-void Tree::QuickCheck() +-{ +- int num_pin = net->pins.size(), num_checked = 0; +- vector pin_exist(num_pin, false); +- preOrder([&](const shared_ptr& node) { +- if (!node) { +- cerr << "Error: empty node" << endl; ++void Tree::QuickCheck() { ++ int numPin = net->pins.size(), numChecked = 0; ++ vector pinExist(numPin, false); ++ PreOrder([&](const shared_ptr& node) { ++ if (!node) { ++ cerr << "Error: empty node" << endl; ++ } ++ if (node->pin) { ++ auto id = node->pin->id; ++ if (!(id >= 0 && id < numPin && pinExist[id] == false)) { ++ cerr << "Error: Steiner node with incorrect id" << endl; ++ } ++ pinExist[id] = true; ++ ++numChecked; ++ } ++ for (auto& c : node->children) { ++ if (!c->parent || c->parent != node) { ++ cerr << "Error: inconsistent parent-child relationship" << endl; ++ } ++ } ++ }); ++ if (numChecked != numPin) { ++ cerr << "Error: pin not covered" << endl; + } +- if (node->pin) { +- auto id = node->pin->id; +- if (!(id >= 0 && id < num_pin && pin_exist[id] == false)) { +- cerr << "Error: Steiner node with incorrect id" << endl; +- } +- pin_exist[id] = true; +- ++num_checked; +- } +- for (auto& c : node->children) { +- if (!c->parent || c->parent != node) { +- cerr << "Error: inconsistent parent-child relationship" << endl; +- } +- } +- }); +- if (num_checked != num_pin) { +- cerr << "Error: pin not covered" << endl; +- } + } + +-void Tree::RemovePhyRedundantSteiner() +-{ +- postOrderCopy([](const shared_ptr& node) { +- if (!node->parent || node->loc != node->parent->loc) +- return; +- if (node->pin) { +- if (node->parent->pin && node->parent->pin != node->pin) +- return; +- node->parent->pin = node->pin; +- } +- for (auto c : node->children) +- TreeNode::setParent(c, node->parent); +- TreeNode::resetParent(node); +- }); ++void Tree::RemovePhyRedundantSteiner() { ++ PostOrderCopy([](const shared_ptr& node) { ++ if (!node->parent || node->loc != node->parent->loc) return; ++ if (node->pin) { ++ if (node->parent->pin && node->parent->pin != node->pin) return; ++ node->parent->pin = node->pin; ++ } ++ for (auto c : node->children) TreeNode::SetParent(c, node->parent); ++ TreeNode::ResetParent(node); ++ }); + } + +-void Tree::RemoveTopoRedundantSteiner() +-{ +- postOrderCopy([](const shared_ptr& node) { +- // degree may change after post-order traversal of its children +- if (node->pin) +- return; +- if (node->children.empty()) { +- TreeNode::resetParent(node); +- } else if (node->children.size() == 1) { +- auto old_parent = node->parent, oldChild = node->children[0]; +- TreeNode::resetParent(node); +- TreeNode::resetParent(oldChild); +- TreeNode::setParent(oldChild, old_parent); +- } +- }); ++void Tree::RemoveTopoRedundantSteiner() { ++ PostOrderCopy([](const shared_ptr& node) { ++ // degree may change after post-order traversal of its children ++ if (node->pin) return; ++ if (node->children.empty()) { ++ TreeNode::ResetParent(node); ++ } else if (node->children.size() == 1) { ++ auto oldParent = node->parent, oldChild = node->children[0]; ++ TreeNode::ResetParent(node); ++ TreeNode::ResetParent(oldChild); ++ TreeNode::SetParent(oldChild, oldParent); ++ } ++ }); + } + +-void Tree::RemoveEmptyChildren() +-{ +- preOrder([](const shared_ptr& node) { +- int size = 0; +- for (int i = 0; i < node->children.size(); ++i) { +- if (node->children[i]) +- node->children[size++] = node->children[i]; +- } +- node->children.resize(size); +- }); ++void Tree::RemoveEmptyChildren() { ++ PreOrder([](const shared_ptr& node) { ++ int size = 0; ++ for (int i = 0; i < node->children.size(); ++i) { ++ if (node->children[i]) node->children[size++] = node->children[i]; ++ } ++ node->children.resize(size); ++ }); + } + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/base/tree.h b/src/third_party/salt/base/tree.h +index 8fde2af2..f66880e7 100644 +--- a/src/third_party/salt/base/tree.h ++++ b/src/third_party/salt/base/tree.h +@@ -1,132 +1,102 @@ + #pragma once + +-#include +- + #include "net.h" + ++#include ++ + namespace salt { + +-class TreeNode +-{ +- public: +- Point loc; +- shared_ptr pin; // nullptr if it is not a pin +- int id; +- vector> children; // empty for leaf +- shared_ptr parent; // nullptr for source +- +- // Constructors +- TreeNode(const Point& l = Point(), shared_ptr p = nullptr, int i = -1) : loc(l), pin(p), id(i) {} +- TreeNode(DTYPE x, DTYPE y, shared_ptr p = nullptr, int i = -1) : loc(x, y), pin(p), id(i) {} +- TreeNode(shared_ptr p) : loc(p->loc), pin(p), id(p->id) {} +- +- // Accessors +- DTYPE WireToParent() const { return Dist(loc, parent->loc); } +- DTYPE WireToParentChecked() const { return parent ? WireToParent() : 0.0; } +- +- // Hunman-readable print +- void PrintSingle(ostream& os = cout) const; +- void PrintRecursiveHelp(ostream& os, vector& prefix) const; // hunman-readable print +- void PrintRecursive(ostream& os = cout) const; +- friend ostream& operator<<(ostream& os, const TreeNode& node) +- { +- node.PrintRecursive(os); +- return os; +- } +- +- // Set/reset/check parent/ancestor +- static void setParent(const shared_ptr& childNode, const shared_ptr& parentNode); +- static void resetParent(const shared_ptr& node); +- static void reroot(const shared_ptr& node); +- static bool isAncestor(const shared_ptr& ancestor, const shared_ptr& descendant); +- +- // Traverse +- static void preOrder(const shared_ptr& node, const function&)>& visit); +- static void postOrder(const shared_ptr& node, const function&)>& visit); +- static void postOrderCopy(const shared_ptr& node, const function&)>& visit); ++class TreeNode { ++public: ++ int id; ++ shared_ptr pin; // nullptr if it is not a pin ++ Point loc; ++ vector> children; // empty for leaf ++ shared_ptr parent; // nullptr for source ++ ++ // Constructors ++ TreeNode(const Point& l = Point(), shared_ptr p = nullptr, int i = -1) : loc(l), pin(p), id(i) {} ++ TreeNode(DTYPE x, DTYPE y, shared_ptr p = nullptr, int i = -1) : loc(x, y), pin(p), id(i) {} ++ TreeNode(shared_ptr p) : loc(p->loc), pin(p), id(p->id) {} ++ ++ // Accessors ++ DTYPE WireToParent() const { return Dist(loc, parent->loc); } ++ DTYPE WireToParentChecked() const { return parent ? WireToParent() : 0.0; } ++ ++ // Hunman-readable print ++ void PrintSingle(ostream& os = cout) const; ++ void PrintRecursiveHelp(ostream& os, vector& prefix) const; // hunman-readable print ++ void PrintRecursive(ostream& os = cout) const; ++ friend ostream& operator<<(ostream& os, const TreeNode& node) { node.PrintRecursive(os); return os; } ++ ++ // Set/reset/check parent/ancestor ++ static void SetParent(const shared_ptr& childNode, const shared_ptr& parentNode); ++ static void ResetParent(const shared_ptr& node); ++ static void Reroot(const shared_ptr& node); ++ static bool IsAncestor(const shared_ptr& ancestor, const shared_ptr& descendant); ++ ++ // Traverse ++ static void PreOrder(const shared_ptr& node, const function&)>& visit); ++ static void PostOrder(const shared_ptr& node, const function&)>& visit); ++ static void PostOrderCopy(const shared_ptr& node, const function&)>& visit); + }; + +-class Tree +-{ +- public: +- shared_ptr source; +- const Net* net; +- +- // Note: take care when using copy assign operator and copy constructor. use swap(). +- Tree(const shared_ptr& sourceNode = nullptr, const Net* associatedNet = nullptr) : source(sourceNode), net(associatedNet) {} +- void Reset(bool freeTreeNodes = true); +- ~Tree() { Reset(); } +- +- // File read/write +- // ------ +- // Format: +- // Tree [-cap] +- // 0 x0 y0 -1 [cap0] +- // 1 x1 y1 parent_idx1 [cap1] +- // 2 x2 y2 parent_idx2 [cap2] +- // ... +- // k xk yk parent_idxk +- // ... +- // ------ +- // Notes: +- // 1. Nodes with indexes [0, pin_num) are pins, others are Steiner +- // 2. Steiner nodes have no cap +- void Read(istream& is); +- void Read(const string& file_name); +- void Write(ostream& os); // TODO: const? but UpdateId +- void Write(const string& prefix, bool with_net_info = true); +- +- // Hunman-readable print +- void Print(ostream& os = cout) const; +- friend ostream& operator<<(ostream& os, const Tree& tree) +- { +- tree.Print(os); +- return os; +- } +- +- // Traverse +- void preOrder(const function&)>& visit) +- { +- if (source) +- TreeNode::preOrder(source, visit); +- } +- void postOrder(const function&)>& visit) +- { +- if (source) +- TreeNode::postOrder(source, visit); +- } +- void postOrderCopy(const function&)>& visit) +- { +- if (source) +- TreeNode::postOrderCopy(source, visit); +- } +- void preOrder(const function&)>& visit) const +- { +- if (source) +- TreeNode::preOrder(source, visit); +- } +- void postOrder(const function&)>& visit) const +- { +- if (source) +- TreeNode::postOrder(source, visit); +- } +- +- // Flatten +- int UpdateId(); // update node ids to [0, nodeNum), return nodeNum +- vector> ObtainNodes() const; +- +- // Legalize parent-child relationship +- void SetParentFromChildren(); +- void SetParentFromUndirectedAdjList(); +- void reroot(); +- void QuickCheck(); // check parent-child and pin coverage +- +- // Remove redundant Steiner nodes +- void RemovePhyRedundantSteiner(); // remove physically redudant ones (i.e., with the same locatoin of a pin) +- void RemoveTopoRedundantSteiner(); // remove topologically redudant ones (i.e., with 0/1 children) +- +- // Remove empty children +- void RemoveEmptyChildren(); ++class Tree { ++public: ++ shared_ptr source; ++ const Net* net; ++ ++ // Note: take care when using copy assign operator and copy constructor. use swap(). ++ Tree(const shared_ptr& sourceNode = nullptr, const Net* associatedNet = nullptr) : source(sourceNode), net(associatedNet) {} ++ void Reset(bool freeTreeNodes = true); ++ ~Tree() { Reset(); } ++ ++ // File read/write ++ // ------ ++ // Format: ++ // Tree [-cap] ++ // 0 x0 y0 -1 [cap0] ++ // 1 x1 y1 parent_idx1 [cap1] ++ // 2 x2 y2 parent_idx2 [cap2] ++ // ... ++ // k xk yk parent_idxk ++ // ... ++ // ------ ++ // Notes: ++ // 1. Nodes with indexes [0, pin_num) are pins, others are Steiner ++ // 2. Steiner nodes have no cap ++ void Read(istream& is); ++ void Read(const string& fileName); ++ void Write(ostream& os); // TODO: const? but UpdateId ++ void Write(const string& prefix, bool withNetInfo = true); ++ ++ // Hunman-readable print ++ void Print(ostream& os = cout) const; ++ friend ostream& operator<<(ostream& os, const Tree& tree) { tree.Print(os); return os; } ++ ++ // Traverse ++ void PreOrder(const function&)>& visit) { if (source) TreeNode::PreOrder(source, visit); } ++ void PostOrder(const function&)>& visit) { if (source) TreeNode::PostOrder(source, visit); } ++ void PostOrderCopy(const function&)>& visit) { if (source) TreeNode::PostOrderCopy(source, visit); } ++ void PreOrder(const function&)>& visit) const { if (source) TreeNode::PreOrder(source, visit); } ++ void PostOrder(const function&)>& visit) const { if (source) TreeNode::PostOrder(source, visit); } ++ ++ // Flatten ++ int UpdateId(); // update node ids to [0, nodeNum), return nodeNum ++ vector> ObtainNodes() const; ++ ++ // Legalize parent-child relationship ++ void SetParentFromChildren(); ++ void SetParentFromUndirectedAdjList(); ++ void Reroot(); ++ void QuickCheck(); // check parent-child and pin coverage ++ ++ // Remove redundant Steiner nodes ++ void RemovePhyRedundantSteiner(); // remove physically redudant ones (i.e., with the same locatoin of a pin) ++ void RemoveTopoRedundantSteiner(); // remove topologically redudant ones (i.e., with 0/1 children) ++ ++ // Remove empty children ++ void RemoveEmptyChildren(); + }; + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/refine/cancel_intersect.cpp b/src/third_party/salt/refine/cancel_intersect.cpp +index f79b7b0e..1e17da44 100644 +--- a/src/third_party/salt/refine/cancel_intersect.cpp ++++ b/src/third_party/salt/refine/cancel_intersect.cpp +@@ -96,16 +96,16 @@ void Cancel(array, 2> oric) { + auto rootN = oric[1 - minD]->parent; + shared_ptr mergeN = nullptr; + for (int d = 0; d < 2; ++d) { +- TreeNode::resetParent(oric[d]); ++ TreeNode::ResetParent(oric[d]); + if (oric[d]->loc == cclosest[d]) mergeN = oric[d]; + } + if (!mergeN) mergeN = make_shared(cclosest[minD]); +- TreeNode::setParent(mergeN, rootN); ++ TreeNode::SetParent(mergeN, rootN); + for (int d = 0; d < 2; ++d) +- if (oric[d] != mergeN) TreeNode::setParent(oric[d], mergeN); ++ if (oric[d] != mergeN) TreeNode::SetParent(oric[d], mergeN); + } + +-void Refine::cancelIntersect(Tree& tree) { ++void Refine::CancelIntersect(Tree& tree) { + bgi::rtree, bgi::indexable, RNodeComp> rtree; + auto nodes = tree.ObtainNodes(); + for (int i = 0; i < nodes.size(); ++i) { +diff --git a/src/third_party/salt/refine/flip.cpp b/src/third_party/salt/refine/flip.cpp +index 5dad3766..fca59b4c 100644 +--- a/src/third_party/salt/refine/flip.cpp ++++ b/src/third_party/salt/refine/flip.cpp +@@ -27,10 +27,10 @@ void UpdateNode(const shared_ptr node, // central node + const vector>& gains, // the gain of each child + int i, // current child + array, 4>& segs, // segments in each direction +- DTYPE acc_gain, // gain accumulated by now ++ DTYPE accGain, // gain accumulated by now + DTYPE& bestGain, // best gain +- vector& low_or_up, // each child edge is low or up +- vector& best_low_or_up // each child edge is low or up for best gain ++ vector& lowOrUp, // each child edge is low or up ++ vector& bestLowOrUp // each child edge is low or up for best gain + ) { + if (i == node->children.size()) { // get to the end of enumeration + for (int j = 0; j < 4; ++j) { +@@ -38,49 +38,49 @@ void UpdateNode(const shared_ptr node, // central node + DTYPE max = 0; + for (auto len : segs[j]) { + if (len > max) { +- acc_gain += max; ++ accGain += max; + max = len; + } else +- acc_gain += len; ++ accGain += len; + } + } +- if (acc_gain > bestGain) { +- bestGain = acc_gain; +- for (auto c : node->children) best_low_or_up[c->id] = low_or_up[c->id]; ++ if (accGain > bestGain) { ++ bestGain = accGain; ++ for (auto c : node->children) bestLowOrUp[c->id] = lowOrUp[c->id]; + } + } else if (align[i]) { // already consider, pass this child +- UpdateNode(node, align, gains, i + 1, segs, acc_gain, bestGain, low_or_up, best_low_or_up); ++ UpdateNode(node, align, gains, i + 1, segs, accGain, bestGain, lowOrUp, bestLowOrUp); + } else { // make a branch because this node-child edge can be L/U + int dir; + DTYPE dist; + bool low = true; // L/U + for (int j = 0; j < 2; ++j) { + GetDirId(node->children[i]->loc, node->loc, low, dir, dist); +- acc_gain += gains[i][j]; ++ accGain += gains[i][j]; + segs[dir].push_back(dist); +- low_or_up[node->children[i]->id] = low; +- UpdateNode(node, align, gains, i + 1, segs, acc_gain, bestGain, low_or_up, best_low_or_up); +- acc_gain -= gains[i][j]; ++ lowOrUp[node->children[i]->id] = low; ++ UpdateNode(node, align, gains, i + 1, segs, accGain, bestGain, lowOrUp, bestLowOrUp); ++ accGain -= gains[i][j]; + segs[dir].pop_back(); + low = false; // L/U + } + } + } + +-void UpdateSubTree(const shared_ptr node, array& res, array, 2>& best_low_or_up) { ++void UpdateSubTree(const shared_ptr node, array& res, array, 2>& bestLowOrUp) { + res = {0, 0}; // low, up + if (node->children.empty()) return; + + // Calc gains of children + unsigned nc = node->children.size(); + vector> gains(nc); +- for (unsigned i = 0; i < nc; ++i) UpdateSubTree(node->children[i], gains[i], best_low_or_up); ++ for (unsigned i = 0; i < nc; ++i) UpdateSubTree(node->children[i], gains[i], bestLowOrUp); + + // Process aligned children + vector align(nc, false); + array, 4> segs; +- DTYPE acc_gain = 0; +- vector low_or_up(best_low_or_up[0].size()); ++ DTYPE accGain = 0; ++ vector lowOrUp(bestLowOrUp[0].size()); + for (unsigned i = 0; i < nc; ++i) { + Point &a = node->children[i]->loc, b = node->loc; + if (a.x == b.x || a.y == b.y) { +@@ -89,7 +89,7 @@ void UpdateSubTree(const shared_ptr node, array& res, array< + GetDirId(a, node->loc, true, dir, dist); + segs[dir].push_back(dist); + align[i] = true; // no need for further processing +- acc_gain += gains[i][0]; ++ accGain += gains[i][0]; + } + } + +@@ -101,12 +101,12 @@ void UpdateSubTree(const shared_ptr node, array& res, array< + for (int j = 0; j < 2; ++j) { + GetDirId(node->parent->loc, node->loc, low, dir, dist); + segs[dir].push_back(dist); +- UpdateNode(node, align, gains, 0, segs, acc_gain, res[j], low_or_up, best_low_or_up[j]); ++ UpdateNode(node, align, gains, 0, segs, accGain, res[j], lowOrUp, bestLowOrUp[j]); + segs[dir].pop_back(); + low = false; // L/U + } + } else // for source node, update res[0] only +- UpdateNode(node, align, gains, 0, segs, acc_gain, res[0], low_or_up, best_low_or_up[0]); ++ UpdateNode(node, align, gains, 0, segs, accGain, res[0], lowOrUp, bestLowOrUp[0]); + + // cout<<*node->pin<<", low="<Print(0,true); + if (node->children.empty()) return; +@@ -141,7 +141,7 @@ void TraverseAndAddSteiner(const shared_ptr& node, bool low, arraychildren; // it may be chagned later +- for (auto c : children_cpy) TraverseAndAddSteiner(c, best_low_or_up[luid][c->id], best_low_or_up); ++ for (auto c : children_cpy) TraverseAndAddSteiner(c, bestLowOrUp[luid][c->id], bestLowOrUp); + + // get overlap info + array>>, 4> dist2node; // for four directions +@@ -153,12 +153,12 @@ void TraverseAndAddSteiner(const shared_ptr& node, bool low, arraychildren) { + if (c->id == -1) continue; +- GetDirId(c->loc, node->loc, best_low_or_up[luid][c->id], dir, dist); ++ GetDirId(c->loc, node->loc, bestLowOrUp[luid][c->id], dir, dist); + dist2node[dir].emplace_back(dist, c); + } + + // add steiner point +- auto ori_parent = node->parent; ++ auto oriParent = node->parent; + for (dir = 0; dir < 4; ++dir) { + auto& cands = dist2node[dir]; + if (cands.size() <= 1) continue; +@@ -171,7 +171,7 @@ void TraverseAndAddSteiner(const shared_ptr& node, bool low, arrayloc[xy]; + p[1 - xy] = cands[cid].second->loc[1 - xy]; +@@ -182,16 +182,16 @@ void TraverseAndAddSteiner(const shared_ptr& node, bool low, array g; // low, up +- int num_node = tree.UpdateId(); +- array, 2> best_low_or_up = {vector(num_node), vector(num_node)}; +- UpdateSubTree(tree.source, g, best_low_or_up); +- TraverseAndAddSteiner(tree.source, true, best_low_or_up); ++ int numNode = tree.UpdateId(); ++ array, 2> bestLowOrUp = {vector(numNode), vector(numNode)}; ++ UpdateSubTree(tree.source, g, bestLowOrUp); ++ TraverseAndAddSteiner(tree.source, true, bestLowOrUp); + tree.RemovePhyRedundantSteiner(); + cur.Update(tree); + } while (cur.wireLength < pre.wireLength); +diff --git a/src/third_party/salt/refine/refine.h b/src/third_party/salt/refine/refine.h +index 370e2cf9..c7a37e42 100644 +--- a/src/third_party/salt/refine/refine.h ++++ b/src/third_party/salt/refine/refine.h +@@ -4,13 +4,12 @@ + + namespace salt { + +-class Refine +-{ +- public: +- static void cancelIntersect(Tree& tree); +- static void flip(Tree& tree); +- static void uShift(Tree& tree); // should be after flip to achieve good quality +- static void substitute(Tree& tree, double eps, bool useRTree = true); ++class Refine { ++public: ++ static void CancelIntersect(Tree& tree); ++ static void Flip(Tree& tree); ++ static void UShift(Tree& tree); // should be after Flip to achieve good quality ++ static void Substitute(Tree& tree, double eps, bool useRTree = true); + }; + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/refine/substitute.cpp b/src/third_party/salt/refine/substitute.cpp +index bb90fead..02083af4 100644 +--- a/src/third_party/salt/refine/substitute.cpp ++++ b/src/third_party/salt/refine/substitute.cpp +@@ -1,12 +1,13 @@ ++#include "refine.h" ++ ++#include "salt/base/eval.h" ++#include "salt/base/mst.h" ++ + #include + #include + #include + #include + +-#include "refine.h" +-#include "salt/base/eval.h" +-#include "salt/base/mst.h" +- + namespace salt { + + namespace bg = boost::geometry; +@@ -17,216 +18,216 @@ using BSegment = bg::model::segment; + using BBox = bg::model::box; + using BPolygon = bg::model::polygon; + using RNode = pair>; // R-Tree node +-struct RNodeComp +-{ +- bool operator()(const RNode& l, const RNode& r) const { return bg::equals(l.first, r.first) && l.second == r.second; } ++struct RNodeComp { ++ bool operator()(const RNode& l, const RNode& r) const { ++ return bg::equals(l.first, r.first) && l.second == r.second; ++ } + }; + +-void Refine::substitute(Tree& tree, double eps, bool useRTree) +-{ +- bgi::rtree, bgi::indexable, RNodeComp> rtree; +- if (useRTree) { +- tree.postOrder([&](const shared_ptr& n) { +- if (n->parent) { +- BBox s; +- bg::envelope(BSegment(BPoint(n->loc.x, n->loc.y), BPoint(n->parent->loc.x, n->parent->loc.y)), s); +- rtree.insert({s, n}); +- } +- }); +- } +- auto disconnect = [&](const shared_ptr& n) { ++void Refine::Substitute(Tree& tree, double eps, bool useRTree) { ++ bgi::rtree, bgi::indexable, RNodeComp> rtree; + if (useRTree) { +- BBox s; +- bg::envelope(BSegment(BPoint(n->loc.x, n->loc.y), BPoint(n->parent->loc.x, n->parent->loc.y)), s); +- rtree.remove({s, n}); ++ tree.PostOrder([&](const shared_ptr& n) { ++ if (n->parent) { ++ BBox s; ++ bg::envelope(BSegment(BPoint(n->loc.x, n->loc.y), BPoint(n->parent->loc.x, n->parent->loc.y)), s); ++ rtree.insert({s, n}); ++ } ++ }); + } +- TreeNode::resetParent(n); +- }; +- auto connect = [&](const shared_ptr& n, const shared_ptr& parent) { +- TreeNode::setParent(n, parent); +- if (useRTree) { +- BBox s; +- bg::envelope(BSegment(BPoint(n->loc.x, n->loc.y), BPoint(parent->loc.x, parent->loc.y)), s); +- rtree.insert({s, n}); +- } +- }; +- while (true) { +- // Get nearest neighbors +- tree.UpdateId(); +- vector> nodes = tree.ObtainNodes(), +- ordered_nodes(nodes.size()); // note: all pins should be covered +- vector points(nodes.size()); +- for (int i = 0; i < nodes.size(); ++i) { +- ordered_nodes[nodes[i]->id] = nodes[i]; +- points[nodes[i]->id] = nodes[i]->loc; // TODO: move within bracket +- } +- nodes = ordered_nodes; +- vector> nearest_neighbors; +- if (!useRTree) { +- MstBuilder mst_builder; +- mst_builder.GetAllNearestNeighbors(points, nearest_neighbors); +- } else { +- nearest_neighbors.resize(nodes.size()); +- for (auto n : nodes) { +- if (n->parent) { +- Point c = n->loc; // center +- DTYPE radius = n->WireToParent(); +- // diamond is too slow... +- // BPolygon diamond; +- // diamond.outer().emplace_back(c.x - radius, c.y); +- // diamond.outer().emplace_back(c.x, c.y + radius); +- // diamond.outer().emplace_back(c.x + radius, c.y); +- // diamond.outer().emplace_back(c.x, c.y - radius); +- // diamond.outer().emplace_back(c.x - radius, c.y); +- BBox query_box{{c.x - radius, c.y - radius}, {c.x + radius, c.y + radius}}; +- vector cands; +- rtree.query(bgi::intersects(query_box), back_inserter(cands)); // TODO: change back_inserter +- for (const auto& cand : cands) { +- nearest_neighbors[n->id].push_back(cand.second->id); +- } ++ auto Disconnect = [&](const shared_ptr& n) { ++ if (useRTree) { ++ BBox s; ++ bg::envelope(BSegment(BPoint(n->loc.x, n->loc.y), BPoint(n->parent->loc.x, n->parent->loc.y)), s); ++ rtree.remove({s, n}); + } +- } +- } +- +- // Prune descendants in nearest neighbors +- vector pre_order_idxes(nodes.size(), -1); +- int global_pre_order_idx = 0; +- function&)> remove_descendants = [&](const shared_ptr& node) { +- pre_order_idxes[node->id] = global_pre_order_idx++; +- for (auto child : node->children) { +- remove_descendants(child); +- } +- for (auto& neigh_idx : nearest_neighbors[node->id]) { +- int neigh_pre_order_idx = pre_order_idxes[neigh_idx]; +- if (neigh_pre_order_idx != -1 && neigh_pre_order_idx >= pre_order_idxes[node->id]) { +- neigh_idx = -1; // -1 stands for "descendant" ++ TreeNode::ResetParent(n); ++ }; ++ auto Connect = [&](const shared_ptr& n, const shared_ptr& parent) { ++ TreeNode::SetParent(n, parent); ++ if (useRTree) { ++ BBox s; ++ bg::envelope(BSegment(BPoint(n->loc.x, n->loc.y), BPoint(parent->loc.x, parent->loc.y)), s); ++ rtree.insert({s, n}); + } +- } + }; +- remove_descendants(tree.source); ++ while (true) { ++ // Get nearest neighbors ++ int num = tree.UpdateId(); ++ vector> nodes = tree.ObtainNodes(), ++ orderedNodes(nodes.size()); // note: all pins should be covered ++ vector points(nodes.size()); ++ for (int i = 0; i < nodes.size(); ++i) { ++ orderedNodes[nodes[i]->id] = nodes[i]; ++ points[nodes[i]->id] = nodes[i]->loc; // TODO: move within bracket ++ } ++ nodes = orderedNodes; ++ vector> nearestNeighbors; ++ if (!useRTree) { ++ MstBuilder mstB; ++ mstB.GetAllNearestNeighbors(points, nearestNeighbors); ++ } else { ++ nearestNeighbors.resize(nodes.size()); ++ for (auto n : nodes) { ++ if (n->parent) { ++ Point c = n->loc; // center ++ DTYPE radius = n->WireToParent(); ++ // diamond is too slow... ++ // BPolygon diamond; ++ // diamond.outer().emplace_back(c.x - radius, c.y); ++ // diamond.outer().emplace_back(c.x, c.y + radius); ++ // diamond.outer().emplace_back(c.x + radius, c.y); ++ // diamond.outer().emplace_back(c.x, c.y - radius); ++ // diamond.outer().emplace_back(c.x - radius, c.y); ++ BBox queryBox{{c.x - radius, c.y - radius}, {c.x + radius, c.y + radius}}; ++ vector cands; ++ rtree.query(bgi::intersects(queryBox), back_inserter(cands)); // TODO: change back_inserter ++ for (const auto& cand : cands) { ++ nearestNeighbors[n->id].push_back(cand.second->id); ++ } ++ } ++ } ++ } + +- // Init path lengths and subtree slacks +- vector path_lengths(nodes.size()); +- vector slacks(nodes.size()); +- auto update_path_lengths = [&](const shared_ptr& node) { +- if (node->parent) { +- path_lengths[node->id] = path_lengths[node->parent->id] + node->WireToParent(); +- } else { +- path_lengths[node->id] = 0; +- } +- }; +- auto update_slacks = [&](const shared_ptr& node) { +- if (node->children.empty()) { +- slacks[node->id] = Dist(node->loc, tree.source->loc) * (1 + eps) - path_lengths[node->id]; // floor here... +- } else { +- DTYPE min_slack = Dist(node->loc, tree.source->loc) * (1 + eps) - path_lengths[node->id]; +- for (auto child : node->children) { +- min_slack = min(min_slack, slacks[child->id]); ++ // Prune descendants in nearest neighbors ++ vector preOrderIdxes(nodes.size(), -1); ++ int globalPreOrderIdx = 0; ++ function&)> removeDescendants = [&](const shared_ptr& node) { ++ preOrderIdxes[node->id] = globalPreOrderIdx++; ++ for (auto child : node->children) { ++ removeDescendants(child); ++ } ++ for (auto& neighIdx : nearestNeighbors[node->id]) { ++ int neighPreOrderIdx = preOrderIdxes[neighIdx]; ++ if (neighPreOrderIdx != -1 && neighPreOrderIdx >= preOrderIdxes[node->id]) { ++ neighIdx = -1; // -1 stands for "descendant" ++ } ++ } ++ }; ++ removeDescendants(tree.source); ++ ++ // Init path lengths and subtree slacks ++ vector pathLengths(nodes.size()); ++ vector slacks(nodes.size()); ++ auto UpdatePathLengths = [&](const shared_ptr& node) { ++ if (node->parent) { ++ pathLengths[node->id] = pathLengths[node->parent->id] + node->WireToParent(); ++ } else { ++ pathLengths[node->id] = 0; ++ } ++ }; ++ auto UpdateSlacks = [&](const shared_ptr& node) { ++ if (node->children.empty()) { ++ slacks[node->id] = ++ Dist(node->loc, tree.source->loc) * (1 + eps) - pathLengths[node->id]; // floor here... ++ } else { ++ DTYPE minSlack = Dist(node->loc, tree.source->loc) * (1 + eps) - pathLengths[node->id]; ++ for (auto child : node->children) { ++ minSlack = min(minSlack, slacks[child->id]); ++ } ++ slacks[node->id] = minSlack; ++ } ++ }; ++ tree.PreOrder(UpdatePathLengths); ++ tree.PostOrder(UpdateSlacks); ++ ++ // Find legal candidate moves ++ using MoveT = tuple, shared_ptr>; ++ vector candidateMoves; // ++ auto GetNearestPoint = [](const shared_ptr& target, const shared_ptr& neigh) { ++ Box box(neigh->loc, neigh->parent->loc); ++ box.Legalize(); ++ return box.GetNearestPointTo(target->loc); ++ }; ++ for (auto node : nodes) { ++ if (!(node->parent)) { ++ continue; ++ } ++ DTYPE bestWireLengthDelta = 0; // the negative, the better ++ shared_ptr bestNewParent; ++ for (int neighIdx : nearestNeighbors[node->id]) { ++ if (neighIdx == -1 || !nodes[neighIdx]->parent) continue; ++ auto neigh = nodes[neighIdx]; ++ auto neighParent = neigh->parent; ++ auto steinerPt = GetNearestPoint(node, neigh); ++ DTYPE wireLengthDelta = Dist(node->loc, steinerPt) - node->WireToParent(); ++ if (wireLengthDelta < bestWireLengthDelta) { // has wire length improvement ++ DTYPE pathLengthDelta = ++ pathLengths[neighParent->id] + Dist(node->loc, neighParent->loc) - pathLengths[node->id]; ++ if (pathLengthDelta <= slacks[node->id]) { // make path length under control ++ bestWireLengthDelta = wireLengthDelta; ++ bestNewParent = neigh; ++ } ++ } ++ } ++ if (bestNewParent) { ++ candidateMoves.emplace_back(bestWireLengthDelta, node, bestNewParent); ++ } ++ } ++ if (candidateMoves.empty()) { ++ break; + } +- slacks[node->id] = min_slack; +- } +- }; +- tree.preOrder(update_path_lengths); +- tree.postOrder(update_slacks); + +- // Find legal candidate moves +- using MoveT = tuple, shared_ptr>; +- vector candidate_moves; // +- auto get_nearest_point = [](const shared_ptr& target, const shared_ptr& neigh) { +- Box box(neigh->loc, neigh->parent->loc); +- box.Legalize(); +- return box.GetNearestPointTo(target->loc); +- }; +- for (auto node : nodes) { +- if (!(node->parent)) { +- continue; +- } +- DTYPE best_wire_length_delta = 0; // the negative, the better +- shared_ptr best_new_parent; +- for (int neigh_idx : nearest_neighbors[node->id]) { +- if (neigh_idx == -1 || !nodes[neigh_idx]->parent) +- continue; +- auto neigh = nodes[neigh_idx]; +- auto neigh_parent = neigh->parent; +- auto steiner_pt = get_nearest_point(node, neigh); +- DTYPE wire_length_delta = Dist(node->loc, steiner_pt) - node->WireToParent(); +- if (wire_length_delta < best_wire_length_delta) { // has wire length improvement +- DTYPE path_length_delta = path_lengths[neigh_parent->id] + Dist(node->loc, neigh_parent->loc) - path_lengths[node->id]; +- if (path_length_delta <= slacks[node->id]) { // make path length under control +- best_wire_length_delta = wire_length_delta; +- best_new_parent = neigh; +- } ++ // Try candidate moves in the order of descending wire length savings ++ // Note that earlier moves may influence the legality of later one ++ sort(candidateMoves.begin(), candidateMoves.end(), [](const MoveT& lhs, const MoveT& rhs){ ++ return get<0>(lhs) < get<0>(rhs); ++ }); ++ for (const auto& move : candidateMoves) { ++ auto node = get<1>(move), neigh = get<2>(move); ++ auto neighParent = neigh->parent; ++ // check due to earlier moves ++ if (TreeNode::IsAncestor(node, neighParent)) continue; ++ DTYPE pathLengthDelta = ++ pathLengths[neighParent->id] + Dist(node->loc, neighParent->loc) - pathLengths[node->id]; ++ if (pathLengthDelta > slacks[node->id]) continue; ++ auto steinerPt = GetNearestPoint(node, neigh); ++ DTYPE wireLengthDelta = Dist(node->loc, steinerPt) - node->WireToParent(); ++ if (wireLengthDelta >= 0) continue; ++ // break ++ Disconnect(node); ++ // reroot ++ if (steinerPt == neigh->loc) { ++ Connect(node, neigh); ++ } else if (steinerPt == neighParent->loc) { ++ Connect(node, neighParent); ++ } else { ++ auto steinerNode = make_shared(steinerPt); ++ Connect(steinerNode, neighParent); ++ Disconnect(neigh); ++ Connect(neigh, steinerNode); ++ Connect(node, steinerNode); ++ // for later moves ++ steinerNode->id = nodes.size(); ++ nodes.push_back(steinerNode); ++ pathLengths.push_back(pathLengths[neighParent->id] + steinerNode->WireToParent()); ++ slacks.push_back(Dist(steinerNode->loc, tree.source->loc) * (1 + eps) - pathLengths.back()); ++ } ++ // update slack for later moves: first subtree, then path to source ++ TreeNode::PreOrder(neighParent, UpdatePathLengths); ++ TreeNode::PostOrder(neighParent, UpdateSlacks); ++ auto tmp = neighParent; ++ while (tmp->parent) { ++ slacks[tmp->parent->id] = min(slacks[tmp->parent->id], slacks[tmp->id]); ++ tmp = tmp->parent; ++ } + } +- } +- if (best_new_parent) { +- candidate_moves.emplace_back(best_wire_length_delta, node, best_new_parent); +- } +- } +- if (candidate_moves.empty()) { +- break; +- } + +- // Try candidate moves in the order of descending wire length savings +- // Note that earlier moves may influence the legality of later one +- sort(candidate_moves.begin(), candidate_moves.end(), [](const MoveT& lhs, const MoveT& rhs) { return get<0>(lhs) < get<0>(rhs); }); +- for (const auto& move : candidate_moves) { +- auto node = get<1>(move), neigh = get<2>(move); +- auto neigh_parent = neigh->parent; +- // check due to earlier moves +- if (TreeNode::isAncestor(node, neigh_parent)) +- continue; +- DTYPE path_length_delta = path_lengths[neigh_parent->id] + Dist(node->loc, neigh_parent->loc) - path_lengths[node->id]; +- if (path_length_delta > slacks[node->id]) +- continue; +- auto steiner_pt = get_nearest_point(node, neigh); +- DTYPE wire_length_delta = Dist(node->loc, steiner_pt) - node->WireToParent(); +- if (wire_length_delta >= 0) +- continue; +- // break +- disconnect(node); +- // reroot +- if (steiner_pt == neigh->loc) { +- connect(node, neigh); +- } else if (steiner_pt == neigh_parent->loc) { +- connect(node, neigh_parent); +- } else { +- auto steiner_node = make_shared(steiner_pt); +- connect(steiner_node, neigh_parent); +- disconnect(neigh); +- connect(neigh, steiner_node); +- connect(node, steiner_node); +- // for later moves +- steiner_node->id = nodes.size(); +- nodes.push_back(steiner_node); +- path_lengths.push_back(path_lengths[neigh_parent->id] + steiner_node->WireToParent()); +- slacks.push_back(Dist(steiner_node->loc, tree.source->loc) * (1 + eps) - path_lengths.back()); +- } +- // update slack for later moves: first subtree, then path to source +- TreeNode::preOrder(neigh_parent, update_path_lengths); +- TreeNode::postOrder(neigh_parent, update_slacks); +- auto tmp = neigh_parent; +- while (tmp->parent) { +- slacks[tmp->parent->id] = min(slacks[tmp->parent->id], slacks[tmp->id]); +- tmp = tmp->parent; +- } ++ // Finalize ++ // tree.RemoveTopoRedundantSteiner(); ++ tree.PostOrderCopy([&](const shared_ptr& node) { ++ // degree may change after post-order traversal of its children ++ if (node->pin) return; ++ if (node->children.empty()) { ++ Disconnect(node); ++ } else if (node->children.size() == 1) { ++ auto oldParent = node->parent, oldChild = node->children[0]; ++ Disconnect(node); ++ Disconnect(oldChild); ++ Connect(oldChild, oldParent); ++ } ++ }); + } +- +- // Finalize +- // tree.RemoveTopoRedundantSteiner(); +- tree.postOrderCopy([&](const shared_ptr& node) { +- // degree may change after post-order traversal of its children +- if (node->pin) +- return; +- if (node->children.empty()) { +- disconnect(node); +- } else if (node->children.size() == 1) { +- auto old_parent = node->parent, old_child = node->children[0]; +- disconnect(node); +- disconnect(old_child); +- connect(old_child, old_parent); +- } +- }); +- } + } + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/refine/u_shift.cpp b/src/third_party/salt/refine/u_shift.cpp +index b923661c..80f662ff 100644 +--- a/src/third_party/salt/refine/u_shift.cpp ++++ b/src/third_party/salt/refine/u_shift.cpp +@@ -7,7 +7,7 @@ namespace salt { + // c pp -> root + // four Nodes: c - cur - p - pp -> root + // four points: out[0] - in[0] - in[1] - out[1]-> root +-void Refine::uShift(Tree& tree) { ++void Refine::UShift(Tree& tree) { + auto nodes = tree.ObtainNodes(); // fix the nodes considered (no deletion will happen) + for (auto cur : nodes) { + Point in[2], out[2]; +@@ -35,9 +35,9 @@ void Refine::uShift(Tree& tree) { + for (int i = 0; i < 2; ++i) newP[i][d] = closer; // set pri dir + for (int i = 0; i < 2; ++i) newP[i][1 - d] = in[i][1 - d]; // set sec dir + +- TreeNode::resetParent(c); +- TreeNode::resetParent(cur); +- TreeNode::resetParent(p); ++ TreeNode::ResetParent(c); ++ TreeNode::ResetParent(cur); ++ TreeNode::ResetParent(p); + // inS[0] inS[1] + // | | + // outS[0] - newS[0] - newS[1] - outS[1] -> root +@@ -50,13 +50,13 @@ void Refine::uShift(Tree& tree) { + else { + newS[i] = make_shared(newP[i]); + if (i == 0) +- TreeNode::setParent(outS[i], newS[i]); ++ TreeNode::SetParent(outS[i], newS[i]); + else +- TreeNode::setParent(newS[i], outS[i]); ++ TreeNode::SetParent(newS[i], outS[i]); + } +- TreeNode::setParent(inS[i], newS[i]); ++ TreeNode::SetParent(inS[i], newS[i]); + } +- TreeNode::setParent(newS[0], newS[1]); ++ TreeNode::SetParent(newS[0], newS[1]); + } + } + +diff --git a/src/third_party/salt/salt.cpp b/src/third_party/salt/salt.cpp +index 6e87682f..34d36d6e 100644 +--- a/src/third_party/salt/salt.cpp ++++ b/src/third_party/salt/salt.cpp +@@ -6,92 +6,86 @@ + + namespace salt { + +-void SaltInterface::Init(Tree& min_tree, shared_ptr src_pin) +-{ +- min_tree.UpdateId(); +- auto mt_nodes = min_tree.ObtainNodes(); +- sl_nodes.resize(mt_nodes.size()); +- shortest_dists.resize(mt_nodes.size()); +- cur_dists.resize(mt_nodes.size()); +- for (auto mt_node : mt_nodes) { +- sl_nodes[mt_node->id] = make_shared(mt_node->loc, mt_node->pin, mt_node->id); +- shortest_dists[mt_node->id] = Dist(mt_node->loc, src_pin->loc); +- cur_dists[mt_node->id] = numeric_limits::max(); +- } +- cur_dists[src_pin->id] = 0; +- sl_src = sl_nodes[src_pin->id]; ++void SaltBase::Init(Tree& minTree, shared_ptr srcP) { ++ minTree.UpdateId(); ++ auto mtNodes = minTree.ObtainNodes(); ++ slNodes.resize(mtNodes.size()); ++ shortestDists.resize(mtNodes.size()); ++ curDists.resize(mtNodes.size()); ++ for (auto mtN : mtNodes) { ++ slNodes[mtN->id] = make_shared(mtN->loc, mtN->pin, mtN->id); ++ shortestDists[mtN->id] = Dist(mtN->loc, srcP->loc); ++ curDists[mtN->id] = numeric_limits::max(); ++ } ++ curDists[srcP->id] = 0; ++ slSrc = slNodes[srcP->id]; + } + +-void SaltInterface::Finalize(const Net& net, Tree& tree) +-{ +- for (auto n : sl_nodes) +- if (n->parent) +- sl_nodes[n->parent->id]->children.push_back(n); +- tree.source = sl_src; +- tree.net = &net; ++void SaltBase::Finalize(const Net& net, Tree& tree) { ++ for (auto n : slNodes) ++ if (n->parent) slNodes[n->parent->id]->children.push_back(n); ++ tree.source = slSrc; ++ tree.net = &net; + } + +-void SaltBuilder::Run(const Net& net, Tree& tree, double eps, int refineLevel) +-{ +- // SMT +- Tree smt; +- FluteBuilder flute_builder; +- flute_builder.Run(net, smt); ++void SaltBuilder::Run(const Net& net, Tree& tree, double eps, int refineLevel) { ++ // SMT ++ Tree smt; ++ FluteBuilder fluteB; ++ fluteB.Run(net, smt); + +- // Refine SMT +- if (refineLevel >= 1) { +- Refine::flip(smt); +- Refine::uShift(smt); +- } ++ // Refine SMT ++ if (refineLevel >= 1) { ++ Refine::Flip(smt); ++ Refine::UShift(smt); ++ } + +- // Init +- Init(smt, net.source()); ++ // Init ++ Init(smt, net.source()); + +- // DFS +- DFS(smt.source, sl_src, eps); +- Finalize(net, tree); +- tree.RemoveTopoRedundantSteiner(); ++ // DFS ++ DFS(smt.source, slSrc, eps); ++ Finalize(net, tree); ++ tree.RemoveTopoRedundantSteiner(); + +- // Connect breakpoints to source by RSA +- salt::RsaBuilder rsa_builder; +- rsa_builder.ReplaceRootChildren(tree); ++ // Connect breakpoints to source by RSA ++ salt::RsaBuilder rsaB; ++ rsaB.ReplaceRootChildren(tree); + +- // Refine SALT +- if (refineLevel >= 1) { +- Refine::cancelIntersect(tree); +- Refine::flip(tree); +- Refine::uShift(tree); +- if (refineLevel >= 2) { +- Refine::substitute(tree, eps, refineLevel == 3); ++ // Refine SALT ++ if (refineLevel >= 1) { ++ Refine::CancelIntersect(tree); ++ Refine::Flip(tree); ++ Refine::UShift(tree); ++ if (refineLevel >= 2) { ++ Refine::Substitute(tree, eps, refineLevel == 3); ++ } + } +- } + } + +-bool SaltBuilder::Relax(const shared_ptr& u, const shared_ptr& v) +-{ +- DTYPE new_dist = cur_dists[u->id] + Dist(u->loc, v->loc); +- if (cur_dists[v->id] > new_dist) { +- cur_dists[v->id] = new_dist; +- v->parent = u; +- return true; +- } else if (cur_dists[v->id] == new_dist && Dist(u->loc, v->loc) < v->WireToParentChecked()) { +- v->parent = u; +- return true; +- } else +- return false; ++bool SaltBuilder::Relax(const shared_ptr& u, const shared_ptr& v) { ++ DTYPE newDist = curDists[u->id] + Dist(u->loc, v->loc); ++ if (curDists[v->id] > newDist) { ++ curDists[v->id] = newDist; ++ v->parent = u; ++ return true; ++ } else if (curDists[v->id] == newDist && Dist(u->loc, v->loc) < v->WireToParentChecked()) { ++ v->parent = u; ++ return true; ++ } else ++ return false; + } + +-void SaltBuilder::DFS(const shared_ptr& mst_node, const shared_ptr& sl_node, double eps) +-{ +- if (mst_node->pin && cur_dists[sl_node->id] > (1 + eps) * shortest_dists[sl_node->id]) { +- sl_node->parent = sl_src; +- cur_dists[sl_node->id] = shortest_dists[sl_node->id]; +- } +- for (auto c : mst_node->children) { +- Relax(sl_node, sl_nodes[c->id]); +- DFS(c, sl_nodes[c->id], eps); +- Relax(sl_nodes[c->id], sl_node); +- } ++void SaltBuilder::DFS(const shared_ptr& smtNode, const shared_ptr& slNode, double eps) { ++ if (smtNode->pin && curDists[slNode->id] > (1 + eps) * shortestDists[slNode->id]) { ++ slNode->parent = slSrc; ++ curDists[slNode->id] = shortestDists[slNode->id]; ++ } ++ for (auto c : smtNode->children) { ++ Relax(slNode, slNodes[c->id]); ++ DFS(c, slNodes[c->id], eps); ++ Relax(slNodes[c->id], slNode); ++ } + } + + } // namespace salt +diff --git a/src/third_party/salt/salt.h b/src/third_party/salt/salt.h +index c4f38769..640e0401 100644 +--- a/src/third_party/salt/salt.h ++++ b/src/third_party/salt/salt.h +@@ -4,28 +4,26 @@ + + namespace salt { + +-class SaltInterface +-{ +- protected: +- vector> sl_nodes; // nodes of the shallow-light tree +- vector shortest_dists; +- vector cur_dists; +- shared_ptr sl_src; // source node of the shallow-light tree ++class SaltBase { ++protected: ++ vector> slNodes; // nodes of the shallow-light tree ++ vector shortestDists; ++ vector curDists; ++ shared_ptr slSrc; // source node of the shallow-light tree + +- void Init(Tree& min_tree, shared_ptr src_pin); // tree of minimum weight +- void Finalize(const Net& net, Tree& tree); +- virtual bool Relax(const shared_ptr& u, const shared_ptr& v) = 0; // from u to v +- virtual void DFS(const shared_ptr& mst_node, const shared_ptr& sl_node, double eps) = 0; ++ void Init(Tree& minTree, shared_ptr srcP); // tree of minimum weight ++ void Finalize(const Net& net, Tree& tree); ++ virtual bool Relax(const shared_ptr& u, const shared_ptr& v) = 0; // from u to v ++ virtual void DFS(const shared_ptr& mstNode, const shared_ptr& slNode, double eps) = 0; + }; + +-class SaltBuilder : public SaltInterface +-{ +- public: +- void Run(const Net& net, Tree& tree, double eps, int refineLevel = 3); ++class SaltBuilder : public SaltBase { ++public: ++ void Run(const Net& net, Tree& tree, double eps, int refineLevel = 3); + +- protected: +- bool Relax(const shared_ptr& u, const shared_ptr& v); // from u to v +- void DFS(const shared_ptr& mst_node, const shared_ptr& sl_node, double eps); ++protected: ++ bool Relax(const shared_ptr& u, const shared_ptr& v); // from u to v ++ void DFS(const shared_ptr& mstNode, const shared_ptr& slNode, double eps); + }; + + } // namespace salt +\ No newline at end of file +diff --git a/src/third_party/salt/utils/geo.h b/src/third_party/salt/utils/geo.h +index 19c5181f..fc0445a2 100644 +--- a/src/third_party/salt/utils/geo.h ++++ b/src/third_party/salt/utils/geo.h +@@ -314,24 +314,24 @@ inline double L2Dist(const BoxT& box1, const BoxT& box2) { + // use BoxT instead of T & BoxT to make it more general + template + void MergeRects(std::vector& boxes, int mergeDir) { +- int boundary_dir = 1 - mergeDir; ++ int boundaryDir = 1 - mergeDir; + std::sort(boxes.begin(), boxes.end(), [&](const BoxT& lhs, const BoxT& rhs) { +- return lhs[boundary_dir].low < rhs[boundary_dir].low || +- (lhs[boundary_dir].low == rhs[boundary_dir].low && lhs[mergeDir].low < rhs[mergeDir].low); ++ return lhs[boundaryDir].low < rhs[boundaryDir].low || ++ (lhs[boundaryDir].low == rhs[boundaryDir].low && lhs[mergeDir].low < rhs[mergeDir].low); + }); +- std::vector merged_boxes; +- merged_boxes.push_back(boxes.front()); ++ std::vector mergedBoxes; ++ mergedBoxes.push_back(boxes.front()); + for (int i = 1; i < boxes.size(); ++i) { +- auto& last_box = merged_boxes.back(); +- auto& sliced_box = boxes[i]; +- if (sliced_box[boundary_dir] == last_box[boundary_dir] && +- sliced_box[mergeDir].low <= last_box[mergeDir].high) { // aligned and intersected +- last_box[mergeDir] = last_box[mergeDir].UnionWith(sliced_box[mergeDir]); ++ auto& lastBox = mergedBoxes.back(); ++ auto& slicedBox = boxes[i]; ++ if (slicedBox[boundaryDir] == lastBox[boundaryDir] && ++ slicedBox[mergeDir].low <= lastBox[mergeDir].high) { // aligned and intersected ++ lastBox[mergeDir] = lastBox[mergeDir].UnionWith(slicedBox[mergeDir]); + } else { // neither misaligned not seperated +- merged_boxes.push_back(sliced_box); ++ mergedBoxes.push_back(slicedBox); + } + } +- boxes = move(merged_boxes); ++ boxes = move(mergedBoxes); + } + + // Slice polygons along sliceDir +@@ -339,40 +339,40 @@ void MergeRects(std::vector& boxes, int mergeDir) { + // assume no degenerated case + template + void SlicePolygons(std::vector>& boxes, int sliceDir) { +- // Line sweep in sweep_dir = 1 - sliceDir +- // Suppose sliceDir = y and sweep_dir = x (sweep from left to right) ++ // Line sweep in sweepDir = 1 - sliceDir ++ // Suppose sliceDir = y and sweepDir = x (sweep from left to right) + // Not scalable impl (brute force interval query) but fast for small case + if (boxes.size() <= 1) return; + +- // sort slice lines in sweep_dir +- int sweep_dir = 1 - sliceDir; ++ // sort slice lines in sweepDir ++ int sweepDir = 1 - sliceDir; + std::vector locs; + for (const auto& box : boxes) { +- locs.push_back(box[sweep_dir].low); +- locs.push_back(box[sweep_dir].high); ++ locs.push_back(box[sweepDir].low); ++ locs.push_back(box[sweepDir].high); + } + std::sort(locs.begin(), locs.end()); + locs.erase(std::unique(locs.begin(), locs.end()), locs.end()); + + // slice each box +- std::vector> sliced_boxes; ++ std::vector> slicedBoxes; + for (const auto& box : boxes) { +- BoxT sliced_box = box; +- auto it_loc = std::lower_bound(locs.begin(), locs.end(), box[sweep_dir].low); +- auto it_end = std::upper_bound(it_loc, locs.end(), box[sweep_dir].high); +- while ((it_loc + 1) != it_end) { +- sliced_box[sweep_dir].Set(*it_loc, *(it_loc + 1)); +- sliced_boxes.push_back(sliced_box); +- ++it_loc; ++ BoxT slicedBox = box; ++ auto itLoc = std::lower_bound(locs.begin(), locs.end(), box[sweepDir].low); ++ auto itEnd = std::upper_bound(itLoc, locs.end(), box[sweepDir].high); ++ while ((itLoc + 1) != itEnd) { ++ slicedBox[sweepDir].Set(*itLoc, *(itLoc + 1)); ++ slicedBoxes.push_back(slicedBox); ++ ++itLoc; + } + } +- boxes = move(sliced_boxes); ++ boxes = move(slicedBoxes); + + // merge overlaped boxes along slice dir + MergeRects(boxes, sliceDir); + + // stitch boxes along sweep dir +- MergeRects(boxes, sweep_dir); ++ MergeRects(boxes, sweepDir); + } + + template +diff --git a/src/third_party/salt/utils/prettyprint.h b/src/third_party/salt/utils/prettyprint.h +index 8acff997..191792f3 100644 +--- a/src/third_party/salt/utils/prettyprint.h ++++ b/src/third_party/salt/utils/prettyprint.h +@@ -15,251 +15,219 @@ + + namespace utils { + +-// SFINAE HasBeginEnd ++// SFINAE has_begin_end + + template +-struct HasBeginEnd : std::false_type +-{ +-}; ++struct has_begin_end : std::false_type {}; + template +-struct HasBeginEnd()), (void) std::end(std::declval()))> : std::true_type +-{ +-}; ++struct has_begin_end()), (void)std::end(std::declval()))> ++ : std::true_type {}; + + // Holds the delimiter values for a specific character type + + template +-struct DelimitersValues +-{ +- using char_type = TChar; +- const char_type* prefix; +- const char_type* delimiter; +- const char_type* postfix; ++struct delimiters_values { ++ using char_type = TChar; ++ const char_type *prefix; ++ const char_type *delimiter; ++ const char_type *postfix; + }; + + // Defines the delimiter values for a specific container and character type + + template +-struct Delimiters +-{ +- using type = DelimitersValues; +- static const type kValues; ++struct delimiters { ++ using type = delimiters_values; ++ static const type values; + }; + + // Functor to print containers. You can use this directly if you want +-// to specificy a non-default Delimiters type. The printing logic can ++// to specificy a non-default delimiters type. The printing logic can + // be customized by specializing the nested template. + +-template , typename TDelimiters = Delimiters> +-struct PrintContainerHelper +-{ +- using delimiters_type = TDelimiters; +- using ostream_type = std::basic_ostream; +- +- template +- struct Printer +- { +- static void printBody(const U& c, ostream_type& stream) +- { +- auto it = std::begin(c); +- const auto the_end = std::end(c); +- +- if (it != the_end) { +- for (;;) { +- stream << *it; +- +- if (++it == the_end) +- break; +- +- if (delimiters_type::values.delimiter != NULL) +- stream << delimiters_type::values.delimiter; ++template , ++ typename TDelimiters = delimiters> ++struct print_container_helper { ++ using delimiters_type = TDelimiters; ++ using ostream_type = std::basic_ostream; ++ ++ template ++ struct printer { ++ static void print_body(const U &c, ostream_type &stream) { ++ auto it = std::begin(c); ++ const auto the_end = std::end(c); ++ ++ if (it != the_end) { ++ for (;;) { ++ stream << *it; ++ ++ if (++it == the_end) break; ++ ++ if (delimiters_type::values.delimiter != NULL) stream << delimiters_type::values.delimiter; ++ } ++ } + } +- } +- } +- }; ++ }; + +- PrintContainerHelper(const T& container) : container_(container) {} ++ print_container_helper(const T &container) : container_(container) {} + +- inline void operator()(ostream_type& stream) const +- { +- if (delimiters_type::values.prefix != NULL) +- stream << delimiters_type::values.prefix; ++ inline void operator()(ostream_type &stream) const { ++ if (delimiters_type::values.prefix != NULL) stream << delimiters_type::values.prefix; + +- Printer::printBody(container_, stream); ++ printer::print_body(container_, stream); + +- if (delimiters_type::values.postfix != NULL) +- stream << delimiters_type::values.postfix; +- } ++ if (delimiters_type::values.postfix != NULL) stream << delimiters_type::values.postfix; ++ } + +- private: +- const T& container_; ++private: ++ const T &container_; + }; + + // Specialization for pairs + + template + template +-struct PrintContainerHelper::Printer> +-{ +- using ostream_type = typename PrintContainerHelper::ostream_type; +- +- static void printBody(const std::pair& c, ostream_type& stream) +- { +- stream << c.first; +- if (PrintContainerHelper::delimiters_type::values.delimiter != NULL) +- stream << PrintContainerHelper::delimiters_type::values.delimiter; +- stream << c.second; +- } ++struct print_container_helper::printer> { ++ using ostream_type = typename print_container_helper::ostream_type; ++ ++ static void print_body(const std::pair &c, ostream_type &stream) { ++ stream << c.first; ++ if (print_container_helper::delimiters_type::values.delimiter != NULL) ++ stream << print_container_helper::delimiters_type::values.delimiter; ++ stream << c.second; ++ } + }; + + // Specialization for tuples + + template + template +-struct PrintContainerHelper::Printer> +-{ +- using ostream_type = typename PrintContainerHelper::ostream_type; +- using element_type = std::tuple; ++struct print_container_helper::printer> { ++ using ostream_type = typename print_container_helper::ostream_type; ++ using element_type = std::tuple; + +- template +- struct Int +- { +- }; ++ template ++ struct Int {}; + +- static void printBody(const element_type& c, ostream_type& stream) { tuplePrint(c, stream, Int<0>()); } ++ static void print_body(const element_type &c, ostream_type &stream) { tuple_print(c, stream, Int<0>()); } + +- static void tuplePrint(const element_type&, ostream_type&, Int) {} ++ static void tuple_print(const element_type &, ostream_type &, Int) {} + +- static void tuplePrint(const element_type& c, ostream_type& stream, +- typename std::conditional, std::nullptr_t>::type) +- { +- stream << std::get<0>(c); +- tuplePrint(c, stream, Int<1>()); +- } ++ static void tuple_print(const element_type &c, ++ ostream_type &stream, ++ typename std::conditional, std::nullptr_t>::type) { ++ stream << std::get<0>(c); ++ tuple_print(c, stream, Int<1>()); ++ } + +- template +- static void tuplePrint(const element_type& c, ostream_type& stream, Int) +- { +- if (PrintContainerHelper::delimiters_type::values.delimiter != NULL) +- stream << PrintContainerHelper::delimiters_type::values.delimiter; ++ template ++ static void tuple_print(const element_type &c, ostream_type &stream, Int) { ++ if (print_container_helper::delimiters_type::values.delimiter != NULL) ++ stream << print_container_helper::delimiters_type::values.delimiter; + +- stream << std::get(c); ++ stream << std::get(c); + +- tuplePrint(c, stream, Int()); +- } ++ tuple_print(c, stream, Int()); ++ } + }; + +-// Prints a PrintContainerHelper to the specified stream. ++// Prints a print_container_helper to the specified stream. + + template +-inline std::basic_ostream& operator<<(std::basic_ostream& stream, +- const PrintContainerHelper& helper) +-{ +- helper(stream); +- return stream; ++inline std::basic_ostream &operator<<( ++ std::basic_ostream &stream, ++ const print_container_helper &helper) { ++ helper(stream); ++ return stream; + } + +-// Basic IsContainer template; specialize to derive from std::true_type for all desired container types ++// Basic is_container template; specialize to derive from std::true_type for all desired container types + + template +-struct IsContainer : std::integral_constant::value> +-{ +-}; ++struct is_container : std::integral_constant::value> {}; + + template +-struct IsContainer> : std::true_type +-{ +-}; ++struct is_container> : std::true_type {}; + + template +-struct IsContainer> : std::true_type +-{ +-}; ++struct is_container> : std::true_type {}; + +-// Default Delimiters ++// Default delimiters + + template +-struct Delimiters +-{ +- static constexpr DelimitersValues kValues = {"[", ", ", "]"}; ++struct delimiters { ++ static constexpr delimiters_values values = {"[", ", ", "]"}; + }; + + // Delimiters for (unordered_)(multi)set + + template +-struct Delimiters> +-{ +- static constexpr DelimitersValues kValues = {"{", ", ", "}"}; ++struct delimiters> { ++ static constexpr delimiters_values values = {"{", ", ", "}"}; + }; + + template +-struct Delimiters> +-{ +- static constexpr DelimitersValues kValues = {"{", ", ", "}"}; ++struct delimiters> { ++ static constexpr delimiters_values values = {"{", ", ", "}"}; + }; + + template +-struct Delimiters> +-{ +- static constexpr DelimitersValues kValues = {"{", ", ", "}"}; ++struct delimiters> { ++ static constexpr delimiters_values values = {"{", ", ", "}"}; + }; + + template +-struct Delimiters> +-{ +- static constexpr DelimitersValues kValues = {"{", ", ", "}"}; ++struct delimiters> { ++ static constexpr delimiters_values values = {"{", ", ", "}"}; + }; + + // Delimiters for pair and tuple + + template +-struct Delimiters> +-{ +- static constexpr DelimitersValues kValues = {"(", ", ", ")"}; ++struct delimiters> { ++ static constexpr delimiters_values values = {"(", ", ", ")"}; + }; + + template +-struct Delimiters> +-{ +- static constexpr DelimitersValues kValues = {"(", ", ", ")"}; ++struct delimiters> { ++ static constexpr delimiters_values values = {"(", ", ", ")"}; + }; + +-// Type-erasing helper class for easy use of custom Delimiters. ++// Type-erasing helper class for easy use of custom delimiters. + // Requires TCharTraits = std::char_traits and TChar = char or wchar_t, and MyDelims needs to be defined for +-// TChar. Usage: "cout << pretty_print::CustomDelims(x)". ++// TChar. Usage: "cout << pretty_print::custom_delims(x)". + +-struct CustomDelimsInterface +-{ +- virtual ~CustomDelimsInterface() {} +- virtual std::ostream& stream(std::ostream&) = 0; ++struct custom_delims_base { ++ virtual ~custom_delims_base() {} ++ virtual std::ostream &stream(std::ostream &) = 0; + }; + + template +-struct CustomDelimsWrapper : CustomDelimsInterface +-{ +- CustomDelimsWrapper(const T& t_) : t(t_) {} ++struct custom_delims_wrapper : custom_delims_base { ++ custom_delims_wrapper(const T &t_) : t(t_) {} + +- std::ostream& stream(std::ostream& s) { return s << PrintContainerHelper, Delims>(t); } ++ std::ostream &stream(std::ostream &s) { ++ return s << print_container_helper, Delims>(t); ++ } + +- private: +- const T& t; ++private: ++ const T &t; + }; + + template +-struct CustomDelims +-{ +- template +- CustomDelims(const Container& c) : base(new CustomDelimsWrapper(c)) +- { +- } +- +- std::unique_ptr base; ++struct custom_delims { ++ template ++ custom_delims(const Container &c) : base(new custom_delims_wrapper(c)) {} ++ ++ std::unique_ptr base; + }; + + template +-inline std::basic_ostream& operator<<(std::basic_ostream& s, const CustomDelims& p) +-{ +- return p.base->stream(s); ++inline std::basic_ostream &operator<<(std::basic_ostream &s, ++ const custom_delims &p) { ++ return p.base->stream(s); + } + + } // namespace utils +@@ -268,13 +236,12 @@ inline std::basic_ostream& operator<<(std::basic_ostream +-inline typename enable_if<::utils::IsContainer::value, basic_ostream&>::type operator<<( +- basic_ostream& stream, const T& container) +-{ +- return stream << ::utils::PrintContainerHelper(container); ++inline typename enable_if<::utils::is_container::value, basic_ostream &>::type operator<<( ++ basic_ostream &stream, const T &container) { ++ return stream << ::utils::print_container_helper(container); + } + + } // namespace std +\ No newline at end of file