Reputation: 531
I am currently trying to implement matrix multiplication methods using the Microsoft SEAL library. I have created a vector<vector<double>>
as input matrix and encoded it with CKKSEncoder
. However the encoder packs an entire vector into a single Plaintext
so I just have a vector<Plaintext>
which makes me lose the 2D structure (and then of course I'll have a vector<Ciphertext>
after encryption). Having a 1D vector allows me to access only the rows entirely but not the columns.
I managed to transpose the matrices before encoding. This allowed me to multiply component-wise the rows of the first matrix and columns (rows in transposed form) of the second matrix but I am unable to sum the elements of the resulting vector together since it's packed into a single Ciphertext. I just need to figure out how to make the vector dot product work in SEAL to perform matrix multiplication. Am I missing something or is my method wrong?
Upvotes: 3
Views: 1194
Reputation: 531
It has been suggested by KyoohyungHan in the issue: https://github.com/microsoft/SEAL/issues/138 that it is possible to solve the problem with rotations by rotating the output vector and summing it up repeatedly.
For example:
// my_output_vector is the Ciphertext output
vector<Ciphertext> rotations_output(my_output_vector.size());
for(int steps = 0; steps < my_output_vector.size(); steps++)
{
evaluator.rotate_vector(my_output_vector, steps, galois_keys, rotations_output[steps]);
}
Ciphertext sum_output;
evaluator.add_many(rotations_output, sum_output);
Upvotes: 2
Reputation: 701
vector of vectors is not the same as an array of arrays (2D, matrix).
While one-dimentional vector<double>.data()
points to contiguous memory space (e.g., you can do memcpy
on that), each of "subvectors" allocates own, separate memory buffer. Therefore vector<vector<double>>.data()
makes no sense and cannot be used as a matrix.
In C++, two-dimensional array array2D[W][H]
is stored in memory identically to array[W*H]
. Therefore both can be processed by the same routines (when it makes sense). Consider the following example:
void fill_array(double *array, size_t size, double value) {
for (size_t i = 0; i < size; ++i) {
array[i] = value;
}
}
int main(int argc, char *argv[])
{
constexpr size_t W = 10;
constexpr size_t H = 5;
double matrix[W][H];
// using 2D array as 1D to fill all elements with 5.
fill_array(&matrix[0][0], W * H, 5);
for (const auto &row: matrix) {
for (const auto v : row) {
cout << v << '\t';
}
cout << '\n';
}
return 0;
}
In the above example, you can substitute double matrix[W][H];
with vector<double> matrix(W * H);
and feed matrix.data()
into fill_array()
. However, you cannot declare vector(W) of vector(H).
P.S. There are plenty of C++ implementations of math vector and matrix. You can use one of those if you don't want to deal with C-style arrays.
Upvotes: -1