Files
cmc-pseudo-polynomials/get_function_len.py

171 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import lzma
import sys
import os
import itertools
from booleantools import generate_function
def is_good_zhegalkin(function_number, args_count):
return all(map(lambda x: len(x) <= 3, generate_function(function_number, args_count).listform))
def get_rank_file_object(args_count, rank_ind):
base_name = "base_{}_rank_{}.txt".format(args_count, rank_ind)
if os.path.exists(base_name):
return open(base_name, "rb")
elif os.path.exists(base_name + ".xz"):
return lzma.LZMAFile(base_name + ".xz", "rb")
else:
return None
def is_function_exists(function_number, file_object):
file_object.seek(function_number // 8)
result_byte = ord(file_object.read(1))
return (result_byte >> (7 - function_number % 8)) % 2 == 1
def function_values_to_number(values):
assert set(values).issubset({"0", "1"})
res = 0
for ch in values:
res *= 2
if ch == "1":
res += 1
return res
def count_lens(args_count, white_map_path):
bit_counts = bytes(bin(x).count("1") for x in range(256))
len_to_count = {}
white_map = None
if white_map_path:
white_map = open(white_map_path, "rb").read()
print(f"Total whitelisted functions: {sum(map(lambda x: bit_counts[x], white_map))}")
for rank_ind in range(1, 10):
file_object = get_rank_file_object(args_count, rank_ind)
if not file_object:
break
src_data = file_object.read()
if white_map:
assert len(src_data) == len(white_map)
src_data = bytes(x & y for x,y in zip(src_data, white_map))
len_to_count[rank_ind] = sum(map(lambda x: bit_counts[x], src_data))
total = sum(len_to_count.values())
for rank_ind, count in len_to_count.items():
print("len {} count {} share {}".format(rank_ind, count, 1.0 * count / total))
print("average: {}".format(sum([key * value for key, value in len_to_count.items()]) / total))
def get_function_len(args_count, function_number):
for rank_ind in range(1, 10):
file_object = get_rank_file_object(args_count, rank_ind)
if not file_object:
assert False
if is_function_exists(function_number, file_object):
return rank_ind
assert False
def count_symmetricals(args_count):
if args_count <= 4:
func_strings = list(open(f"./build/functions_strings_{args_count}.txt").read().split("\n")[:-1])
else:
func_strings = []
print(f"Total {len(func_strings)} representations")
functions_to_check = set()
for layer_values in itertools.product([0, 1], repeat=args_count + 1):
func_values = []
for argument_number in range(2 ** args_count):
if layer_values[bin(argument_number).count("1")]:
func_values.append("1")
else:
func_values.append("0")
function_number = function_values_to_number("".join(func_values))
functions_to_check.add(function_number)
function_ranks = {}
for fn in functions_to_check:
rank = get_function_len(args_count, fn)
if rank not in function_ranks:
function_ranks[rank] = []
function_ranks[rank].append(fn)
zhegalkin_functions = {key: list(filter(lambda x: is_good_zhegalkin(x, args_count), value)) for key,value in function_ranks.items()}
for processed_function_ranks in [function_ranks, zhegalkin_functions]:
if processed_function_ranks is zhegalkin_functions:
print("Со степенью <= 3:")
len_to_count = {key: len(value) for key, value in processed_function_ranks.items()}
total = sum(len_to_count.values())
for rank_ind, count in sorted(len_to_count.items(), key=lambda x: x[0]):
print("len {} count {} share {}".format(rank_ind, count, 1.0 * count / total))
print(
"average: {}".format(
sum([1.0 * key * value for key, value in len_to_count.items()]) / total
)
)
print(r"\begin{center}")
print(r"\begin{longtable}{| l| r | p{11cm}|}")
print(r"\hline")
if args_count <= 4:
print(r"Длина функции & Номер & ПСПФ\\")
else:
print(r"Длина функции & Номер & Полином Жегалкина\\")
print(r"\hline")
print(r"\endhead")
print(r"\hline \multicolumn{3}{r}{\textit{Продолжение на следующей странице}} \\")
print(r"\endfoot")
print(r"\hline")
print(r"\endlastfoot")
for rank in sorted(function_ranks.keys()):
for function_number in sorted(function_ranks[rank]):
if args_count <= 4:
function_representation = func_strings[function_number]
else:
function_representation = generate_function(function_number, args_count).tex_str().strip()
print(f"{rank} & {function_number} & ${function_representation}$\\\\")
if rank != max(function_ranks.keys()):
print(r"\hline")
print(r"\hline")
print(r"\end{longtable}")
print(r"\addtocounter{table}{-1}")
print(r"\end{center}")
def main():
if sys.argv[1] == "count_lens":
white_map_path = None
if len(sys.argv) > 3:
white_map_path = sys.argv[3]
count_lens(sys.argv[2], white_map_path)
return
elif sys.argv[1] == "count_symmetricals":
count_symmetricals(int(sys.argv[2]))
return
args_count = {
8: 3,
16: 4,
32: 5,
}[len(sys.argv[1])]
function_number = function_values_to_number(sys.argv[1])
print("Function number is {}".format(function_number))
for rank_ind in range(1, 10):
file_object = get_rank_file_object(args_count, rank_ind)
if not file_object:
print("No results file for {} arguments rank {}".format(args_count, rank_ind))
sys.exit(1)
if is_function_exists(function_number, file_object):
print("Result len is {}".format(rank_ind))
return
if __name__ == "__main__":
main()