in src/hit/api/linearalgebra/linearalgebra.cpp [517:558]
EncryptedColVector LinearAlgebra::extract_col(const EncryptedMatrix &enc_mat_b_trans, int col) {
EncodingUnit unit = enc_mat_b_trans.encoding_unit();
// create a mask for the k^th row of B^T, which is the k^th column of B
// row_mask is a single encoding unit which will be replicated for every
// horizontal unit of the encoding of B^T
vector<double> row_mask(enc_mat_b_trans.num_slots());
// compute which unit row the desired column is in
int unit_row = col / unit.encoding_height();
// row_in_unit is the row within the encoding unit that contains the masked row
int row_in_unit = col % unit.encoding_height();
// create the column mask encoding unit
for (size_t i = 0; i < enc_mat_b_trans.num_slots(); i++) {
if (i / unit.encoding_width() == row_in_unit) {
row_mask[i] = 1;
} else {
row_mask[i] = 0;
}
}
vector<CKKSCiphertext> isolated_row_cts(enc_mat_b_trans.num_horizontal_units());
parallel_for(enc_mat_b_trans.num_horizontal_units(), [&](int j) {
isolated_row_cts[j] = eval.multiply_plain(enc_mat_b_trans.cts[unit_row][j], row_mask);
eval.rescale_to_next_inplace(isolated_row_cts[j]);
// we now have isolated the k^th row of B^T. To get an encoding of the k^th column of B
// we need to replicate this row across all rows of the encoding unit
// An easy way to do this is to invoke sum_rows,
// but it requires some packing and unpacking.
// [Note: sum_rows nominally spawns new threads, but this matrix only has a
// single unit, so no additional threads are created.
// First, compute the j^th component of the k^th column of B
// Then place it in isolated_row_cts
isolated_row_cts[j] = sum_rows_core(
EncryptedMatrix(unit.encoding_height(), unit.encoding_width(), unit,
vector<vector<CKKSCiphertext>>{vector<CKKSCiphertext>{isolated_row_cts[j]}}),
0, false);
});
return EncryptedColVector(enc_mat_b_trans.width(), unit, isolated_row_cts);
}