Example #1
0
 def __init__(self, store_clauses=True, store_comments=False):
     Cadical.__init__(self)
     self.__var = 1
     self.__dbg_clauses = []
     self.__dbg_comments = {}
     self.num_clauses = 0
     self.store_clauses = store_clauses
     self.store_comments = store_comments
Example #2
0
 def add_clause(self, clause, no_return=True):
     assert (max(map(abs, clause)) < self.__var)
     if self.store_clauses:
         self.__dbg_clauses.append(clause)
     self.num_clauses += 1
     cl = clause.copy()
     if self.clock_act is not None: cl.append(-self.clock_act)
     Cadical.add_clause(self, cl, no_return)
Example #3
0
def calc_avg_sensitivity(model, n=100):
    solver = Cadical(bootstrap_with=model['clauses'])
    s = 0
    for i in range(n):
        input_vals = [
            model['net_map'][inp] * sample([-1, 1], 1)[0]
            for inp in model['inputs']
        ]
        solver.solve(assumptions=input_vals)
        m = solver.get_model()
        s += sum(
            [m[model['net_map'][o] - 1] < 0
             for o in model['flip_outputs']]) / len(model['inputs'])

    model['avg_sensitivity'] = s / n
Example #4
0
def construct_solver(c, assumptions=None, engine="cadical"):
    """
    Constructs a SAT solver instance with the given circuit and assumptions

    Parameters
    ----------
    c : Circuit
            circuit to encode
    assumptions : dict of str:int
            Assumptions to add to solver

    Returns
    -------
    solver : pysat.Cadical
            SAT solver instance
    variables : pysat.IDPool
            solver variable mapping
    """
    formula, variables = cnf(c)
    if assumptions:
        for n in assumptions.keys():
            if n not in c:
                raise ValueError(f"incorrect assumption key: {n}")
        add_assumptions(formula, variables, assumptions)

    if engine == "cadical":
        solver = Cadical(bootstrap_with=formula)
    elif engine == "glucose":
        solver = Glucose4(bootstrap_with=formula, incr=True)
    elif engine == "lingeling":
        solver = Lingeling(bootstrap_with=formula)
    else:
        raise ValueError(f"unsupported solver: {engine}")
    return solver, variables
Example #5
0
def calc_sensitivity(model):
    n_eq = 0
    it = ITotalizer(lits=[model['net_map'][n] for n in model['flip_outputs']],
                    top_id=len(model['net_map']),
                    ubound=len(model['inputs']))
    solver = Cadical(bootstrap_with=model['clauses'] + it.cnf.clauses)
    while True:
        if solver.solve(assumptions=[-it.rhs[n_eq]]):
            break
        else:
            n_eq += 1

        if n_eq == len(model['inputs']):
            print('0 sensitivity reached')
            exit()

    model['sensitivity'] = (len(model['inputs']) - n_eq) / len(model['inputs'])
Example #6
0
def checkModelQBF(clauses, universals, existentials, assumptions=[]):
    assumptions_set = set(assumptions)

    clauses_reduced = [
        reduceClause(clause, assumptions_set) for clause in clauses
        if not set(clause).intersection(assumptions_set)
    ]
    logging.debug(
        "Model encoding under assumptions: {}".format(clauses_reduced))
    variables = {abs(l) for clause in clauses_reduced for l in clause}
    assert variables <= set(universals).union(existentials), "free variables"

    result, certificate = solve2QBF(clauses_reduced, universals, existentials)
    if not result:
        logging.debug("CADET UNSAT certificate: {}".format(certificate))
        solver = Cadical(bootstrap_with=clauses_reduced)
        assert not solver.solve(certificate), "Certification of UNSAT failed."
    return result, certificate
