Example #1
0
def transform(c: Circuit, prefix: str='') -> Cnf:
    '''The function transform takes a Circuit c and returns a Cnf obtained by the
    Tseitin transformation of c. The optional prefix string will be used for
    all variable names in the Cnf.

    '''
    inputs.clear()
    signals.clear()
    solution = Cnf()

    # Filling input dictionary
    for in_str in c.getInputs():
        inputs[in_str] = SatVar(prefix + in_str)

    # Filling signals dictionary (outputs and internal signals)
    for sig_str in c.getSignals():
        signals[sig_str] = SatVar(prefix + sig_str)

    # Obtaining the CNFs for each signal (either intern or output)
    for sig_str in c.getSignals():
        node = c.getEquation(sig_str)
        solution = solution & transform_node(node, signals[sig_str], c)

    return solution
    pass
Example #2
0
def transform(c: Circuit, prefix: str = '') -> Cnf:

    myCnf = Cnf()
    inputs = c.getSignals()

    #On parcourt l'ensemble des inputs pour trouver la transformation Tseitin
    for signal in inputs:
        mySatVar = SatVar(prefix + signal)
        node = c.getEquation(signal)
        child = node.getChildren()

        # Il y a une erreur dans test.py : Did not find value for output signal 's_8' in solution
        # En se rendant dans cra8.crc, on se rend compte qu'il y a une opération d'affection :
        # 	s_8 = x19
        # On crée donc la fonction EQ dans le fichier adder.py qui est simplement
        # une opération d'égalité nécessaire pour passer le test de cra8.crc
        if type(node).__name__ == "Variable":
            SatVarName = SatVar(prefix + node.getName())
            myCnf = myCnf & EQ(SatVarName, mySatVar)

        if type(node).__name__ == "Literal":
            myCnf = LiteralNode(node, mySatVar, myCnf)

        if type(node).__name__ == "BinOp":
            myCnf = BinOpNode(node, mySatVar, myCnf, prefix)

        if type(node).__name__ == "UnOp":
            myCnf = UnOpNode(node, mySatVar, myCnf, prefix)

    return myCnf
Example #3
0
File: ec.py Project: geoffmt/SE206
def check(c1: Circuit, c2: Circuit) -> (bool, Solution):

    numberOutputs_1 = len(c1.getOutputs())

    # Les deux circuits sont incompatibles
    if (c1.getInputs() == c2.getInputs()
            and c1.getOutputs() == c2.getOutputs()) == 0:
        return (False, None)

    # Etape 1 : transformation Tseitin des circuits c1 et c2
    cnf1 = transform(c1, 'c1_')
    cnf2 = transform(c2, 'c2_')

    cnf = cnf1 & cnf2

    output_mitter = SatVar('output_mitter')

    # Etape 2 : On connecte les entrées c1 et c2 grâce à connector_in
    for inputs_1 in c1.getInputs():
        connector_in = SatVar(inputs_1)  #futur lien entre c2 et c1
        c1_in = SatVar('c1_' + str(inputs_1))
        c2_in = SatVar('c2_' + str(inputs_1))
        cnf = cnf & EQ(c1_in, connector_in) & EQ(c2_in, connector_in)

    # Etape 3 : On connecte les sorties aux différents XOR
    connector_out_XOR_TAB = []
    for outputs_1 in c1.getOutputs():
        connector_out = SatVar(outputs_1)
        connector_out_XOR_TAB.append(connector_out)
        c1_out = SatVar('c1_' + str(outputs_1))
        c2_out = SatVar('c2_' + str(outputs_1))
        cnf = cnf & XOR(c1_out, c2_out, connector_out)

    # Etape 4 : On connecte les sorties des XOR à la porte logique OR finale
    if (numberOutputs_1 == 1):
        cnf = cnf & EQ(output_mitter, connector_out_XOR_TAB[0])
    else:
        connector_out_OR_TAB = [SatVar('connector_or' + str(0))]
        cnf = cnf & OR(connector_out_XOR_TAB[0], connector_out_XOR_TAB[1],
                       connector_out_OR_TAB[0])

        for i in range(1, len(connector_out_XOR_TAB) - 2):
            connector_out_OR_TAB.append(SatVar('connector_or' + str(i)))
            cnf = cnf & OR(connector_out_XOR_TAB[i + 1],
                           connector_out_OR_TAB[i - 1],
                           connector_out_OR_TAB[i])

        cnf = cnf & EQ(output_mitter, connector_out_OR_TAB[
            len(connector_out_XOR_TAB) - 3])  # On connecte à la sortie finale

    cnf = cnf & output_mitter

    solution = Solver().solve(cnf)

    if (solution):
        return (False, solution)
    else:
        return (True, None)
