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
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
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
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
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
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
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
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