Skip to content

Commit

Permalink
added optional variables for context (e.g. krns_delta, num_digits) an…
Browse files Browse the repository at this point in the history
…d tests
  • Loading branch information
christopherngutierrez committed Jan 8, 2025
1 parent 9ed33df commit 3c43c32
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 8 deletions.
53 changes: 46 additions & 7 deletions kerngen/high_parser/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,46 @@ class EmptyLine(BaseModel):
NATIVE_POLY_SIZE = 8192
MIN_POLY_SIZE = 16384
MAX_POLY_SIZE = 131072
MAX_KRNS_DELTA = 128
MAX_DIGIT = 3
MIN_KRNS_DELTA = MIN_DIGIT = 0


def _parse_optional(optionals: list[str]):
"""Parse optional key/value pairs"""
krns_delta = None
num_digits = None

def valid_num_option(value: str, min_val: int, max_val: int):
"""Validate numeric options with min/max range"""
if value.isnumeric() and int(value) > min_val and int(value) < max_val:
return True
return False

for option in optionals:
try:
key, value = option.split("=")
match key:
case "krns_delta":
if not valid_num_option(value, MIN_KRNS_DELTA, MAX_KRNS_DELTA):
raise ValueError(
f"krns_delta must be in range ({MIN_KRNS_DELTA}, {MAX_KRNS_DELTA}): krns_delta={krns_delta}"
)
krns_delta = int(value)
case "num_digits":
if not valid_num_option(value, MIN_DIGIT, MAX_DIGIT):
raise ValueError(
f"num_digits must be in range ({MIN_DIGIT}, {MAX_DIGIT}): num_digits={num_digits}"
)
num_digits = int(value)
case _:
raise KeyError(f"Invalid optional key for Context: {key}")
except ValueError as err:
raise ValueError(
f"Optional variables must be key/value pairs (e.g. krns_delta=1, num_digits=3): '{option}'"
) from err

return krns_delta, num_digits


class Context(BaseModel):
Expand All @@ -149,18 +189,15 @@ class Context(BaseModel):
scheme: str
poly_order: int # the N
max_rns: int
# optional vars for context
key_rns: int | None
num_digits: int | None

@classmethod
def from_string(cls, line: str):
"""Construct context from a string"""
scheme, poly_order, max_rns, *optional = line.split()
try:
krns, *rest = optional
except ValueError:
krns = None
if optional != [] and rest != []:
raise ValueError(f"too many parameters for context given: {line}")
krns_delta, num_digits = _parse_optional(optional)
int_poly_order = int(poly_order)
if (
int_poly_order < MIN_POLY_SIZE
Expand All @@ -172,12 +209,14 @@ def from_string(cls, line: str):
)

int_max_rns = int(max_rns)
int_key_rns = int_max_rns + int(krns) if krns else None
int_key_rns = int_max_rns + krns_delta if krns_delta else None
int_num_digits = num_digits if num_digits else None
return cls(
scheme=scheme.upper(),
poly_order=int_poly_order,
max_rns=int_max_rns,
key_rns=int_key_rns,
num_digits=int_num_digits,
)

@property
Expand Down
33 changes: 32 additions & 1 deletion kerngen/tests/test_kerngen.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,37 @@ def test_multiple_contexts(kerngen_path):
assert result.returncode != 0


def test_context_optional_without_key(kerngen_path):
"""Test kerngen raises an exception when more than one context is given"""
input_string = "CONTEXT BGV 16384 4 1\nData a 2\n"
result = execute_process(
[kerngen_path],
data_in=input_string,
)
assert not result.stdout
assert (
"ValueError: Optional variables must be key/value pairs (e.g. krns_delta=1, num_digits=3): '1'"
in result.stderr
)
assert result.returncode != 0


@pytest.mark.parametrize("invalid", [-1, 256, 0.1, "str"])
def test_context_optional_invalid_values(kerngen_path, invalid):
"""Test kerngen raises an exception if value is out of range for correct key"""
input_string = f"CONTEXT BGV 16384 4 krns_delta={invalid}\nData a 2\n"
result = execute_process(
[kerngen_path],
data_in=input_string,
)
assert not result.stdout
assert (
f"ValueError: Optional variables must be key/value pairs (e.g. krns_delta=1, num_digits=3): 'krns_delta={invalid}'"
in result.stderr
)
assert result.returncode != 0


def test_unrecognised_opname(kerngen_path):
"""Test kerngen raises an exception when receiving an unrecognised
opname"""
Expand Down Expand Up @@ -99,7 +130,7 @@ def test_invalid_scheme(kerngen_path):
@pytest.mark.parametrize("invalid_poly", [16000, 2**12, 2**13, 2**18])
def test_invalid_poly_order(kerngen_path, invalid_poly):
"""Poly order should be powers of two >= 2^14 and <= 2^17"""
input_string = "CONTEXT BGV " + str(invalid_poly) + " 4 2\nADD a b c\n"
input_string = "CONTEXT BGV " + str(invalid_poly) + " 4\nADD a b c\n"
result = execute_process(
[kerngen_path],
data_in=input_string,
Expand Down

0 comments on commit 3c43c32

Please sign in to comment.