Example #7
0
def optimal_comb(api: GBD, args):
    result = api.query_search(args.query, [], args.runtimes)
    result = [[
        int(float(val)) if is_number(val) and float(val) < float(args.tlim)
        else int(2 * args.tlim) for val in row[1:]
    ] for row in result]

    cnf = dimacs.DIMACSPrinter()
    _ACT = [cnf.create_literal() for _ in range(0, len(args.runtimes))]
    _MAX = get_bitvector(cnf, int(pow(2, _BW - 1) - 1))
    for c in encode_at_most_k_constraint_ltseq(cnf, args.size, _ACT):
        cnf.consume_clause(c)

    # encode row-wise minima
    MINS = []
    for row in result:
        i = 0
        B0_ = get_bitvector(cnf, int(row[0]))
        B0 = if_then_else(cnf, B0_, _MAX, _ACT[i])
        for rt in row[1:]:
            i = i + 1
            B1_ = get_bitvector(cnf, int(rt))
            B1 = if_then_else(cnf, B1_, _MAX, _ACT[i])
            Bcarry = get_carry_bits(cnf, B1, [-i for i in B0])
            Bmin = if_then_else(cnf, B0, B1, Bcarry[_BW - 1])
            B0 = Bmin
        MINS.append(B0)  # B0 is now minimum of row

    # encode sum of minima
    A = MINS[0]
    for B in MINS[1:]:
        SUM = get_sum_bits(cnf, A, B)
        A = SUM

    solver = Cadical(bootstrap_with=cnf.clauses, with_proof=False)
    result = solver.solve()
    if result == True:
        model = solver.get_model()
        print(slice_model(model, _ACT))
        print(decode_bitvector(slice_model(model, A)))
Example #8
0
def construct_solver(c, assumptions=None):
    """
    Constructs a SAT solver instance with the given circuit and assumptions

    Parameters
    ----------
    c : Circuit
            circuit to encode
    assumptions : dict of str:int
            Assumptions to add to solver

    Returns
    -------
    solver : pysat.Cadical
            SAT solver instance
    variables : pysat.IDPool
            solver variable mapping
    """
    formula, variables = cnf(c)
    if assumptions:
        add_assumptions(formula, variables, assumptions)
    solver = Cadical(bootstrap_with=formula)
    return solver, variables
Example #9
0
def checkModel(universals_variables, dependency_dict, matrix,model,model_clauses,check_defined,check_consistency,check_dependencies,use_extended_dependencies) :
  """
  Checks if the canditate-model given by <filename_model> certifies the trueness
  of the DQBF given by <filename_formula>.
  
  Parameters
  ----------
  universals_variables : List
      The universal variables appearing in the formula.
  dependency_dict : Dictionary
      Maps each existential variable to its dependencies.
  matrix : List
      The matrix of the formula of interest.
  model : Dictionary
      Maps each existential variable to a list of clauses (the clausal representation of the model for the variable)
  model_clauses : List
      Contains all clauses appearing in some model.
  check_defined : bool
      If true, check if each existential variable has a definition.
  check_consistency : bool
      If true check for each existential variable if the model clauses are consistent.
  check_dependencies : bool
      If true check if the model clauses only use variables according to the dependencies.
  use_extended_dependencies : bool
      If true extended dependencies are used for the depdendency check. The extended dependencies
      consist of the "normal" dependencies plus the existential variables whose dependencies are contained.
  Returns
  -------
  True, if the given candidate-model passes all checks.

  """
  existential_variables = list(dependency_dict) 
  if check_dependencies :
    if use_extended_dependencies:
      dependencies=computeExtendedDependencies(dependency_dict)
    else:
      dependencies=dependency_dict
    variables_to_consider=universals_variables + existential_variables
    for e in existential_variables:
      if e in model:
        #The candidate-model may contain additional variables as those contained in the matrix.
        #Thus the check shall pass if additional variables occur in the candidate-model --
        #as long as those variables do not occur in the matrix
        variablesOK, false_variables = check_occuring_variables(model[e],variables_to_consider,dependencies[e]+[e])
        if not variablesOK:
          print("The given model for variable {0} contains the invalid variables: {1}.".format(e,false_variables))
          return False 
  #Additional sanity check. If the candidate-model is UNSAT it is necessarily inconsistent.
  #Thus it does not certify that the given DQBF is true.
  model_checker = Cadical(bootstrap_with=model_clauses)
  if not model_checker.solve() :
    print("Model inconsistent")
    return False
  if check_consistency :
    consistent = consistency_checker(model_clauses,universals_variables,existential_variables)
    if not consistent :
      print("Model inconsistent")
      # print("Certificate: {}".format(certificate))
      return False  
  if check_defined:
    definability_checker = DefinabilityChecker(model_clauses, existential_variables)
    for e in existential_variables :
      depends_on = dependencies[e]
      is_defined, counterexample = definability_checker.checkDefinability(depends_on, e)
      if not is_defined:
        print("The model does not uniquely define variable: {}".format(e))
        return False                                                     
  model_ok = check_matrix(model_checker,matrix)
  if model_ok:
    return True
  else:
    model = model_checker.get_model()
    print("Universal assignment: {}".format([l for l in model if abs(l) in universals_variables]))
    print("Existential assignment: {}".format([l for l in model if abs(l) in existential_variables]))

    auxiliary_variables_in_model={abs(l) for clause in model_clauses for l in clause 
      if (not abs(l) in set(universals_variables)) and (not abs(l) in set(existential_variables))}
    print("Auxiliary assignment: {}".format([l for l in model if abs(l) in auxiliary_variables_in_model]))
  return model_ok
