17 component_index[comp.name] = components.size();
18 components.push_back(comp);
21 if (components.back().position.x == 0 && components.back().position.y == 0) {
22 components.back().position = generate_random_position();
32 best_positions.clear();
33 for (
const auto& comp : components) {
34 best_positions.push_back(comp.position);
38 current_cost = evaluate_cost();
39 best_cost = current_cost;
40 current_temperature = config.initial_temperature;
42 std::cout <<
"Starting simulated annealing optimization..." << std::endl;
43 std::cout <<
"Initial cost: " << current_cost.total_cost << std::endl;
46 for (
size_t iter = 0; iter < config.max_iterations; ++iter) {
47 if (make_random_move()) {
48 auto new_cost = evaluate_cost();
49 double delta_cost = new_cost.total_cost - current_cost.total_cost;
53 if (delta_cost < 0 || accept_probability(delta_cost)) {
56 current_cost = new_cost;
59 if (new_cost.total_cost < best_cost.total_cost) {
61 for (
size_t i = 0; i < components.size(); ++i) {
62 best_positions[i] = components[i].position;
73 current_temperature *= config.cooling_rate;
76 if (iter % 10000 == 0) {
77 double acceptance_rate =
static_cast<double>(accepted_moves) / total_moves;
78 std::cout <<
"Iteration " << iter
79 <<
", Temperature: " << current_temperature
80 <<
", Cost: " << current_cost.total_cost
81 <<
", Acceptance: " << acceptance_rate * 100 <<
"%"
86 if (current_temperature < config.final_temperature) {
87 std::cout <<
"Reached final temperature, stopping..." << std::endl;
93 for (
size_t i = 0; i < components.size(); ++i) {
94 components[i].position = best_positions[i];
97 std::cout <<
"Optimization completed!" << std::endl;
98 std::cout <<
"Final cost: " << best_cost.total_cost << std::endl;
99 std::cout <<
"Improvement: " << (current_cost.total_cost - best_cost.total_cost) / current_cost.total_cost * 100 <<
"%" << std::endl;
104CostResult SimulatedAnnealingOptimizer::evaluate_cost()
const {
109 result.
area_cost = calculate_area_cost();
122double SimulatedAnnealingOptimizer::calculate_wirelength_cost()
const {
123 double total_wirelength = 0.0;
125 for (
const auto& net : nets) {
127 auto driver_it = component_index.find(net.driver_component);
128 if (driver_it == component_index.end())
continue;
130 geometry::Point driver_pos = components[driver_it->second].position;
133 double net_wirelength = 0.0;
134 for (
const auto& [sink_comp, sink_pin] : net.sinks) {
135 auto sink_it = component_index.find(sink_comp);
136 if (sink_it == component_index.end())
continue;
138 geometry::Point sink_pos = components[sink_it->second].position;
139 double distance = driver_pos.distance_to(sink_pos);
140 net_wirelength += distance;
144 total_wirelength += net_wirelength * net.weight * (1.0 + net.criticality);
147 return total_wirelength;
150double SimulatedAnnealingOptimizer::calculate_timing_cost()
const {
151 double timing_cost = 0.0;
153 for (
const auto& net : nets) {
154 if (net.criticality > 0.8) {
155 auto driver_it = component_index.find(net.driver_component);
156 if (driver_it == component_index.end())
continue;
158 geometry::Point driver_pos = components[driver_it->second].position;
160 for (
const auto& [sink_comp, sink_pin] : net.sinks) {
161 auto sink_it = component_index.find(sink_comp);
162 if (sink_it == component_index.end())
continue;
164 geometry::Point sink_pos = components[sink_it->second].position;
165 double distance = driver_pos.distance_to(sink_pos);
176double SimulatedAnnealingOptimizer::calculate_area_cost()
const {
178 if (components.empty())
return 0.0;
180 double min_x = components[0].position.x;
181 double max_x = min_x + components[0].shape.width;
182 double min_y = components[0].position.y;
183 double max_y = min_y + components[0].shape.height;
185 for (
const auto& comp : components) {
186 min_x = std::min(min_x,
comp.position.x);
187 max_x = std::max(max_x,
comp.position.x +
comp.shape.width);
188 min_y = std::min(min_y,
comp.position.y);
189 max_y = std::max(max_y,
comp.position.y +
comp.shape.height);
192 double total_area = (max_x - min_x) * (max_y - min_y);
193 double target_area = placement_area.area();
196 if (total_area > target_area) {
197 return total_area - target_area;
203double SimulatedAnnealingOptimizer::calculate_power_cost()
const {
207 double power_cost = 0.0;
209 for (
size_t i = 0; i < components.size(); ++i) {
210 for (
size_t j = i + 1; j < components.size(); ++j) {
211 const auto& comp1 = components[i];
212 const auto& comp2 = components[j];
214 double distance = comp1.position.distance_to(comp2.position);
215 double power_product = comp1.power_consumption * comp2.power_consumption;
218 if (power_product > 0.001 && distance < 10.0) {
219 power_cost += power_product / (
distance + 1.0);
227double SimulatedAnnealingOptimizer::calculate_constraint_violations()
const {
228 double violations = 0.0;
231 for (
size_t i = 0; i < components.size(); ++i) {
232 for (
size_t j = i + 1; j < components.size(); ++j) {
233 const auto& comp1 = components[i];
234 const auto& comp2 = components[j];
237 geometry::Rectangle rect1(comp1.position.x, comp1.position.y,
238 comp1.shape.width, comp1.shape.height);
239 geometry::Rectangle rect2(comp2.position.x, comp2.position.y,
240 comp2.shape.width, comp2.shape.height);
242 double distance = rect1.distance_to(rect2);
244 if (distance < config.min_spacing) {
245 violations += (config.min_spacing -
distance);
251 for (
const auto& comp : components) {
252 geometry::Rectangle comp_rect(
comp.position.x,
comp.position.y,
253 comp.shape.width,
comp.shape.height);
255 if (!placement_area.contains(comp_rect)) {
263bool SimulatedAnnealingOptimizer::make_random_move() {
264 if (components.empty())
return false;
267 std::vector<size_t> movable_components;
268 for (
size_t i = 0; i < components.size(); ++i) {
269 if (!components[i].is_fixed) {
270 movable_components.push_back(i);
274 if (movable_components.empty())
return false;
276 std::uniform_int_distribution<size_t> comp_dist(0, movable_components.size() - 1);
277 size_t selected_idx = movable_components[comp_dist(rng)];
280 old_position = components[selected_idx].position;
281 selected_component = selected_idx;
284 std::uniform_real_distribution<double> move_dist(-current_temperature, current_temperature);
285 geometry::Point new_pos(
286 components[selected_idx].position.x + move_dist(rng),
287 components[selected_idx].position.y + move_dist(rng)
291 if (is_position_valid(selected_idx, new_pos)) {
292 components[selected_idx].position = new_pos;
299void SimulatedAnnealingOptimizer::accept_move() {
303void SimulatedAnnealingOptimizer::reject_move() {
305 if (selected_component < components.size()) {
306 components[selected_component].position = old_position;
310bool SimulatedAnnealingOptimizer::accept_probability(
double delta_cost)
const {
311 if (current_temperature <= 0)
return false;
313 double probability = std::exp(-delta_cost / current_temperature);
314 std::uniform_real_distribution<double> uniform(0.0, 1.0);
316 return uniform(rng) < probability;
319geometry::Point SimulatedAnnealingOptimizer::generate_random_position()
const {
320 std::uniform_real_distribution<double> x_dist(placement_area.x,
321 placement_area.x + placement_area.width);
322 std::uniform_real_distribution<double> y_dist(placement_area.y,
323 placement_area.y + placement_area.height);
325 return geometry::Point(x_dist(rng), y_dist(rng));
328bool SimulatedAnnealingOptimizer::is_position_valid(
size_t comp_idx,
const geometry::Point& pos)
const {
329 const auto&
comp = components[comp_idx];
332 if (pos.x < placement_area.x ||
333 pos.y < placement_area.y ||
334 pos.x +
comp.shape.width > placement_area.x + placement_area.width ||
335 pos.y +
comp.shape.height > placement_area.y + placement_area.height) {
347 stats.
acceptance_rate = total_moves > 0 ?
static_cast<double>(accepted_moves) / total_moves : 0.0;
348 stats.
improvement_rate = total_moves > 0 ?
static_cast<double>(improved_moves) / total_moves : 0.0;
356 std::cout <<
"Starting force-directed placement..." << std::endl;
358 std::vector<geometry::Point> velocities(components.size(),
geometry::Point(0, 0));
360 for (
size_t iter = 0; iter < max_iterations; ++iter) {
361 bool converged =
true;
364 for (
size_t i = 0; i < components.size(); ++i) {
365 if (components[i]->is_fixed)
continue;
370 auto net_force = calculate_net_force(*components[i]);
371 total_force.
x += net_force.x;
372 total_force.
y += net_force.y;
375 auto repulsion_force = calculate_repulsion_force(*components[i]);
376 total_force.
x += repulsion_force.x;
377 total_force.
y += repulsion_force.y;
380 auto boundary_force = calculate_boundary_force(*components[i]);
381 total_force.
x += boundary_force.x;
382 total_force.
y += boundary_force.y;
385 velocities[i].x = velocities[i].x * damping_factor + total_force.
x * time_step;
386 velocities[i].y = velocities[i].y * damping_factor + total_force.
y * time_step;
389 components[i]->position.x += velocities[i].x * time_step;
390 components[i]->position.y += velocities[i].y * time_step;
393 if (std::abs(velocities[i].x) > 0.1 || std::abs(velocities[i].y) > 0.1) {
398 if (iter % 100 == 0) {
399 std::cout <<
"Iteration " << iter << std::endl;
403 std::cout <<
"Force-directed placement converged at iteration " << iter << std::endl;
408 std::cout <<
"Force-directed placement completed (max iterations reached)" << std::endl;
415 for (
const auto& net : nets) {
416 bool is_connected =
false;
419 if (net.driver_component == comp.name) {
422 for (
const auto& [sink_comp, sink_pin] : net.sinks) {
423 if (sink_comp == comp.name) {
430 if (!is_connected)
continue;
433 geometry::Point center_of_mass(0, 0);
434 int connected_count = 0;
436 for (
const auto& other_comp : components) {
437 if (other_comp->name ==
comp.name)
continue;
439 bool is_other_connected =
false;
440 if (net.driver_component == other_comp->name) {
441 is_other_connected =
true;
443 for (
const auto& [sink_comp, sink_pin] : net.sinks) {
444 if (sink_comp == other_comp->name) {
445 is_other_connected =
true;
451 if (is_other_connected) {
452 center_of_mass.x += other_comp->position.x;
453 center_of_mass.y += other_comp->position.y;
458 if (connected_count > 0) {
459 center_of_mass.x /= connected_count;
460 center_of_mass.y /= connected_count;
463 double dx = center_of_mass.x -
comp.position.x;
464 double dy = center_of_mass.y -
comp.position.y;
466 force.x += spring_constant * dx * net.weight;
467 force.y += spring_constant * dy * net.weight;
474geometry::Point ForceDirectedPlacer::calculate_repulsion_force(
const Component& comp)
const {
475 geometry::Point force(0, 0);
477 for (
const auto& other_comp : components) {
478 if (other_comp->name ==
comp.name)
continue;
480 double dx =
comp.position.x - other_comp->position.x;
481 double dy =
comp.position.y - other_comp->position.y;
482 double distance_sq = dx * dx + dy * dy;
484 if (distance_sq > 0) {
485 double distance = std::sqrt(distance_sq);
486 double repulsion = repulsion_constant / distance_sq;
488 force.x += repulsion * dx /
distance;
489 force.y += repulsion * dy /
distance;
496geometry::Point ForceDirectedPlacer::calculate_boundary_force(
const Component& comp)
const {
497 geometry::Point force(0, 0);
500 double left_dist =
comp.position.x - placement_area.x;
501 double right_dist = (placement_area.x + placement_area.width) - (
comp.position.x +
comp.shape.width);
502 double bottom_dist =
comp.position.y - placement_area.y;
503 double top_dist = (placement_area.y + placement_area.height) - (
comp.position.y +
comp.shape.height);
505 double boundary_strength = 100.0;
507 if (left_dist < 0) force.x += boundary_strength * (-left_dist);
508 if (right_dist < 0) force.x -= boundary_strength * (-right_dist);
509 if (bottom_dist < 0) force.y += boundary_strength * (-bottom_dist);
510 if (top_dist < 0) force.y -= boundary_strength * (-top_dist);
519 return std::make_unique<SimulatedAnnealingOptimizer>(area, config);
525 return std::make_unique<HierarchicalOptimizer>(area, config);
530 return std::make_unique<ForceDirectedPlacer>(area);
534 size_t component_count,
536 bool timing_critical) {
538 if (component_count > 100000) {
540 }
else if (timing_critical) {
542 }
else if (component_count > 1000) {
2D point with high-precision coordinates and utility methods
Axis-aligned rectangle for bounding boxes and simple EDA components.
bool optimize(size_t max_iterations=1000)
Run force-directed placement.
static std::unique_ptr< HierarchicalOptimizer > create_hierarchical_optimizer(const geometry::Rectangle &area, const OptimizationConfig &config=OptimizationConfig{})
static std::unique_ptr< SimulatedAnnealingOptimizer > create_sa_optimizer(const geometry::Rectangle &area, const OptimizationConfig &config=OptimizationConfig{})
static std::unique_ptr< ForceDirectedPlacer > create_force_directed_placer(const geometry::Rectangle &area)
static AlgorithmType recommend_algorithm(size_t component_count, size_t net_count, bool timing_critical=false)
Choose optimal algorithm based on problem characteristics.
Statistics get_statistics() const
void add_net(const Net &net)
void add_component(const Component &comp)
CostResult optimize()
Run simulated annealing optimization.
Advanced EDA layout optimization algorithms.
double distance(const Point &p1, const Point &p2)
Calculate distance between two points.
Main namespace for ZLayout library.
Circuit component with connectivity information.
double constraint_violations
Net (electrical connection) between components.
Layout optimization objectives and constraints.
Get optimization statistics.