From 41b1785ea65e54444a414ae10eb8b775f21bc12e Mon Sep 17 00:00:00 2001 From: Rotem Elimelech Date: Thu, 18 Apr 2024 16:39:52 +0300 Subject: [PATCH 1/4] basic usage --- execute_from_json.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 execute_from_json.py diff --git a/execute_from_json.py b/execute_from_json.py new file mode 100644 index 0000000..4c79bde --- /dev/null +++ b/execute_from_json.py @@ -0,0 +1,17 @@ +from blind_delta import calc_individual +import json +import sys + +DEFAULT_OUTPUT_FILENAME = 'blind_delta_output.csv' + + +def main(): + if len(sys.argv) not in (2, 3) or sys.argv[1] in ('-h', '--help', '-?', '/?'): + print('Usage:') + print('execute_from_json.py coefficent_ranges.json [output_filename.csv]') + + exit() + + +if __name__ == '__main__': + main() \ No newline at end of file From a55dc0f5950da88f7cb308e65d1c2a354ca6e1c0 Mon Sep 17 00:00:00 2001 From: Rotem Elimelech Date: Thu, 18 Apr 2024 17:44:01 +0300 Subject: [PATCH 2/4] executing from configuration files --- execute_from_json.py | 85 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/execute_from_json.py b/execute_from_json.py index 4c79bde..b652076 100644 --- a/execute_from_json.py +++ b/execute_from_json.py @@ -1,17 +1,92 @@ from blind_delta import calc_individual +from itertools import product import json import sys +import csv DEFAULT_OUTPUT_FILENAME = 'blind_delta_output.csv' +DEFAULT_DEPTH = 2000 +DEFAULT_P = 2 +DEFAULT_PRECISSION = 100_000 +DEFAULT_NOT_CALCULATED_MARKER = -1010 +DEFAULT_RATIONAL_MARKER = -2020 +DEFAULT_LIMIT_CONSTANT = 1e10 + + +def blind_delta_multi_pcf_wrapper(coefficents_ranges, coefficients_lengths, depth=DEFAULT_DEPTH, p=DEFAULT_P, + precision=DEFAULT_PRECISSION, not_calculated_marker=DEFAULT_NOT_CALCULATED_MARKER, + rational_marker=DEFAULT_RATIONAL_MARKER, limit_constant=DEFAULT_LIMIT_CONSTANT): + """ + A wrapper function from that executes blind_delta.calc_individual (which executes the blind delta algorithm on a + single pcf), over a set of continued fractions. + + Parameters: + - coefficents_ranges (list): Coefficient ranges to scan. Every element should contain a tuple with the minimal and + maximal value allowd for the coefficent. For example, [(1, 2), (3, 4)] entails that blind delta will be executed on + the paramters (1,3), (1,4), (2,3), (2,4). + The rest of the parameters are identical to those of blind_delta.calc_individual. + - coefficients_lengths (list): Lengths (or the degree+1) of a_n and b_n polynomials. + - depth (int): Calculation depth. + - p (int): The relation between the calculation depth and the point where the blind delta is sampled. + - precision (int): Precision for calculations. + - not_calculated_marker: Marker for not calculated values. + - rational_marker: Marker for rational values. + - LIMIT_CONSTANT: A constant mimicing infinity. + """ + # Expand coefficents_ranges to a list of coefficent combinations in the range. + combinations = product(*[range(min_val, max_val+1) for min_val, max_val in coefficents_ranges]) + + # Discard cases where one of the polynomials is strictly zero + filtered_combinations = [] + for coefs in combinations: + an_coefs = coefs[:coefficients_lengths[0]] + bn_coefs = coefs[coefficients_lengths[0]:] + + if all(c == 0 for c in an_coefs) or all(c == 0 for c in bn_coefs): + # Bad pcf + continue + + filtered_combinations.append(coefs) + + # Run blind delta on all PCFs in the filtered set. + results = [] + for coefs in filtered_combinations: + print(coefs) + results.append(calc_individual( + coefficients=coefs, + coefficients_lengths=coefficients_lengths, + depth=depth, + p=p, + precision=precision, + not_calculated_marker=not_calculated_marker, + rational_marker=rational_marker, + LIMIT_CONSTANT=limit_constant)) + + return results def main(): - if len(sys.argv) not in (2, 3) or sys.argv[1] in ('-h', '--help', '-?', '/?'): - print('Usage:') - print('execute_from_json.py coefficent_ranges.json [output_filename.csv]') + if len(sys.argv) not in (2, 3) or sys.argv[1] in ('-h', '--help', '-?', '/?'): + print('Usage:') + print('execute_from_json.py delta2_job.json [output_filename.csv]') + + exit() + + job_config_filename = sys.argv[1] + output_filename = sys.argv[2] if len(sys.argv) == 3 else DEFAULT_OUTPUT_FILENAME + + with open(job_config_filename, 'r') as f: + job_data = json.load(f) + results = blind_delta_multi_pcf_wrapper(**job_data) + + with open(output_filename, "w") as csvfile: + csvwriter = csv.writer(csvfile) + fields = results[0].keys() + csvwriter.writerow(fields) - exit() + for result in results: + csvwriter.writerow(result.values()) if __name__ == '__main__': - main() \ No newline at end of file + main() \ No newline at end of file From 6478235f3f45f68157f674a8698989e8cbf125a9 Mon Sep 17 00:00:00 2001 From: Rotem Elimelech Date: Thu, 18 Apr 2024 17:44:45 +0300 Subject: [PATCH 3/4] adding example job --- delta2_job.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 delta2_job.json diff --git a/delta2_job.json b/delta2_job.json new file mode 100644 index 0000000..e02531b --- /dev/null +++ b/delta2_job.json @@ -0,0 +1,18 @@ +{ + "coefficents_ranges": [ + [1, 1], + [4, 4], + [5, 5], + [-3, -3], + [-2, -2], + [0, 5] + ], + "coefficients_lengths": + [3, 3], + "depth": 2000, + "p": 2, + "precision": 100000, + "not_calculated_marker": -1010, + "rational_marker": -2020, + "limit_constant": 1000000000 +} \ No newline at end of file From 32ec1dae03e6632d09d43d33eaefae6d3b141cc2 Mon Sep 17 00:00:00 2001 From: Rotem Elimelech Date: Thu, 18 Apr 2024 19:35:03 +0300 Subject: [PATCH 4/4] adding unitests --- test_boinc_worker.py | 31 +++++++++++++++++++++++++++++++ tests_data/test_job.json | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test_boinc_worker.py create mode 100644 tests_data/test_job.json diff --git a/test_boinc_worker.py b/test_boinc_worker.py new file mode 100644 index 0000000..d552723 --- /dev/null +++ b/test_boinc_worker.py @@ -0,0 +1,31 @@ +import unittest +from blind_delta import search +import os +import pandas as pd + + +class TestBoincWorker(unittest.TestCase): + def test_worker_vs_mp_version(self): + # Run original version + search(2000, 2, [3, 3], 0, 1, 100000, -1010, -2020, 1000000000, 3) + mp_output_filename = 'BlindDelta[3, 3]_0_1.csv' + + # Run worker, as it would in BOINC + test_config_file = os.path.join('tests_data', 'test_job.json') + worker_output_filename = os.path.join('tests_data', 'test_output.csv') + os.system(f'execute_from_json.py {test_config_file} {worker_output_filename}') + + mp_output = pd.read_csv(mp_output_filename) + worker_output = pd.read_csv(worker_output_filename) + + # There is a mismatch in the way we strore the coefficents, in one we use () and the other [] + worker_output['Coefficients'] = worker_output['Coefficients'].apply(lambda x: x.strip('()[]')) + mp_output['Coefficients'] = mp_output['Coefficients'].apply(lambda x: x.strip('()[]')) + + # In more complicated search spaces, the two versions might not be sortted. + # Here it is not a problem. + assert all(worker_output == mp_output) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests_data/test_job.json b/tests_data/test_job.json new file mode 100644 index 0000000..9e9137a --- /dev/null +++ b/tests_data/test_job.json @@ -0,0 +1,18 @@ +{ + "coefficents_ranges": [ + [0, 1], + [0, 1], + [0, 1], + [0, 1], + [0, 1], + [0, 1] + ], + "coefficients_lengths": + [3, 3], + "depth": 2000, + "p": 2, + "precision": 100000, + "not_calculated_marker": -1010, + "rational_marker": -2020, + "limit_constant": 1000000000 +} \ No newline at end of file