@@ -69,6 +69,74 @@ AnalyticalSolver::AnalyticalSolver(const APNetlist& netlist)
69
69
70
70
#ifdef EIGEN_INSTALLED
71
71
72
+ /* *
73
+ * @brief Helper method to add a connection between a src moveable node and a
74
+ * target APBlock with the given weight. This updates the tripleList and
75
+ * the constant vectors with the values necessary to solve the quadratic
76
+ * objective function.
77
+ *
78
+ * The A_sparse matrix is square and symmetric, so the use of the "row_id" as
79
+ * input is arbitrary; it could easily have been "src_col_id".
80
+ *
81
+ * The src_row_id always represents a moveable node in the linear system. It can
82
+ * represent a moveable APBlock or a star node.
83
+ *
84
+ * The target_blk_id may be either a moveable or fixed block.
85
+ *
86
+ * If the target block (t) is moveable, with source row s:
87
+ * A[s][s] = A[s][s] + weight
88
+ * A[t][t] = A[t][t] + weight
89
+ * A[s][t] = A[s][t] - weight
90
+ * A[t][s] = A[t][s] - weight
91
+ * If the target block is fixed:
92
+ * A[s][s] = A[s][s] + weight
93
+ * b[s] = b[s] + pos[block(t)] * weight
94
+ *
95
+ * These update equations come from taking the partial derivatives of the
96
+ * quadratic objective function w.r.t the moveable block locations. This is
97
+ * explained in detail in the FastPlace paper.
98
+ */
99
+ static inline void add_connection_to_system (size_t src_row_id,
100
+ APBlockId target_blk_id,
101
+ double weight,
102
+ std::vector<Eigen::Triplet<double >>& tripletList,
103
+ Eigen::VectorXd& b_x,
104
+ Eigen::VectorXd& b_y,
105
+ Eigen::SparseMatrix<double >& A_sparse,
106
+ vtr::vector<APBlockId, APRowId>& blk_id_to_row_id,
107
+ const APNetlist& netlist) {
108
+ // Verify that this is a valid row.
109
+ VTR_ASSERT_DEBUG (src_row_id < (size_t )A_sparse.rows ());
110
+ VTR_ASSERT_DEBUG (A_sparse.rows () == A_sparse.cols ());
111
+ // Verify that this is a valid block id.
112
+ VTR_ASSERT_DEBUG (target_blk_id.is_valid ());
113
+ // The src_row_id is always a moveable block (rows in the matrix always
114
+ // coorespond to a moveable APBlock or a star node.
115
+ if (netlist.block_mobility (target_blk_id) == APBlockMobility::MOVEABLE) {
116
+ // If the target is also moveable, update the coefficient matrix.
117
+ size_t target_row_id = (size_t )blk_id_to_row_id[target_blk_id];
118
+ VTR_ASSERT_DEBUG (target_row_id < (size_t )A_sparse.rows ());
119
+ tripletList.emplace_back (src_row_id, src_row_id, weight);
120
+ tripletList.emplace_back (target_row_id, target_row_id, weight);
121
+ tripletList.emplace_back (src_row_id, target_row_id, -weight);
122
+ tripletList.emplace_back (target_row_id, src_row_id, -weight);
123
+ } else {
124
+ // If the target is fixed, update the coefficient matrix and the
125
+ // constant vectors.
126
+ tripletList.emplace_back (src_row_id, src_row_id, weight);
127
+ VTR_ASSERT_DEBUG (netlist.block_loc (target_blk_id).x >= 0 );
128
+ VTR_ASSERT_DEBUG (netlist.block_loc (target_blk_id).y >= 0 );
129
+ // FIXME: These fixed block locations are aligned to the anchor of
130
+ // the tiles they are in. This is not correct. A method
131
+ // should be added to the netlist class or to a util file
132
+ // which can get a more accurate position.
133
+ double blk_loc_x = netlist.block_loc (target_blk_id).x ;
134
+ double blk_loc_y = netlist.block_loc (target_blk_id).y ;
135
+ b_x (src_row_id) += weight * blk_loc_x;
136
+ b_y (src_row_id) += weight * blk_loc_y;
137
+ }
138
+ }
139
+
72
140
void QPHybridSolver::init_linear_system () {
73
141
// Count the number of star nodes that the netlist will have.
74
142
size_t num_star_nodes = 0 ;
@@ -86,50 +154,20 @@ void QPHybridSolver::init_linear_system() {
86
154
// Create a list of triplets that will be used to create the sparse
87
155
// coefficient matrix. This is the method recommended by Eigen to initialize
88
156
// this matrix.
157
+ // A triplet represents a non-zero entry in a sparse matrix:
158
+ // (row index, col index, value)
159
+ // Where triplets at the same (row index, col index) are summed together.
89
160
std::vector<Eigen::Triplet<double >> tripletList;
90
161
// Reserve enough space for the triplets. This is just to help with
91
162
// performance.
163
+ // This is an over-estimate that assumes that each net connnects to all
164
+ // moveable blocks using a star node.
165
+ // TODO: This can be made more space-efficient by getting the average fanout
166
+ // of all nets in the APNetlist. Ideally this should be not enough
167
+ // space, but be within a constant factor.
92
168
size_t num_nets = netlist_.nets ().size ();
93
169
tripletList.reserve (num_moveable_blocks_ * num_nets);
94
170
95
- // Lambda expression to add a connection to the linear system from the src
96
- // to the target with the given weight. The src_row_id may represent a star
97
- // node (so it does not represent an APBlock) or a moveable APBlock. The
98
- // target_blk_id may be a fixed or moveable block.
99
- auto add_connection_to_system = [&](size_t src_row_id,
100
- APBlockId target_blk_id,
101
- double weight) {
102
- // Verify that this is a valid row.
103
- VTR_ASSERT_DEBUG (src_row_id < A_sparse.rows ());
104
- // Verify that this is a valid block id.
105
- VTR_ASSERT_DEBUG (target_blk_id.is_valid ());
106
- // The src_row_id is always a moveable block (rows in the matrix always
107
- // coorespond to a moveable APBlock or a star node.
108
- if (netlist_.block_mobility (target_blk_id) == APBlockMobility::MOVEABLE) {
109
- // If the target is also moveable, update the coefficient matrix.
110
- size_t target_row_id = (size_t )blk_id_to_row_id_[target_blk_id];
111
- VTR_ASSERT_DEBUG (target_row_id < A_sparse.rows ());
112
- tripletList.emplace_back (src_row_id, src_row_id, weight);
113
- tripletList.emplace_back (target_row_id, target_row_id, weight);
114
- tripletList.emplace_back (src_row_id, target_row_id, -weight);
115
- tripletList.emplace_back (target_row_id, src_row_id, -weight);
116
- } else {
117
- // If the target is fixed, update the coefficient matrix and the
118
- // constant vectors.
119
- tripletList.emplace_back (src_row_id, src_row_id, weight);
120
- VTR_ASSERT_DEBUG (netlist_.block_loc (target_blk_id).x >= 0 );
121
- VTR_ASSERT_DEBUG (netlist_.block_loc (target_blk_id).y >= 0 );
122
- // FIXME: These fixed block locations are aligned to the anchor of
123
- // the tiles they are in. This is not correct. A method
124
- // should be added to the netlist class or to a util file
125
- // which can get a more accurate position.
126
- double blk_loc_x = netlist_.block_loc (target_blk_id).x ;
127
- double blk_loc_y = netlist_.block_loc (target_blk_id).y ;
128
- b_x (src_row_id) += weight * blk_loc_x;
129
- b_y (src_row_id) += weight * blk_loc_y;
130
- }
131
- };
132
-
133
171
// Create the connections using a hybrid connection model of the star and
134
172
// clique connnection models.
135
173
size_t star_node_offset = 0 ;
@@ -140,17 +178,21 @@ void QPHybridSolver::init_linear_system() {
140
178
// Create a star node and connect each block in the net to the star
141
179
// node.
142
180
// Using the weight from FastPlace
181
+ // TODO: Investigate other weight terms.
143
182
double w = static_cast <double >(num_pins) / static_cast <double >(num_pins - 1 );
144
183
size_t star_node_id = num_moveable_blocks_ + star_node_offset;
145
184
for (APPinId pin_id : netlist_.net_pins (net_id)) {
146
185
APBlockId blk_id = netlist_.pin_block (pin_id);
147
- add_connection_to_system (star_node_id, blk_id, w);
186
+ add_connection_to_system (star_node_id, blk_id, w, tripletList,
187
+ b_x, b_y, A_sparse, blk_id_to_row_id_,
188
+ netlist_);
148
189
}
149
190
star_node_offset++;
150
191
} else {
151
192
// Create a clique connection where every block in a net connects
152
193
// exactly once to every other block in the net.
153
194
// Using the weight from FastPlace
195
+ // TODO: Investigate other weight terms.
154
196
double w = 1.0 / static_cast <double >(num_pins - 1 );
155
197
for (size_t ipin_idx = 0 ; ipin_idx < num_pins; ipin_idx++) {
156
198
APPinId first_pin_id = netlist_.net_pin (net_id, ipin_idx);
@@ -171,7 +213,9 @@ void QPHybridSolver::init_linear_system() {
171
213
std::swap (first_blk_id, second_blk_id);
172
214
}
173
215
size_t first_row_id = (size_t )blk_id_to_row_id_[first_blk_id];
174
- add_connection_to_system (first_row_id, second_blk_id, w);
216
+ add_connection_to_system (first_row_id, second_blk_id, w, tripletList,
217
+ b_x, b_y, A_sparse, blk_id_to_row_id_,
218
+ netlist_);
175
219
}
176
220
}
177
221
}
@@ -194,8 +238,19 @@ void QPHybridSolver::init_linear_system() {
194
238
* b[i] = b[i] + pos[block(i)] * coeff_pseudo_anchor;
195
239
* Where coeff_pseudo_anchor grows with each iteration.
196
240
*
197
- * This is basically a fast way of adding a connection between a moveable block
198
- * and a fixed block.
241
+ * This is basically a fast way of adding a connection between all moveable
242
+ * blocks in the netlist and their target fixed placement location.
243
+ *
244
+ * See add_connection_to_system.
245
+ *
246
+ * @param A_sparse_diff The ceofficient matrix to update.
247
+ * @param b_x_diff The x-dimension constant vector to update.
248
+ * @param b_y_diff The y-dimension constant vector to update.
249
+ * @param p_placement The location the moveable blocks should be anchored
250
+ * to.
251
+ * @param num_moveable_blocks The number of moveable blocks in the netlist.
252
+ * @param row_id_to_blk_id Lookup for the row id from the APBlock Id.
253
+ * @param iteration The current iteration of the Global Placer.
199
254
*/
200
255
static inline void update_linear_system_with_anchors (
201
256
Eigen::SparseMatrix<double > &A_sparse_diff,
@@ -252,9 +307,14 @@ void QPHybridSolver::solve(unsigned iteration, PartialPlacement &p_placement) {
252
307
VTR_ASSERT (cg.info () == Eigen::Success && " Conjugate Gradient failed at solving b_y!" );
253
308
254
309
// Write the results back into the partial placement object.
310
+ // NOTE: The first [0, num_moveable_blocks_) rows always represent the
311
+ // moveable APBlocks. The star nodes always come after and are ignored
312
+ // in the solution.
255
313
for (size_t row_id_idx = 0 ; row_id_idx < num_moveable_blocks_; row_id_idx++) {
256
314
APRowId row_id = APRowId (row_id_idx);
257
315
APBlockId blk_id = row_id_to_blk_id_[row_id];
316
+ VTR_ASSERT_DEBUG (blk_id.is_valid ());
317
+ VTR_ASSERT_DEBUG (netlist_.block_mobility (blk_id) == APBlockMobility::MOVEABLE);
258
318
p_placement.block_x_locs [blk_id] = x[row_id_idx];
259
319
p_placement.block_y_locs [blk_id] = y[row_id_idx];
260
320
}
0 commit comments