From ab17668414aea47b7e23e9e70b1ef576d6b21be9 Mon Sep 17 00:00:00 2001 From: VictorGolenkov Date: Tue, 9 Sep 2025 18:08:40 +0400 Subject: [PATCH 1/6] Lab 2 done --- lab_2/.gitignore | 162 +++++++++++++++++ lab_2/NIST_tests.py | 163 ++++++++++++++++++ lab_2/Report_C++ | 10 ++ lab_2/Report_Java | 10 ++ lab_2/binary_sequences/generate.cpp | 35 ++++ lab_2/binary_sequences/generate.java | 19 ++ .../binary_sequences/generated_sequences.json | 4 + lab_2/main.py | 69 ++++++++ lab_2/requirements.txt | 2 + lab_2/settings.json | 9 + lab_2/tools.py | 38 ++++ 11 files changed, 521 insertions(+) create mode 100644 lab_2/.gitignore create mode 100644 lab_2/NIST_tests.py create mode 100644 lab_2/Report_C++ create mode 100644 lab_2/Report_Java create mode 100644 lab_2/binary_sequences/generate.cpp create mode 100644 lab_2/binary_sequences/generate.java create mode 100644 lab_2/binary_sequences/generated_sequences.json create mode 100644 lab_2/main.py create mode 100644 lab_2/requirements.txt create mode 100644 lab_2/settings.json create mode 100644 lab_2/tools.py diff --git a/lab_2/.gitignore b/lab_2/.gitignore new file mode 100644 index 000000000..82f927558 --- /dev/null +++ b/lab_2/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/lab_2/NIST_tests.py b/lab_2/NIST_tests.py new file mode 100644 index 000000000..e26bd53f3 --- /dev/null +++ b/lab_2/NIST_tests.py @@ -0,0 +1,163 @@ +import math +import numpy as np +from scipy import special + +def frequency_test(sequence: str) -> float: + """Функция реализует частотный побитовый тест NIST + + Args: + sequence (str): Бинарная последовательность длиной 128 + + Raises: + ValueError: Генерирует исключение если последовательность пустая + ValueError: Генерирует исключение если последовательность содержит какие-либо символы кроме "0" и "1" + ValueError: Генерирует исключение если длина последовательности не 128 бит + + Returns: + float: P-значение + """ + try: + if not sequence: + raise ValueError("Пустая последовательность") + if not all(bit in '01' for bit in sequence): + raise ValueError("Последовательность должна содержать только '0' и '1'") + + N = len(sequence) + + if N < 128: + raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") + + S_n = 0 + for bit in sequence: + if bit == '1': + S_n += 1 + else: + S_n += -1 + S_n = S_n/np.sqrt(len(sequence)) + + P = math.erfc(S_n / np.sqrt(2)) + + except ValueError as e: + print(f"Ошибка в данных: {e}") + return -1 + except Exception as e: + print(f"Неожиданная ошибка: {e}") + return -1 + + return P + +def indentical_bits(sequence: str) -> float: + """Функция реализует тест NIST на одинаковые подряд идущие биты + + Args: + sequence (str): Бинарная последовательность длиной 128 + + Raises: + ValueError: Генерирует исключение если последовательность пустая + ValueError: Генерирует исключение если последовательность содержит какие-либо символы кроме "0" и "1" + ValueError: Генерирует исключение если длина последовательности не 128 бит + + Returns: + float: P-значение + """ + try: + if not sequence: + raise ValueError("Пустая последовательность") + if not all(bit in '01' for bit in sequence): + raise ValueError("Последовательность должна содержать только '0' и '1'") + + N = len(sequence) + + if N != 128: + raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") + + zeta = sum(int(bit) for bit in sequence) / N + + if(np.abs(zeta-0.5) >= 2/np.sqrt(N)): + return 0 + + V_n = 0 + prev = sequence[0] + for bit in sequence[1:]: + if bit != prev: + V_n += 1 + prev = bit + + P = math.erfc(abs(V_n - (2 * N * zeta * (1-zeta))) / + (2 * np.sqrt(2 * N) * zeta * (1 - zeta))) + + except ValueError as e: + print(f"Ошибка в данных: {e}") + return -1 + except Exception as e: + print(f"Неожиданная ошибка: {e}") + return -1 + + return P + +def longest_seq(sequence: str) -> float: + """Функция реализует тест NIST на самую длинную последовательность единиц в блоке + Args: + sequence (str): Бинарная последовательность длиной 128 + + Raises: + ValueError: Генерирует исключение если последовательность пустая + ValueError: Генерирует исключение если последовательность содержит какие-либо символы кроме "0" и "1" + ValueError: Генерирует исключение если длина последовательности не 128 бит + + Returns: + float: P-значение + """ + try: + if not sequence: + raise ValueError("Пустая последовательность") + if not all(bit in '01' for bit in sequence): + raise ValueError("Последовательность должна содержать только '0' и '1'") + + N = len(sequence) + M = 8 + + if N < 128: + raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") + + num_of_blocks = N // M + blocks = (sequence[i * M:(i + 1) * M] for i in range(num_of_blocks)) + + statistics = [0] * 4 + + for block in blocks: + curr_n = 0 + max_n = 0 + + for bit in block: + if bit == "1": + curr_n += 1 + max_n = max(max_n, curr_n) + else: + curr_n = 0 + + if max_n <= 1: + statistics[0] += 1 + elif max_n == 2: + statistics[1] += 1 + elif max_n == 3: + statistics[2] += 1 + else: + statistics[3] += 1 + + xi_square = 0 + p_i = [0.2148, 0.3672, 0.2305, 0.1875] + + for v, p in zip(statistics, p_i): + xi_square += (v - 16 * p) ** 2 / (16 * p) + + P = (special.gammaincc(3/2, xi_square/2)) + + except ValueError as e: + print(f"Ошибка в данных: {e}") + return -1 + except Exception as e: + print(f"Неожиданная ошибка: {e}") + return -1 + + return P \ No newline at end of file diff --git a/lab_2/Report_C++ b/lab_2/Report_C++ new file mode 100644 index 000000000..70da934ea --- /dev/null +++ b/lab_2/Report_C++ @@ -0,0 +1,10 @@ +Двоичная последовательность, сгенерированная с помощью стандартного ГСПЧ языка C++: +10011101001111101001111000001111111101011011100101011000100001110011011000000110011011111011000000111001111111000001001011110100 + +Результаты тестов NIST для данной двоичной последовательности: +Частотный побитовый тест: P = 0.37675911781158217 +Тест на одинаковые подряд идущие биты: P = 0.05915929910713417 +Тест на самую длинную последовательность единиц в блоке: P = 0.05296688162816608 + +Нулевая гипотеза принимается, альтернативная гипотеза опровергается: +Последовательность является истинно случайной diff --git a/lab_2/Report_Java b/lab_2/Report_Java new file mode 100644 index 000000000..f1ae836dc --- /dev/null +++ b/lab_2/Report_Java @@ -0,0 +1,10 @@ +Двоичная последовательность, сгенерированная с помощью стандартного ГСПЧ языка Java: +01111110011111001000110111101111011100010011000101011010001111100101011000010011100010000001111110110100100001000001001101010010 + +Результаты тестов NIST для данной двоичной последовательности: +Частотный побитовый тест: P = 1.0 +Тест на одинаковые подряд идущие биты: P = 0.4795001221869534 +Тест на самую длинную последовательность единиц в блоке: P = 0.31263961190997863 + +Нулевая гипотеза принимается, альтернативная гипотеза опровергается: +Последовательность является истинно случайной diff --git a/lab_2/binary_sequences/generate.cpp b/lab_2/binary_sequences/generate.cpp new file mode 100644 index 000000000..2439b1b46 --- /dev/null +++ b/lab_2/binary_sequences/generate.cpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +using namespace std; + +/** + * Generates random binary a sequence of length 128 + * + * @return string of generated binary sequence +*/ +string generate() { + std::random_device rd; + std::mt19937_64 gen(rd()); + + uint64_t part1 = gen(); + uint64_t part2 = gen(); + + std::bitset<64> bits1(part1); + std::bitset<64> bits2(part2); + + return(bits2.to_string() + bits1.to_string()); +} + +/** + * Main function that generates and prints a random binary sequence + * + * @return int Exit status code (0 for success) + */ +int main() { + std::cout << generate() << std::endl; + + return 0; +} \ No newline at end of file diff --git a/lab_2/binary_sequences/generate.java b/lab_2/binary_sequences/generate.java new file mode 100644 index 000000000..d60fd902c --- /dev/null +++ b/lab_2/binary_sequences/generate.java @@ -0,0 +1,19 @@ +import java.util.Random; + +public class Main { + /** + * Generates a 128-bit random binary sequence + * + * @param args Command line arguments (not used) + */ + public static void main(String[] args) { + Random random = new Random(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < 128; i++) { + sb.append(random.nextBoolean() ? '1' : '0'); + } + + System.out.println(sb.toString()); + } +} \ No newline at end of file diff --git a/lab_2/binary_sequences/generated_sequences.json b/lab_2/binary_sequences/generated_sequences.json new file mode 100644 index 000000000..fc8b46325 --- /dev/null +++ b/lab_2/binary_sequences/generated_sequences.json @@ -0,0 +1,4 @@ +{ + "cpp": "10011101001111101001111000001111111101011011100101011000100001110011011000000110011011111011000000111001111111000001001011110100", + "java": "01111110011111001000110111101111011100010011000101011010001111100101011000010011100010000001111110110100100001000001001101010010" +} \ No newline at end of file diff --git a/lab_2/main.py b/lab_2/main.py new file mode 100644 index 000000000..2b0dc2c09 --- /dev/null +++ b/lab_2/main.py @@ -0,0 +1,69 @@ +import NIST_tests as tst +import tools as t + +def gen_report(binary_sequence: str, filename: str, lan: str): + """Сохраняет в файле отчёт о проверке бинарной последовательности тестами NIST. + + Args: + binary_sequence (str): Проверяемая бинарная последовательность + filename (str): Имя файла, в котором необходимо сохранить отчёт + lan (str): Язык, с помощью которого была сгенерирована бинарная последовательность + + Raises: + ValueError: Значение P = -1 + """ + try: + with open(filename, 'w', encoding="utf-8") as f: + + results = [tst.frequency_test(binary_sequence), + tst.indentical_bits(binary_sequence), + tst.longest_seq(binary_sequence)] + + print(f"Двоичная последовательность, сгенерированная с помощью стандартного ГСПЧ языка {lan}: ", file = f) + print(binary_sequence, file = f) + f.write("\n") + print("Результаты тестов NIST для данной двоичной последовательности: ", file = f) + + print(f"Частотный побитовый тест: P = {results[0]}", file = f) + print(f"Тест на одинаковые подряд идущие биты: P = {results[1]}", file = f) + print(f"Тест на самую длинную последовательность единиц в блоке: P = {results[2]}", file = f) + + check: list[bool] = [] + for P in results: + if P >= 0.01: + check.append(True) + elif P < 0.01 or P >= 0: + check.append(False) + else: + raise ValueError("Получено некорректное значение P") + + f.write("\n") + if all(check): + print("Нулевая гипотеза принимается, альтернативная гипотеза опровергается:", file = f) + print("Последовательность является истинно случайной", file = f) + else: + print("Альтернативная гипотеза принимается, нулевая гипотеза опровергается:", file = f) + print("Последовательность не является истинно случайной", file = f) + + except ValueError as e: + print(f"Ошибка в данных: {e}") + return + except Exception as e: + print(f"Неожиданная ошибка: {e}") + return + +def main(): + + stgs = t.read_json("settings.json") + + sequences = t.read_json(stgs["gen_seq"]) + + cpp_sequence = sequences["cpp"] + java_sequence = sequences["java"] + + gen_report(cpp_sequence, stgs["Report_C++"], stgs["lan_1"]) + gen_report(java_sequence, stgs["Report_Java"], stgs["lan_2"]) + +if __name__ == "__main__": + main() + \ No newline at end of file diff --git a/lab_2/requirements.txt b/lab_2/requirements.txt new file mode 100644 index 000000000..7f2a0d412 --- /dev/null +++ b/lab_2/requirements.txt @@ -0,0 +1,2 @@ +numpy==2.3.2 +scipy==1.16.1 diff --git a/lab_2/settings.json b/lab_2/settings.json new file mode 100644 index 000000000..28557f812 --- /dev/null +++ b/lab_2/settings.json @@ -0,0 +1,9 @@ +{ + "gen_seq": "binary_sequences/generated_sequences.json", + + "Lan_1_report": "Report_C++", + "Lan_2_report": "Report_Java", + + "Lan_1": "C++", + "Lan_2": "Java" +} \ No newline at end of file diff --git a/lab_2/tools.py b/lab_2/tools.py new file mode 100644 index 000000000..83e1ce98f --- /dev/null +++ b/lab_2/tools.py @@ -0,0 +1,38 @@ +import json +from typing import Any, Dict + +def read_txt(file_name: str) -> str: + """Считывает текcт из .txt файла + + Args: + file_name (str): Путь к файлу + + Returns: + str: Содержимое файла + """ + with open(file_name, 'r', encoding="utf-8") as f: + text: str = f.read() + return text + +def save_txt(file_name: str, text: str): + """Удаляет содержимое файла и сохраняет в нём новый текст. + Если файла не существует, создаёт его. + + Args: + file_name (str): Путь к файлу + text (str): Текст, который необходимо сохранить + """ + with open(file_name, 'w', encoding="utf-8") as f: + f.write(text) + +def read_json(file_name: str) -> Dict[str, Any]: + """Считывает данные из .json файла + + Args: + file_name (str): Путь к файлу + + Returns: + Dict[str, Any]: Словарь объектов, содеражавшихся в .json файле + """ + with open(file_name, 'r', encoding='utf-8') as f: + return(json.load(f)) \ No newline at end of file From dcb72a1b241896d023dcbed72920b48d0b419ac2 Mon Sep 17 00:00:00 2001 From: VictorGolenkov Date: Tue, 9 Sep 2025 18:35:21 +0400 Subject: [PATCH 2/6] Lab2 done once more --- lab_2/NIST_tests.py | 6 +++--- lab_2/main.py | 8 ++++---- lab_2/settings.json | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lab_2/NIST_tests.py b/lab_2/NIST_tests.py index e26bd53f3..c0ea7dd5c 100644 --- a/lab_2/NIST_tests.py +++ b/lab_2/NIST_tests.py @@ -95,7 +95,7 @@ def indentical_bits(sequence: str) -> float: return P -def longest_seq(sequence: str) -> float: +def longest_seq(sequence: str, p_i: str) -> float: """Функция реализует тест NIST на самую длинную последовательность единиц в блоке Args: sequence (str): Бинарная последовательность длиной 128 @@ -146,9 +146,9 @@ def longest_seq(sequence: str) -> float: statistics[3] += 1 xi_square = 0 - p_i = [0.2148, 0.3672, 0.2305, 0.1875] + p_in = (int(p) for p in p_i) - for v, p in zip(statistics, p_i): + for v, p in zip(statistics, p_in): xi_square += (v - 16 * p) ** 2 / (16 * p) P = (special.gammaincc(3/2, xi_square/2)) diff --git a/lab_2/main.py b/lab_2/main.py index 2b0dc2c09..7bdf33877 100644 --- a/lab_2/main.py +++ b/lab_2/main.py @@ -1,7 +1,7 @@ import NIST_tests as tst import tools as t -def gen_report(binary_sequence: str, filename: str, lan: str): +def gen_report(binary_sequence: str, filename: str, lan: str, p_i: str): """Сохраняет в файле отчёт о проверке бинарной последовательности тестами NIST. Args: @@ -17,7 +17,7 @@ def gen_report(binary_sequence: str, filename: str, lan: str): results = [tst.frequency_test(binary_sequence), tst.indentical_bits(binary_sequence), - tst.longest_seq(binary_sequence)] + tst.longest_seq(binary_sequence, p_i)] print(f"Двоичная последовательность, сгенерированная с помощью стандартного ГСПЧ языка {lan}: ", file = f) print(binary_sequence, file = f) @@ -61,8 +61,8 @@ def main(): cpp_sequence = sequences["cpp"] java_sequence = sequences["java"] - gen_report(cpp_sequence, stgs["Report_C++"], stgs["lan_1"]) - gen_report(java_sequence, stgs["Report_Java"], stgs["lan_2"]) + gen_report(cpp_sequence, stgs["Report_C++"], stgs["lan_1"], stgs["p_i"]) + gen_report(java_sequence, stgs["Report_Java"], stgs["lan_2"], stgs["p_i"]) if __name__ == "__main__": main() diff --git a/lab_2/settings.json b/lab_2/settings.json index 28557f812..bc8e7c958 100644 --- a/lab_2/settings.json +++ b/lab_2/settings.json @@ -5,5 +5,7 @@ "Lan_2_report": "Report_Java", "Lan_1": "C++", - "Lan_2": "Java" + "Lan_2": "Java", + + "p_i": ["0.2148", "0.3672", "0.2305", "0.1875"] } \ No newline at end of file From 4078ef2bdd6b2640b43897435df2f71c3e0e78cb Mon Sep 17 00:00:00 2001 From: VictorGolenkov Date: Mon, 22 Sep 2025 18:41:31 +0400 Subject: [PATCH 3/6] Some improvements --- .gitignore | 1 + lab_2/NIST_tests.py | 37 ++++++++++++++----------------------- lab_2/main.py | 30 +++++++++++++++++++----------- lab_2/settings.json | 2 ++ 4 files changed, 36 insertions(+), 34 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ba698c7d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode/launch.json diff --git a/lab_2/NIST_tests.py b/lab_2/NIST_tests.py index c0ea7dd5c..bbe901ae6 100644 --- a/lab_2/NIST_tests.py +++ b/lab_2/NIST_tests.py @@ -2,7 +2,7 @@ import numpy as np from scipy import special -def frequency_test(sequence: str) -> float: +def frequency_test(sequence: str, N: int) -> float: """Функция реализует частотный побитовый тест NIST Args: @@ -22,17 +22,12 @@ def frequency_test(sequence: str) -> float: if not all(bit in '01' for bit in sequence): raise ValueError("Последовательность должна содержать только '0' и '1'") - N = len(sequence) - if N < 128: raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") S_n = 0 for bit in sequence: - if bit == '1': - S_n += 1 - else: - S_n += -1 + S_n += 1 if bit == '1' else -1 S_n = S_n/np.sqrt(len(sequence)) P = math.erfc(S_n / np.sqrt(2)) @@ -46,7 +41,7 @@ def frequency_test(sequence: str) -> float: return P -def indentical_bits(sequence: str) -> float: +def indentical_bits(sequence: str, N: int) -> float: """Функция реализует тест NIST на одинаковые подряд идущие биты Args: @@ -66,8 +61,6 @@ def indentical_bits(sequence: str) -> float: if not all(bit in '01' for bit in sequence): raise ValueError("Последовательность должна содержать только '0' и '1'") - N = len(sequence) - if N != 128: raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") @@ -95,7 +88,7 @@ def indentical_bits(sequence: str) -> float: return P -def longest_seq(sequence: str, p_i: str) -> float: +def longest_seq(sequence: str, p_i: str, N: int, M: int) -> float: """Функция реализует тест NIST на самую длинную последовательность единиц в блоке Args: sequence (str): Бинарная последовательность длиной 128 @@ -114,9 +107,6 @@ def longest_seq(sequence: str, p_i: str) -> float: if not all(bit in '01' for bit in sequence): raise ValueError("Последовательность должна содержать только '0' и '1'") - N = len(sequence) - M = 8 - if N < 128: raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") @@ -136,17 +126,18 @@ def longest_seq(sequence: str, p_i: str) -> float: else: curr_n = 0 - if max_n <= 1: - statistics[0] += 1 - elif max_n == 2: - statistics[1] += 1 - elif max_n == 3: - statistics[2] += 1 - else: - statistics[3] += 1 + match max_n: + case n if n <= 1: + statistics[0] += 1 + case 2: + statistics[1] += 1 + case 3: + statistics[2] += 1 + case _: + statistics[3] += 1 xi_square = 0 - p_in = (int(p) for p in p_i) + p_in = (float(p) for p in p_i) for v, p in zip(statistics, p_in): xi_square += (v - 16 * p) ** 2 / (16 * p) diff --git a/lab_2/main.py b/lab_2/main.py index 7bdf33877..0b9b0d9bc 100644 --- a/lab_2/main.py +++ b/lab_2/main.py @@ -1,7 +1,7 @@ import NIST_tests as tst import tools as t -def gen_report(binary_sequence: str, filename: str, lan: str, p_i: str): +def gen_report(binary_sequence: str, filename: str, lan: str, p_i: str, len_of_binary_sequense: int, len_of_block: int): """Сохраняет в файле отчёт о проверке бинарной последовательности тестами NIST. Args: @@ -15,9 +15,9 @@ def gen_report(binary_sequence: str, filename: str, lan: str, p_i: str): try: with open(filename, 'w', encoding="utf-8") as f: - results = [tst.frequency_test(binary_sequence), - tst.indentical_bits(binary_sequence), - tst.longest_seq(binary_sequence, p_i)] + results = [tst.frequency_test(binary_sequence, len_of_binary_sequense), + tst.indentical_bits(binary_sequence, len_of_binary_sequense), + tst.longest_seq(binary_sequence, p_i, len_of_binary_sequense, len_of_block)] print(f"Двоичная последовательность, сгенерированная с помощью стандартного ГСПЧ языка {lan}: ", file = f) print(binary_sequence, file = f) @@ -53,16 +53,24 @@ def gen_report(binary_sequence: str, filename: str, lan: str, p_i: str): return def main(): + SETTINGS = t.read_json("settings.json") + SEQUENCES = t.read_json(SETTINGS["gen_seq"]) - stgs = t.read_json("settings.json") + CPP_SEQUENCE = SEQUENCES["cpp"] + JAVA_SEQUENCE = SEQUENCES["java"] - sequences = t.read_json(stgs["gen_seq"]) + CPP_REPORT_PATH = SETTINGS["Lan_1_report"] + JAVA_REPORT_PATH = SETTINGS["Lan_2_report"] + CPP_LANGUAGE_NAME = SETTINGS["Lan_1"] + JAVA_LANGUAGE_NAME = SETTINGS["Lan_2"] + P_I = SETTINGS["p_i"] + SEQUENCE_LENGTH = int(SETTINGS["len_of_seq"]) + BLOCK_LENGTH = int(SETTINGS["len_of_block"]) - cpp_sequence = sequences["cpp"] - java_sequence = sequences["java"] - - gen_report(cpp_sequence, stgs["Report_C++"], stgs["lan_1"], stgs["p_i"]) - gen_report(java_sequence, stgs["Report_Java"], stgs["lan_2"], stgs["p_i"]) + gen_report(CPP_SEQUENCE, CPP_REPORT_PATH, CPP_LANGUAGE_NAME, + P_I, SEQUENCE_LENGTH, BLOCK_LENGTH) + gen_report(JAVA_SEQUENCE, JAVA_REPORT_PATH, JAVA_LANGUAGE_NAME, + P_I, SEQUENCE_LENGTH, BLOCK_LENGTH) if __name__ == "__main__": main() diff --git a/lab_2/settings.json b/lab_2/settings.json index bc8e7c958..28ed0d4c4 100644 --- a/lab_2/settings.json +++ b/lab_2/settings.json @@ -1,5 +1,7 @@ { "gen_seq": "binary_sequences/generated_sequences.json", + "len_of_seq": "128", + "len_of_block": "8", "Lan_1_report": "Report_C++", "Lan_2_report": "Report_Java", From d1394d7075fd5733bce98944ec46edc0d03ec6b8 Mon Sep 17 00:00:00 2001 From: VictorGolenkov Date: Mon, 22 Sep 2025 18:47:07 +0400 Subject: [PATCH 4/6] Some more improvements --- lab_2/main.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lab_2/main.py b/lab_2/main.py index 0b9b0d9bc..9c0e9d86c 100644 --- a/lab_2/main.py +++ b/lab_2/main.py @@ -30,13 +30,14 @@ def gen_report(binary_sequence: str, filename: str, lan: str, p_i: str, len_of_b check: list[bool] = [] for P in results: - if P >= 0.01: - check.append(True) - elif P < 0.01 or P >= 0: - check.append(False) - else: - raise ValueError("Получено некорректное значение P") - + match P: + case p if p >= 0.01: + check.append(True) + case p if 0 <= p < 0.01: + check.append(False) + case _: + raise ValueError(f"Получено некорректное значение P: {P}") + f.write("\n") if all(check): print("Нулевая гипотеза принимается, альтернативная гипотеза опровергается:", file = f) From 74beca6c57146173236a27d832051337fdb39acc Mon Sep 17 00:00:00 2001 From: VictorGolenkov Date: Mon, 22 Sep 2025 20:29:53 +0400 Subject: [PATCH 5/6] Once more --- lab_2/NIST_tests.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lab_2/NIST_tests.py b/lab_2/NIST_tests.py index bbe901ae6..43b7a88a5 100644 --- a/lab_2/NIST_tests.py +++ b/lab_2/NIST_tests.py @@ -21,9 +21,6 @@ def frequency_test(sequence: str, N: int) -> float: raise ValueError("Пустая последовательность") if not all(bit in '01' for bit in sequence): raise ValueError("Последовательность должна содержать только '0' и '1'") - - if N < 128: - raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") S_n = 0 for bit in sequence: @@ -60,9 +57,6 @@ def indentical_bits(sequence: str, N: int) -> float: raise ValueError("Пустая последовательность") if not all(bit in '01' for bit in sequence): raise ValueError("Последовательность должна содержать только '0' и '1'") - - if N != 128: - raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") zeta = sum(int(bit) for bit in sequence) / N @@ -106,9 +100,6 @@ def longest_seq(sequence: str, p_i: str, N: int, M: int) -> float: raise ValueError("Пустая последовательность") if not all(bit in '01' for bit in sequence): raise ValueError("Последовательность должна содержать только '0' и '1'") - - if N < 128: - raise ValueError(f"Длина последовательности должна быть 128 бит, получено {N}") num_of_blocks = N // M blocks = (sequence[i * M:(i + 1) * M] for i in range(num_of_blocks)) From 2f113a76f45338c71c3489a461c838682addcddc Mon Sep 17 00:00:00 2001 From: VictorGolenkov Date: Sat, 27 Sep 2025 10:38:55 +0400 Subject: [PATCH 6/6] Added exceptions in file word functions --- .gitignore | 165 +++++++++++++++++++++++++++++++++++++++++++++++++ lab_2/tools.py | 34 +++++----- 2 files changed, 185 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index ba698c7d2..c9732042d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,166 @@ .vscode/launch.json + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +.vscode/ + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/lab_2/tools.py b/lab_2/tools.py index 83e1ce98f..79feaf874 100644 --- a/lab_2/tools.py +++ b/lab_2/tools.py @@ -3,36 +3,42 @@ def read_txt(file_name: str) -> str: """Считывает текcт из .txt файла - Args: file_name (str): Путь к файлу - Returns: str: Содержимое файла """ - with open(file_name, 'r', encoding="utf-8") as f: - text: str = f.read() - return text - + try: + with open(file_name, 'r', encoding="utf-8") as f: + text: str = f.read() + return text + except Exception as e: + print(f"Error: {e}") + return "" + def save_txt(file_name: str, text: str): """Удаляет содержимое файла и сохраняет в нём новый текст. Если файла не существует, создаёт его. - Args: file_name (str): Путь к файлу text (str): Текст, который необходимо сохранить """ - with open(file_name, 'w', encoding="utf-8") as f: - f.write(text) - + try: + with open(file_name, 'w', encoding="utf-8") as f: + f.write(text) + except Exception as e: + print(f"Error: {e}") + def read_json(file_name: str) -> Dict[str, Any]: """Считывает данные из .json файла - Args: file_name (str): Путь к файлу - Returns: Dict[str, Any]: Словарь объектов, содеражавшихся в .json файле """ - with open(file_name, 'r', encoding='utf-8') as f: - return(json.load(f)) \ No newline at end of file + try: + with open(file_name, 'r', encoding='utf-8') as f: + return(json.load(f)) + except Exception as e: + print(f"Error: {e}") + return {} \ No newline at end of file