def generate_STS(self, var_str, init_str, invar_str, trans_str): ts = TS("Additional system") init = [] trans = [] invar = [] sparser = StringParser() for var in var_str: ts.add_state_var(self._define_var(var)) for init_s in init_str: init.append(sparser.parse_formula(init_s)) for invar_s in invar_str: invar.append(sparser.parse_formula(invar_s)) for trans_s in trans_str: trans.append(sparser.parse_formula(trans_s)) ts.init = And(init) ts.invar = And(invar) ts.trans = And(trans) return ts
def parse_string(self, strinput): hts = HTS() ts = TS() nodemap = {} node_covered = set([]) # list of tuples of var and cond_assign_list # cond_assign_list is tuples of (condition, value) # where everything is a pysmt FNode # for btor, the condition is always True ftrans = [] initlist = [] invarlist = [] invar_props = [] ltl_props = [] prop_count = 0 # clean string input, remove special characters from names for sc, rep in special_char_replacements.items(): strinput = strinput.replace(sc, rep) def getnode(nid): node_covered.add(nid) if int(nid) < 0: return Ite(BV2B(nodemap[str(-int(nid))]), BV(0,1), BV(1,1)) return nodemap[nid] def binary_op(bvop, bop, left, right): if (get_type(left) == BOOL) and (get_type(right) == BOOL): return bop(left, right) return bvop(B2BV(left), B2BV(right)) def unary_op(bvop, bop, left): if (get_type(left) == BOOL): return bop(left) return bvop(left) for line in strinput.split(NL): linetok = line.split() if len(linetok) == 0: continue if linetok[0] == COM: continue (nid, ntype, *nids) = linetok if ntype == SORT: (stype, *attr) = nids if stype == BITVEC: nodemap[nid] = BVType(int(attr[0])) node_covered.add(nid) if stype == ARRAY: nodemap[nid] = ArrayType(getnode(attr[0]), getnode(attr[1])) node_covered.add(nid) if ntype == WRITE: nodemap[nid] = Store(*[getnode(n) for n in nids[1:4]]) if ntype == READ: nodemap[nid] = Select(getnode(nids[1]), getnode(nids[2])) if ntype == ZERO: nodemap[nid] = BV(0, getnode(nids[0]).width) if ntype == ONE: nodemap[nid] = BV(1, getnode(nids[0]).width) if ntype == ONES: width = getnode(nids[0]).width nodemap[nid] = BV((2**width)-1, width) if ntype == REDOR: width = get_type(getnode(nids[1])).width zeros = BV(0, width) nodemap[nid] = BVNot(BVComp(getnode(nids[1]), zeros)) if ntype == REDXOR: width = get_type(getnode(nids[1])).width nodemap[nid] = BV(0, width) zeros = BV(0, width) for yx_i in range(width): tmp = BV(1 << yx_i, width) tmp_2 = BVAnd(tmp, B2BV(getnode(nids[1]))) tmp_3 = BVZExt(B2BV(BVComp(tmp_2, zeros)), int(width - 1)) nodemap[nid] = BVAdd(tmp_3, nodemap[nid]) nodemap[nid] = BVComp(BVAnd(BV(1, width), nodemap[nid]), BV(1, width)) if ntype == REDAND: width = get_type(getnode(nids[1])).width ones = BV((2**width)-1, width) nodemap[nid] = BVComp(getnode(nids[1]), ones) if ntype == CONSTD: width = getnode(nids[0]).width nodemap[nid] = BV(int(nids[1]), width) if ntype == CONST: width = getnode(nids[0]).width nodemap[nid] = BV(bin_to_dec(nids[1]), width) if ntype == STATE: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_state_var(nodemap[nid]) if ntype == INPUT: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_input_var(nodemap[nid]) if ntype == OUTPUT: # unfortunately we need to create an extra symbol just to have the output name # we could be smarter about this, but then this parser can't be greedy original_symbol = getnode(nids[0]) output_symbol = Symbol(nids[1], original_symbol.get_type()) nodemap[nid] = EqualsOrIff(output_symbol, original_symbol) invarlist.append(nodemap[nid]) node_covered.add(nid) ts.add_output_var(output_symbol) if ntype == AND: nodemap[nid] = binary_op(BVAnd, And, getnode(nids[1]), getnode(nids[2])) if ntype == CONCAT: nodemap[nid] = BVConcat(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == XOR: nodemap[nid] = binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2])) if ntype == XNOR: nodemap[nid] = BVNot(binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2]))) if ntype == NAND: bvop = lambda x,y: BVNot(BVAnd(x, y)) bop = lambda x,y: Not(And(x, y)) nodemap[nid] = binary_op(bvop, bop, getnode(nids[1]), getnode(nids[2])) if ntype == IMPLIES: nodemap[nid] = BVOr(BVNot(getnode(nids[1])), getnode(nids[2])) if ntype == NOT: nodemap[nid] = unary_op(BVNot, Not, getnode(nids[1])) if ntype == NEG: nodemap[nid] = unary_op(BVNeg, Not, getnode(nids[1])) if ntype == UEXT: nodemap[nid] = BVZExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == SEXT: nodemap[nid] = BVSExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == OR: nodemap[nid] = binary_op(BVOr, Or, getnode(nids[1]), getnode(nids[2])) if ntype == ADD: nodemap[nid] = BVAdd(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SUB: nodemap[nid] = BVSub(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGT: nodemap[nid] = BVUGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGTE: nodemap[nid] = BVUGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULT: nodemap[nid] = BVULT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULTE: nodemap[nid] = BVULE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGT: nodemap[nid] = BVSGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGTE: nodemap[nid] = BVSGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLT: nodemap[nid] = BVSLT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLTE: nodemap[nid] = BVSLE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == EQ: nodemap[nid] = BVComp(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == NEQ: nodemap[nid] = BVNot(BVComp(getnode(nids[1]), getnode(nids[2]))) if ntype == MUL: nodemap[nid] = BVMul(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLICE: nodemap[nid] = BVExtract(B2BV(getnode(nids[1])), int(nids[3]), int(nids[2])) if ntype == SLL: nodemap[nid] = BVLShl(getnode(nids[1]), getnode(nids[2])) if ntype == SRA: nodemap[nid] = BVAShr(getnode(nids[1]), getnode(nids[2])) if ntype == SRL: nodemap[nid] = BVLShr(getnode(nids[1]), getnode(nids[2])) if ntype == ITE: if (get_type(getnode(nids[2])) == BOOL) or (get_type(getnode(nids[3])) == BOOL): nodemap[nid] = Ite(BV2B(getnode(nids[1])), B2BV(getnode(nids[2])), B2BV(getnode(nids[3]))) else: nodemap[nid] = Ite(BV2B(getnode(nids[1])), getnode(nids[2]), getnode(nids[3])) if ntype == NEXT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): lval = TS.get_prime(getnode(nids[1])) rval = BV2B(getnode(nids[2])) else: lval = TS.get_prime(getnode(nids[1])) rval = getnode(nids[2]) nodemap[nid] = EqualsOrIff(lval, rval) ftrans.append( (lval, [(TRUE(), rval)]) ) if ntype == INIT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(getnode(nids[1])), BV2B(getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(getnode(nids[1]), getnode(nids[2])) initlist.append(getnode(nid)) if ntype == CONSTRAINT: nodemap[nid] = BV2B(getnode(nids[0])) invarlist.append(getnode(nid)) if ntype == BAD: nodemap[nid] = getnode(nids[0]) if ASSERTINFO in line: filename_lineno = os.path.basename(nids[3]) assert_name = 'embedded_assertion_%s'%filename_lineno description = "Embedded assertion at line {1} in {0}".format(*filename_lineno.split(COLON_REP)) else: assert_name = 'embedded_assertion_%i'%prop_count description = 'Embedded assertion number %i'%prop_count prop_count += 1 # Following problem format (name, description, strformula) invar_props.append((assert_name, description, Not(BV2B(getnode(nid))))) if nid not in nodemap: Logger.error("Unknown node type \"%s\""%ntype) # get wirename if it exists if ntype not in {STATE, INPUT, OUTPUT, BAD}: # check for wirename, if it's an integer, then it's a node ref try: a = int(nids[-1]) except: try: wire = Symbol(str(nids[-1]), getnode(nids[0])) invarlist.append(EqualsOrIff(wire, B2BV(nodemap[nid]))) ts.add_var(wire) except: pass if Logger.level(1): name = lambda x: str(nodemap[x]) if nodemap[x].is_symbol() else x uncovered = [name(x) for x in nodemap if x not in node_covered] uncovered.sort() if len(uncovered) > 0: Logger.warning("Unlinked nodes \"%s\""%",".join(uncovered)) if not self.symbolic_init: init = simplify(And(initlist)) else: init = TRUE() invar = simplify(And(invarlist)) # instead of trans, we're using the ftrans format -- see below ts.set_behavior(init, TRUE(), invar) # add ftrans for var, cond_assign_list in ftrans: ts.add_func_trans(var, cond_assign_list) hts.add_ts(ts) return (hts, invar_props, ltl_props)
def generate_HTS(self, module, modulesdic): hts = HTS(module.name) ts = TS("TS %s" % module.name) init = [] trans = [] invar = [] params = [] sparser = StringParser() (vars, states, inputs, outputs) = self._collect_sub_variables(module, modulesdic, path=[], varlist=[], statelist=[], inputlist=[], outputlist=[]) for var in vars: ts.add_var(self._define_var(var, module.name)) for var in states: ts.add_state_var(self._define_var(var, module.name)) for var in inputs: ts.add_input_var(self._define_var(var, module.name)) for var in outputs: ts.add_output_var(self._define_var(var, module.name)) self._check_parameters(module, modulesdic, ts.vars) for par in module.pars: assert len(par) == 2, "Expecting a variable" hts.add_param(self._define_var((par[0], par[1]), module.name)) for init_s in module.init: formula = sparser.parse_formula(quote_names(init_s, module.name), False) init.append(formula) for invar_s in module.invar: formula = sparser.parse_formula(quote_names(invar_s, module.name), False) invar.append(formula) for trans_s in module.trans: formula = sparser.parse_formula(quote_names(trans_s, module.name), False) trans.append(formula) for sub in module.subs: hts.add_sub(sub[0], self.generate_HTS(modulesdic[sub[1]], modulesdic), tuple([v[0] for v in sub[2]])) ts.init = And(init) ts.invar = And(invar) ts.trans = And(trans) hts.add_ts(ts) return hts
def parse_string(self, strinput): hts = HTS() ts = TS() nodemap = {} node_covered = set([]) # list of tuples of var and cond_assign_list # cond_assign_list is tuples of (condition, value) # where everything is a pysmt FNode # for btor, the condition is always True ftrans = [] initlist = [] invarlist = [] invar_props = [] ltl_props = [] prop_count = 0 # clean string input, remove special characters from names for sc, rep in special_char_replacements.items(): strinput = strinput.replace(sc, rep) def getnode(nid): node_covered.add(nid) if int(nid) < 0: return Ite(BV2B(nodemap[str(-int(nid))]), BV(0, 1), BV(1, 1)) return nodemap[nid] def binary_op(bvop, bop, left, right): if (get_type(left) == BOOL) and (get_type(right) == BOOL): return bop(left, right) return bvop(B2BV(left), B2BV(right)) def unary_op(bvop, bop, left): if (get_type(left) == BOOL): return bop(left) return bvop(left) for line in strinput.split(NL): linetok = line.split() if len(linetok) == 0: continue if linetok[0] == COM: continue (nid, ntype, *nids) = linetok if ntype == SORT: (stype, *attr) = nids if stype == BITVEC: nodemap[nid] = BVType(int(attr[0])) node_covered.add(nid) if stype == ARRAY: nodemap[nid] = ArrayType(getnode(attr[0]), getnode(attr[1])) node_covered.add(nid) if ntype == WRITE: nodemap[nid] = Store(*[getnode(n) for n in nids[1:4]]) if ntype == READ: nodemap[nid] = Select(getnode(nids[1]), getnode(nids[2])) if ntype == ZERO: nodemap[nid] = BV(0, getnode(nids[0]).width) if ntype == ONE: nodemap[nid] = BV(1, getnode(nids[0]).width) if ntype == ONES: width = getnode(nids[0]).width nodemap[nid] = BV((2**width) - 1, width) if ntype == REDOR: width = get_type(getnode(nids[1])).width zeros = BV(0, width) nodemap[nid] = BVNot(BVComp(getnode(nids[1]), zeros)) if ntype == REDAND: width = get_type(getnode(nids[1])).width ones = BV((2**width) - 1, width) nodemap[nid] = BVComp(getnode(nids[1]), ones) if ntype == CONSTD: width = getnode(nids[0]).width nodemap[nid] = BV(int(nids[1]), width) if ntype == CONST: width = getnode(nids[0]).width try: nodemap[nid] = BV(bin_to_dec(nids[1]), width) except ValueError: if not all([i == 'x' or i == 'z' for i in nids[1]]): raise RuntimeError( "If not a valid number, only support " "all don't cares or high-impedance but got {}". format(nids[1])) # create a fresh variable for this non-deterministic constant nodemap[nid] = Symbol('const_' + nids[1], BVType(width)) ts.add_state_var(nodemap[nid]) Logger.warning( "Creating a fresh symbol for unsupported X/Z constant %s" % nids[1]) if ntype == STATE: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN % nid), getnode(nids[0])) ts.add_state_var(nodemap[nid]) if ntype == INPUT: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN % nid), getnode(nids[0])) ts.add_input_var(nodemap[nid]) if ntype == OUTPUT: # unfortunately we need to create an extra symbol just to have the output name # we could be smarter about this, but then this parser can't be greedy original_symbol = B2BV(getnode(nids[0])) output_symbol = Symbol(nids[1], original_symbol.get_type()) nodemap[nid] = EqualsOrIff(output_symbol, original_symbol) invarlist.append(nodemap[nid]) node_covered.add(nid) ts.add_output_var(output_symbol) if ntype == AND: nodemap[nid] = binary_op(BVAnd, And, getnode(nids[1]), getnode(nids[2])) if ntype == CONCAT: nodemap[nid] = BVConcat(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == XOR: nodemap[nid] = binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2])) if ntype == XNOR: nodemap[nid] = BVNot( binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2]))) if ntype == NAND: bvop = lambda x, y: BVNot(BVAnd(x, y)) bop = lambda x, y: Not(And(x, y)) nodemap[nid] = binary_op(bvop, bop, getnode(nids[1]), getnode(nids[2])) if ntype == IMPLIES: nodemap[nid] = BVOr(BVNot(getnode(nids[1])), getnode(nids[2])) if ntype == NOT: nodemap[nid] = unary_op(BVNot, Not, getnode(nids[1])) if ntype == NEG: nodemap[nid] = unary_op(BVNeg, Not, getnode(nids[1])) if ntype == UEXT: nodemap[nid] = BVZExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == SEXT: nodemap[nid] = BVSExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == OR: nodemap[nid] = binary_op(BVOr, Or, getnode(nids[1]), getnode(nids[2])) if ntype == ADD: nodemap[nid] = BVAdd(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SUB: nodemap[nid] = BVSub(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGT: nodemap[nid] = BVUGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGTE: nodemap[nid] = BVUGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULT: nodemap[nid] = BVULT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULTE: nodemap[nid] = BVULE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGT: nodemap[nid] = BVSGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SGTE: nodemap[nid] = BVSGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLT: nodemap[nid] = BVSLT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLTE: nodemap[nid] = BVSLE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == EQ: nodemap[nid] = BVComp(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == NEQ: nodemap[nid] = BVNot(BVComp(getnode(nids[1]), getnode(nids[2]))) if ntype == MUL: nodemap[nid] = BVMul(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLICE: nodemap[nid] = BVExtract(B2BV(getnode(nids[1])), int(nids[3]), int(nids[2])) if ntype == SLL: nodemap[nid] = BVLShl(getnode(nids[1]), getnode(nids[2])) if ntype == SRA: nodemap[nid] = BVAShr(getnode(nids[1]), getnode(nids[2])) if ntype == SRL: nodemap[nid] = BVLShr(getnode(nids[1]), getnode(nids[2])) if ntype == ITE: if (get_type(getnode(nids[2])) == BOOL) or (get_type( getnode(nids[3])) == BOOL): nodemap[nid] = Ite(BV2B(getnode(nids[1])), B2BV(getnode(nids[2])), B2BV(getnode(nids[3]))) else: nodemap[nid] = Ite(BV2B(getnode(nids[1])), getnode(nids[2]), getnode(nids[3])) if ntype == NEXT: if (get_type(getnode(nids[1])) == BOOL) or (get_type( getnode(nids[2])) == BOOL): lval = TS.get_prime(getnode(nids[1])) rval = B2BV(getnode(nids[2])) else: lval = TS.get_prime(getnode(nids[1])) rval = getnode(nids[2]) nodemap[nid] = EqualsOrIff(lval, rval) ftrans.append((lval, [(TRUE(), rval)])) if ntype == INIT: if (get_type(getnode(nids[1])) == BOOL) or (get_type( getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(getnode(nids[1])), BV2B(getnode(nids[2]))) elif get_type(getnode(nids[1])).is_array_type(): _type = get_type(getnode(nids[1])) nodemap[nid] = EqualsOrIff( getnode(nids[1]), Array(_type.index_type, default=getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(getnode(nids[1]), getnode(nids[2])) initlist.append(getnode(nid)) if ntype == CONSTRAINT: nodemap[nid] = BV2B(getnode(nids[0])) invarlist.append(getnode(nid)) if ntype == BAD: nodemap[nid] = getnode(nids[0]) if len(nids) > 1: assert_name = nids[1] description = "Embedded assertion: {}".format(assert_name) else: assert_name = 'embedded_assertion_%i' % prop_count description = 'Embedded assertion number %i' % prop_count prop_count += 1 # Following problem format (name, description, strformula) invar_props.append( (assert_name, description, Not(BV2B(getnode(nid))))) if nid not in nodemap: Logger.error("Unknown node type \"%s\"" % ntype) # get wirename if it exists if ntype not in {STATE, INPUT, OUTPUT, BAD}: # disregard comments at the end of the line try: symbol_idx = nids.index(';') symbol_idx -= 1 # the symbol should be before the comment except: # the symbol is just the end symbol_idx = -1 # check for wirename, if it's an integer, then it's a node ref try: a = int(nids[symbol_idx]) except: try: name = str(nids[symbol_idx]) # use the exact name, unless it has already been used wire = Symbol(name, getnode(nids[0])) if wire in ts.vars: wire = FreshSymbol(getnode(nids[0]), template=name + "%d") invarlist.append(EqualsOrIff(wire, B2BV(nodemap[nid]))) ts.add_var(wire) except: pass if Logger.level(1): name = lambda x: str(nodemap[x]) if nodemap[x].is_symbol() else x uncovered = [name(x) for x in nodemap if x not in node_covered] uncovered.sort() if len(uncovered) > 0: Logger.warning("Unlinked nodes \"%s\"" % ",".join(uncovered)) if not self.symbolic_init: init = simplify(And(initlist)) else: init = TRUE() invar = simplify(And(invarlist)) # instead of trans, we're using the ftrans format -- see below ts.set_behavior(init, TRUE(), invar) # add ftrans for var, cond_assign_list in ftrans: ts.add_func_trans(var, cond_assign_list) hts.add_ts(ts) return (hts, invar_props, ltl_props)
def generate_STS(self, lines): ts = TS("Additional system") init = TRUE() trans = TRUE() invar = TRUE() states = {} assigns = set([]) varsmap = {} def def_var(name, vtype): if name in varsmap: return varsmap[name] var = Symbol(name, vtype) ts.add_state_var(var) return var for line in lines: if line.comment: continue if line.init: if T_I not in states: states[T_I] = TRUE() if line.init.varname != "": (value, typev) = self.__get_value(line.init.value) ivar = def_var(line.init.varname, typev) state = EqualsOrIff(ivar, value) else: state = TRUE() if line.init.value == T_TRUE else FALSE() states[T_I] = And(states[T_I], state) # Optimization for the initial state assignment init = And(init, state) state = TRUE() if line.state: sname = T_S + line.state.id if (line.state.varname != ""): (value, typev) = self.__get_value(line.state.value) ivar = def_var(line.state.varname, typev) state = EqualsOrIff(ivar, value) assval = (sname, line.state.varname) if assval not in assigns: assigns.add(assval) else: Logger.error( "Double assignment for variable \"%s\" at state \"%s\"" % (line.state.varname, sname)) else: state = TRUE() if line.state.value == T_TRUE else FALSE() if sname not in states: states[sname] = TRUE() states[sname] = And(states[sname], state) stateid_width = math.ceil(math.log(len(states)) / math.log(2)) stateid_var = Symbol(self.new_state_id(), BVType(stateid_width)) init = And(init, EqualsOrIff(stateid_var, BV(0, stateid_width))) invar = And( invar, Implies(EqualsOrIff(stateid_var, BV(0, stateid_width)), states[T_I])) states[T_I] = EqualsOrIff(stateid_var, BV(0, stateid_width)) count = 1 state_items = list(states.keys()) state_items.sort() for state in state_items: if state == T_I: continue invar = And( invar, Implies(EqualsOrIff(stateid_var, BV(count, stateid_width)), states[state])) states[state] = EqualsOrIff(stateid_var, BV(count, stateid_width)) count += 1 transdic = {} for line in lines: if line.comment: continue if line.trans: if states[line.trans.start] not in transdic: transdic[states[line.trans.start]] = [] transdic[states[line.trans.start]].append( states[line.trans.end]) for transition in transdic: (start, end) = (transition, transdic[transition]) trans = And(trans, Implies(start, TS.to_next(Or(end)))) vars_ = [v for v in get_free_variables(trans) if not TS.is_prime(v)] vars_ += get_free_variables(init) vars_ += get_free_variables(invar) invar = And(invar, BVULE(stateid_var, BV(count - 1, stateid_width))) ts.set_behavior(init, trans, invar) ts.add_state_var(stateid_var) hts = HTS("ETS") hts.add_ts(ts) invar_props = [] ltl_props = [] return (hts, invar_props, ltl_props)
def solve_problems(self, problems_config: ProblemsManager) -> None: general_config = problems_config.general_config model_extension = general_config.model_extension assume_if_true = general_config.assume_if_true self.sparser = StringParser(general_config) self.lparser = LTLParser() self.coi = ConeOfInfluence() modifier = None if general_config.model_extension is not None: modifier = lambda hts: ModelExtension.extend( hts, ModelModifiersFactory.modifier_by_name(general_config. model_extension)) # generate main system system hts, invar_props, ltl_props = self.parse_model( general_config.model_files, problems_config.relative_path, general_config, "System 1", modifier) # Generate second models if any are necessary for problem in problems_config.problems: if problem.verification == VerificationType.EQUIVALENCE: if problem.equal_to is None: raise RuntimeError( "No second model for equivalence " "checking provided for problem {}".format( problem.name)) hts2, _, _ = self.parse_model(problem.equal_to, problems_config.relative_path, general_config, "System 2", modifier) problems_config.add_second_model(problem, hts2) # TODO : contain these types of passes in functions # they should be registered as passes if general_config.init is not None: iparser = InitParser() init_hts, inv_a, ltl_a = iparser.parse_file( general_config.init, general_config) assert inv_a is None and ltl_a is None, "Not expecting assertions from init state file" # remove old inits for ts in hts.tss: ts.init = TRUE() hts.combine(init_hts) hts.single_init(rebuild=True) # set default bit-wise initial values (0 or 1) if general_config.default_initial_value is not None: def_init_val = int(general_config.default_initial_value) try: if int(def_init_val) not in {0, 1}: raise RuntimeError except: raise RuntimeError( "Expecting 0 or 1 for default_initial_value," "but received {}".format(def_init_val)) def_init_ts = TS("Default initial values") new_init = [] initialized_vars = get_free_variables(hts.single_init()) state_vars = hts.state_vars num_def_init_vars = 0 num_state_vars = len(state_vars) const_arr_supported = True if hts.logic == L_ABV: for p in problems_config.problems: if p.solver_name not in CONST_ARRAYS_SUPPORT: const_arr_supported = False Logger.warning( "Using default_initial_value with arrays, " "but one of the selected solvers, " "{} does not support constant arrays. " "Any assumptions on initial array values will " "have to be done manually".format( problem.solver_name)) break for sv in state_vars - initialized_vars: if sv.get_type().is_bv_type(): width = sv.get_type().width if int(def_init_val) == 1: val = BV((2**width) - 1, width) else: val = BV(0, width) num_def_init_vars += 1 elif sv.get_type().is_array_type() and \ sv.get_type().elem_type.is_bv_type() and \ const_arr_supported: svtype = sv.get_type() width = svtype.elem_type.width if int(def_init_val) == 1: val = BV((2**width) - 1, width) else: val = BV(0, width) # create a constant array with a default value val = Array(svtype.index_type, val) else: continue def_init_ts.add_state_var(sv) new_init.append(EqualsOrIff(sv, val)) def_init_ts.set_behavior(simplify(And(new_init)), TRUE(), TRUE()) hts.add_ts(def_init_ts) Logger.msg( "Set {}/{} state elements to zero " "in initial state\n".format(num_def_init_vars, num_state_vars), 1) problems_config.hts = hts # TODO: Update this so that we can control whether embedded assertions are solved automatically if not general_config.skip_embedded: for invar_prop in invar_props: problems_config.add_problem( verification=VerificationType.SAFETY, name=invar_prop[0], description=invar_prop[1], properties=invar_prop[2]) self.properties.append(invar_prop[2]) for ltl_prop in ltl_props: problems_config.add_problem(verification=VerificationType.LTL, name=invar_prop[0], description=invar_prop[1], properties=invar_prop[2]) self.properties.append(ltl_prop[2]) Logger.log( "Solving with abstract_clock=%s, add_clock=%s" % (general_config.abstract_clock, general_config.add_clock), 2) # ensure the miter_out variable exists miter_out = None for problem in problems_config.problems: if problem.name is not None: Logger.log( "\n*** Analyzing problem \"%s\" ***" % (problem.name), 1) Logger.msg("Solving \"%s\" " % problem.name, 0, not (Logger.level(1))) # apply parametric behaviors (such as toggling the clock) # Note: This is supposed to be *before* creating the combined system for equivalence checking # we want this assumption to be applied to both copies of the clock problem_hts = ParametricBehavior.apply_to_problem( problems_config.hts, problem, general_config, self.model_info) if problem.verification == VerificationType.EQUIVALENCE: hts2 = problems_config.get_second_model(problem) problem_hts, miter_out = Miter.combine_systems( hts, hts2, problem.bmc_length, general_config.symbolic_init, problem.properties, True) try: # convert the formulas to PySMT FNodes # lemmas, assumptions and precondition always use the regular parser lemmas, assumptions, precondition = self.convert_formulae( [ problem.lemmas, problem.assumptions, problem.precondition ], parser=self.sparser, relative_path=problems_config.relative_path) if problem.verification != VerificationType.LTL: parser = self.sparser else: parser = self.lparser prop = None if problem.properties is not None: prop = self.convert_formula( problem.properties, relative_path=problems_config.relative_path, parser=parser) assert len(prop) == 1, "Properties should already have been split into " \ "multiple problems but found {} properties here".format(len(prop)) prop = prop[0] self.properties.append(prop) else: if problem.verification == VerificationType.SIMULATION: prop = TRUE() elif (problem.verification is not None) and (problem.verification != VerificationType.EQUIVALENCE): Logger.error( "Property not provided for problem {}".format( problem.name)) if problem.verification == VerificationType.EQUIVALENCE: assert miter_out is not None # set property to be the miter output # if user provided a different equivalence property, this has already # been incorporated in the miter_out prop = miter_out # reset the miter output miter_out = None if precondition: assert len(precondition ) == 1, "There should only be one precondition" prop = Implies(precondition[0], prop) # TODO: keep assumptions separate from the hts # IMPORTANT: CLEAR ANY PREVIOUS ASSUMPTIONS AND LEMMAS # This was previously done in __solve_problem and has been moved here # during the frontend refactor in April 2019 # this is necessary because the problem hts is just a reference to the # overall (shared) HTS problem_hts.assumptions = None problem_hts.lemmas = None # Compute the Cone Of Influence # Returns a *new* hts (not pointing to the original one anymore) if problem.coi: if Logger.level(2): timer = Logger.start_timer("COI") hts = self.coi.compute(hts, prop) if Logger.level(2): Logger.get_timer(timer) if general_config.time: timer_solve = Logger.start_timer( "Problem %s" % problem.name, False) status, trace, traces, region = self.__solve_problem( problem_hts, prop, lemmas, assumptions, problem) # set status for this problem problems_config.set_problem_status(problem, status) # TODO: Determine whether we need both trace and traces assert trace is None or traces is None, "Expecting either a trace or a list of traces" if trace is not None: problem_traces = self.__process_trace( hts, trace, general_config, problem) problems_config.set_problem_traces(problem, problem_traces) if traces is not None: traces_to_add = [] for trace in traces: problem_trace = self.__process_trace( hts, trace, general_config, problem) for pt in problem_trace: traces_to_add.append(pt) problems_config.set_problem_traces(problem, traces_to_add) if problem.verification == VerificationType.PARAMETRIC: assert region is not None problems_config.set_problem_region(problem, region) if status is not None: Logger.msg(" %s\n" % status, 0, not (Logger.level(1))) if (assume_if_true) and \ (status == VerificationStatus.TRUE) and \ (problem.assumptions == None) and \ (problem.verification == VerificationType.SAFETY): # TODO: relax the assumption on problem.assumptions # can still add it, just need to make it an implication ass_ts = TS("Previous assumption from property") if TS.has_next(prop): ass_ts.trans = prop else: ass_ts.invar = prop # add assumptions to main system problem_hts.reset_formulae() problem_hts.add_ts(ass_ts) if general_config.time: problems_config.set_problem_time( problem, Logger.get_timer(timer_solve, False)) except KeyboardInterrupt as e: Logger.msg("\b\b Skipped!\n", 0)
def parse_string(self, strinput): hts = HTS() ts = TS() nodemap = {} node_covered = set([]) translist = [] initlist = [] invarlist = [] invar_props = [] ltl_props = [] def getnode(nid): node_covered.add(nid) if int(nid) < 0: return Ite(BV2B(nodemap[str(-int(nid))]), BV(0,1), BV(1,1)) return nodemap[nid] def binary_op(bvop, bop, left, right): if (get_type(left) == BOOL) and (get_type(right) == BOOL): return bop(left, right) return bvop(B2BV(left), B2BV(right)) def unary_op(bvop, bop, left): if (get_type(left) == BOOL): return bop(left) return bvop(left) for line in strinput.split(NL): linetok = line.split() if len(linetok) == 0: continue if linetok[0] == COM: continue (nid, ntype, *nids) = linetok if ntype == SORT: (stype, *attr) = nids if stype == BITVEC: nodemap[nid] = BVType(int(attr[0])) node_covered.add(nid) if stype == ARRAY: nodemap[nid] = ArrayType(getnode(attr[0]), getnode(attr[1])) node_covered.add(nid) if ntype == WRITE: nodemap[nid] = Store(*[getnode(n) for n in nids[1:4]]) if ntype == READ: nodemap[nid] = Select(getnode(nids[1]), getnode(nids[2])) if ntype == ZERO: nodemap[nid] = BV(0, getnode(nids[0]).width) if ntype == ONE: nodemap[nid] = BV(1, getnode(nids[0]).width) if ntype == ONES: width = getnode(nids[0]).width nodemap[nid] = BV((2**width)-1, width) if ntype == REDOR: width = get_type(getnode(nids[1])).width zeros = BV(0, width) nodemap[nid] = BVNot(BVComp(getnode(nids[1]), zeros)) if ntype == REDAND: width = get_type(getnode(nids[1])).width ones = BV((2**width)-1, width) nodemap[nid] = BVComp(getnode(nids[1]), ones) if ntype == CONSTD: width = getnode(nids[0]).width nodemap[nid] = BV(int(nids[1]), width) if ntype == CONST: width = getnode(nids[0]).width nodemap[nid] = BV(bin_to_dec(nids[1]), width) if ntype == STATE: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_state_var(nodemap[nid]) if ntype == INPUT: if len(nids) > 1: nodemap[nid] = Symbol(nids[1], getnode(nids[0])) else: nodemap[nid] = Symbol((SN%nid), getnode(nids[0])) ts.add_input_var(nodemap[nid]) if ntype == OUTPUT: if len(nids) > 2: symbol = Symbol(nids[2], getnode(nids[0])) else: symbol = Symbol((SN%nid), getnode(nids[0])) nodemap[nid] = EqualsOrIff(symbol, B2BV(getnode(nids[1]))) invarlist.append(nodemap[nid]) node_covered.add(nid) ts.add_output_var(symbol) if ntype == AND: nodemap[nid] = binary_op(BVAnd, And, getnode(nids[1]), getnode(nids[2])) if ntype == CONCAT: nodemap[nid] = BVConcat(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == XOR: nodemap[nid] = binary_op(BVXor, Xor, getnode(nids[1]), getnode(nids[2])) if ntype == NAND: bvop = lambda x,y: BVNot(BVAnd(x, y)) bop = lambda x,y: Not(And(x, y)) nodemap[nid] = binary_op(bvop, bop, getnode(nids[1]), getnode(nids[2])) if ntype == IMPLIES: nodemap[nid] = BVOr(BVNot(getnode(nids[1])), getnode(nids[2])) if ntype == NOT: nodemap[nid] = unary_op(BVNot, Not, getnode(nids[1])) if ntype == UEXT: nodemap[nid] = BVZExt(B2BV(getnode(nids[1])), int(nids[2])) if ntype == OR: nodemap[nid] = binary_op(BVOr, Or, getnode(nids[1]), getnode(nids[2])) if ntype == ADD: nodemap[nid] = BVAdd(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SUB: nodemap[nid] = BVSub(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGT: nodemap[nid] = BVUGT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == UGTE: nodemap[nid] = BVUGE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULT: nodemap[nid] = BVULT(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == ULTE: nodemap[nid] = BVULE(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == EQ: nodemap[nid] = BVComp(getnode(nids[1]), getnode(nids[2])) if ntype == NE: nodemap[nid] = BVNot(BVComp(getnode(nids[1]), getnode(nids[2]))) if ntype == MUL: nodemap[nid] = BVMul(B2BV(getnode(nids[1])), B2BV(getnode(nids[2]))) if ntype == SLICE: nodemap[nid] = BVExtract(B2BV(getnode(nids[1])), int(nids[3]), int(nids[2])) if ntype == SLL: nodemap[nid] = BVLShl(getnode(nids[1]), getnode(nids[2])) if ntype == SRA: nodemap[nid] = BVAShr(getnode(nids[1]), getnode(nids[2])) if ntype == SRL: nodemap[nid] = BVLShr(getnode(nids[1]), getnode(nids[2])) if ntype == ITE: if (get_type(getnode(nids[2])) == BOOL) or (get_type(getnode(nids[3])) == BOOL): nodemap[nid] = Ite(BV2B(getnode(nids[1])), BV2B(getnode(nids[2])), BV2B(getnode(nids[3]))) else: nodemap[nid] = Ite(BV2B(getnode(nids[1])), getnode(nids[2]), getnode(nids[3])) if ntype == NEXT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(TS.get_prime(getnode(nids[1]))), BV2B(getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(TS.get_prime(getnode(nids[1])), getnode(nids[2])) translist.append(getnode(nid)) if ntype == INIT: if (get_type(getnode(nids[1])) == BOOL) or (get_type(getnode(nids[2])) == BOOL): nodemap[nid] = EqualsOrIff(BV2B(getnode(nids[1])), BV2B(getnode(nids[2]))) else: nodemap[nid] = EqualsOrIff(getnode(nids[1]), getnode(nids[2])) initlist.append(getnode(nid)) if ntype == CONSTRAINT: nodemap[nid] = BV2B(getnode(nids[0])) invarlist.append(getnode(nid)) if ntype == BAD: nodemap[nid] = getnode(nids[0]) invar_props.append(Not(BV2B(getnode(nid)))) if nid not in nodemap: Logger.error("Unknown node type \"%s\""%ntype) if Logger.level(1): name = lambda x: str(nodemap[x]) if nodemap[x].is_symbol() else x uncovered = [name(x) for x in nodemap if x not in node_covered] uncovered.sort() if len(uncovered) > 0: Logger.warning("Unlinked nodes \"%s\""%",".join(uncovered)) if not self.symbolic_init: init = simplify(And(initlist)) else: init = TRUE() trans = simplify(And(translist)) invar = simplify(And(invarlist)) ts.set_behavior(init, trans, invar) hts.add_ts(ts) return (hts, invar_props, ltl_props)
def parse_file(self, file_path, config, flags=None): # coreir needs a string representing the path strfile = str(file_path) self.config = config self.__reset_structures() Logger.msg("Reading CoreIR system... ", 1) top_module = self.context.load_from_file(strfile) if config.run_coreir_passes: self.run_passes() Modules.abstract_clock = self.config.abstract_clock Modules.symbolic_init = self.config.symbolic_init top_def = top_module.definition interface = list(top_module.type.items()) modules = {} sym_map = {} not_defined_mods = [] hts = HTS(top_module.name) invar_props = [] ltl_props = [] Logger.msg("Starting encoding... ", 1) count = 0 def extract_value(x, modname, inst_intr, inst_conf, inst_mod): if x in inst_intr: return self.BVVar(modname + x, inst_intr[x].size) if x in inst_conf: xval = inst_conf[x].value if type(xval) == bool: xval = 1 if xval else 0 else: if type(xval) != int: try: xval = xval.as_uint() except: xval = None return xval if inst_mod.generated: inst_args = inst_mod.generator_args if x in inst_args: return inst_args[x].value return None if Logger.level(1): timer = Logger.start_timer("IntConvertion", False) en_tprinting = False if Logger.level(2): ttimer = Logger.start_timer("Convertion", False) td_instances = top_def.instances top_def_instances = [(inst.selectpath, inst.config, inst.module) for inst in td_instances] # sorting keeps the behavior deterministic top_def_instances.sort() totalinst = len(top_def_instances) for inst in top_def_instances: if Logger.level(1): count += 1 if count % 300 == 0: dtime = Logger.get_timer(timer, False) if dtime > 2: en_tprinting = True if en_tprinting: Logger.inline( "%s" % status_bar( (float(count) / float(totalinst))), 1) timer = Logger.start_timer("IntConvertion", False) if Logger.level(2): Logger.get_timer(timer, False) ts = None (inst_name, inst_conf, inst_mod) = inst inst_type = inst_mod.name inst_intr = dict(inst_mod.type.items()) modname = (SEP.join(inst_name)) + SEP values_dic = {} for x in self.attrnames: values_dic[x] = extract_value(x, modname, inst_intr, inst_conf, inst_mod) def args(ports_list): return [values_dic[x] for x in ports_list] sym = self.__mod_to_sym(inst_type, args) if sym is not None: sym_map[sym[0].symbol_name()] = (sym[0], sym[1]) continue ts = self.__mod_to_impl(inst_type, args) if ts is not None: if flags is not None: if CoreIRModelFlags.NO_INIT in flags: ts.init = TRUE() if CoreIRModelFlags.FC_LEMMAS in flags: for v in ts.vars: v_name = v.symbol_name() if (CR in v_name) or (RCR in v_name): cons_v_name = v_name[:len( CR)] if CR in v_name else v_name[:len(RCR)] cons_v = Symbol(cons_v_name, v.symbol_type()) lemma = EqualsOrIff( cons_v, BV(values_dic[self.VALUE], cons_v.symbol_type().width)) hts.add_lemma(lemma) for v in ts.state_vars: lemma = EqualsOrIff( v, BV(values_dic[self.INIT], v.symbol_type().width)) hts.add_lemma(lemma) hts.add_ts(ts) else: if inst_type not in not_defined_mods: intface = ", ".join([ "%s" % (v) for v in values_dic if values_dic[v] is not None ]) Logger.error( "Module type \"%s\" with interface \"%s\" is not defined" % (inst_type, intface)) not_defined_mods.append(inst_type) Logger.clear_inline(1) # sorting keeps the behavior deterministic interface.sort() for var in interface: varname = SELF + SEP + var[0] bvvar = self.BVVar(varname, var[1].size) if (var[1].is_input()): hts.add_input_var(bvvar) else: hts.add_output_var(bvvar) if var[1].kind == NAMED and var[1].name == COREIR_CLK: self.clock_list.add(bvvar) if self.config.abstract_clock: self.abstract_clock_list.add( (bvvar, (BV(0, var[1].size), BV(1, var[1].size)))) else: # add state variable that stores the previous clock value # This is IMPORTANT for model checking soundness, but # it isn't obvious that this is necessary # # imagine we have an explicit clock encoding (not abstract_clock), e.g. # next(state_var) = (!clk & next(clk)) ? <state_update> : <old value> # and if we're trying to prove something using k-induction, there's a "loop free" # constraint that the state and output variables don't repeat (reach the same # state twice) in the trace # but on a negedge clock, there can be scenarios where no state or outputs # can be updated and we'll get a trivial unsat which will be interpreted as # a converged proof -- uh oh # # adding this state element just ensures that the loop free constraint won't # be violated trivially # e.g. on a neg-edge clock, this new state element will have changed # make it hidden (won't be printed) # HIDDEN_VAR is a prefix that printers check for trailing_clock_var = self.BVVar( "{}{}__prev".format(HIDDEN_VAR, varname), var[1].size) ts = TS() ts.add_state_var(trailing_clock_var) # the initial state for this trailing variable is unconstrained ts.set_behavior( TRUE(), EqualsOrIff(TS.get_prime(trailing_clock_var), bvvar), TRUE()) hts.add_ts(ts) varmap = dict([(s.symbol_name(), s) for s in hts.vars]) def split_paths(path): ret = [] for el in path: ret += el.split(CSEP) return ret def dict_select(dic, el): return dic[el] if el in dic else None eq_conns = [] eq_vars = set([]) td_connections = top_def.connections top_def_connections = [ ((conn.first.selectpath, conn.second.selectpath) if conn.first.selectpath < conn.second.selectpath else (conn.second.selectpath, conn.first.selectpath), conn) for conn in td_connections ] # sorting keeps the behavior deterministic top_def_connections.sort() for conn in top_def_connections: first_selectpath = split_paths(conn[0][0]) second_selectpath = split_paths(conn[0][1]) first = SEP.join(first_selectpath) second = SEP.join(second_selectpath) firstvar = None secondvar = None if is_number(first_selectpath[-1]): firstname = SEP.join(first_selectpath[:-1]) else: firstname = SEP.join(first_selectpath) if is_number(second_selectpath[-1]): secondname = SEP.join(second_selectpath[:-1]) else: secondname = SEP.join(second_selectpath) first = (dict_select(varmap, self.remap_or2an(firstname)), None) second = (dict_select(varmap, self.remap_or2an(secondname)), None) firstvar = first[0] secondvar = second[0] if (firstvar is None) and (self.remap_or2an(firstname) in sym_map): firstvar = sym_map[self.remap_or2an(firstname)][1] if (secondvar is None) and (self.remap_or2an(secondname) in sym_map): secondvar = sym_map[self.remap_or2an(secondname)][1] if (firstvar is None) and (secondvar is not None): Logger.error("Symbol \"%s\" is not defined" % firstname) first = (Symbol(self.remap_or2an(firstname), secondvar.symbol_type()), None) else: if firstvar.is_constant(): sel = int(first_selectpath[-1]) if (is_number( first_selectpath[-1])) else None first = (firstvar, sel) else: if (is_number(first_selectpath[-1])) and ( firstvar.symbol_type() != BOOL) and (firstvar.symbol_type().width > 1): sel = int(first_selectpath[-1]) first = (firstvar, sel) if (firstvar is not None) and (secondvar is None): Logger.error("Symbol \"%s\" is not defined" % secondname) second = (Symbol(self.remap_or2an(secondname), firstvar.symbol_type()), None) else: if secondvar.is_constant(): sel = int(second_selectpath[-1]) if (is_number( second_selectpath[-1])) else None second = (secondvar, sel) else: if (is_number(second_selectpath[-1])) and ( secondvar.symbol_type() != BOOL) and (secondvar.symbol_type().width > 1): sel = int(second_selectpath[-1]) second = (secondvar, sel) assert ((firstvar is not None) and (secondvar is not None)) eq_conns.append((first, second)) if firstvar.is_symbol(): eq_vars.add(firstvar) if secondvar.is_symbol(): eq_vars.add(secondvar) conns_len = len(eq_conns) if self.pack_connections: eq_conns = self.__pack_connections(eq_conns) if len(eq_conns) < conns_len: Logger.log("Packed %d connections" % (conns_len - len(eq_conns)), 1) eq_formula = TRUE() for eq_conn in eq_conns: (fst, snd) = eq_conn if fst[1] is None: first = fst[0] else: if len(fst) > 2: first = BVExtract(fst[0], fst[1], fst[2]) else: first = BVExtract(fst[0], fst[1], fst[1]) if snd[1] is None: second = snd[0] else: if len(snd) > 2: second = BVExtract(snd[0], snd[1], snd[2]) else: second = BVExtract(snd[0], snd[1], snd[1]) if (first.get_type() != BOOL) and (second.get_type() == BOOL): second = Ite(second, BV(1, 1), BV(0, 1)) if (first.get_type() == BOOL) and (second.get_type() != BOOL): first = Ite(first, BV(1, 1), BV(0, 1)) eq_formula = And(eq_formula, EqualsOrIff(first, second)) Logger.log(str(EqualsOrIff(first, second)), 3) ts = TS("Connections") ts.invar = eq_formula ts.vars = eq_vars hts.add_ts(ts) if self.enc_map is not None: del (self.enc_map) if Logger.level(2): Logger.get_timer(ttimer) # check that clocks were detected if there's any state if hts.state_vars: assert self.clock_list, "Expecting clocks if there are state variables" return (hts, invar_props, ltl_props)