Example #4
0
def createInputCnf(inputs: set, prefix1: str, prefix2: str) -> Cnf:
    '''The fucntion createInputCnf takes the common inputs of the circuits being checked,
    taking into account their different prefixes, and builds the input connections required
    by the miter circuit logic. Its output is the cnf representing these connections
    '''
    inputCnf = Cnf()

    for i in inputs:
        inputCnf &= equivalent(SatVar(i), SatVar(prefix1 + i))
        inputCnf &= equivalent(SatVar(i), SatVar(prefix2 + i))

    return inputCnf
Example #5
0
def transform_node(n: Node, out: SatVar, c: Circuit) -> Cnf:
    '''The function transformNode recursively analyses the nodes objects it receives and 
    builds the corresponding CNF. Each step's output is its node's CNF so that the final
    execution has the complete CNF for a given node.
    '''
    cnf = Cnf()

    # Child nodes analysis for operation nodes
    children = []
    for child in n.getChildren():
        if isinstance(child, Literal):
            lit = SatVar('l_' + str(child.getID()))
            children.append(lit)
            if child.getValue() == True:
                cnf &= lit
            else:
                cnf &= ~lit
        elif isinstance(child, Variable):
            if child.getName() in inputs:
                var = inputs[child.getName()]
            elif child.getName() in signals:
                var = signals[child.getName()]
            children.append(var)
        elif isinstance(child, OpNode):
            internal = SatVar('y_' + str(child.getID()))
            children.append(internal)
            cnf &= transform_node(child, internal, c)

    # CNF building
    if isinstance(n, OpNode):
        if len(children) == 1:
            if n.getOp() == '~':
                cnf &= gate_not(children[0], out)
        elif len(children) == 2:
            if n.getOp() == '&':
                cnf &= gate_and(children[0], children[1], out)
            elif n.getOp() == '|':
                cnf &= gate_or(children[0], children[1], out)
            elif n.getOp() == '^':
                cnf &= gate_xor(children[0], children[1], out)
    elif isinstance(n, Variable):
            cnf &= equivalent(signals[n.getName()], out)
    elif isinstance(n, Literal):
            lit = SatVar('l_' + str(n.getID()))
            cnf &= equivalent(lit, out)
            if n.getValue() == True:
                cnf &= lit
            else:
                cnf &= ~lit

    return cnf
Example #6
0
def transform(c: Circuit, prefix: str='') -> Cnf:
    '''The function transform takes a Circuit c and returns a Cnf obtained by the
    Tseitin transformation of c. The optional prefix string will be used for
    all variable names in the Cnf.
    '''

    cnf = Cnf()
    for keys in c.getSignals():
        s = SatVar(prefix+keys)
        node = c.getEquation(keys)

        children = node.getChildren()

        # This case should not really happen in a real circuit.
        if type(node).__name__ == "Variable":
            a = SatVar(prefix+node.getName())
            cnf = cnf & mk_eq(s, a)

        if type(node).__name__ == "Literal":
            if (node.getValue()):
                cnf = cnf & s
            else:
                cnf = cnf & ~s

        if type(node).__name__ == "BinOp":
            a, cnf1 = transform_rec(node.getChild(0), prefix)
            b, cnf2 = transform_rec(node.getChild(1), prefix)
            cnf = cnf & cnf1 & cnf2
            if (node.getOp() == "&"):
                cnf = cnf & mk_and(s, a, b)
            elif (node.getOp() == "^"):
                cnf = cnf & mk_xor(s, a, b)
            elif (node.getOp() == "|"):
                cnf = cnf & mk_or(s, a, b)
            else:
                raise ValueError("Unrecognized operator " + node.getOp())


        if type(node).__name__ == "UnOp":
            a, cnf1 = transform_rec(node.getChild(0), prefix)
            cnf = cnf & cnf1
            if (node.getOp() == "~"):
                cnf = cnf & mk_not(s, a)
            else:
                raise ValueError("Unrecognized operator " + node.getOp())

    return cnf
