Skip to content

Commit

Permalink
feat: Added integration of rationals with NadaArray and bump version …
Browse files Browse the repository at this point in the history
…number (#16)

* feat: Added integration of rationals with NadaArray

* chore: bump version number
  • Loading branch information
jcabrero authored Jun 3, 2024
1 parent 0c5a9dc commit 161072f
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 33 deletions.
59 changes: 41 additions & 18 deletions nada_algebra/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
Integer,
UnsignedInteger,
)
from nada_algebra.types import Rational, SecretRational
from nada_algebra.types import Rational, SecretRational, RationalConfig

_NadaOperand = Union[
"NadaArray",
Expand Down Expand Up @@ -380,7 +380,12 @@ def array(
party: Party,
prefix: str,
nada_type: Union[
SecretInteger, SecretUnsignedInteger, PublicInteger, PublicUnsignedInteger
SecretInteger,
SecretUnsignedInteger,
PublicInteger,
PublicUnsignedInteger,
SecretRational,
Rational,
] = SecretInteger,
) -> "NadaArray":
"""
Expand All @@ -394,22 +399,33 @@ def array(
Returns:
NadaArray: The created NadaArray.
"""
Raises:
ValueError: Raised if the nada_type is not supported.
"""
generator = None
if nada_type in (Rational, SecretRational):
generator = lambda name, party: nada_type(name=name, party=party)
elif nada_type in (
SecretInteger,
SecretUnsignedInteger,
PublicInteger,
PublicUnsignedInteger,
):
generator = lambda name, party: nada_type(Input(name=name, party=party))
else:
raise ValueError(f"Unsupported nada_type: {nada_type}")

return NadaArray(
np.array(
NadaArray.create_list(
dims,
party,
prefix,
lambda name, party: nada_type(Input(name=name, party=party)),
)
)
np.array(NadaArray.create_list(dims, party, prefix, generator))
)

@staticmethod
def random(
dims: list,
nada_type: Union[SecretInteger, SecretUnsignedInteger] = SecretInteger,
nada_type: Union[
SecretInteger, SecretUnsignedInteger, SecretRational
] = SecretInteger,
) -> "NadaArray":
"""
Create a random NadaArray with the specified dimensions.
Expand All @@ -420,14 +436,21 @@ def random(
Returns:
NadaArray: The created random NadaArray.
Raises:
ValueError: Raised if the nada_type is not supported.
"""
return NadaArray(
np.array(
NadaArray.create_list(
dims, None, None, lambda name, party: nada_type.random()
)
generator = None
if nada_type is SecretRational:
generator = lambda name, party: SecretRational.from_parts(
SecretInteger.random(), RationalConfig.LOG_SCALE
)
)
elif nada_type in (SecretInteger, SecretUnsignedInteger):
generator = lambda name, party: nada_type.random()
else:
raise ValueError(f"Unsupported nada_type: {nada_type}")

return NadaArray(np.array(NadaArray.create_list(dims, None, None, generator)))

def __getattr__(self, name: str) -> Any:
"""Routes other attributes to the inner NumPy array.
Expand Down
4 changes: 3 additions & 1 deletion nada_algebra/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
PublicVariableUnsignedInteger,
)
import numpy as np
from nada_algebra.types import RationalConfig
from nada_algebra.types import RationalConfig, Rational, SecretRational


def parties(num: int, prefix: str = "Party") -> list:
Expand All @@ -36,6 +36,8 @@ def array(
SecretUnsignedInteger,
PublicVariableInteger,
PublicVariableUnsignedInteger,
Rational,
SecretRational,
] = SecretInteger,
) -> dict:
"""
Expand Down
34 changes: 21 additions & 13 deletions nada_algebra/funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
and manipulation of arrays and party objects.
"""

from typing import Any, Iterable
from typing import Any, Iterable, Union
from nada_dsl import (
Party,
SecretInteger,
Expand All @@ -13,8 +13,14 @@
Integer,
UnsignedInteger,
)

import numpy as np
from nada_algebra.array import NadaArray
from nada_algebra.types import Rational, SecretRational


_NadaCleartextType = Union[Integer, UnsignedInteger, Rational]
""" A Nada Cleartext Type is: `Integer`, `UnsignedInteger`, or `Rational` """


def parties(num: int, prefix: str = "Party") -> list:
Expand All @@ -31,7 +37,7 @@ def parties(num: int, prefix: str = "Party") -> list:
return [Party(name=f"{prefix}{i}") for i in range(num)]


def __from_numpy(arr: np.ndarray, nada_type: Integer | UnsignedInteger) -> list:
def __from_numpy(arr: np.ndarray, nada_type: _NadaCleartextType) -> list:
"""
Recursively convert a n-dimensional NumPy array to a nested list of NadaInteger objects.
Expand All @@ -43,11 +49,13 @@ def __from_numpy(arr: np.ndarray, nada_type: Integer | UnsignedInteger) -> list:
list: A nested list of NadaInteger objects.
"""
if len(arr.shape) == 1:
if isinstance(nada_type, Rational):
return [nada_type(elem) for elem in arr]
return [nada_type(int(elem)) for elem in arr]
return [__from_numpy(arr[i], nada_type) for i in range(arr.shape[0])]


