@@ -120,8 +120,7 @@ matrix *copy_sparsity_spd_alloc(const stacked_pd *A)
120120 (permuted_dense * * ) SP_MALLOC (n_blocks * sizeof (permuted_dense * ));
121121 for (int k = 0 ; k < n_blocks ; k ++ )
122122 {
123- const matrix * Ak = (matrix * ) A -> blocks [k ];
124- C_blocks [k ] = (permuted_dense * ) Ak -> copy_sparsity (Ak );
123+ C_blocks [k ] = (permuted_dense * ) copy_sparsity_pd_alloc (A -> blocks [k ]);
125124 }
126125
127126 matrix * C = new_stacked_pd (A -> base .m , A -> base .n , n_blocks , C_blocks , NULL , NULL );
@@ -137,9 +136,14 @@ void DA_spd_fill_values(const double *d, const stacked_pd *A, stacked_pd *C)
137136 }
138137}
139138
140- /* ------------------------------------------------------------------ */
141- /* Transpose */
142- /* ------------------------------------------------------------------ */
139+ // ----------------------------------------------------------------------------------
140+ // Transpose C = A^T where A is stacked_pd. Blockwise logic followed by coalescing:
141+ // we first transpose each block independently, yielding a raw spd with the same
142+ // block count and swapped row/col perms as the final output but potentially
143+ // overlapping row perms. We then coalesce that raw spd to get the final output with
144+ // disjoint row perms. We keep the raw spd around on `out->work` for reuse by
145+ // `transpose_spd_fill_values` since its per-block transposes are also needed there.
146+ // ----------------------------------------------------------------------------------
143147
144148matrix * transpose_spd_alloc (const stacked_pd * A )
145149{
@@ -148,8 +152,7 @@ matrix *transpose_spd_alloc(const stacked_pd *A)
148152 (permuted_dense * * ) SP_MALLOC (n_blocks * sizeof (permuted_dense * ));
149153 for (int k = 0 ; k < n_blocks ; k ++ )
150154 {
151- matrix * blk = (matrix * ) A -> blocks [k ];
152- AT_blocks [k ] = (permuted_dense * ) blk -> transpose_alloc (blk );
155+ AT_blocks [k ] = (permuted_dense * ) transpose_pd_alloc (A -> blocks [k ]);
153156 }
154157
155158 /* Raw spd: dimensions swapped, identity src_block_idx_*; rows may
@@ -168,16 +171,17 @@ void transpose_spd_fill_values(const stacked_pd *A, stacked_pd *C)
168171 stacked_pd * raw = C -> work ;
169172 for (int k = 0 ; k < A -> n_blocks ; k ++ )
170173 {
171- matrix * A_blk = (matrix * ) A -> blocks [k ];
172- matrix * raw_blk = (matrix * ) raw -> blocks [k ];
173- A_blk -> transpose_fill_values (A_blk , raw_blk );
174+ transpose_pd_fill_values (A -> blocks [k ], raw -> blocks [k ]);
174175 }
175176 coalesce_spd_fill_values (raw , C );
176177}
177178
178- /* ------------------------------------------------------------------ */
179- /* ATA / ATDA */
180- /* ------------------------------------------------------------------ */
179+ // ------------------------------------------------------------------------------------
180+ // ATDA for stacked_pd A. Let A = [A1; A2; A3] where Ai has n columns (the same
181+ // number as A). Then ATDA = A1^T D1 A1 + A2^T D2 A2 + A3^T D3 A3. Term i and j
182+ // overlap if Ai and Aj have overlapping column entries. We therefore first compute
183+ // Ai^T Di Ai and then take care of the accumulation.
184+ // ------------------------------------------------------------------------------------
181185
182186matrix * ATA_spd_alloc (const stacked_pd * A )
183187{
@@ -207,49 +211,6 @@ matrix *ATA_spd_alloc(const stacked_pd *A)
207211 return out ;
208212}
209213
210- /* Scatter + add each scratch PD into its destination block in C. Multiple scratch
211- PDs may target the same Ck (their cells overlap by design — that's why we
212- accumulate). Caller is responsible for zeroing C->base.x first. */
213- static inline void accumulate_scratch_blocks (const stacked_pd * scratch ,
214- stacked_pd * C )
215- {
216- /* for each block Ck of C */
217- for (int k = 0 ; k < C -> n_blocks ; k ++ )
218- {
219- permuted_dense * Ck = C -> blocks [k ];
220- int s_lo = C -> src_block_idx_p [k ];
221- int s_hi = C -> src_block_idx_p [k + 1 ];
222-
223- /* for each block Eq = Ai^T D Ai in scratch contributing to block Ck in C */
224- for (int qq = s_lo ; qq < s_hi ; qq ++ )
225- {
226- const permuted_dense * Eq = scratch -> blocks [C -> src_block_idx [qq ]];
227-
228- /* for each row in Eq */
229- for (int i = 0 ; i < Eq -> m0 ; i ++ )
230- {
231- int Ck_row_idx = Ck -> row_inv [Eq -> row_perm [i ]];
232- if (Ck_row_idx < 0 )
233- {
234- /* this row in Eq does not contribute to Ck */
235- continue ;
236- }
237-
238- double * Ck_row = Ck -> X + Ck_row_idx * Ck -> n0 ;
239- double * Eq_row = Eq -> X + i * Eq -> n0 ;
240-
241- /* place each col in Eq_row at its correct position in Ck_row */
242- for (int j = 0 ; j < Eq -> n0 ; j ++ )
243- {
244- int out_j = Ck -> col_inv [Eq -> col_perm [j ]];
245- assert (out_j >= 0 );
246- Ck_row [out_j ] += Eq_row [j ];
247- }
248- }
249- }
250- }
251- }
252-
253214void ATDA_spd_fill_values (const stacked_pd * A , const double * d , stacked_pd * C )
254215{
255216 /* Let A = [A1; A2; A3] where Ai has n columns (the same number as A). Then
@@ -270,7 +231,7 @@ void ATDA_spd_fill_values(const stacked_pd *A, const double *d, stacked_pd *C)
270231 memset (C -> base .x , 0 , C -> base .nnz * sizeof (double ));
271232
272233 /* scatter + add each Ai^T Di Ai into its destination C block. */
273- accumulate_scratch_blocks (scratch , C );
234+ coalesce_spd_fill_values_accumulate (scratch , C );
274235}
275236
276237/* ------------------------------------------------------------------ */
0 commit comments