Example #7
0
def transform_recursive(nd: Node, prefix: str = ''):

    newCnf = Cnf()

    if type(nd).__name__ == "Variable":
        newSatVarName = SatVar(prefix + nd.getName())
        return newSatVarName, newCnf

    newSatVar = SatVar(prefix + str(nd.getID()))
    if type(nd).__name__ == "Literal":
        newCnf = LiteralNode(nd, newSatVar, newCnf)

    if type(nd).__name__ == "BinOp":
        newCnf = BinOpNode(nd, newSatVar, newCnf, prefix)

    if type(nd).__name__ == "UnOp":
        newCnf = UnOpNode(nd, newSatVar, newCnf, prefix)

    return newSatVar, newCnf
Example #8
0
def createComparatorCnf(outputs: set, prefix1: str,
                        prefix2: str) -> (Cnf, SatVar):
    '''The function createComparatorCnf takes the common outputs of the circuits being checked,
    taking into account their differente prefixes, and builds the output miter logic
    with its XOR and OR gates. Its output is both the miter output CNF and the SatVar
    variable for the miter output symbol
    '''
    # Generation of XOR gates for miter circuit output
    comparator = Cnf()
    comp_signals = []
    i = 0
    for output in outputs:
        xor_i = SatVar('xor_' + str(i))
        output1 = SatVar(prefix1 + output)
        output2 = SatVar(prefix2 + output)
        comparator &= gate_xor(output1, output2, xor_i)
        comp_signals.append(xor_i)
        i += 1

    # Generation of OR gates for miter circuit output
    or_neutral = SatVar('or_neutral')
    comparator &= (~or_neutral)
    i = 0
    for xor_i in comp_signals:
        out = SatVar('or_' + str(i))
        curr = xor_i
        if i == 0:
            comparator &= gate_or(or_neutral, xor_i, out)
        else:
            prev = SatVar('or_' + str(i - 1))
            comparator &= gate_or(prev, xor_i, out)
        i += 1

    return comparator, out
Example #9
0
def transform_rec(node, prefix = ''):
    cnf = Cnf()

    children = node.getChildren()
    if type(node).__name__ == "Variable":
        s = SatVar(prefix+node.getName())
        return s, cnf

    s = SatVar(prefix+ "s" + str(node.getID()))
    if type(node).__name__ == "Literal":
        if (node.getValue()):
            cnf = cnf & s
        else:
            cnf = cnf & ~s
        return s, cnf

    if type(node).__name__ == "BinOp":
        a, cnf1 = transform_rec(node.getChild(0), prefix)
        b, cnf2 = transform_rec(node.getChild(1), prefix)
        cnf = cnf & cnf1 & cnf2
        if (node.getOp() == "&"):
            cnf = cnf & mk_and(s, a, b)
        elif (node.getOp() == "^"):
            cnf = cnf & mk_xor(s, a, b)
        elif (node.getOp() == "|"):
            cnf = cnf & mk_or(s, a, b)
        else:
            raise ValueError("Unrecognized operator " + node.getOp())
        return s, cnf

    if type(node).__name__ == "UnOp":
        a, cnf1 = transform_rec(node.getChild(0), prefix)
        cnf = cnf & cnf1
        if (node.getOp() == "~"):
            cnf = cnf & mk_not(s, a)
        else:
            raise ValueError("Unrecognized operator " + node.getOp())
        return s, cnf
Example #10
0
#!/usr/bin/env python3

import circuit.circuit as circ
from circuit.cnf import SatVar, Solver, Cnf

# circ full_adder {
#      inputs: a, b, cin
#      outputs: s, cout
#      s0 = a ^ b
#      s = s0 ^ cin
#      cout = (a & b) | (s0 & cin)
# }