def from_list(lst: list, nada_type: Integer | UnsignedInteger = Integer) -> NadaArray:
def from_list(lst: list, nada_type: _NadaCleartextType = Integer) -> NadaArray:
"""
Create a cleartext NadaArray from a list of integers.
Expand All @@ -63,9 +71,7 @@ def from_list(lst: list, nada_type: Integer | UnsignedInteger = Integer) -> Nada
return NadaArray(np.array(__from_numpy(lst, nada_type)))


def ones(
dims: Iterable[int], nada_type: Integer | UnsignedInteger = Integer
) -> NadaArray:
def ones(dims: Iterable[int], nada_type: _NadaCleartextType = Integer) -> NadaArray:
"""
Create a cleartext NadaArray filled with ones.
Expand All @@ -80,7 +86,7 @@ def ones(


def ones_like(
a: np.ndarray | NadaArray, nada_type: Integer | UnsignedInteger = Integer
a: np.ndarray | NadaArray, nada_type: _NadaCleartextType = Integer
) -> NadaArray:
"""
Create a cleartext NadaArray filled with one with the same shape and type as a given array.
Expand All @@ -97,9 +103,7 @@ def ones_like(
return from_list(np.ones_like(a), nada_type)


def zeros(
dims: Iterable[int], nada_type: Integer | UnsignedInteger = Integer
) -> NadaArray:
def zeros(dims: Iterable[int], nada_type: _NadaCleartextType = Integer) -> NadaArray:
"""
Create a cleartext NadaArray filled with zeros.
Expand All @@ -114,7 +118,7 @@ def zeros(


def zeros_like(
a: np.ndarray | NadaArray, nada_type: Integer | UnsignedInteger = Integer
a: np.ndarray | NadaArray, nada_type: _NadaCleartextType = Integer
) -> NadaArray:
"""
Create a cleartext NadaArray filled with zeros with the same shape and type as a given array.
Expand Down Expand Up @@ -168,7 +172,11 @@ def array(
party: Party,
prefix: str,
nada_type: (
SecretInteger | SecretUnsignedInteger | PublicInteger | PublicUnsignedInteger
SecretInteger
| SecretUnsignedInteger
| PublicInteger
| PublicUnsignedInteger
| SecretRational
) = SecretInteger,
) -> NadaArray:
"""
Expand All @@ -188,7 +196,7 @@ def array(

def random(
dims: Iterable[int],
nada_type: SecretInteger | SecretUnsignedInteger = SecretInteger,
nada_type: SecretInteger | SecretUnsignedInteger | SecretRational = SecretInteger,
) -> NadaArray:
"""
Create a random NadaArray with the specified dimensions.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "nada-algebra"
version = "0.2.0"
version = "0.2.1"
description = ""
authors = ["José Cabrero-Holgueras <jose.cabrero@nillion.com>"]
readme = "README.md"
Expand Down
4 changes: 4 additions & 0 deletions tests/nada-tests/nada-project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,8 @@ prime_size = 128

[[programs]]
path = "src/chained_rational_operations.py"
prime_size = 128

[[programs]]
path = "src/rational_array.py"
prime_size = 128
31 changes: 31 additions & 0 deletions tests/nada-tests/src/rational_array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from nada_dsl import *
import nada_algebra as na


def nada_main():
parties = na.parties(2)

a = na.array([3], parties[0], "A", nada_type=na.SecretRational)
b = na.array([3], parties[0], "B", nada_type=na.SecretRational)
c = na.ones([3], na.Rational)

out_0 = a + b
out_1 = a - b
out_2 = a * b
out_3 = a / b

out_4 = a + c
out_5 = a - c
out_6 = a * c
out_7 = a / c

return (
out_0.output(parties[1], "out_0")
+ out_1.output(parties[1], "out_1")
+ out_2.output(parties[1], "out_2")
+ out_3.output(parties[1], "out_3")
+ out_4.output(parties[1], "out_4")
+ out_5.output(parties[1], "out_5")
+ out_6.output(parties[1], "out_6")
+ out_7.output(parties[1], "out_7")
)
66 changes: 66 additions & 0 deletions tests/nada-tests/tests/rational_array.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
program: rational_array
inputs:
secrets:
A_0:
SecretInteger: "0" # 0
A_1:
SecretInteger: "65536" # 1
A_2:
SecretInteger: "131072" # 2
B_0:
SecretInteger: "65536" # 1
B_1:
SecretInteger: "131072" # 2
B_2:
SecretInteger: "196608" # 3
public_variables: {}
expected_outputs:
out_0_0:
SecretInteger: "65536"
out_0_1:
SecretInteger: "196608"
out_0_2:
SecretInteger: "327680"
out_1_0:
SecretInteger: "-65536"
out_1_1:
SecretInteger: "-65536"
out_1_2:
SecretInteger: "-65536"
out_2_0:
SecretInteger: "0"
out_2_1:
SecretInteger: "131072"
out_2_2:
SecretInteger: "393216"
out_3_0:
SecretInteger: "0"
out_3_1:
SecretInteger: "32768"
out_3_2:
SecretInteger: "43690"
out_4_0:
SecretInteger: "65536"
out_4_1:
SecretInteger: "131072"
out_4_2:
SecretInteger: "196608"
out_5_0:
SecretInteger: "-65536"
out_5_1:
SecretInteger: "0"
out_5_2:
SecretInteger: "65536"
out_6_0:
SecretInteger: "0"
out_6_1:
SecretInteger: "65536"
out_6_2:
SecretInteger: "131072"
out_7_0:
SecretInteger: "0"
out_7_1:
SecretInteger: "65536"
out_7_2:
SecretInteger: "131072"
1 change: 1 addition & 0 deletions tests/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"secret_rational_arithmetic",
"secret_rational_comparison",
"chained_rational_operations",
"rational_array",
# Not supported yet
# "unsigned_matrix_inverse",
# "private_inverse"
Expand Down

0 comments on commit 161072f

Please sign in to comment.