def check_overall_TMR(in_circ_file):
    main_circuit_etalon = sa.read_scheme(in_circ_file)
    initial_area = get_area(main_circuit_etalon)
    initial_reliability = external_reliability(main_circuit_etalon, 100000)
    tmr_circ = createTMRCirc(main_circuit_etalon)
    new_area = get_area(tmr_circ)
    new_reliability = external_reliability(tmr_circ, 100000)
    print('Initial reliability: {}'.format(initial_reliability))
    print('TMR reliability: {}'.format(new_reliability))
    print('New area: {} Initial Area: {} Growth Percent: {}%'.format(new_area, initial_area, round((100.0*new_area)/initial_area), 2))
def create_circuit_external_yosys (circuit):
    dfile = get_project_directory()
    run_path = os.path.join(dfile, "utils", "bin", "win32", "yosys")
    yosys_exe = os.path.join(run_path, "yosys.exe")
    circuit_file = os.path.join(dfile, "temp", "tmp_sheme_yosys.v")
    run_file = os.path.join(dfile, "temp", "tmp_runfile_yosys.txt")
    synth_file = os.path.join(dfile, "temp", "tmp_synth.v")
    converted_circuit_file = os.path.join(dfile, "temp", "tmp_synth_conv.txt")
    graph_file = os.path.join(dfile, "temp", "synth.svg")
    debug_file = os.path.join(dfile, "temp", "yosys_fail.txt")

    if os.path.isfile(circuit_file):
        os.remove(circuit_file)
    if os.path.isfile(run_file):
        os.remove(run_file)
    if os.path.isfile(synth_file):
        os.remove(synth_file)
    if os.path.isfile(converted_circuit_file):
        os.remove(converted_circuit_file)

    print_circuit_in_verilog_file(circuit, "circ", circuit_file)
    print_run_file(run_file, circuit_file, synth_file, graph_file)

    exe = yosys_exe + " < " + run_file
    try:
        ret = subprocess.check_output(exe, shell=True, cwd=run_path).decode('UTF-8')
    except:
        ret = 'Error'

    if not os.path.isfile(synth_file):
        # Если была проблема с Yosys выводим схему для последующего дебага
        circuit.print_circuit_in_file(debug_file)
        print('Yosys error')
        return None

    convert_file_to_relic_format(circuit, synth_file, converted_circuit_file)
    if os.path.isfile(converted_circuit_file) == False:
        return None
    new_ckt = sa.read_scheme(converted_circuit_file)
    return new_ckt