# Inputs
a = SatVar('a')
b = SatVar('b')
cin = SatVar('cin')

# Outputs
s = SatVar('s')
cout = SatVar('cout')

# Internal variables (if needed)
s0 = SatVar('s0')
s1 = SatVar('s1')
s2 = SatVar('s2')


def gate_and(in1: SatVar, in2: SatVar, out: SatVar) -> Cnf:
    return (~in1 | ~in2 | out) & (in1 | ~out) & (in2 | ~out)
Example #11
0
for sig in signals:
    node = c.getEquation(sig)
    print("{} = {}".format(sig, node))

nd = c.getEquation('x92')
print("Node s_13: {} [type {}]".format(nd, type(nd)))
print("Node id: {}".format(nd.getID()))
print("Node operation: {}".format(nd.getOp()))
for ch in nd.getChildren():
    print("Child node (id: {}): {} [type: {}]".format(ch.getID(), ch,
                                                      type(ch)))

# ===================================== CNF formulas and SAT solving
print("===============================")

x = SatVar('x')
y = SatVar('y')
z = SatVar('z')

cnf = (x | ~y) & (z | y)
print(cnf)

solver = Solver()
solution = solver.solve(cnf)
print(solution)

cnf &= ~x
print(cnf)
solution = solver.solve(cnf)
print(solution)
if solution:
Example #12
0
 def constr(x):
     return SatVar(x) if test[x] else ~SatVar(x)
Example #13
0
def check(c1: Circuit, c2: Circuit) -> (bool, Solution):
    '''The function check() takes two Circuits as input and performs an equivalence
    check using a SAT solver. it returns a tuple, where the first entry is a
    Boolean value (True for equivalent, False for different) and the second
    value is -- in case of a difference found -- a Solution to the underlying
    SAT problem, representing a counterexample. If the circuits are indeed
    equivalent, the second entry will be None.

    '''

    if not (c1.getInputs() == c2.getInputs() and c1.getOutputs() == c2.getOutputs()):
        return (False, None)

    cnf1 = transform(c1, "c1_")
    cnf2 = transform(c2, "c2_")

    cnf = cnf1 & cnf2

    # Inputs should be the same.
    # Mitter_input isn't necessary. (Only here to preserve the name of the entree. Easier to get along with)
    for input in c1.getInputs():
        mitter_input = SatVar(input)
        c1_input = SatVar("c1_" + input)
        c2_input = SatVar("c2_" + input)
        cnf = cnf & mk_eq(mitter_input, c1_input) & mk_eq(mitter_input, c2_input)

    outputs = list(c1.getOutputs())
    n = len(outputs)
    s = SatVar("mitter_output")

    # Computation of the mitter output :
    # Xor of the outputs of the Circuits
    # Then an or of all these xor (as we only have made a binary_or function, we do as many or as needed)
    #
    # The code would be simplier if a 1 Litteral were added to always make a binary or, even when there only is one xor
    # But it would be less efficient.
    if n == 1:
        c1_output = SatVar("c1_" + outputs[0])
        c2_output = SatVar("c2_" + outputs[0])
        cnf = cnf & mk_xor(s, c1_output, c2_output)
    else:
        for i, output in enumerate(outputs):
            c1_output = SatVar("c1_" + output)
            c2_output = SatVar("c2_" + output)
            xor_output = SatVar("mitter_xor_" + output)
            cnf = cnf & mk_xor(xor_output, c1_output, c2_output)

            if i == 1:
                ith_or = SatVar("mitter_or_1")
                if i + 1 == n:
                    ith_or = s

                xor_prev = SatVar("mitter_xor_" + outputs[0]) # = [i-1]

                cnf = cnf & mk_or(ith_or, xor_prev, xor_output)
            if i>1:
                ith_or = SatVar("mitter_or_" + str(i))
                if i + 1 == n:
                    ith_or = s

                or_prev = SatVar("mitter_or_" + str(i-1))
                cnf = cnf & mk_or(ith_or, or_prev, xor_output)


    cnf = cnf & s

    solution = Solver().solve(cnf)

    if not solution:
        return (True, None)
    else:
        return (False, solution.assignment)