def max_eof_p(sch, max_degree=None, debug=False, max_tests=None): """ :param sch: Input scheme. :param max_degree: Max degree of result polinomial. :param debug: If True debug information will be printed due to process. :return: Upper bound of probability of failure with up to max_degree-1 errors in scheme. """ n = sch.inputs() m = sch.elements() nonerror = (0,) * m if max_degree is None: max_degree = m sch_process = d.make_process_func(sch) if debug: start = time.time() counter = 0 while time.time() - start < 1: output_true = sch_process((0,) * n, (0,) * m) vec2num(output_true) vec2num(output_true) counter += 1 process_time = (time.time() - start) / counter inputs = 2 ** n errors = sum(choose(m, degree) for degree in range(max_degree + 1)) estimated_time = process_time * inputs * errors print("Estimated time eof_p: ", estimated_time) polinomial = [Fraction(0, 1)] * (m + 1) sch_process = d.make_process_func(sch) for input_values in product(range(2), repeat=n): if debug: print(input_values) for degree in range(max_degree): for error_comb in combinations(range(m), degree): error_vec = [0] * m for i in error_comb: error_vec[i] = 1 if sch_process(input_values, error_vec) != sch_process(input_values, nonerror): for i in range(degree, m + 1): polinomial[i] += choose(m - degree, i - degree) * (-1) ** (i - degree) polinomial = [coeff / 2 ** n for coeff in polinomial] for degree in range(max_degree, m + 1): for i in range(degree, m + 1): polinomial[i] += choose(m, degree) * choose(m - degree, i - degree) * (-1) ** (i - degree) return polinomial
def correlation_multiout(sch1, sch2): # compares correlation between two circuits (0% - 100%) if sch1.inputs() != sch2.inputs(): return False if sch1.outputs() != sch2.outputs(): return False correl = 0 capacity = min(32, 2 ** sch1.inputs()) mask = 2 ** capacity - 1 sch1_func = d.make_process_func(sch1, capacity=capacity) sch2_func = d.make_process_func(sch2, capacity=capacity) n = sch1.inputs() for i in inputs_combinations(sch1.inputs(), capacity=capacity): output = (mask ^ out1 ^ out2 for out1, out2 in zip(sch1_func(i), sch2_func(i))) correl += sum(map(ones, output)) correl /= 2 ** n * sch1.outputs() return correl
def max_transition_table_p(sch, indexes=None, max_degree=None, debug=False): """ :param sch: Input scheme. :param indexes: Indexes of scheme outputs. :return: Table of probabilities (k coefficient in k*p + O(p)) of transition form one output combination to another. """ n = sch.inputs() l = sch.elements() m = sch.outputs() if indexes is None: ttable_size = 2 ** sch.outputs() indexes = range(m) else: ttable_size = 2 ** len(indexes) if max_degree is None or max_degree > l: max_degree = l ttable = [[[0 for i in range(l + 1)] for x in range(ttable_size)] for x in range(ttable_size)] nonerror = [0] * l tests = 2 ** n errors = 2 ** l sch_process = d.make_process_func(sch) start = time.time() counter = 0 while time.time() - start < 5: output_true = sch_process((0,) * n, (0,) * l) vec2num(output_true) vec2num(output_true) counter += 1 process_time = (time.time() - start) / counter inputs = 2 ** n errors = sum(choose(l, degree) for degree in range(max_degree + 1)) estimated_time = process_time * inputs * errors print("Estimated time: ", estimated_time) for input_values in product(range(2), repeat=n): if debug: print(input_values) output_true = sch_process(input_values, nonerror) if len(indexes) < m: output_true = [output_true[index] for index in indexes] for degree in range(max_degree): for error_comb in combinations(range(l), degree): error_vec = [0] * l for i in error_comb: error_vec[i] = 1 if len(indexes) < m: output_error = [sch_process(input_values, error_vec)[index] for index in indexes] else: output_error = sch_process(input_values, error_vec) true_index = vec2num(output_true) error_index = vec2num(output_error) for i in range(degree, max_degree + 1): ttable[true_index][error_index][i] += ( choose(l - degree, i - degree) * (-1) ** (i - degree) / (2 ** n) ) for degree in range(max_degree, l + 1): pass return ttable
def eof_p_interval(sch, max_degree=None, debug=False, max_tests=None): """ :param sch: Input scheme. :param max_degree: Max degree of result polinomial. :param debug: If True debug information will be printed due to process. :param capacity: Number of bits in used numbers. :param max_tests: Maximum number of tests to process. :return: First max_degree+1 members of polinomial EOF(p) for input scheme. """ tests_performed = 0 n = sch.inputs() m = sch.elements() sch_process = d.make_process_func(sch) nonerror = (0,) * m min_polynomial = [Fraction(0, 1)] * (m + 1) max_polynomial = [Fraction(1, 1)] + [Fraction(0, 1)] * m if max_degree is None: max_degree = m if max_tests is None or max_tests >= 2 ** (n + m): max_tests = 2 ** (n + m) def inputs_generator(rand=False): if rand: return product(*[random.choice(((0, 1), (1, 0))) for _ in range(n)]) else: return product((0, 1), repeat=n) def make_errors_vector(indexes): errors_vector = [0] * m for index in indexes: errors_vector[index] = 1 return tuple(errors_vector) def errors_generator(degree, rand=False): if rand: return ( make_errors_vector(indexes=combination) for combination in combinations(random.sample(list(range(m)), m), r=degree) ) else: return (make_errors_vector(indexes=combination) for combination in combinations(list(range(m)), r=degree)) def update_polynomials(successes, fails, degree): for i in range(m + 1 - degree): min_polynomial[i + degree] += Fraction((-1) ** i * choose(m - degree, i) * fails, 2 ** n) max_polynomial[i + degree] -= Fraction((-1) ** i * choose(m - degree, i) * successes, 2 ** n) for degree in range(max_degree + 1): tests_remained = max_tests - tests_performed if debug: print(max_tests, tests_remained) rand = tests_remained < choose(m, degree) * 2 ** n errors_number = choose(m, degree) if rand: inputs_number = max(1, min(int(tests_remained / errors_number), 2 ** n)) else: inputs_number = 2 ** n total_fails = 0 total_successes = 0 for errors in errors_generator(degree, rand): if not tests_remained: return min_polynomial, max_polynomial inputs_number = min(inputs_number, tests_remained) fails = sum( sch_process(inputs, errors) != sch_process(inputs) for inputs in islice(inputs_generator(rand), inputs_number) ) successes = inputs_number - fails total_fails += fails total_successes += successes tests_remained -= inputs_number tests_performed += inputs_number update_polynomials(total_successes, total_fails, degree) return min_polynomial, max_polynomial
def eof_p_opt(sch, max_degree=None, debug=False, capacity=None): """ :param sch: Input scheme. :param max_degree: Max degree of result polinomial. :param debug: If True debug information will be printed due to process. :return: First max_degree+1 members of polinomial EOF(p) for input scheme. """ n = sch.inputs() m = sch.elements() if capacity is None: capacity = min([2 ** sch.inputs(), 32]) nonerror = (0,) * m if max_degree is None: max_degree = m sch_process = d.make_process_func(sch, capacity=capacity) if debug: start = time.time() counter = 0 while time.time() - start < 1: output_true = sch_process((0,) * n, (0,) * m) vec2num(output_true) vec2num(output_true) counter += 1 process_time = (time.time() - start) / counter inputs = 2 ** n / capacity errors = sum(choose(m, degree) for degree in range(max_degree + 1)) estimated_time = process_time * inputs * errors print("Estimated time eof_p: ", estimated_time) poly = Polynomial([Fraction(0, 1)]) input_prob = Fraction(1, 2 ** n) p = Polynomial([Fraction(0, 1), Fraction(1, 1)]) sum_poly = Polynomial([Fraction(0, 1)]) for input_values in inputs_combinations(n, capacity=capacity): output_true = sch_process(input_values, nonerror) if debug: print(input_values) for degree in range(max_degree + 1): error_prob = Polynomial(polypow(p.coef, degree, maxpower=100)) * Polynomial( polypow((1 - p).coef, m - degree, maxpower=100) ) # print(error_prob.coef) errors_number = 0 if debug: print(len(list(combinations(range(m), r=degree)))) for error_comb in combinations(range(m), r=degree): error_vec = [0] * m for i in error_comb: error_vec[i] = 2 ** capacity - 1 output_error = sch_process(input_values, error_vec) errors = [i ^ j for i, j in zip(output_true, output_error)] errors_number += ones(reduce(or_, errors)) if debug: print(errors_number) if errors_number: poly += errors_number * input_prob * error_prob result = list(poly.coef) # removing trailing zeros while not result[-1]: result.pop() return result