From 118eb5989cb1fb9ca0400b9de7d7cd5fe02d4241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Cabrero-Holgueras?= Date: Wed, 25 Sep 2024 17:32:56 +0000 Subject: [PATCH] feat: working matrix inverse (not integrated) --- examples/linear_regression/nada-project.toml | 3 + .../linear_regression/src/matrix_inverse.py | 13 +--- .../linear_regression/tests/matrix_inverse.py | 24 +++++++ .../tests/matrix_inverse.yaml | 62 ------------------- poetry.lock | 15 ++++- pyproject.toml | 1 + tests/test_all.py | 2 +- 7 files changed, 46 insertions(+), 74 deletions(-) create mode 100644 examples/linear_regression/tests/matrix_inverse.py delete mode 100644 examples/linear_regression/tests/matrix_inverse.yaml diff --git a/examples/linear_regression/nada-project.toml b/examples/linear_regression/nada-project.toml index 1d8d8af..afd7966 100644 --- a/examples/linear_regression/nada-project.toml +++ b/examples/linear_regression/nada-project.toml @@ -2,6 +2,9 @@ name = "linear-regression" version = "0.1.0" authors = [""] +[test_framework.nada-test] +command = "nada-test ./tests" + [[programs]] path = "src/linear_regression.py" prime_size = 64 diff --git a/examples/linear_regression/src/matrix_inverse.py b/examples/linear_regression/src/matrix_inverse.py index fa63b24..8e50d01 100644 --- a/examples/linear_regression/src/matrix_inverse.py +++ b/examples/linear_regression/src/matrix_inverse.py @@ -40,7 +40,7 @@ def public_modular_inverse( power = value ** Integer( mod - 1 ) # value ** modulo = value ** (modulo // 2) * modulo ** (modulo // 2) - power = power * power * value if rem else Integer(1) # value ** mo + power = power * power * (value if rem else Integer(1)) # value ** mo return power @@ -133,14 +133,7 @@ def gauss_jordan_zn(mat: na.NadaArray, modulo: int): # Forward elimination for i in range(rows): - # # Find pivot row - # pivot_row = i - # while pivot_row < rows and (mat[pivot_row][i] == Integer(0)) is Boolean(True): - # pivot_row += 1 - - # # Swap pivot row with current row - # mat[[i, pivot_row]] = mat[[pivot_row, i]] - + # Scale pivot row to have leading 1 diagonal_element = mat[i][i] pivot_inv = public_modular_inverse(diagonal_element, modulo) @@ -186,7 +179,7 @@ def matrix_inverse(matrix: np.ndarray, modulo: int): def nada_main(): parties = na.parties(3) - A = na.array([4, 4], parties[0], "A", nada_type=SecretInteger) + A = na.array([10, 10], parties[0], "A", nada_type=SecretInteger) A_inv = matrix_inverse(A, PRIME) result = A @ A_inv diff --git a/examples/linear_regression/tests/matrix_inverse.py b/examples/linear_regression/tests/matrix_inverse.py new file mode 100644 index 0000000..9ab7832 --- /dev/null +++ b/examples/linear_regression/tests/matrix_inverse.py @@ -0,0 +1,24 @@ +from nada_test import nada_test, NadaTest +import sys +import nada_numpy.client as na +import numpy as np + +# Functional style test +@nada_test(program="matrix_inverse") +def my_test(): + n = 10 + m = np.random.rand(n, n) + mx = np.sum(np.abs(m), axis=1) + np.fill_diagonal(m, mx) + A = na.array(m * (1 << 16), "A", nada_type=int) + print("INPUTS:", A, file=sys.stderr) + outputs = yield A + print(outputs, file=sys.stderr) + for output, value in outputs.items(): + output = output.split("_") + if output[-1] == output[-2]: + assert value == 1, f"Expected 1 {output}, got {value}" + else: + assert value == 0, f"Expected 0 {output}, got {value}" + + #assert outputs["my_output"] == a + b \ No newline at end of file diff --git a/examples/linear_regression/tests/matrix_inverse.yaml b/examples/linear_regression/tests/matrix_inverse.yaml deleted file mode 100644 index 1d5968b..0000000 --- a/examples/linear_regression/tests/matrix_inverse.yaml +++ /dev/null @@ -1,62 +0,0 @@ -program: matrix_inverse -inputs: - A_0_0: -256 - A_0_1: 256 - A_0_2: -251 - A_0_3: 158 - A_0_4: 141 - A_0_5: -212 - A_1_0: 121 - A_1_1: -7 - A_1_2: -6 - A_1_3: -29 - A_1_4: 51 - A_1_5: 163 - A_2_0: 227 - A_2_1: 19 - A_2_2: -150 - A_2_3: 43 - A_2_4: -136 - A_2_5: 157 - A_3_0: 101 - A_3_1: 190 - A_3_2: -178 - A_3_3: 59 - A_3_4: 204 - A_3_5: -194 - A_4_0: -252 - A_4_1: -45 - A_4_2: -9 - A_4_3: 157 - A_4_4: 92 - A_4_5: -149 - A_5_0: -208 - A_5_1: 29 - A_5_2: 60 - A_5_3: 2 - A_5_4: -132 - A_5_5: -54 - b_0: -255 - b_1: -108 - b_2: -183 - b_3: 73 - b_4: -92 - b_5: -65 - B: 456 -expected_outputs: - my_output_0_0: 1 - my_output_0_1: 0 - my_output_0_2: 0 - my_output_0_3: 0 - my_output_1_0: 0 - my_output_1_1: 1 - my_output_1_2: 0 - my_output_1_3: 0 - my_output_2_0: 0 - my_output_2_1: 0 - my_output_2_2: 1 - my_output_2_3: 0 - my_output_3_0: 0 - my_output_3_1: 0 - my_output_3_2: 0 - my_output_3_3: 1 diff --git a/poetry.lock b/poetry.lock index 84c0a53..eab3b84 100644 --- a/poetry.lock +++ b/poetry.lock @@ -563,6 +563,19 @@ docs = ["sphinx (>=5,<9)", "sphinx-rtd-theme (>=1.0,<2.1)", "toml (>=0.10.2,<0.1 lint = ["pylint (>=2.17,<3.3)"] test = ["pytest (>=7.4,<9.0)", "pytest-cov (>=4,<6)"] +[[package]] +name = "nada-test" +version = "0.6.0" +description = "Nillion Nada Test Framework" +optional = false +python-versions = ">=3.10" +files = [ + {file = "nada_test-0.6.0-py3-none-any.whl", hash = "sha256:985bf53411562478684b5869ea0c7c5dfe8e936bf776477338430a20d8cde062"}, +] + +[package.extras] +lint = ["pylint (>=2.17,<3.3)"] + [[package]] name = "nillion-python-helpers" version = "0.3.1" @@ -1224,4 +1237,4 @@ linter = ["black", "isort"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "988468fb1d039ce86e25f619f2c62893e0baf09176b6341402dc500184baa865" +content-hash = "2a8caf5f826dcc51363c5ee9f6c5e82452dfe780d95b2e4e487e3ef61eac32ad" diff --git a/pyproject.toml b/pyproject.toml index 9a4d12a..efae330 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ nillion-python-helpers = "^0.3.0" black = {version="24.8.0", optional=true} isort = {version="^5.13.2", optional=true} scikit-learn = {version="^1.5.1", optional=true} +nada-test = "^0.6.0" [tool.poetry.group.dev.dependencies] pytest = "^8.2.0" diff --git a/tests/test_all.py b/tests/test_all.py index db9639d..205de46 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -69,7 +69,7 @@ ("linear_regression", "determinant", "determinant_2"), ("linear_regression", "determinant", "determinant_3"), ("linear_regression", "gauss_jordan", "gauss_jordan"), - ("linear_regression", "matrix_inverse", "matrix_inverse"), + ("linear_regression", "matrix_inverse", "nada-test::matrix_inverse.py:my_test"), ("linear_regression", "linear_regression", "linear_regression"), ("linear_regression", "linear_regression", "linear_regression_1"), ("linear_regression", "linear_regression", "linear_regression_2"),