def lebl(c, bw, ng):
    """
    Locks a circuitgraph with Logic-Enhanced Banyan Locking as outlined in
    Joseph Sweeney, Marijn J.H. Heule, and Lawrence Pileggi
    Modeling Techniques for Logic Locking. In Proceedings
    of the International Conference on Computer Aided Design 2020 (ICCAD-39).

    Parameters
    ----------
    circuit: circuitgraph.CircuitGraph
            Circuit to lock.
    bw: int
            Width of Banyan network.
    lw: int
            Minimum number of gates mapped to network.

    Returns
    -------
    circuitgraph.CircuitGraph, dict of str:bool
            the locked circuit and the correct key value for each key input
    """
    # create copy to lock
    cl = cg.copy(c)

    # generate switch and mux
    s = cg.Circuit(name='switch')
    m2 = cg.strip_io(logic.mux(2))
    s.extend(cg.relabel(m2, {n: f'm2_0_{n}' for n in m2.nodes()}))
    s.extend(cg.relabel(m2, {n: f'm2_1_{n}' for n in m2.nodes()}))
    m4 = cg.strip_io(logic.mux(4))
    s.extend(cg.relabel(m4, {n: f'm4_0_{n}' for n in m4.nodes()}))
    s.extend(cg.relabel(m4, {n: f'm4_1_{n}' for n in m4.nodes()}))
    s.add('in_0', 'buf', fanout=['m2_0_in_0', 'm2_1_in_1'])
    s.add('in_1', 'buf', fanout=['m2_0_in_1', 'm2_1_in_0'])
    s.add('out_0', 'buf', fanin='m4_0_out')
    s.add('out_1', 'buf', fanin='m4_1_out')
    s.add('key_0', 'input', fanout=['m2_0_sel_0', 'm2_1_sel_0'])
    s.add('key_1', 'input', fanout=['m4_0_sel_0', 'm4_1_sel_0'])
    s.add('key_2', 'input', fanout=['m4_0_sel_1', 'm4_1_sel_1'])

    # generate banyan
    I = int(2 * cg.clog2(bw) - 2)
    J = int(bw / 2)

    # add switches and muxes
    for i in range(I * J):
        cl.extend(cg.relabel(s, {n: f'swb_{i}_{n}' for n in s}))

    # make connections
    swb_ins = [f'swb_{i//2}_in_{i%2}' for i in range(I * J * 2)]
    swb_outs = [f'swb_{i//2}_out_{i%2}' for i in range(I * J * 2)]
    connect_banyan(cl, swb_ins, swb_outs, bw)

    # get banyan io
    net_ins = swb_ins[:bw]
    net_outs = swb_outs[-bw:]

    # generate key
    key = {
        f'swb_{i//3}_key_{i%3}': choice([True, False])
        for i in range(3 * I * J)
    }

    # generate connections between banyan nodes
    bfi = {n: set() for n in swb_outs + net_ins}
    bfo = {n: set() for n in swb_outs + net_ins}
    for n in swb_outs + net_ins:
        if cl.fanout(n):
            fo_node = cl.fanout(n).pop()
            swb_i = fo_node.split('_')[1]
            bfi[f'swb_{swb_i}_out_0'].add(n)
            bfi[f'swb_{swb_i}_out_1'].add(n)
            bfo[n].add(f'swb_{swb_i}_out_0')
            bfo[n].add(f'swb_{swb_i}_out_1')

    # find a mapping of circuit onto banyan
    net_map = IDPool()
    for bn in swb_outs + net_ins:
        for cn in c:
            net_map.id(f'm_{bn}_{cn}')

    # mapping implications
    clauses = []
    for bn in swb_outs + net_ins:
        # fanin
        if bfi[bn]:
            for cn in c:
                if c.fanin(cn):
                    for fcn in c.fanin(cn):
                        clause = [-net_map.id(f'm_{bn}_{cn}')]
                        clause += [
                            net_map.id(f'm_{fbn}_{fcn}') for fbn in bfi[bn]
                        ]
                        clause += [
                            net_map.id(f'm_{fbn}_{cn}') for fbn in bfi[bn]
                        ]
                        clauses.append(clause)
                else:
                    clause = [-net_map.id(f'm_{bn}_{cn}')]
                    clause += [net_map.id(f'm_{fbn}_{cn}') for fbn in bfi[bn]]
                    clauses.append(clause)

        # fanout
        if bfo[bn]:
            for cn in c:
                clause = [-net_map.id(f'm_{bn}_{cn}')]
                clause += [net_map.id(f'm_{fbn}_{cn}') for fbn in bfo[bn]]
                for fcn in c.fanout(cn):
                    clause += [net_map.id(f'm_{fbn}_{fcn}') for fbn in bfo[bn]]
                clauses.append(clause)

    # no feed through
    for cn in c:
        net_map.id(f'INPUT_OR_{cn}')
        net_map.id(f'OUTPUT_OR_{cn}')
        clauses.append([-net_map.id(f'INPUT_OR_{cn}')] +
                       [net_map.id(f'm_{bn}_{cn}') for bn in net_ins])
        clauses.append([-net_map.id(f'OUTPUT_OR_{cn}')] +
                       [net_map.id(f'm_{bn}_{cn}') for bn in net_outs])
        for bn in net_ins:
            clauses.append(
                [net_map.id(f'INPUT_OR_{cn}'), -net_map.id(f'm_{bn}_{cn}')])
        for bn in net_outs:
            clauses.append(
                [net_map.id(f'OUTPUT_OR_{cn}'), -net_map.id(f'm_{bn}_{cn}')])
        clauses.append(
            [-net_map.id(f'OUTPUT_OR_{cn}'), -net_map.id(f'INPUT_OR_{cn}')])

    # at least ngates
    for bn in swb_outs + net_ins:
        net_map.id(f'NGATES_OR_{bn}')
        clauses.append([-net_map.id(f'NGATES_OR_{bn}')] +
                       [net_map.id(f'm_{bn}_{cn}') for cn in c])
        for cn in c:
            clauses.append(
                [net_map.id(f'NGATES_OR_{bn}'), -net_map.id(f'm_{bn}_{cn}')])
    clauses += CardEnc.atleast(
        bound=ng,
        lits=[net_map.id(f'NGATES_OR_{bn}') for bn in swb_outs + net_ins],
        vpool=net_map).clauses

    # at most one mapping per out
    for bn in swb_outs + net_ins:
        clauses += CardEnc.atmost(lits=[
            net_map.id(f'm_{bn}_{cn}') for cn in c
        ],
                                  vpool=net_map).clauses

    # limit number of times a gate is mapped to net outputs to fanout of gate
    for cn in c:
        lits = [net_map.id(f'm_{bn}_{cn}') for bn in net_outs]
        bound = len(c.fanout(cn))
        if len(lits) < bound: continue
        clauses += CardEnc.atmost(bound=bound, lits=lits,
                                  vpool=net_map).clauses

    # prohibit outputs from net
    for bn in swb_outs + net_ins:
        for cn in c.outputs():
            clauses += [[-net_map.id(f'm_{bn}_{cn}')]]

    # solve
    solver = Cadical(bootstrap_with=clauses)
    if not solver.solve():
        print(f'no config for width: {bw}')
        core = solver.get_core()
        print(core)
        code.interact(local=dict(globals(), **locals()))
    model = solver.get_model()

    # get mapping
    mapping = {}
    for bn in swb_outs + net_ins:
        selected_gates = [
            cn for cn in c if model[net_map.id(f'm_{bn}_{cn}') - 1] > 0
        ]
        if len(selected_gates) > 1:
            print(f'multiple gates mapped to: {bn}')
            code.interact(local=dict(globals(), **locals()))
        mapping[bn] = selected_gates[0] if selected_gates else None

    potential_net_fanins = list(c.nodes() -
                                (c.endpoints() | set(mapping.values())
                                 | mapping.keys() | c.startpoints()))

    # connect net inputs
    for bn in net_ins:
        if mapping[bn]:
            cl.connect(mapping[bn], bn)
        else:
            cl.connect(choice(potential_net_fanins), bn)
    mapping.update({cl.fanin(bn).pop(): cl.fanin(bn).pop() for bn in net_ins})
    potential_net_fanouts = list(c.nodes() -
                                 (c.startpoints() | set(mapping.values())
                                  | mapping.keys() | c.endpoints()))

    #selected_fo = {}

    # connect switch boxes
    for i, bn in enumerate(swb_outs):
        # get keys
        if key[f'swb_{i//2}_key_1'] and key[f'swb_{i//2}_key_2']:
            k = 3
        elif not key[f'swb_{i//2}_key_1'] and key[f'swb_{i//2}_key_2']:
            k = 2
        elif key[f'swb_{i//2}_key_1'] and not key[f'swb_{i//2}_key_2']:
            k = 1
        elif not key[f'swb_{i//2}_key_1'] and not key[f'swb_{i//2}_key_2']:
            k = 0
        switch_key = 1 if key[f'swb_{i//2}_key_0'] == 1 else 0

        mux_input = f'swb_{i//2}_m4_{i%2}_in_{k}'

        # connect inner nodes
        mux_gate_types = set()

        # constant output, hookup to a node that is already in the affected outputs fanin, not in others
        if not mapping[bn] and bn in net_outs:
            decoy_fanout_gate = choice(potential_net_fanouts)
            #selected_fo[bn] = decoy_fanout_gate
            cl.connect(bn, decoy_fanout_gate)
            if cl.type(decoy_fanout_gate) in ['and', 'nand']:
                cl.set_type(mux_input, '1')
            elif cl.type(decoy_fanout_gate) in ['or', 'nor', 'xor', 'xnor']:
                cl.set_type(mux_input, '0')
            elif cl.type(decoy_fanout_gate) in ['buf']:
                if randint(0, 1):
                    cl.set_type(mux_input, '1')
                    cl.set_type(decoy_fanout_gate, choice(['and', 'xnor']))
                else:
                    cl.set_type(mux_input, '0')
                    cl.set_type(decoy_fanout_gate, choice(['or', 'xor']))
            elif cl.type(decoy_fanout_gate) in ['not']:
                if randint(0, 1):
                    cl.set_type(mux_input, '1')
                    cl.set_type(decoy_fanout_gate, choice(['nand', 'xor']))
                else:
                    cl.set_type(mux_input, '0')
                    cl.set_type(decoy_fanout_gate, choice(['nor', 'xnor']))
            elif cl.type(decoy_fanout_gate) in ['0', '1']:
                cl.set_type(mux_input, cl.type(decoy_fanout_gate))
                cl.set_type(decoy_fanout_gate, 'buf')
            else:
                print('gate error')
                code.interact(local=dict(globals(), **locals()))
            mux_gate_types.add(cl.type(mux_input))

        # feedthrough
        elif mapping[bn] in [mapping[fbn] for fbn in bfi[bn]]:
            cl.set_type(mux_input, 'buf')
            mux_gate_types.add('buf')
            if mapping[cl.fanin(f'swb_{i//2}_in_0').pop()] == mapping[bn]:
                cl.connect(f'swb_{i//2}_m2_{switch_key}_out', mux_input)
            else:
                cl.connect(f'swb_{i//2}_m2_{1-switch_key}_out', mux_input)

        # gate
        elif mapping[bn]:
            cl.set_type(mux_input, cl.type(mapping[bn]))
            mux_gate_types.add(cl.type(mapping[bn]))
            gfi = cl.fanin(mapping[bn])
            if mapping[cl.fanin(f'swb_{i//2}_in_0').pop()] in gfi:
                cl.connect(f'swb_{i//2}_m2_{switch_key}_out', mux_input)
                gfi.remove(mapping[cl.fanin(f'swb_{i//2}_in_0').pop()])
            if mapping[cl.fanin(f'swb_{i//2}_in_1').pop()] in gfi:
                cl.connect(f'swb_{i//2}_m2_{1-switch_key}_out', mux_input)

        # mapped to None, any key works
        else:
            k = None

        # fill out random gates
        for j in range(4):
            if j != k:
                t = sample(
                    set([
                        'buf', 'or', 'nor', 'and', 'nand', 'not', 'xor',
                        'xnor', '0', '1'
                    ]) - mux_gate_types, 1)[0]
                mux_gate_types.add(t)
                mux_input = f'swb_{i//2}_m4_{i%2}_in_{j}'
                cl.set_type(mux_input, t)
                if t == 'not' or t == 'buf':
                    # pick a random fanin
                    cl.connect(f'swb_{i//2}_m2_{randint(0,1)}_out', mux_input)
                elif t == '1' or t == '0':
                    pass
                else:
                    cl.connect(f'swb_{i//2}_m2_0_out', mux_input)
                    cl.connect(f'swb_{i//2}_m2_1_out', mux_input)
        if [
                n for n in cl
                if cl.type(n) in ['buf', 'not'] and len(cl.fanin(n)) > 1
        ]:
            import code
            code.interact(local=dict(globals(), **locals()))

    # connect outputs non constant outs
    rev_mapping = {}
    for bn in net_outs:
        if mapping[bn]:
            if mapping[bn] not in rev_mapping:
                rev_mapping[mapping[bn]] = set()
            rev_mapping[mapping[bn]].add(bn)

    for cn in rev_mapping.keys():
        #for fcn in cl.fanout(cn):
        #    cl.connect(sample(rev_mapping[cn],1)[0],fcn)
        for fcn, bn in zip_longest(cl.fanout(cn),
                                   rev_mapping[cn],
                                   fillvalue=list(rev_mapping[cn])[0]):
            cl.connect(bn, fcn)

    # delete mapped gates
    deleted = True
    while deleted:
        deleted = False
        for n in cl.nodes():
            # node and all fanout are in the net
            if n not in mapping and n in mapping.values():
                if all(s not in mapping and s in mapping.values()
                       for s in cl.fanout(n)):
                    cl.remove(n)
                    deleted = True
            # node in net fanout
            if n in [mapping[o] for o in net_outs] and n in cl:
                cl.remove(n)
                deleted = True
    cg.lint(cl)
    return cl, key
 def test_as_DIMACS_CNF(self):
     for index, g in enumerate(self.games):
         cond = g.get_cnf_solution()
         solver = Cadical(CNF(from_string=as_DIMACS_CNF(cond)))
         self.assertTrue(solver.solve())
 def test_condition_three_clauses(self):
     for index, g in enumerate(self.games):
         cond = g.condition_three_clauses()
         solver = Cadical(CNF(from_string=as_DIMACS_CNF(cond)))
         self.assertTrue(solver.solve())
 def test_condition_one_clauses(self):
     for index, g in enumerate(self.games):
         cond = g.condition_one_clauses()
         self.assertLessEqual(len(cond), 8 * g.capacity)
         solver = Cadical(CNF(from_string=as_DIMACS_CNF(cond)))
         self.assertTrue(solver.solve())
