def categorize_bounds(formula: FNode, sender_symbol: FNode): """ categorize symbolic bounds for a given variable :param formula: FNode formula in CNF form :param sender_symbol: FNode of the bounded variable :return: upper_bounds, lower_bounds, parent_atoms """ clauses = set() formula = simplify(formula) if formula.is_or() or is_literal(formula): clauses.add(formula) else: # formula of CNF form for clause in formula.args(): assert is_literal(clause) or clause.is_or() clauses.add(clause) bounds = defaultdict(list) for clause in clauses: if clause.is_le() or clause.is_lt(): # single literal clause bound, bound_type = atom_to_bound(clause, sender_symbol) bounds[bound_type].append(bound) continue for atom in clause.get_atoms(): # atom: inequality a * x + b * y < c assert atom.is_le() or atom.is_lt() bound, bound_type = atom_to_bound(atom, sender_symbol) bounds[bound_type].append(bound) return list(set(bounds[UPPER])), list(set(bounds[LOWER])), \ list(set(bounds[NEITHER]))
def ast_contains(self, node: FNode, what: Callable[[FNode], bool]) -> bool: if what(node): return True for child in node.args(): if self.ast_contains(child, what): return True return False
def extract_labels_and_weight(weight: FNode) -> Tuple[label_dict_type, FNode]: labels = dict() terms = [] if weight.is_times(): for arg in weight.args(): # type: FNode label = get_bool_label(arg) if label is not None: labels[label[0]] = tuple(label[1:]) else: terms.append(arg) return labels, Times(*terms) else: return labels, weight
def formula_to_interval_set(formula: FNode, sender_symbol: FNode, test_point: float): clauses = set() if formula.is_or() or is_literal(formula): clauses.add(formula) else: # formula of CNF form for clause in formula.args(): assert is_literal(clause) or clause.is_or() clauses.add(clause) interval_list = [] for clause in clauses: intervals = clause_to_intervals(clause, sender_symbol, test_point) if intervals: interval_list.append(intervals) return interval_list
def get_bool_label(formula: FNode) -> Optional[Tuple[str, FNode, FNode]]: if formula.is_ite(): c, t, e = formula.args() # type: FNode if c.is_symbol() and c.symbol_type() == BOOL: return c.symbol_name(), t, e return None
def vlog_match_widths(left: FNode, right: FNode, extend=False) -> Tuple[FNode, FNode]: ''' Match the bit-widths for assignment using the Verilog standard semantics. if extend: zero extend to largest width else: left_width == right_width: no change left_width > right_width: right side is zero extended or sign extended depending on signedness left_width < right_width: right side is truncated (MSBs removed) ''' assert type(left) == FNode and get_type( left).is_bv_type(), "Expecting a bit-vector" assert type(right) == FNode and get_type( right).is_bv_type(), "Expecting a bit-vector" left_width, right_width = left.bv_width(), right.bv_width() if left_width == right_width: pass elif left_width > right_width: # TODO: Check signed-ness of right-side fun = None padding = 0 # handle ops with overflow: if right.is_bv_add(): fun = BVAdd padding = 1 elif right.is_bv_mul(): fun = BVMul padding = 1 elif right.is_bv_lshl(): fun = BVLShl padding = left_width - right_width assert padding >= 0, "Expecting a non-negative padding" # TODO: Handle signed values here as well # re-build the node if padding > 0: args = [BVZExt(a, padding) for a in right.args()] right = fun(*args) # re-evauluate left_width and right_width, in case they're updated left_width, right_width = left.bv_width(), right.bv_width() assert left_width >= right_width, "Unexpected bitwidth mismatch" if left_width > right_width: right = BVZExt(right, left_width - right_width) else: if extend: left = BVZExt(left, right_width - left_width) else: right = BVExtract(right, 0, left_width - 1) return simplify(left), simplify(right)