def improve_circuit_by_resynthesis_ver6(in_circ_file, out_circ_file, needed_replacements, max_area_overhead):
    """
    :param in_circ_file: File with input circuit .
    :param out_circ_file: File to store resulted circuit
    :param needed_replacements: Number of successfull replacemnts
    :param max_area_overhead: koeff for defined maximum area of generated circuit related to initial circuit (from 1.0)
    :return: true or false
    """
    overall_start = timeit.default_timer()
    calc_type = 1
    print("Start processing circuit:")
    main_circuit_etalon = sa.read_scheme(in_circ_file)
    initial_area = get_area(main_circuit_etalon)
    initial_circ_delay = getMaxLevel(main_circuit_etalon)
    main_circuit = sa.read_scheme(in_circ_file)
    (initial_reliability, vulnerability_map) = external_vulnerability_map(main_circuit, MONTE_CARLO_ITER)
    latest_reliability = initial_reliability
    success_replacements_part1 = 0
    success_replacements = 0
    between_replacements = 0
    iterations = 50000

    bestFunction = [0] * 6
    bestFunctionReplace = [0] * 6
    inputOutputTotal = dict()
    inputOutputReplacements = dict()
    replacementLevelIncrease = []

    for zzz in range(1, iterations):
        print("\n|||||||||||||| Iteration "+ zzz.__str__() + " ||||||||||||||")
        # main_circuit = cleanCKTFromBUFs(main_circuit)
        if calc_type == 1:
            rnd1 = get_random_subcircuit_v2(main_circuit, vulnerability_map, random.randint(2,6), 1)
        else:
            rnd1 = get_random_subcircuit(main_circuit, random.randint(2,6), 1)

        if rnd1.inputs() < 2:
            print("Too small subckt")
            continue
        if rnd1.inputs() > 9:
            print("Too big subckt")
            continue
        if rnd1.outputs() > 11:
            print("Too many outputs subckt")
            continue

        if (rnd1.inputs(), rnd1.outputs()) in inputOutputTotal:
            inputOutputTotal[rnd1.inputs(), rnd1.outputs()] += 1
        else:
            inputOutputTotal[rnd1.inputs(), rnd1.outputs()] = 1

        between_replacements += 1
        print("OK subckt [Inputs: {} Outputs: {}]".format(rnd1.inputs(), rnd1.outputs()))
        trtable = create_truth_table(rnd1)
        data = goEspresso_external(trtable, rnd1)

        # Здесь добавляем произвольный набор схем претендентов на замену
        t1 = current_milli_time()
        subckt = []
        subckt.append(createSubckt_method1(data, rnd1))
        subckt.append(createSubckt_method2(data, rnd1))
        subckt.append(createSubckt_method3(data, rnd1))
        yosys_subckt = create_circuit_external_yosys(rnd1)
        if yosys_subckt != None:
            subckt.append(yosys_subckt)
        if 0:
            tmrSubCkt = createTMRCirc(rnd1)
            # Проверяем что троирование не приведет к увеличению схемы сверх указанного
            if (get_area(main_circuit) - get_area(rnd1) + get_area(tmrSubCkt)) < initial_area*max_area_overhead:
                subckt.append(tmrSubCkt)
            else:
                print('TMR SUBCKT skipped due to large area growth')
        t2 = current_milli_time()
        # print('Gen {} subckt OK. Generation time: {}'.format(len(subckt), round((t2-t1)/1000, 3)))

        # Проверяем что все сгенерированные подсхемы работают одинаково
        # Это можно будет убрать после полноценного тестирования
        for s in subckt:
            try:
                cmp = scheme_cmp(rnd1, s)
                if cmp == False:
                    print('Subckt have less inputs. Skip for now')
                    continue
                elif cmp < 0.99999:
                    print('Error with subckt it works incorrect check it')
                    exit(0)
            except:
                print(rnd1)
                print(s)
                main_circuit.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'main_circuit_io_problem.txt'))
                rnd1.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'rnd1_io_problem.txt'))
                s.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'subckt_io_problem.txt'))
                print('Input/output problem')
                exit()
                continue

        # Рассчитываем вероятности комбинаций на входах подсхемы
        iternum = pow(2, rnd1.inputs())*1000
        t1 = current_milli_time()
        distr = distribution_estim_external(main_circuit, rnd1.input_labels(), rnd1.output_labels(), iternum)
        t2 = current_milli_time()
        # print('Distribution Estim C: {} seconds'.format(round((t2-t1)/1000, 3)))
        t1 = current_milli_time()
        subckt_reliability = external_reliability_uneven(rnd1, distr)
        t2 = current_milli_time()
        # print('Reliability uneven: {} seconds'.format(round((t2-t1)/1000, 3)))
        bestval = subckt_reliability + 1000000

        # Из набора подсхем выбираем самую надежную
        t1 = current_milli_time()
        subCKTNum = 0
        bestCKTIndex = 0
        allVals = []
        for s in subckt:
            subCKTNum += 1
            if s.input_labels() != rnd1.input_labels():
                print('Invalid input order in subckt')
                print(s.input_labels())
                print(rnd1.input_labels())
                exit()

            val2 = external_reliability_uneven(s, distr)
            allVals.append(val2)
            if val2 < bestval:
                bestckt = copy.deepcopy(s)
                bestval = val2
                bestCKTIndex = subCKTNum

        bestFunction[bestCKTIndex] += 1
        t2 = current_milli_time()
        # print('Get best CKT {}: {} seconds'.format(bestCKTIndex, round((t2-t1)/1000, 3)))

        print('Array of reliability: {}'.format(allVals))
        if subckt_reliability > bestval + 0.05:
            print("Success (Stage 1) {} > {} (CKT Index {})! =)".format(subckt_reliability, bestval, bestCKTIndex))
            success_replacements_part1 += 1
            t1 = current_milli_time()
            main_circuit_new = replace_subckt_v2(main_circuit, rnd1, bestckt)
            t2 = current_milli_time()
            # print('Replace subckt: {} seconds'.format(round((t2-t1)/1000, 3)))
            t1 = current_milli_time()
            (val_main_circuit_new, vulnerability_new) = external_vulnerability_map(main_circuit_new, MONTE_CARLO_ITER)
            compare_same_logic_for_circuit_monte_carlo(main_circuit, main_circuit_new, 10)
            if latest_reliability > val_main_circuit_new:
                print("Success (Stage 2) {} > {} ! =)".format(latest_reliability, val_main_circuit_new))
                # Заменяем карту уязвимостей
                vulnerability_map = copy.deepcopy(vulnerability_new)
                main_circuit = copy.deepcopy(main_circuit_new)
                latest_reliability = val_main_circuit_new
                cur_area = get_area(main_circuit_new)
                print('New area: {} Initial Area: {} Growth Percent: {}%'.format(cur_area, initial_area, round((100.0*cur_area)/initial_area), 2))
                success_replacements += 1
                between_replacements = 0
                # Статистика по входам выходам замененной подсхемы
                if (rnd1.inputs(), rnd1.outputs()) in inputOutputReplacements:
                    inputOutputReplacements[rnd1.inputs(), rnd1.outputs()] += 1
                else:
                    inputOutputReplacements[rnd1.inputs(), rnd1.outputs()] = 1
                # Сохраняем значение увеличения уровней подсхемы
                levelRnd1 = getMaxLevel(rnd1)
                levelBestCkt = getMaxLevel(bestckt)
                replacementLevelIncrease.append(levelBestCkt/levelRnd1)
                bestFunctionReplace[bestCKTIndex] += 1
            else:
                print("Fail (Stage 2) {} < {} ! =(".format(latest_reliability, val_main_circuit_new))
                # Для тестирования ошибок во внешней проге
                rnd1.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'rnd1.txt'))
                bestckt.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'subckt.txt'))
                main_circuit.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'main_circuit.txt'))
                main_circuit_new.print_circuit_in_file(os.path.join(get_project_directory(), 'temp', 'main_circuit_new.txt'))

            t2 = current_milli_time()
            print('External reliability: {} seconds'.format(round((t2-t1)/1000, 3)))
            if success_replacements >= needed_replacements:
                break
        else:
            print("Fail (Stage 1)! =( " + subckt_reliability.__str__() + " <= " + bestval.__str__())

        # Если за тысячу итераций не было успешных замен выходим
        if between_replacements > 1000:
            break

    endpoint_reliability = external_reliability(main_circuit, MONTE_CARLO_ITER)
    print("Total Iterations : " + zzz.__str__())
    print("Success replacements (P1): " + success_replacements_part1.__str__())
    print("Success replacements (P2): " + success_replacements.__str__())
    if success_replacements_part1 == 0:
        percent = 100
    else:
        percent = round((100*success_replacements)/success_replacements_part1, 2)
    print("Success rate: ", percent.__str__())
    print("Initial  reliability: " + initial_reliability.__str__())
    print("Endpoint reliability: " + endpoint_reliability.__str__())
    print("Initial number of elements: {}".format(initial_area))
    print("Endpoint number of elements: {}".format(get_area(main_circuit)))
    print("Best subckt generators: {}".format(bestFunction))
    overall_end = timeit.default_timer()
    print("Total runtime: {} seconds".format((overall_end - overall_start)))
    main_circuit.print_circuit_in_file(out_circ_file)
    compare_same_logic_for_circuit_monte_carlo(main_circuit_etalon, main_circuit, 1000)
    printInputOutputNumbersInReplaceStats(inputOutputTotal, inputOutputReplacements)
    printLevelIncreaseStat(replacementLevelIncrease)
    print("Best CKT for replace")
    print(bestFunctionReplace)
    resynt_circ_delay = getMaxLevel(main_circuit)
    circ_delay_percent = round((100*resynt_circ_delay)/initial_circ_delay, 2)
    print("Levels in circ. Initial: {}, Resyntesized: {}, Percent: {}".format(initial_circ_delay, resynt_circ_delay, circ_delay_percent))