Example #14
0
def analyse_sat_solvers(games: [GameEncoder], show_png=False):
    from timeit import default_timer as timer
    from pysat.solvers import Cadical, Glucose4, Lingeling, Minisat22, Maplesat
    df = pd.DataFrame(columns=["Solver", "Execution time [sec]", "Algorithm"])
    for g in games:
        cnf_ = CNF(from_string=as_DIMACS_CNF(g.get_cnf_solution()))
        solvers = {
            "Cadical": Cadical(cnf_),
            "Glucose4": Glucose4(cnf_),
            "Lingeling": Lingeling(cnf_),
            "Minisat22": Minisat22(cnf_),
            "Maplesat": Maplesat(cnf_)
        }
        for name, solver in solvers.items():
            start = timer()
            solved = solver.solve()
            end = timer()
            delta_t = end - start
            print(name, "\tSolved:", solved, "\tTime:", delta_t)
            df = df.append(
                {
                    "Solver": name,
                    "Execution time [sec]": delta_t,
                    "Algorithm": g.algo_name
                },
                ignore_index=True)
    df.to_csv("data\\solver_analysis.csv", index=False)
    print("Saved data-frame as csv.")
    plt.yscale('log')
    sns.barplot(x="Solver", y="Execution time [sec]", hue="Algorithm", data=df)
    plt.savefig("data\\solver_performance_analysis.png")
    if show_png:
        print("Plotting graph...")
        plt.show()

    class EncodingPerformanceAnalysis:
        def __init__(self, efficient=True):
            print(
                f"EFFICIENT={efficient}: Creating and solving multiple games, this might take a while..."
            )
            paths = glob.glob("tent-inputs\\*.txt")
            self.efficient = efficient
            self.games = [
                GameEncoderBinomial.from_text_file(path,
                                                   efficient=self.efficient,
                                                   verbose=False)
                for path in paths
            ]
            self.games_cnf = [g.get_cnf_solution() for g in self.games]

        def store_metrics(self):
            df = pd.DataFrame(columns=[
                "Field-size", "Literals", "Variables", "Clauses", "Algorithm"
            ])
            for index, cnf in enumerate(self.games_cnf):
                game_size = self.games[index].capacity
                clauses_n = len(cnf)
                literals = list(chain(*cnf))
                variables = set(abs(x) for x in literals)
                df = df.append(
                    {
                        "Algorithm":
                        "Efficient" if self.efficient else "Simple",
                        "Clauses": clauses_n,
                        "Field-size": game_size,
                        "Literals": len(literals),
                        "Variables": len(variables)
                    },
                    ignore_index=True)
            df.Capacity = df.Capacity.astype(int)
            df.Literals = df.Literals.astype(int)
            df.Variables = df.Variables.astype(int)
            time_id = datetime.datetime.now().strftime('%m-%d_%H-%M-%S')
            df.to_csv(f"data\\encoding_performance_analysis_{time_id}.csv",
                      index=False)
            print("Saved data-frame as csv.")
