Marwan N
Marwan N

Reputation: 531

Vector dot product in Microsoft SEAL with CKKS

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

Answers (2)

Marwan N
Marwan N

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

PooSH
PooSH

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

Related Questions