3

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?

Marwan N
  • 531
  • 6
  • 20

2 Answers2

2

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);
Marwan N
  • 531
  • 6
  • 20
-1

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.

PooSH
  • 601
  • 4
  • 11
  • That's not really my problem here. I'm just asking if it's possible to do vector dot product using Microsoft SEAL. I know there's a difference between vector of vectors and array of arrays but if I want to create a 2D array then I'll have to encode every single element from it which is computationally expensive. I'm trying to encode a full vector to benefit from SIMD. – Marwan N Feb 13 '20 at 10:33