12
12
#include < memory>
13
13
#include < utility>
14
14
#include < vector>
15
+ #include " device_grid.h"
16
+ #include " flat_placement_types.h"
15
17
#include " partial_placement.h"
16
18
#include " ap_netlist.h"
17
19
#include " vpr_error.h"
36
38
#endif // EIGEN_INSTALLED
37
39
38
40
std::unique_ptr<AnalyticalSolver> make_analytical_solver (e_analytical_solver solver_type,
39
- const APNetlist& netlist) {
41
+ const APNetlist& netlist,
42
+ const DeviceGrid& device_grid) {
40
43
// Based on the solver type passed in, build the solver.
41
44
switch (solver_type) {
42
45
case e_analytical_solver::QP_HYBRID:
43
46
#ifdef EIGEN_INSTALLED
44
- return std::make_unique<QPHybridSolver>(netlist);
47
+ return std::make_unique<QPHybridSolver>(netlist, device_grid );
45
48
#else
46
49
(void )netlist;
47
50
VPR_FATAL_ERROR (VPR_ERROR_AP,
@@ -64,8 +67,11 @@ AnalyticalSolver::AnalyticalSolver(const APNetlist& netlist)
64
67
// row ID from [0, num_moveable_blocks) for each moveable block in the
65
68
// netlist.
66
69
num_moveable_blocks_ = 0 ;
70
+ num_fixed_blocks_ = 0 ;
67
71
size_t current_row_id = 0 ;
68
72
for (APBlockId blk_id : netlist.blocks ()) {
73
+ if (netlist.block_mobility (blk_id) == APBlockMobility::FIXED)
74
+ num_fixed_blocks_++;
69
75
if (netlist.block_mobility (blk_id) != APBlockMobility::MOVEABLE)
70
76
continue ;
71
77
APRowId new_row_id = APRowId (current_row_id);
@@ -155,10 +161,10 @@ void QPHybridSolver::init_linear_system() {
155
161
}
156
162
157
163
// Initialize the linear system with zeros.
158
- size_t num_variables = num_moveable_blocks_ + num_star_nodes;
159
- A_sparse = Eigen::SparseMatrix<double >(num_variables, num_variables );
160
- b_x = Eigen::VectorXd::Zero (num_variables );
161
- b_y = Eigen::VectorXd::Zero (num_variables );
164
+ num_variables_ = num_moveable_blocks_ + num_star_nodes;
165
+ A_sparse = Eigen::SparseMatrix<double >(num_variables_, num_variables_ );
166
+ b_x = Eigen::VectorXd::Zero (num_variables_ );
167
+ b_y = Eigen::VectorXd::Zero (num_variables_ );
162
168
163
169
// Create a list of triplets that will be used to create the sparse
164
170
// coefficient matrix. This is the method recommended by Eigen to initialize
@@ -254,7 +260,55 @@ void QPHybridSolver::update_linear_system_with_anchors(
254
260
}
255
261
}
256
262
263
+ void QPHybridSolver::init_guesses (const DeviceGrid& device_grid) {
264
+ // If the number of fixed blocks is zero, initialized the guesses to the
265
+ // center of the device.
266
+ if (num_fixed_blocks_ == 0 ) {
267
+ guess_x = Eigen::VectorXd::Constant (num_variables_, device_grid.width () / 2.0 );
268
+ guess_y = Eigen::VectorXd::Constant (num_variables_, device_grid.height () / 2.0 );
269
+ return ;
270
+ }
271
+
272
+ // Compute the centroid of all fixed blocks in the netlist.
273
+ t_flat_pl_loc centroid ({0 .0f , 0 .0f , 0 .0f });
274
+ unsigned num_blks_summed = 0 ;
275
+ for (APBlockId blk_id : netlist_.blocks ()) {
276
+ // We only get the centroid of fixed blocks since these are the only
277
+ // blocks with positions that we know.
278
+ if (netlist_.block_mobility (blk_id) != APBlockMobility::FIXED)
279
+ continue ;
280
+ // Get the flat location of the fixed block.
281
+ APFixedBlockLoc fixed_blk_loc = netlist_.block_loc (blk_id);
282
+ VTR_ASSERT_SAFE (fixed_blk_loc.x != APFixedBlockLoc::UNFIXED_DIM);
283
+ VTR_ASSERT_SAFE (fixed_blk_loc.y != APFixedBlockLoc::UNFIXED_DIM);
284
+ VTR_ASSERT_SAFE (fixed_blk_loc.layer_num != APFixedBlockLoc::UNFIXED_DIM);
285
+ t_flat_pl_loc flat_blk_loc;
286
+ flat_blk_loc.x = fixed_blk_loc.x ;
287
+ flat_blk_loc.y = fixed_blk_loc.y ;
288
+ flat_blk_loc.layer = fixed_blk_loc.layer_num ;
289
+ // Accumulate into the centroid.
290
+ centroid += flat_blk_loc;
291
+ num_blks_summed++;
292
+ }
293
+ // Divide the sum by the number of fixed blocks.
294
+ VTR_ASSERT_SAFE (num_blks_summed == num_fixed_blocks_);
295
+ centroid /= static_cast <float >(num_blks_summed);
296
+
297
+ // Set the guesses to the centroid location.
298
+ guess_x = Eigen::VectorXd::Constant (num_variables_, centroid.x );
299
+ guess_y = Eigen::VectorXd::Constant (num_variables_, centroid.y );
300
+ VTR_LOG (" (%g, %g)\n " , centroid.x , centroid.y );
301
+ }
302
+
257
303
void QPHybridSolver::solve (unsigned iteration, PartialPlacement& p_placement) {
304
+ // In the first iteration, if the number of fixed blocks is 0, set the
305
+ // placement to be equal to the guess. The solver below will just set the
306
+ // solution to the zero vector if we do not set it to the guess directly.
307
+ if (iteration == 0 && num_fixed_blocks_ == 0 ) {
308
+ store_solution_into_placement (guess_x, guess_y, p_placement);
309
+ return ;
310
+ }
311
+
258
312
// Create a temporary linear system which will contain the original linear
259
313
// system which may be updated to include the anchor points.
260
314
Eigen::SparseMatrix<double > A_sparse_diff = Eigen::SparseMatrix<double >(A_sparse);
@@ -280,14 +334,24 @@ void QPHybridSolver::solve(unsigned iteration, PartialPlacement& p_placement) {
280
334
cg.compute (A_sparse_diff);
281
335
VTR_ASSERT (cg.info () == Eigen::Success && " Conjugate Gradient failed at compute!" );
282
336
// Use the solver to solve for x and y using the constant vectors
283
- // TODO: Use solve with guess to make this faster. Use the previous placement
284
- // as a guess.
285
- Eigen::VectorXd x = cg.solve (b_x_diff);
337
+ Eigen::VectorXd x = cg.solveWithGuess (b_x_diff, guess_x);
286
338
VTR_ASSERT (cg.info () == Eigen::Success && " Conjugate Gradient failed at solving b_x!" );
287
- Eigen::VectorXd y = cg.solve (b_y_diff);
339
+ Eigen::VectorXd y = cg.solveWithGuess (b_y_diff, guess_y );
288
340
VTR_ASSERT (cg.info () == Eigen::Success && " Conjugate Gradient failed at solving b_y!" );
289
341
290
342
// Write the results back into the partial placement object.
343
+ store_solution_into_placement (x, y, p_placement);
344
+
345
+ // Update the guess. The guess for the next iteration is the solution in
346
+ // this iteration.
347
+ guess_x = x;
348
+ guess_y = y;
349
+ }
350
+
351
+ void QPHybridSolver::store_solution_into_placement (const Eigen::VectorXd& x_soln,
352
+ const Eigen::VectorXd& y_soln,
353
+ PartialPlacement& p_placement) {
354
+
291
355
// NOTE: The first [0, num_moveable_blocks_) rows always represent the
292
356
// moveable APBlocks. The star nodes always come after and are ignored
293
357
// in the solution.
@@ -296,8 +360,23 @@ void QPHybridSolver::solve(unsigned iteration, PartialPlacement& p_placement) {
296
360
APBlockId blk_id = row_id_to_blk_id_[row_id];
297
361
VTR_ASSERT_DEBUG (blk_id.is_valid ());
298
362
VTR_ASSERT_DEBUG (netlist_.block_mobility (blk_id) == APBlockMobility::MOVEABLE);
299
- p_placement.block_x_locs [blk_id] = x[row_id_idx];
300
- p_placement.block_y_locs [blk_id] = y[row_id_idx];
363
+ // Due to the iterative nature of CG, it is possible for the solver to
364
+ // overstep 0 and return a negative number by an incredibly small margin.
365
+ // Clamp the number to 0 in this case.
366
+ // TODO: Should investigate good bounds on this, the bounds below were
367
+ // chosen since any difference higher than 1e-9 would concern me.
368
+ double x_pos = x_soln[row_id_idx];
369
+ if (x_pos < 0.0 ) {
370
+ VTR_ASSERT_SAFE (std::abs (x_pos) < 1e-9 );
371
+ x_pos = 0.0 ;
372
+ }
373
+ double y_pos = y_soln[row_id_idx];
374
+ if (y_pos < 0.0 ) {
375
+ VTR_ASSERT_SAFE (std::abs (y_pos) < 1e-9 );
376
+ y_pos = 0.0 ;
377
+ }
378
+ p_placement.block_x_locs [blk_id] = x_pos;
379
+ p_placement.block_y_locs [blk_id] = y_pos;
301
380
}
302
381
}
303
382
0 commit comments