implement shuffle benchmark
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
output
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,6 +4,7 @@ import random
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from statistics import mean, variance
|
from statistics import mean, variance
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Benchmark:
|
class Benchmark:
|
||||||
@@ -15,18 +16,18 @@ class ShuffleTypes(Enum):
|
|||||||
FULL_SHUFFLE = "FULL_SHUFFLE"
|
FULL_SHUFFLE = "FULL_SHUFFLE"
|
||||||
SPLIT_SHUFFLE = "SPLIT_SHUFFLE"
|
SPLIT_SHUFFLE = "SPLIT_SHUFFLE"
|
||||||
|
|
||||||
def observations(number_of_keys, properties_per_key, passcode_len, shuffle_type: ShuffleTypes = ShuffleTypes.SPLIT_SHUFFLE):
|
def observations(number_of_keys, properties_per_key, passcode_len, complexity: int, disparity: int, shuffle_type: ShuffleTypes):
|
||||||
k = number_of_keys
|
k = number_of_keys
|
||||||
p = properties_per_key
|
p = properties_per_key
|
||||||
n = passcode_len
|
n = passcode_len
|
||||||
nkode = [random.randint(0, k*p-1) for _ in range(n)]
|
passcode = passcode_generator(k, p, n, complexity, disparity)
|
||||||
keypad = Keypad.new_keypad(k, p)
|
keypad = Keypad.new_keypad(k, p)
|
||||||
|
|
||||||
def obs_gen():
|
def obs_gen():
|
||||||
for _ in range(100): # finite number of yields
|
for _ in range(100): # finite number of yields
|
||||||
yield Observation(
|
yield Observation(
|
||||||
keypad=keypad.keypad.copy(),
|
keypad=keypad.keypad.copy(),
|
||||||
key_selection=keypad.key_entry(target_passcode=nkode)
|
key_selection=keypad.key_entry(target_passcode=passcode)
|
||||||
)
|
)
|
||||||
match shuffle_type:
|
match shuffle_type:
|
||||||
case ShuffleTypes.FULL_SHUFFLE:
|
case ShuffleTypes.FULL_SHUFFLE:
|
||||||
@@ -38,25 +39,94 @@ def observations(number_of_keys, properties_per_key, passcode_len, shuffle_type:
|
|||||||
|
|
||||||
return obs_gen()
|
return obs_gen()
|
||||||
|
|
||||||
def split_shuffle_benchmark(
|
def passcode_generator(k: int, p: int, n: int, c: int, d: int) -> list[int]:
|
||||||
|
assert n >= c
|
||||||
|
assert p*k >= c
|
||||||
|
|
||||||
|
assert n >= d
|
||||||
|
assert p >= d
|
||||||
|
passcode_prop = []
|
||||||
|
passcode_set = []
|
||||||
|
valid_choices = {i for i in range(k*p)}
|
||||||
|
repeat_set = n-d
|
||||||
|
repeat_prop = n-c
|
||||||
|
prop_added = set()
|
||||||
|
set_added = set()
|
||||||
|
|
||||||
|
for _ in range(n):
|
||||||
|
prop = random.choice(list(valid_choices))
|
||||||
|
prop_set = prop//p
|
||||||
|
passcode_prop.append(prop)
|
||||||
|
passcode_set.append(prop_set)
|
||||||
|
|
||||||
|
if prop in prop_added:
|
||||||
|
repeat_prop -= 1
|
||||||
|
if prop_set in set_added:
|
||||||
|
repeat_set -= 1
|
||||||
|
|
||||||
|
prop_added.add(prop)
|
||||||
|
set_added.add(prop_set)
|
||||||
|
|
||||||
|
if repeat_prop <= 0:
|
||||||
|
valid_choices -= prop_added
|
||||||
|
|
||||||
|
if repeat_set <= 0:
|
||||||
|
for el in valid_choices.copy():
|
||||||
|
if el // p in set_added:
|
||||||
|
valid_choices.remove(el)
|
||||||
|
|
||||||
|
return passcode_prop
|
||||||
|
|
||||||
|
|
||||||
|
def shuffle_benchmark(
|
||||||
number_of_keys: int,
|
number_of_keys: int,
|
||||||
properties_per_key: int,
|
properties_per_key: int,
|
||||||
passcode_len: int,
|
passcode_len: int,
|
||||||
max_tries_before_lockout: int,
|
max_tries_before_lockout: int,
|
||||||
run_count: int,
|
run_count: int,
|
||||||
|
complexity: int,
|
||||||
|
disparity: int,
|
||||||
|
shuffle_type: ShuffleTypes,
|
||||||
|
file_path: str = '../output',
|
||||||
|
overwrite: bool = False
|
||||||
) -> Benchmark:
|
) -> Benchmark:
|
||||||
|
file_name = f"{shuffle_type.name.lower()}-{number_of_keys}-{properties_per_key}-{passcode_len}-{max_tries_before_lockout}-{complexity}-{disparity}-{run_count}.txt"
|
||||||
|
full_path = Path(file_path) / file_name
|
||||||
|
if not overwrite and full_path.exists():
|
||||||
|
print(f"file exists {file_path}")
|
||||||
|
|
||||||
|
with open(full_path, "r") as fp:
|
||||||
|
runs = fp.readline()
|
||||||
|
runs = runs.split(',')
|
||||||
|
runs = [int(i) for i in runs]
|
||||||
|
return Benchmark(
|
||||||
|
mean=mean(runs),
|
||||||
|
variance=variance(runs),
|
||||||
|
runs=runs
|
||||||
|
)
|
||||||
runs = []
|
runs = []
|
||||||
for _ in range(run_count):
|
for _ in range(run_count):
|
||||||
evilkode = Evilkode(
|
evilkode = Evilkode(
|
||||||
observations=observations(number_of_keys, properties_per_key, passcode_len),
|
observations=observations(
|
||||||
number_of_keys=number_of_keys,
|
number_of_keys=number_of_keys,
|
||||||
properties_per_key=properties_per_key,
|
properties_per_key=properties_per_key,
|
||||||
passcode_len=passcode_len,
|
passcode_len=passcode_len,
|
||||||
max_tries_before_lockout=max_tries_before_lockout
|
complexity=complexity,
|
||||||
|
disparity=disparity,
|
||||||
|
shuffle_type=shuffle_type,
|
||||||
|
),
|
||||||
|
number_of_keys=number_of_keys,
|
||||||
|
properties_per_key=properties_per_key,
|
||||||
|
passcode_len=passcode_len,
|
||||||
|
max_tries_before_lockout=max_tries_before_lockout,
|
||||||
)
|
)
|
||||||
evilout = evilkode.run()
|
evilout = evilkode.run()
|
||||||
runs.append(evilout.iterations)
|
runs.append(evilout.iterations)
|
||||||
|
|
||||||
|
full_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(full_path, "w") as fp:
|
||||||
|
fp.write(",".join([str(i) for i in runs])),
|
||||||
|
|
||||||
return Benchmark(
|
return Benchmark(
|
||||||
mean=mean(runs),
|
mean=mean(runs),
|
||||||
variance=variance(runs),
|
variance=variance(runs),
|
||||||
@@ -70,15 +140,24 @@ def full_shuffle_benchmark(
|
|||||||
passcode_len: int,
|
passcode_len: int,
|
||||||
max_tries_before_lockout: int,
|
max_tries_before_lockout: int,
|
||||||
run_count: int,
|
run_count: int,
|
||||||
|
complexity: int,
|
||||||
|
disparity: int,
|
||||||
) -> Benchmark:
|
) -> Benchmark:
|
||||||
runs = []
|
runs = []
|
||||||
for _ in range(run_count):
|
for _ in range(run_count):
|
||||||
evilkode = Evilkode(
|
evilkode = Evilkode(
|
||||||
observations=observations(number_of_keys, properties_per_key, passcode_len, shuffle_type=ShuffleTypes.FULL_SHUFFLE),
|
observations=observations(
|
||||||
number_of_keys=number_of_keys,
|
number_of_keys=number_of_keys,
|
||||||
properties_per_key=properties_per_key,
|
properties_per_key=properties_per_key,
|
||||||
passcode_len=passcode_len,
|
passcode_len=passcode_len,
|
||||||
max_tries_before_lockout=max_tries_before_lockout
|
complexity=complexity,
|
||||||
|
disparity=disparity,
|
||||||
|
shuffle_type=ShuffleTypes.FULL_SHUFFLE,
|
||||||
|
),
|
||||||
|
number_of_keys=number_of_keys,
|
||||||
|
properties_per_key=properties_per_key,
|
||||||
|
passcode_len=passcode_len,
|
||||||
|
max_tries_before_lockout=max_tries_before_lockout,
|
||||||
)
|
)
|
||||||
evilout = evilkode.run()
|
evilout = evilkode.run()
|
||||||
runs.append(evilout.iterations)
|
runs.append(evilout.iterations)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import math
|
import math
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from itertools import chain
|
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
tests/test_benchmark.py
Normal file
15
tests/test_benchmark.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from src.benchmark import passcode_generator
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"k, p, n, c, d, runs",
|
||||||
|
[
|
||||||
|
(6, 9, 4, 4, 4, 100)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_passcode_generator(k, p, n, c, d, runs):
|
||||||
|
for _ in range(runs):
|
||||||
|
passcode = passcode_generator(k=k, p=p, n=n, c=c, d=d)
|
||||||
|
passcode_sets = [el//p for el in passcode]
|
||||||
|
assert c <= len(set(passcode))
|
||||||
|
assert d <= len(set(passcode_sets))
|
||||||
Reference in New Issue
Block a user