From 419f7eb7689691755a83fd492b6a7a4cfb1c03e2 Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 16:40:40 +0100 Subject: [PATCH 01/13] implement square and power functions for CKKS vector --- tenseal/tensors/ckksvector.cpp | 56 ++++++++++++++++++++++++++++++++++ tenseal/tensors/ckksvector.h | 12 ++++++++ 2 files changed, 68 insertions(+) diff --git a/tenseal/tensors/ckksvector.cpp b/tenseal/tensors/ckksvector.cpp index 48dd0f2b..a8a53dea 100644 --- a/tenseal/tensors/ckksvector.cpp +++ b/tenseal/tensors/ckksvector.cpp @@ -84,6 +84,62 @@ CKKSVector& CKKSVector::negate_inplace() { return *this; } +CKKSVector CKKSVector::square() { + CKKSVector new_vector = *this; + new_vector.square_inplace(); + + return new_vector; +} + +CKKSVector& CKKSVector::square_inplace() { + this->context->evaluator->square_inplace(this->ciphertext); + + if (this->context->auto_relin()) { + this->context->evaluator->relinearize_inplace( + this->ciphertext, *this->context->relin_keys()); + } + + if (this->context->auto_rescale()) { + this->context->evaluator->rescale_to_next_inplace(this->ciphertext); + this->ciphertext.scale() = this->init_scale; + } + + return *this; +} + +CKKSVector CKKSVector::power(int power) { + CKKSVector new_vector = *this; + new_vector.power_inplace(power); + + return new_vector; +} + +CKKSVector& CKKSVector::power_inplace(int power) { + if (power <= 0) { + throw invalid_argument( + "can't compute CKKSVector to a null or a negative power"); + } + + if (power == 1) { + return *this; + } + + if (power == 2) { + this->square_inplace(); + return *this; + } + + int closest_power_of_2 = 1 << static_cast(floor(log2(power))); + power -= closest_power_of_2; + if (power == 0) { + this->power_inplace(closest_power_of_2 / 2) + .mul_inplace(this->power(closest_power_of_2 / 2)); + } else { + this->power_inplace(power).mul_inplace(this->power(closest_power_of_2)); + } + return *this; +} + CKKSVector CKKSVector::add(CKKSVector to_add) { CKKSVector new_vector = *this; new_vector.add_inplace(to_add); diff --git a/tenseal/tensors/ckksvector.h b/tenseal/tensors/ckksvector.h index 062ff4f3..ed4d793a 100644 --- a/tenseal/tensors/ckksvector.h +++ b/tenseal/tensors/ckksvector.h @@ -57,6 +57,18 @@ class CKKSVector { CKKSVector negate(); CKKSVector& negate_inplace(); + /* + Compute the square of the CKKSVector. + */ + CKKSVector square(); + CKKSVector& square_inplace(); + + /* + Compute the power of the CKKSVector with minimal multiplication depth. + */ + CKKSVector power(int power); + CKKSVector& power_inplace(int power); + /* Encrypted evaluation function operates on two encrypted vectors and returns a new CKKSVector which is the result of either addition, From 7055d172ea9b9fd52509dd96898c5199ecdc0e8e Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 16:41:21 +0100 Subject: [PATCH 02/13] python binding for CKKS vector square and power functions --- tenseal/binding.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tenseal/binding.cpp b/tenseal/binding.cpp index 25d097a1..8b673b11 100644 --- a/tenseal/binding.cpp +++ b/tenseal/binding.cpp @@ -87,6 +87,12 @@ PYBIND11_MODULE(_tenseal_cpp, m) { .def("neg", &CKKSVector::negate) .def("neg_", &CKKSVector::negate_inplace) .def("neg_inplace", &CKKSVector::negate_inplace) + .def("square", &CKKSVector::square) + .def("square_", &CKKSVector::square_inplace) + .def("square_inplace", &CKKSVector::square_inplace) + .def("pow", &CKKSVector::power) + .def("pow_", &CKKSVector::power_inplace) + .def("pow_inplace", &CKKSVector::power_inplace) .def("add", &CKKSVector::add) .def("add_", &CKKSVector::add_inplace) .def("add_plain", py::overload_cast(&CKKSVector::add_plain)) @@ -130,6 +136,8 @@ PYBIND11_MODULE(_tenseal_cpp, m) { .def("mm_", &CKKSVector::matmul_plain_inplace) // python arithmetic .def("__neg__", &CKKSVector::negate) + .def("__pow__", &CKKSVector::power) + .def("__ipow__", &CKKSVector::power_inplace) .def("__add__", &CKKSVector::add) .def("__add__", py::overload_cast(&CKKSVector::add_plain)) .def("__add__", From 6612bb946df912361abc649aae721499a69f0600 Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 16:42:04 +0100 Subject: [PATCH 03/13] tests for CKKS vector square and power functions --- tests/tensors/test_ckks_vector.py | 90 +++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index b649fa34..31197ce8 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -43,6 +43,96 @@ def test_negate_inplace(context, plain_vec): assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" +@pytest.mark.parametrize( + "plain_vec, power", + [ + ([], 2), + ([0], 3), + ([1, -1, 2, -2], 1), + ([1, -1, 2, -2], 2), + ([1, -1, 2, -2], 3), + ([1, -2, 3, -4], 1), + ([1, -2, 3, -4], 2), + ([1, -2, 3, -4], 3), + ], +) +def test_power(context, plain_vec, power): + ckks_vec = ts.ckks_vector(context, plain_vec) + expected = [np.power(v, power) for v in plain_vec] + new_vec = ckks_vec ** power + decrypted_result = new_vec.decrypt() + assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + assert _almost_equal(ckks_vec.decrypt(), plain_vec, 1), "Something went wrong in memory." + + +@pytest.mark.parametrize( + "plain_vec, power", + [ + ([], 2), + ([0], 3), + ([1, -1, 2, -2], 1), + ([1, -1, 2, -2], 2), + ([1, -1, 2, -2], 3), + ([1, -2, 3, -4], 1), + ([1, -2, 3, -4], 2), + ([1, -2, 3, -4], 3), + ], +) +def test_power_inplace(context, plain_vec, power): + ckks_vec = ts.ckks_vector(context, plain_vec) + expected = [np.power(v, power) for v in plain_vec] + ckks_vec **= power + decrypted_result = ckks_vec.decrypt() + assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + + +@pytest.mark.parametrize( + "plain_vec", + [ + [], + [0], + [1], + [2], + [1, -1, 2, -2], + [1, -1, 6, -2], + [2, 1, -2, -2], + [1, -2, 3, -4], + [3, -2, 5, -4], + [1, -4, 3, 5], + ], +) +def test_square(context, plain_vec): + ckks_vec = ts.ckks_vector(context, plain_vec) + expected = [np.power(v, 2) for v in plain_vec] + new_vec = ckks_vec.square() + decrypted_result = new_vec.decrypt() + assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + assert _almost_equal(ckks_vec.decrypt(), plain_vec, 1), "Something went wrong in memory." + + +@pytest.mark.parametrize( + "plain_vec", + [ + [], + [0], + [1], + [2], + [1, -1, 2, -2], + [1, -1, 6, -2], + [2, 1, -2, -2], + [1, -2, 3, -4], + [3, -2, 5, -4], + [1, -4, 3, 5], + ], +) +def test_square_inplace(context, plain_vec): + ckks_vec = ts.ckks_vector(context, plain_vec) + expected = [np.power(v, 2) for v in plain_vec] + ckks_vec.square_() + decrypted_result = ckks_vec.decrypt() + assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + + @pytest.mark.parametrize( "vec1, vec2", [ From 1528f0e2fc8350b76c7a9aa42e67503cfa7f189a Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 16:55:03 +0100 Subject: [PATCH 04/13] replace x.mul_inplace(x) with x.square() --- tenseal/tensors/ckksvector.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tenseal/tensors/ckksvector.cpp b/tenseal/tensors/ckksvector.cpp index a8a53dea..3910fc52 100644 --- a/tenseal/tensors/ckksvector.cpp +++ b/tenseal/tensors/ckksvector.cpp @@ -510,8 +510,7 @@ CKKSVector& CKKSVector::polyval_inplace(const vector& coefficients) { x_squares.reserve(max_square + 1); x_squares.push_back(x); // x for (int i = 1; i <= max_square; i++) { - // TODO: use square - x.mul_inplace(x); + x.square_inplace(); x_squares.push_back(x); // x^(2^i) } From 9d2480e36b24b49d60df92d42aa6b9859b2105ab Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 17:13:29 +0100 Subject: [PATCH 05/13] zero power --- tenseal/tensors/ckksvector.cpp | 12 +++++++++--- tests/tensors/test_ckks_vector.py | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tenseal/tensors/ckksvector.cpp b/tenseal/tensors/ckksvector.cpp index 3910fc52..e5c4c5da 100644 --- a/tenseal/tensors/ckksvector.cpp +++ b/tenseal/tensors/ckksvector.cpp @@ -115,9 +115,15 @@ CKKSVector CKKSVector::power(int power) { } CKKSVector& CKKSVector::power_inplace(int power) { - if (power <= 0) { - throw invalid_argument( - "can't compute CKKSVector to a null or a negative power"); + if (power < 0) { + throw invalid_argument("can't compute CKKSVector to a negative power"); + } + + // if the power is zero, return a new encrypted vector of ones + if (power == 0) { + vector ones(this->size(), 1); + *this = CKKSVector(this->context, ones, this->init_scale); + return *this; } if (power == 1) { diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index 31197ce8..16e1dd8f 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -48,6 +48,7 @@ def test_negate_inplace(context, plain_vec): [ ([], 2), ([0], 3), + ([0, 1, -1, 2, -2], 0), ([1, -1, 2, -2], 1), ([1, -1, 2, -2], 2), ([1, -1, 2, -2], 3), @@ -70,6 +71,7 @@ def test_power(context, plain_vec, power): [ ([], 2), ([0], 3), + ([0, 1, -1, 2, -2], 0), ([1, -1, 2, -2], 1), ([1, -1, 2, -2], 2), ([1, -1, 2, -2], 3), From f01137c08635c65c4ed4edc88c93d3dc7f5d4360 Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 18:20:53 +0100 Subject: [PATCH 06/13] requested changes --- tenseal/tensors/ckksvector.cpp | 11 +++-------- tenseal/tensors/ckksvector.h | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tenseal/tensors/ckksvector.cpp b/tenseal/tensors/ckksvector.cpp index e5c4c5da..5ed189df 100644 --- a/tenseal/tensors/ckksvector.cpp +++ b/tenseal/tensors/ckksvector.cpp @@ -107,18 +107,14 @@ CKKSVector& CKKSVector::square_inplace() { return *this; } -CKKSVector CKKSVector::power(int power) { +CKKSVector CKKSVector::power(unsigned int power) { CKKSVector new_vector = *this; new_vector.power_inplace(power); return new_vector; } -CKKSVector& CKKSVector::power_inplace(int power) { - if (power < 0) { - throw invalid_argument("can't compute CKKSVector to a negative power"); - } - +CKKSVector& CKKSVector::power_inplace(unsigned int power) { // if the power is zero, return a new encrypted vector of ones if (power == 0) { vector ones(this->size(), 1); @@ -138,8 +134,7 @@ CKKSVector& CKKSVector::power_inplace(int power) { int closest_power_of_2 = 1 << static_cast(floor(log2(power))); power -= closest_power_of_2; if (power == 0) { - this->power_inplace(closest_power_of_2 / 2) - .mul_inplace(this->power(closest_power_of_2 / 2)); + this->power_inplace(closest_power_of_2 / 2).square_inplace(); } else { this->power_inplace(power).mul_inplace(this->power(closest_power_of_2)); } diff --git a/tenseal/tensors/ckksvector.h b/tenseal/tensors/ckksvector.h index ed4d793a..a83965cb 100644 --- a/tenseal/tensors/ckksvector.h +++ b/tenseal/tensors/ckksvector.h @@ -66,8 +66,8 @@ class CKKSVector { /* Compute the power of the CKKSVector with minimal multiplication depth. */ - CKKSVector power(int power); - CKKSVector& power_inplace(int power); + CKKSVector power(unsigned int power); + CKKSVector& power_inplace(unsigned int power); /* Encrypted evaluation function operates on two encrypted vectors and From 3314279f6c535e7baa8c9d5adfad832769fcf52e Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 18:43:26 +0100 Subject: [PATCH 07/13] add more test-case with power of 4 --- tests/tensors/test_ckks_vector.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index 16e1dd8f..114aa549 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -75,9 +75,11 @@ def test_power(context, plain_vec, power): ([1, -1, 2, -2], 1), ([1, -1, 2, -2], 2), ([1, -1, 2, -2], 3), + ([1, -2, 3, -4], 4), ([1, -2, 3, -4], 1), ([1, -2, 3, -4], 2), ([1, -2, 3, -4], 3), + ([1, -2, 3, -4], 4), ], ) def test_power_inplace(context, plain_vec, power): From 27954c92bfc7eaba000961e1de4475f51aef00a2 Mon Sep 17 00:00:00 2001 From: philomath213 Date: Mon, 13 Jul 2020 22:23:48 +0100 Subject: [PATCH 08/13] remove _inplace function from python api --- tenseal/binding.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tenseal/binding.cpp b/tenseal/binding.cpp index 8b673b11..3c8cb969 100644 --- a/tenseal/binding.cpp +++ b/tenseal/binding.cpp @@ -86,13 +86,10 @@ PYBIND11_MODULE(_tenseal_cpp, m) { .def("save_size", &CKKSVector::save_size) .def("neg", &CKKSVector::negate) .def("neg_", &CKKSVector::negate_inplace) - .def("neg_inplace", &CKKSVector::negate_inplace) .def("square", &CKKSVector::square) .def("square_", &CKKSVector::square_inplace) - .def("square_inplace", &CKKSVector::square_inplace) .def("pow", &CKKSVector::power) .def("pow_", &CKKSVector::power_inplace) - .def("pow_inplace", &CKKSVector::power_inplace) .def("add", &CKKSVector::add) .def("add_", &CKKSVector::add_inplace) .def("add_plain", py::overload_cast(&CKKSVector::add_plain)) From 0db9caaf9133b2e80e2c82dc5502a1166ca0b4c1 Mon Sep 17 00:00:00 2001 From: philomath213 Date: Tue, 14 Jul 2020 10:50:09 +0100 Subject: [PATCH 09/13] add more test-case with power of 4 --- tests/tensors/test_ckks_vector.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index 114aa549..0f4c6165 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -52,9 +52,11 @@ def test_negate_inplace(context, plain_vec): ([1, -1, 2, -2], 1), ([1, -1, 2, -2], 2), ([1, -1, 2, -2], 3), + ([1, -2, 3, -4], 4), ([1, -2, 3, -4], 1), ([1, -2, 3, -4], 2), ([1, -2, 3, -4], 3), + ([1, -2, 3, -4], 4), ], ) def test_power(context, plain_vec, power): From 7865f0e6ee8228e3068e353150925e8b58deec62 Mon Sep 17 00:00:00 2001 From: Bilal Retiat Date: Tue, 14 Jul 2020 11:15:42 +0100 Subject: [PATCH 10/13] fix power_inplace Co-authored-by: Ayoub Benaissa --- tenseal/tensors/ckksvector.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tenseal/tensors/ckksvector.cpp b/tenseal/tensors/ckksvector.cpp index 5ed189df..fb12a3a6 100644 --- a/tenseal/tensors/ckksvector.cpp +++ b/tenseal/tensors/ckksvector.cpp @@ -136,7 +136,8 @@ CKKSVector& CKKSVector::power_inplace(unsigned int power) { if (power == 0) { this->power_inplace(closest_power_of_2 / 2).square_inplace(); } else { - this->power_inplace(power).mul_inplace(this->power(closest_power_of_2)); + CKKSVector closest_pow2_vector = this->power(closest_power_of_2); + this->power_inplace(power).mul_inplace(closest_pow2_vector); } return *this; } From 6160b6adc5216219b14b9c6062448d19df90047c Mon Sep 17 00:00:00 2001 From: philomath213 Date: Tue, 14 Jul 2020 11:24:49 +0100 Subject: [PATCH 11/13] more tests to cover all function branches --- tests/tensors/test_ckks_vector.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index 0f4c6165..b2be7590 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -57,9 +57,13 @@ def test_negate_inplace(context, plain_vec): ([1, -2, 3, -4], 2), ([1, -2, 3, -4], 3), ([1, -2, 3, -4], 4), + ([1, -2, 3, -4], 5), + ([1, -2, 3, -4], 6), ], ) def test_power(context, plain_vec, power): + context = ts.context(ts.SCHEME_TYPE.CKKS, 16384, coeff_mod_bit_sizes=[60, 40, 40, 40, 40, 60]) + context.global_scale = pow(2, 40) ckks_vec = ts.ckks_vector(context, plain_vec) expected = [np.power(v, power) for v in plain_vec] new_vec = ckks_vec ** power @@ -82,9 +86,13 @@ def test_power(context, plain_vec, power): ([1, -2, 3, -4], 2), ([1, -2, 3, -4], 3), ([1, -2, 3, -4], 4), + ([1, -2, 3, -4], 5), + ([1, -2, 3, -4], 6), ], ) def test_power_inplace(context, plain_vec, power): + context = ts.context(ts.SCHEME_TYPE.CKKS, 16384, coeff_mod_bit_sizes=[60, 40, 40, 40, 40, 60]) + context.global_scale = pow(2, 40) ckks_vec = ts.ckks_vector(context, plain_vec) expected = [np.power(v, power) for v in plain_vec] ckks_vec **= power From 529b647cc5f03a2264330b5c066977c65e74f026 Mon Sep 17 00:00:00 2001 From: philomath213 Date: Wed, 15 Jul 2020 19:35:12 +0100 Subject: [PATCH 12/13] more tests --- tests/tensors/test_ckks_vector.py | 246 ++++++++++++++++-------------- 1 file changed, 129 insertions(+), 117 deletions(-) diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index b2be7590..2bfecf94 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -21,83 +21,95 @@ def context(): return context +# default precision is 1, otherwise it can be specified in the test-case +@pytest.fixture(scope="function") +def precision(): + return 1 + + @pytest.mark.parametrize( "plain_vec", [[], [0], [-1], [1], [21, 81, 90], [-73, -81, -90], [-11, 82, -43, 52]] ) -def test_negate(context, plain_vec): +def test_negate(context, plain_vec, precision): ckks_vec = ts.ckks_vector(context, plain_vec) expected = [-v for v in plain_vec] result = -ckks_vec decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" @pytest.mark.parametrize( "plain_vec", [[], [0], [-1], [1], [21, 81, 90], [-73, -81, -90], [-11, 82, -43, 52]] ) -def test_negate_inplace(context, plain_vec): +def test_negate_inplace(context, plain_vec, precision): ckks_vec = ts.ckks_vector(context, plain_vec) expected = [-v for v in plain_vec] ckks_vec.neg_() decrypted_result = ckks_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" @pytest.mark.parametrize( - "plain_vec, power", + "plain_vec, power, precision", [ - ([], 2), - ([0], 3), - ([0, 1, -1, 2, -2], 0), - ([1, -1, 2, -2], 1), - ([1, -1, 2, -2], 2), - ([1, -1, 2, -2], 3), - ([1, -2, 3, -4], 4), - ([1, -2, 3, -4], 1), - ([1, -2, 3, -4], 2), - ([1, -2, 3, -4], 3), - ([1, -2, 3, -4], 4), - ([1, -2, 3, -4], 5), - ([1, -2, 3, -4], 6), + ([], 2, 1), + ([0], 3, 1), + ([0, 1, -1, 2, -2], 0, 1), + ([1, -1, 2, -2], 1, 1), + ([1, -1, 2, -2], 2, 1), + ([1, -1, 2, -2], 3, 1), + ([1, -2, 3, -4], 4, 1), + ([1, -2, 3, -4], 1, 1), + ([1, -2, 3, -4], 2, 1), + ([1, -2, 3, -4], 3, 1), + ([1, -2, 3, -4], 4, 1), + ([1, -2, 3, -4], 5, 1), + ([1, -2, 3, -4], 6, 1), + ([1, -2, 3, -4], 7, 0), + ([1, -2, 3, -4], 8, -1), ], ) -def test_power(context, plain_vec, power): +def test_power(context, plain_vec, power, precision): context = ts.context(ts.SCHEME_TYPE.CKKS, 16384, coeff_mod_bit_sizes=[60, 40, 40, 40, 40, 60]) context.global_scale = pow(2, 40) ckks_vec = ts.ckks_vector(context, plain_vec) expected = [np.power(v, power) for v in plain_vec] new_vec = ckks_vec ** power decrypted_result = new_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" - assert _almost_equal(ckks_vec.decrypt(), plain_vec, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" + assert _almost_equal( + ckks_vec.decrypt(), plain_vec, precision + ), "Something went wrong in memory." @pytest.mark.parametrize( - "plain_vec, power", + "plain_vec, power, precision", [ - ([], 2), - ([0], 3), - ([0, 1, -1, 2, -2], 0), - ([1, -1, 2, -2], 1), - ([1, -1, 2, -2], 2), - ([1, -1, 2, -2], 3), - ([1, -2, 3, -4], 4), - ([1, -2, 3, -4], 1), - ([1, -2, 3, -4], 2), - ([1, -2, 3, -4], 3), - ([1, -2, 3, -4], 4), - ([1, -2, 3, -4], 5), - ([1, -2, 3, -4], 6), + ([], 2, 1), + ([0], 3, 1), + ([0, 1, -1, 2, -2], 0, 1), + ([1, -1, 2, -2], 1, 1), + ([1, -1, 2, -2], 2, 1), + ([1, -1, 2, -2], 3, 1), + ([1, -2, 3, -4], 4, 1), + ([1, -2, 3, -4], 1, 1), + ([1, -2, 3, -4], 2, 1), + ([1, -2, 3, -4], 3, 1), + ([1, -2, 3, -4], 4, 1), + ([1, -2, 3, -4], 5, 1), + ([1, -2, 3, -4], 6, 1), + ([1, -2, 3, -4], 7, 0), + ([1, -2, 3, -4], 8, -1), ], ) -def test_power_inplace(context, plain_vec, power): +def test_power_inplace(context, plain_vec, power, precision): context = ts.context(ts.SCHEME_TYPE.CKKS, 16384, coeff_mod_bit_sizes=[60, 40, 40, 40, 40, 60]) context.global_scale = pow(2, 40) ckks_vec = ts.ckks_vector(context, plain_vec) expected = [np.power(v, power) for v in plain_vec] ckks_vec **= power decrypted_result = ckks_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" @pytest.mark.parametrize( @@ -115,13 +127,13 @@ def test_power_inplace(context, plain_vec, power): [1, -4, 3, 5], ], ) -def test_square(context, plain_vec): +def test_square(context, plain_vec, precision): ckks_vec = ts.ckks_vector(context, plain_vec) expected = [np.power(v, 2) for v in plain_vec] new_vec = ckks_vec.square() decrypted_result = new_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" - assert _almost_equal(ckks_vec.decrypt(), plain_vec, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" + assert _almost_equal(ckks_vec.decrypt(), plain_vec, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -139,12 +151,12 @@ def test_square(context, plain_vec): [1, -4, 3, 5], ], ) -def test_square_inplace(context, plain_vec): +def test_square_inplace(context, plain_vec, precision): ckks_vec = ts.ckks_vector(context, plain_vec) expected = [np.power(v, 2) for v in plain_vec] ckks_vec.square_() decrypted_result = ckks_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Decryption of vector is incorrect" + assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" @pytest.mark.parametrize( @@ -166,7 +178,7 @@ def test_square_inplace(context, plain_vec): ([1, 0, -2, 0, -8, 4, 73], [81,]), ], ) -def test_add(context, vec1, vec2): +def test_add(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -181,9 +193,9 @@ def test_add(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Addition of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Addition of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -205,7 +217,7 @@ def test_add(context, vec1, vec2): ([1, 0, -2, 0, -8, 4, 73], [81,]), ], ) -def test_add_inplace(context, vec1, vec2): +def test_add_inplace(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -220,8 +232,8 @@ def test_add_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Addition of vectors is incorrect." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Addition of vectors is incorrect." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -242,7 +254,7 @@ def test_add_inplace(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_add_plain(context, vec1, vec2): +def test_add_plain(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 result = first_vec + second_vec @@ -253,8 +265,8 @@ def test_add_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Addition of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Addition of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -275,7 +287,7 @@ def test_add_plain(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_radd_plain(context, vec1, vec2): +def test_radd_plain(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) result = vec2 + first_vec if isinstance(vec2, list): @@ -285,8 +297,8 @@ def test_radd_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Addition of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Addition of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -307,7 +319,7 @@ def test_radd_plain(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_add_plain_inplace(context, vec1, vec2): +def test_add_plain_inplace(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 first_vec += second_vec @@ -318,7 +330,7 @@ def test_add_plain_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Addition of vectors is incorrect." + assert _almost_equal(decrypted_result, expected, precision), "Addition of vectors is incorrect." @pytest.mark.parametrize( @@ -340,7 +352,7 @@ def test_add_plain_inplace(context, vec1, vec2): ([1, 0, -2, 0, -8, 4, 73], [81,]), ], ) -def test_sub(context, vec1, vec2): +def test_sub(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -355,9 +367,9 @@ def test_sub(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Substraction of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -379,7 +391,7 @@ def test_sub(context, vec1, vec2): ([1, 0, -2, 0, -8, 4, 73], [81,]), ], ) -def test_sub_inplace(context, vec1, vec2): +def test_sub_inplace(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -394,8 +406,8 @@ def test_sub_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Substraction of vectors is incorrect." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -416,7 +428,7 @@ def test_sub_inplace(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_sub_plain(context, vec1, vec2): +def test_sub_plain(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 result = first_vec - second_vec @@ -427,8 +439,8 @@ def test_sub_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Substraction of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -449,7 +461,7 @@ def test_sub_plain(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_rsub_plain(context, vec1, vec2): +def test_rsub_plain(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) result = vec2 - first_vec if isinstance(vec2, list): @@ -459,8 +471,8 @@ def test_rsub_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Substraction of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -481,7 +493,7 @@ def test_rsub_plain(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_sub_plain_inplace(context, vec1, vec2): +def test_sub_plain_inplace(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 first_vec -= second_vec @@ -492,7 +504,7 @@ def test_sub_plain_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Substraction of vectors is incorrect." + assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." @pytest.mark.parametrize( @@ -514,7 +526,7 @@ def test_sub_plain_inplace(context, vec1, vec2): ([1, 0, -2, 0, -8, 4, 73], [81,]), ], ) -def test_mul(context, vec1, vec2): +def test_mul(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -529,9 +541,9 @@ def test_mul(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Multiplication of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -553,7 +565,7 @@ def test_mul(context, vec1, vec2): ([1, 0, -2, 0, -8, 4, 73], [81,]), ], ) -def test_mul_inplace(context, vec1, vec2): +def test_mul_inplace(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -568,8 +580,8 @@ def test_mul_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Multiplication of vectors is incorrect." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -590,7 +602,7 @@ def test_mul_inplace(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_mul_plain(context, vec1, vec2): +def test_mul_plain(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 result = first_vec * second_vec @@ -601,8 +613,8 @@ def test_mul_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Multiplication of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -623,7 +635,7 @@ def test_mul_plain(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_rmul_plain(context, vec1, vec2): +def test_rmul_plain(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) result = vec2 * first_vec if isinstance(vec2, list): @@ -633,8 +645,8 @@ def test_rmul_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Multiplication of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -655,7 +667,7 @@ def test_rmul_plain(context, vec1, vec2): ([1, 2, 3, 4], -2), ], ) -def test_mul_plain_inplace(context, vec1, vec2): +def test_mul_plain_inplace(context, vec1, vec2, precision): first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 first_vec *= second_vec @@ -666,7 +678,7 @@ def test_mul_plain_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Multiplication of vectors is incorrect." + assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." @pytest.mark.parametrize( @@ -688,7 +700,7 @@ def test_mul_plain_inplace(context, vec1, vec2): ([1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1]), ], ) -def test_dot_product(context, vec1, vec2): +def test_dot_product(context, vec1, vec2, precision): context.generate_galois_keys() first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -697,9 +709,9 @@ def test_dot_product(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Dot product of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -721,7 +733,7 @@ def test_dot_product(context, vec1, vec2): ([1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1]), ], ) -def test_dot_product_inplace(context, vec1, vec2): +def test_dot_product_inplace(context, vec1, vec2, precision): context.generate_galois_keys() first_vec = ts.ckks_vector(context, vec1) second_vec = ts.ckks_vector(context, vec2) @@ -730,8 +742,8 @@ def test_dot_product_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Dot product of vectors is incorrect." - assert _almost_equal(second_vec.decrypt(), vec2, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -753,7 +765,7 @@ def test_dot_product_inplace(context, vec1, vec2): ([1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1]), ], ) -def test_dot_product_plain(context, vec1, vec2): +def test_dot_product_plain(context, vec1, vec2, precision): context.generate_galois_keys() first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 @@ -762,8 +774,8 @@ def test_dot_product_plain(context, vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Dot product of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -785,7 +797,7 @@ def test_dot_product_plain(context, vec1, vec2): ([1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1]), ], ) -def test_dot_product_plain_inplace(context, vec1, vec2): +def test_dot_product_plain_inplace(context, vec1, vec2, precision): context.generate_galois_keys() first_vec = ts.ckks_vector(context, vec1) second_vec = vec2 @@ -794,7 +806,7 @@ def test_dot_product_plain_inplace(context, vec1, vec2): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Dot product of vectors is incorrect." + assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." @pytest.mark.parametrize( @@ -813,7 +825,7 @@ def test_dot_product_plain_inplace(context, vec1, vec2): ([1, 2, 3, 4, 5, 6, 7, 8]), ], ) -def test_sum(context, vec1): +def test_sum(context, vec1, precision): context.generate_galois_keys() first_vec = ts.ckks_vector(context, vec1) result = first_vec.sum() @@ -821,8 +833,8 @@ def test_sum(context, vec1): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Sum of vector is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Sum of vector is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -841,7 +853,7 @@ def test_sum(context, vec1): ([1, 2, 3, 4, 5, 6, 7, 8]), ], ) -def test_sum_inplace(context, vec1): +def test_sum_inplace(context, vec1, precision): context.generate_galois_keys() first_vec = ts.ckks_vector(context, vec1) result = first_vec.sum() @@ -849,7 +861,7 @@ def test_sum_inplace(context, vec1): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Sum of vector is incorrect." + assert _almost_equal(decrypted_result, expected, precision), "Sum of vector is incorrect." @pytest.mark.parametrize( @@ -866,7 +878,7 @@ def test_sum_inplace(context, vec1): ([1, 2], [-73, -10]), ], ) -def test_mul_without_global_scale(vec1, vec2): +def test_mul_without_global_scale(vec1, vec2, precision): context = ts.context(ts.SCHEME_TYPE.CKKS, 8192, coeff_mod_bit_sizes=[60, 40, 40, 60]) scale = 2 ** 40 @@ -877,8 +889,8 @@ def test_mul_without_global_scale(vec1, vec2): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Multiplication of vectors is incorrect." - assert _almost_equal(first_vec.decrypt(), vec1, 1), "Something went wrong in memory." + assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -892,13 +904,13 @@ def test_mul_without_global_scale(vec1, vec2): ), ], ) -def test_vec_plain_matrix_mul(context, vec, matrix): +def test_vec_plain_matrix_mul(context, vec, matrix, precision): context.generate_galois_keys() ct = ts.ckks_vector(context, vec) result = ct.mm(matrix) expected = (np.array(vec) @ np.array(matrix)).tolist() - assert _almost_equal(result.decrypt(), expected, 1), "Matrix multiplciation is incorrect." - assert _almost_equal(ct.decrypt(), vec, 1), "Something went wrong in memory." + assert _almost_equal(result.decrypt(), expected, precision), "Matrix multiplciation is incorrect." + assert _almost_equal(ct.decrypt(), vec, precision), "Something went wrong in memory." @pytest.mark.parametrize( @@ -912,12 +924,12 @@ def test_vec_plain_matrix_mul(context, vec, matrix): ), ], ) -def test_vec_plain_matrix_mul_inplace(context, vec, matrix): +def test_vec_plain_matrix_mul_inplace(context, vec, matrix, precision): context.generate_galois_keys() ct = ts.ckks_vector(context, vec) ct.mm_(matrix) expected = (np.array(vec) @ np.array(matrix)).tolist() - assert _almost_equal(ct.decrypt(), expected, 1), "Matrix multiplciation is incorrect." + assert _almost_equal(ct.decrypt(), expected, precision), "Matrix multiplciation is incorrect." @pytest.mark.parametrize( @@ -941,12 +953,12 @@ def test_vec_plain_matrix_mul_inplace(context, vec, matrix): ), ], ) -def test_vec_plain_matrix_mul_depth2(context, vec, matrix1, matrix2): +def test_vec_plain_matrix_mul_depth2(context, vec, matrix1, matrix2, precision): context.generate_galois_keys() ct = ts.ckks_vector(context, vec) result = ct @ matrix1 @ matrix2 expected = (np.array(vec) @ np.array(matrix1) @ np.array(matrix2)).tolist() - assert _almost_equal(result.decrypt(), expected, 1), "Matrix multiplication is incorrect." + assert _almost_equal(result.decrypt(), expected, precision), "Matrix multiplication is incorrect." @pytest.mark.parametrize( @@ -968,13 +980,13 @@ def test_vec_plain_matrix_mul_depth2(context, vec, matrix1, matrix2): ([0, -1, -2, -3, -4], [-3, -2, -4, -5, 1]), ], ) -def test_polynomial(context, data, polynom): +def test_polynomial(context, data, polynom, precision): ct = ts.ckks_vector(context, data) expected = [np.polyval(polynom[::-1], x) for x in data] result = ct.polyval(polynom) decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, 1), "Polynomial evaluation is incorrect." + assert _almost_equal(decrypted_result, expected, precision), "Polynomial evaluation is incorrect." @pytest.mark.parametrize( @@ -1005,7 +1017,7 @@ def test_polynomial(context, data, polynom): ([0, -1, 1, -2, 2], [0] * 16 + [2]), ], ) -def test_high_degree_polynomial(data, polynom): +def test_high_degree_polynomial(data, polynom, precision): # special context for higher depth context = ts.context( ts.SCHEME_TYPE.CKKS, 16384, coeff_mod_bit_sizes=[60, 40, 40, 40, 40, 40, 60] From 846a199b2cd4c1ac85c28968d8c8a0cbd89de8cf Mon Sep 17 00:00:00 2001 From: philomath213 Date: Wed, 15 Jul 2020 19:37:08 +0100 Subject: [PATCH 13/13] python linting --- tests/tensors/test_ckks_vector.py | 76 +++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/tests/tensors/test_ckks_vector.py b/tests/tensors/test_ckks_vector.py index 2bfecf94..f935a959 100644 --- a/tests/tensors/test_ckks_vector.py +++ b/tests/tensors/test_ckks_vector.py @@ -133,7 +133,9 @@ def test_square(context, plain_vec, precision): new_vec = ckks_vec.square() decrypted_result = new_vec.decrypt() assert _almost_equal(decrypted_result, expected, precision), "Decryption of vector is incorrect" - assert _almost_equal(ckks_vec.decrypt(), plain_vec, precision), "Something went wrong in memory." + assert _almost_equal( + ckks_vec.decrypt(), plain_vec, precision + ), "Something went wrong in memory." @pytest.mark.parametrize( @@ -367,7 +369,9 @@ def test_sub(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Substraction of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @@ -406,7 +410,9 @@ def test_sub_inplace(context, vec1, vec2, precision): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Substraction of vectors is incorrect." assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @@ -439,7 +445,9 @@ def test_sub_plain(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Substraction of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @@ -471,7 +479,9 @@ def test_rsub_plain(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Substraction of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @@ -504,7 +514,9 @@ def test_sub_plain_inplace(context, vec1, vec2, precision): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Substraction of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Substraction of vectors is incorrect." @pytest.mark.parametrize( @@ -541,7 +553,9 @@ def test_mul(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Multiplication of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @@ -580,7 +594,9 @@ def test_mul_inplace(context, vec1, vec2, precision): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Multiplication of vectors is incorrect." assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @@ -613,7 +629,9 @@ def test_mul_plain(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Multiplication of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @@ -645,7 +663,9 @@ def test_rmul_plain(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Multiplication of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @@ -678,7 +698,9 @@ def test_mul_plain_inplace(context, vec1, vec2, precision): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Multiplication of vectors is incorrect." @pytest.mark.parametrize( @@ -709,7 +731,9 @@ def test_dot_product(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Dot product of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @@ -742,7 +766,9 @@ def test_dot_product_inplace(context, vec1, vec2, precision): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Dot product of vectors is incorrect." assert _almost_equal(second_vec.decrypt(), vec2, precision), "Something went wrong in memory." @@ -774,7 +800,9 @@ def test_dot_product_plain(context, vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Dot product of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @@ -806,7 +834,9 @@ def test_dot_product_plain_inplace(context, vec1, vec2, precision): # Decryption decrypted_result = first_vec.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Dot product of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Dot product of vectors is incorrect." @pytest.mark.parametrize( @@ -889,7 +919,9 @@ def test_mul_without_global_scale(vec1, vec2, precision): # Decryption decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Multiplication of vectors is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Multiplication of vectors is incorrect." assert _almost_equal(first_vec.decrypt(), vec1, precision), "Something went wrong in memory." @@ -909,7 +941,9 @@ def test_vec_plain_matrix_mul(context, vec, matrix, precision): ct = ts.ckks_vector(context, vec) result = ct.mm(matrix) expected = (np.array(vec) @ np.array(matrix)).tolist() - assert _almost_equal(result.decrypt(), expected, precision), "Matrix multiplciation is incorrect." + assert _almost_equal( + result.decrypt(), expected, precision + ), "Matrix multiplciation is incorrect." assert _almost_equal(ct.decrypt(), vec, precision), "Something went wrong in memory." @@ -958,7 +992,9 @@ def test_vec_plain_matrix_mul_depth2(context, vec, matrix1, matrix2, precision): ct = ts.ckks_vector(context, vec) result = ct @ matrix1 @ matrix2 expected = (np.array(vec) @ np.array(matrix1) @ np.array(matrix2)).tolist() - assert _almost_equal(result.decrypt(), expected, precision), "Matrix multiplication is incorrect." + assert _almost_equal( + result.decrypt(), expected, precision + ), "Matrix multiplication is incorrect." @pytest.mark.parametrize( @@ -986,7 +1022,9 @@ def test_polynomial(context, data, polynom, precision): result = ct.polyval(polynom) decrypted_result = result.decrypt() - assert _almost_equal(decrypted_result, expected, precision), "Polynomial evaluation is incorrect." + assert _almost_equal( + decrypted_result, expected, precision + ), "Polynomial evaluation is incorrect." @pytest.mark.parametrize(