TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
anneal_state.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Internal: the incremental annealing state shared by simulated annealing, parallel tempering, large-
4// neighbourhood search and exact windows (anneal.cpp, tempering.cpp, lns.cpp). Not part of the public API.
5//
6// The state is always legal for the movable parts (every committed move passed the exact test). Its cost is an
7// exact integer, kept incrementally: Σ w·HPWL + α·crossings + β·RUDY overflow.
8#include <array>
9#include <chrono>
10#include <cmath>
11#include <cstdint>
12#include <vector>
13
14#include "core/rng.hpp"
15#include "place/anneal.hpp"
16#include "place/congestion.hpp"
17#include "place/wirelength.hpp"
18
20
21inline constexpr Coord kLattice = 10'000; // committed positions on a 10 µm lattice
22inline constexpr int kMaxMove = 12; // parts in one compound move (LNS windows)
23inline constexpr double kLnsPhase = 0.3; // LNS windows run in the last 30 % of an annealing budget
24
25inline Coord snap(Coord v) { return (v >= 0 ? (v + kLattice / 2) : (v - kLattice / 2)) / kLattice * kLattice; }
26inline Point snap(Point q) { return Point{snap(q.x), snap(q.y)}; }
27inline std::int64_t alpha_units(double alpha_mm) { return static_cast<std::int64_t>(std::llround(alpha_mm * 1e6)) * kSignalWeight; }
28// Cost of one nm of RUDY overflow: β (mm of signal HPWL per mm of overflow) × signal weight; resolution 0.1.
29// Cost of one estimated via per unit of net weight: a via on a signal net (weight kSignalWeight) costs via_mm of
30// signal HPWL.
31inline std::int64_t via_units(double via_mm) { return static_cast<std::int64_t>(std::llround(via_mm * 1e6)); }
32inline std::int64_t beta_units(double beta) { return static_cast<std::int64_t>(std::llround(beta * kSignalWeight)); }
33
34inline Point body_centre(const Part& pt, int rot) {
35 const Box& b = pt.geom[z(rot)].body;
36 return Point{(b.x0 + b.x1) / 2, (b.y0 + b.y1) / 2};
37}
38
39struct Move {
40 int n = 0; // parts moved
41 std::array<int, kMaxMove> part{};
42 std::array<Point, kMaxMove> pos{}, old_pos{};
43 std::array<std::uint8_t, kMaxMove> rot{}, old_rot{};
44};
45
46// Temperature slot: the temperature and the shift-radius adaptation that belongs to it (parallel tempering
47// exchanges slots between replicas, so a replica arriving at a temperature inherits its tuned radius).
48struct Slot {
49 double t = 1;
50 double radius = 1;
51 std::uint64_t tried = 0, acc = 0;
52};
53
55 bool improved = false, proven = false;
56 long nodes = 0, leaves = 0;
57 std::int64_t delta = 0;
58};
59
60class Annealer {
61 public:
62 Annealer(const Problem& p, const std::vector<std::vector<int>>& pn, const Placement& start, const AnnealOptions& o, int stream);
63
64 std::int64_t cost() const { return whp_ + alpha_ * cross_ + beta_ * ovf_ + via_ * vias_; }
65 std::int64_t crossings() const { return cross_; }
66 std::int64_t overflow() const { return ovf_; }
67 const Placement& current() const { return pl_; }
68
69 // Initial temperature: mean uphill delta of random shift moves, accepted with probability p0.
70 double estimate_t0(double p0);
71 Coord r0() const { return r0_; }
72 // Simulated annealing with a geometric schedule over `moves` steps (independent-runs mode).
73 void run(std::uint64_t moves, std::chrono::steady_clock::time_point deadline, bool has_deadline);
74 // `n` steps at the slot's fixed temperature (parallel tempering).
75 void sweep(Slot& s, std::uint64_t n);
76 // One step: an ordinary move at temperature t, or (with probability lns_rate, while LNS is on) an LNS window.
77 void step(Slot& s);
78 // LNS windows are greedy (kept only if better), so they only pay off in the cold part of the schedule: the
79 // drivers switch them on for the last kLnsPhase of the budget.
80 void set_lns(bool on) { lns_on_ = on; }
81
82 // Large-neighbourhood search: rip up a window of parts around a seed part and re-place them (exactly by
83 // branch and bound for small windows, else greedily); kept only if the cost strictly falls.
84 bool lns_step();
85 bool repair(std::vector<int> window);
86 // Exact optimum of the window over its candidate set (branch and bound; `prune` = false enumerates every
87 // combination: the reference path). Applied only if strictly better.
88 WindowStats solve_window(std::vector<int> window, bool prune, long max_leaves = 200'000);
89 std::vector<int> window_around(int seed, int k) const;
90
91 void note_best();
92 const Placement& best() const { return best_pl_; }
93 const std::vector<Placement>& trace() const { return trace_; }
94 const std::vector<double>& trace_t() const { return trace_t_; }
95 std::int64_t best_cost() const { return best_cost_; }
96 std::int64_t start_cost() const { return start_cost_; }
97 std::uint64_t moves() const { return moves_; }
98 std::uint64_t accepted() const { return accepted_; }
99 std::uint64_t illegal() const { return illegal_; }
100 std::uint64_t lns_tried() const { return lns_tried_; }
101 std::uint64_t lns_improved() const { return lns_improved_; }
102 bool time_limited() const { return time_limited_; }
103 bool movable_empty() const { return movable_.empty(); }
104 int movable_part(std::size_t i) const { return movable_[i]; }
105 std::size_t movable_size() const { return movable_.size(); }
106 double next() { return rng_.uniform(ctr_++); }
107 std::uint64_t next_u64() { return rng_.u64(ctr_++); }
108
109 // Move primitives (pl_ is modified by evaluate; follow with revert or commit).
110 std::int64_t evaluate(const Move& m);
111 bool legal(const Move& m) const; // n ≤ 2 only
112 void revert(const Move& m);
113 void commit(const Move& m);
114
115 private:
116 int pick_movable() { return movable_[z(static_cast<int>(next_u64() % movable_.size()))]; }
117 bool propose_shift(Move& m, Coord radius);
118 bool propose_median(Move& m, Coord radius);
119 bool propose_rotate(Move& m);
120 bool propose_swap(Move& m);
121 bool propose_swap_near(Move& m, Coord radius);
122 bool propose_flip(Move& m, Coord radius);
123 bool single(Move& m, int a, Point q, std::uint8_t r);
124 // Weighted median of the other pins of a's nets for rotation r (origin placed so the pin centroid sits there).
125 bool median_target(int a, int r, Point& out) const;
126 void candidates(int a, const std::vector<int>& window, const std::vector<Point>& old_pos,
127 const std::vector<std::uint8_t>& old_rot, std::vector<std::pair<Point, std::uint8_t>>& out) const;
128 void restore_window(const std::vector<int>& window, const std::vector<Point>& old_pos, const std::vector<std::uint8_t>& old_rot);
129
130 void mst_of(int n, std::vector<Seg>& out);
131 void cell_range(const Seg& s, int& x0, int& y0, int& x1, int& y1) const;
132 void insert_segs(int n, const std::vector<Seg>& segs);
133 void remove_segs(int n);
134 std::int64_t grid_cross(const Seg& s);
135 static std::int64_t within(const std::vector<std::vector<Seg>>& sets);
136 void touch_bin(std::size_t k);
137
138 const Problem& p_;
139 const std::vector<std::vector<int>>& pn_;
140 const AnnealOptions& o_;
141 Placement pl_, best_pl_;
142 std::vector<Placement> trace_; // live state every o_.trace_every steps (recording only; never read back)
143 std::vector<double> trace_t_;
144 std::uint64_t steps_ = 0;
145 Legality L_;
146 RngStream rng_;
147 std::uint64_t ctr_ = 0;
148 std::int64_t alpha_ = 0, beta_ = 0;
149 std::vector<int> movable_, focus_;
150 std::vector<int> group_;
151 std::vector<std::vector<int>> groups_;
152 std::vector<Coord> hp_;
153 std::int64_t whp_ = 0, cross_ = 0, ovf_ = 0;
154 Coord r0_ = 0;
155 // Segment grid.
156 Coord gcell_ = 0, gox_ = 0, goy_ = 0;
157 int gnx_ = 1, gny_ = 1;
158 std::vector<std::vector<int>> cells_;
159 std::vector<Seg> pool_;
160 std::vector<int> free_;
161 std::vector<std::vector<int>> net_ids_;
162 std::vector<std::uint32_t> stamp_;
163 std::uint32_t epoch_ = 0;
164 std::vector<std::uint8_t> in_c_;
165 // Congestion (RUDY) state.
166 CongestionMap cmap_;
167 std::vector<std::int64_t> demand_, saved_;
168 std::vector<Box> nbox_, new_box_;
169 std::vector<std::uint32_t> bstamp_;
170 std::uint32_t bepoch_ = 0;
171 std::vector<std::size_t> touched_;
172 std::int64_t dovf_ = 0;
173 // Side assignment: front/back surface-mount pin counts per net, Σ w·min(front, back), and the move's changes.
174 bool sides_ = false;
175 std::vector<int> flippable_;
176 std::int64_t via_ = 0, vias_ = 0, dvia_ = 0;
177 std::vector<std::array<int, 2>> side_cnt_;
178 std::vector<std::pair<int, std::array<int, 2>>> side_saved_;
179 // Scratch.
180 std::vector<int> nets_, cnets_, near_;
181 std::vector<Coord> new_hp_;
182 std::vector<std::vector<Seg>> old_segs_, new_segs_;
183 std::vector<Point> pts_;
184 std::int64_t dcross_ = 0, last_old_c_ = 0;
185 // Results.
186 std::int64_t best_cost_ = 0, start_cost_ = 0;
187 std::uint64_t moves_ = 0, accepted_ = 0, illegal_ = 0, lns_tried_ = 0, lns_improved_ = 0;
188 bool time_limited_ = false;
189 bool lns_on_ = true;
190};
191
192// Parallel-tempering driver (tempering.cpp).
193AnnealResult anneal_tempering(const Problem& p, const std::vector<std::vector<int>>& pn, const Placement& start, const AnnealOptions& o,
194 std::uint64_t moves);
195// Fills the result fields shared by both drivers from the winning replica.
196void finish_result(const Problem& p, const AnnealOptions& o, AnnealResult& res);
197
198} // namespace tmk::place::detail
(E) Detailed placement by simulated annealing (design doc 04 §3 E; Kirkpatrick, Gelatt,...
A random stream identified by (seed, stage, item).
Definition rng.hpp:62
const Placement & best() const
std::int64_t crossings() const
void step(Slot &s)
One step: an ordinary move at temperature t, or (with probability lns_rate, while LNS is on) an LNS w...
const std::vector< Placement > & trace() const
void set_lns(bool on)
LNS windows are greedy (kept only if better), so they only pay off in the cold part of the schedule: ...
std::uint64_t moves() const
std::int64_t overflow() const
std::uint64_t accepted() const
void sweep(Slot &s, std::uint64_t n)
n steps at the slot's fixed temperature (parallel tempering).
std::uint64_t illegal() const
const Placement & current() const
std::uint64_t lns_improved() const
Annealer(const Problem &p, const std::vector< std::vector< int > > &pn, const Placement &start, const AnnealOptions &o, int stream)
int movable_part(std::size_t i) const
std::int64_t evaluate(const Move &m)
Move primitives (pl_ is modified by evaluate; follow with revert or commit).
std::vector< int > window_around(int seed, int k) const
void revert(const Move &m)
WindowStats solve_window(std::vector< int > window, bool prune, long max_leaves=200 '000)
Exact optimum of the window over its candidate set (branch and bound; prune = false enumerates every ...
std::int64_t start_cost() const
bool lns_step()
Large-neighbourhood search: rip up a window of parts around a seed part and re-place them (exactly by...
void commit(const Move &m)
void run(std::uint64_t moves, std::chrono::steady_clock::time_point deadline, bool has_deadline)
Simulated annealing with a geometric schedule over moves steps (independent-runs mode).
std::size_t movable_size() const
const std::vector< double > & trace_t() const
bool legal(const Move &m) const
n ≤ 2 only
std::int64_t cost() const
std::uint64_t lns_tried() const
bool repair(std::vector< int > window)
std::int64_t best_cost() const
double estimate_t0(double p0)
Initial temperature: mean uphill delta of random shift moves, accepted with probability p0.
Routability estimate for placement (design doc 04 §3 B R(x), E β·RUDY overflow, G).
std::int64_t beta_units(double beta)
void finish_result(const Problem &p, const AnnealOptions &o, AnnealResult &res)
Fills the result fields shared by both drivers from the winning replica.
Coord snap(Coord v)
AnnealResult anneal_tempering(const Problem &p, const std::vector< std::vector< int > > &pn, const Placement &start, const AnnealOptions &o, std::uint64_t moves)
Parallel-tempering driver (tempering.cpp).
constexpr int kMaxMove
parts in one compound move (LNS windows)
Point body_centre(const Part &pt, int rot)
constexpr double kLnsPhase
LNS windows run in the last 30 % of an annealing budget.
std::int64_t via_units(double via_mm)
Cost of one nm of RUDY overflow: β (mm of signal HPWL per mm of overflow) × signal weight; resolution...
constexpr Coord kLattice
committed positions on a 10 µm lattice
std::int64_t alpha_units(double alpha_mm)
constexpr int kSignalWeight
Net weights are small integers so every cost is an exact integer (CLAUDE.md rule 2).
Definition problem.hpp:24
std::size_t z(int i)
Definition problem.hpp:21
std::int64_t Coord
Engine coordinate: signed 64-bit nanometres.
Definition units.hpp:12
Deterministic, counter-based random numbers (design doc 02 §6.2).
Coord y1
empty when x1 < x0
Definition point.hpp:21
std::array< PartGeom, kStates > geom
per state (states 4–7 only filled for flippable parts)
Definition problem.hpp:77
std::array< std::uint8_t, kMaxMove > old_rot
std::array< Point, kMaxMove > pos
std::array< Point, kMaxMove > old_pos
std::array< std::uint8_t, kMaxMove > rot
std::array< int, kMaxMove > part
Temperature slot: the temperature and the shift-radius adaptation that belongs to it (parallel temper...
Wirelength and airwire metrics: weighted half-perimeter wirelength (HPWL) and crossings between the m...