Example #15
0
 def get_solution(conditions):
     cnf_string = as_DIMACS_CNF(conditions)
     solver = Cadical(CNF(from_string=cnf_string))
     solved, solution = solver.solve(), solver.get_model()
     return solved, solution
Example #16
0
def solve_instance(cnf):
    with Cadical(CNF(from_file=cnf), use_timer=True) as solver:
        ans = solver.solve()
        return cnf.stem, ans, solver.status, solver.get_model(
        ), solver.get_core(), solver.nof_vars(), solver.time()
Example #17
0
        c.add_edge(inp_con, f'flip_{inp}_{inp_con}')

    # add output xnor
    c.add_node(f'flip_{inp}_output_xnor', gate='xnor')
    c.add_edge(f'flip_{inp}_out', f'flip_{inp}_output_xnor')
    c.add_edge('out', f'flip_{inp}_output_xnor')
    flip_outputs.append(f'flip_{inp}_output_xnor')

# get dimacs
clauses, net_map = gates2dimacs(c)

# encode sensitivity value
it = ITotalizer(lits=[net_map[n] for n in flip_outputs],
                top_id=len(net_map),
                ubound=len(protected_inputs))
solver = Cadical(bootstrap_with=clauses + it.cnf.clauses)

# find max sensitivity input, check
n_eq = 0
while n_eq < len(protected_inputs):
    if solver.solve(assumptions=[-it.rhs[n_eq]]):
        # get input output
        m = solver.get_model()
        inp = {i: m[net_map[i] - 1] > 0 for i in protected_inputs}
        s = (len(protected_inputs) - n_eq) / len(protected_inputs)
        print(f'found input w/ sensitivity {s}')

        # check input against key
        if all(inp[f'protected_in_{i}_'] == k for i, k in enumerate(key)):
            sensitivity = (len(protected_inputs) -
                           n_eq) / len(protected_inputs)
Example #18
0
 def add_clause(self, clause, no_return=True):
     assert (max(map(abs, clause)) < self.__var)
     if self.store_clauses:
         self.__dbg_clauses.append(clause)
     self.num_clauses += 1
     Cadical.add_clause(self, clause, no_return)