def _op_raw_Or(self, *args): return z3.Or(*(tuple(args) + (self._context, )))
def construct_invariant(var_names, eq_coeff, ges, les, eqs, learned_ineqs, pred_str='', non_loop_invariant=None): OPS = { '=': operator.eq, '>': operator.gt, '<': operator.lt, '>=': operator.ge, '<=': operator.le, } pred1, pred2 = None, None if pred_str is not None: if ('<' in pred_str) or ('<=' in pred_str): pred = pred_str.split() try: v1 = int(pred[2]) except ValueError: v1 = z3.Real(pred[2]) try: v2 = int(pred[3]) except ValueError: v2 = z3.Real(pred[3]) if pred[1] == '<': pred1 = v1 < v2 pred2 = v1 <= v2 elif pred[1] == '<=': pred1 = v1 <= v2 pred2 = v1 <= v2 + 1 reals = [] for var in var_names: if var == '1': reals.append(1) else: reals.append(z3.Real(var)) ands = [] ineqs = [] if eq_coeff is not None: eq_constraint = 0 * 0 if (eq_coeff[0, 0] != 0): eq_constraint = reals[0] * eq_coeff[0, 0] for i, real in enumerate(reals[1:]): if (eq_coeff[0, i + 1] != 0): eq_constraint += eq_coeff[0, i + 1] * real if isinstance(eq_constraint == 0, z3.BoolRef): ands += [eq_constraint == 0] for ge in ges: ands.append(reals[var_names.index(ge[0])] >= ge[1]) ineqs.append(reals[var_names.index(ge[0])] >= ge[1]) for le in les: ands.append(reals[var_names.index(le[0])] <= le[1]) ineqs.append(reals[var_names.index(ge[0])] >= ge[1]) for eq_ in eqs: if eq_[0] != '1': ands.append(reals[var_names.index(eq_[0])] == eq_[1]) for ineq in learned_ineqs: coeffs, b, op_str = ineq op = OPS[op_str] z3_ineq = 0 for i, (var, coeff) in enumerate(coeffs.items()): if i == 0: z3_ineq = reals[var_names.index(var)] * coeff else: z3_ineq += reals[var_names.index(var)] * coeff ands.append(op(z3_ineq, b)) I0 = z3.And(*ineqs) I1 = z3.And(*ands) I2, I3 = None, None if pred1 is not None and pred2 is not None: I2 = z3.And(*ands, pred1) I3 = z3.And(*ands, pred2) if non_loop_invariant is not None: I1 = z3.Or(I1, non_loop_invariant) if pred1 is not None and pred2 is not None: I2 = z3.Or(I2, non_loop_invariant) I3 = z3.Or(I3, non_loop_invariant) Is = [I1] if I2 is not None and I3 is not None: Is.extend([I2, I3]) Is.append(I0) return Is
def solve(self, G): """ Find the pipes diameter for a given aqueduct topology respecting the following constraints: - pipes velocities between 0.5 and 1 m/s - pipes diameters commercially available """ import z3 # add a solver solver = z3.Solver() # +-----------------------+ # | variables declaration | # +-----------------------+ # water demand in each node X = dict([(node, z3.Real("demand_%s" % i)) for i, (node, datadict) in enumerate(G.nodes.items())]) # water flow in each pipe Q = dict([(edge, z3.Real("Q_%s" % i)) for i, (edge, datadict) in enumerate(G.edges.items())]) # water speed in each pipe V = dict([(edge, z3.Real("V_%s" % i)) for i, (edge, datadict) in enumerate(G.edges.items())]) # pipes diameter D = dict([(edge, z3.Real("D_%s" % i)) for i, (edge, datadict) in enumerate(G.edges.items())]) # +---------------------+ # | boundary conditions | # +---------------------+ # water demand in each node boudary_c = [] for node, datadict in G.nodes.items(): if not datadict["Tank"]: boudary_c.append(X[node] == datadict["DEMAND"]) # closing equation in each pipe: Q = V * A def sym_abs(x): return z3.If(x >= 0, x, -x) closing_c = [ sym_abs(Q[edge]) / 1000 == V[edge] * (D[edge] / 1000 / 2)**2 * math.pi for edge in G.edges ] # speed limits speed_c = [] for edge, datadict in G.edges.items(): if datadict["LEVEL"] == 1: speed_c.append(z3.And(V[edge] >= 0.1, V[edge] <= 1.)) else: speed_c.append(z3.And(V[edge] >= 0.01, V[edge] <= 1.5)) # pipes diameters diameter_c = [] available_measures = [ 75., 90., 110., 125., 140., 160., 180., 200., 225., 250., 280., 315., 355., 400. ] for edge, datadict in G.edges.items(): if datadict["LEVEL"] == 1: diameter_c += [ z3.Or( [D[edge] == measure for measure in available_measures]) ] else: diameter_c += [ z3.Or([ D[edge] == measure for measure in available_measures + [15., 25., 50.] ]) ] # kirchoff lows in the nodes kirchoff_c = [] for n1 in G.nodes: kirchoff_c.append( z3.Sum([X[n1]] + [ Q[(n1, n2)] if (n1, n2) in Q else -Q[(n2, n1)] for n2 in G.neighbors(n1) ]) == 0) # add conditons solver.add(boudary_c + closing_c + speed_c + kirchoff_c + diameter_c) def compute_head(): """ Computes head in meters for each node in the graph. The value is calculated imposing the head in the tank and than subtracting the loss on the pipes """ for node, datadict in G.nodes.items(): if datadict["Tank"] == True: start = node H = {start: 164} visited, queue = set(), [start] while queue: node = queue.pop(0) if node not in visited: visited.add(node) queue.extend(set(G.neighbors(node)) - visited) for neighbour in G.neighbors(node): l = G[node][neighbour]["LENGHT"] K = 10.67 / 120**1.852 def contain(d, k1, k2): if k1 in d: if k2 in d[k1]: return True return False if (node, neighbour) in dict(G.nodes): q = G[node][neighbour]["Q"] else: q = -G[neighbour][node]["Q"] d = G[node][neighbour]["DIAMETER"] H[neighbour] = H[node] - (K * l * math.copysign( (abs(q) / 1000)**1.852, q) / (d / 1000)**4.8704) return H if solver.check() == z3.sat: print("solved") m = solver.model() solver.add( z3.Or([D[edge] != m.evaluate(D[edge]) for edge in G.edges])) X = dict([(node, float(m.evaluate(X[node]).numerator_as_long()) / float(m.evaluate(X[node]).denominator_as_long())) for node in X]) nx.set_node_attributes(G, X, "Q") Q = dict([(edge, float(m.evaluate(Q[edge]).numerator_as_long()) / float(m.evaluate(Q[edge]).denominator_as_long())) for edge in Q]) V = dict([(edge, float(m.evaluate(V[edge]).numerator_as_long()) / float(m.evaluate(V[edge]).denominator_as_long())) for edge in V]) D = dict([(edge, float(m.evaluate(D[edge]).numerator_as_long()) / float(m.evaluate(D[edge]).denominator_as_long())) for edge in D]) data = dict([("Q", Q), ("V", V), ("DIAMETER", D)]) for key, datadict in data.items(): nx.set_edge_attributes(G, datadict, key) H = compute_head() nx.set_node_attributes(G, H, "H") else: print("no solutions")
def Or(*expressions): return z3.Or(*expressions)
def _sat_expr( self, regex: Tuple ) -> Tuple[z3.SeqRef, z3.BoolRef, z3.BoolRef, z3.BoolRef]: """ :returns: string that matches regex, constraint on string, whether string contains caret, whether string contains dollar Whether there is a caret or dollar needs to be tracked because they imply constraints on neighboring strings to the one returned. """ ty = regex[0] if ty == EMPTY: return (z3.StringVal(''), z3.BoolVal(True), z3.BoolVal(False), z3.BoolVal(False)) elif ty == CHAR: return (z3.StringVal(regex[1]), z3.BoolVal(True), z3.BoolVal(False), z3.BoolVal(False)) elif ty == DOT: x = self._gen_string_var() constraint = z3.And( z3.Implies(self.ignore_wildcards, x == z3.StringVal('')), z3.Implies( z3.Not(self.ignore_wildcards), z3.Or(*(x == z3.StringVal(y) for y in self.dot_charset)))) return (x, constraint, z3.BoolVal(False), z3.BoolVal(False)) elif ty == STAR: # STAR should have been approximated with something else during preprocessing. raise NotImplementedError elif ty == BAR: ys, constraints_list, carets_list, dollars_list = zip( *map(self._sat_expr, regex[1:])) x = self._gen_string_var() x_constraint = z3.Or( *(z3.And(x == y, y_constraint) for y, y_constraint in zip(ys, constraints_list))) return (x, x_constraint, z3.Or(*carets_list), z3.Or(*dollars_list)) elif ty == CONCAT: ys, y_constraints, carets_list, dollars_list = zip( *map(self._sat_expr, regex[1:])) x = z3.Concat(*ys) start_constraints = (z3.Implies(b, z3.Length(y) == 0) for ii, b in enumerate(carets_list) for y in ys[:ii]) end_constraints = (z3.Implies(b, z3.Length(y) == 0) for ii, b in enumerate(dollars_list) for y in ys[ii + 1:]) x_constraint = z3.And(*toolz.concatv( y_constraints, start_constraints, end_constraints)) return (x, x_constraint, z3.Or(*carets_list), z3.Or(*dollars_list)) elif ty == GROUP: # backrefs not supported idx = regex[ 1] - 1 # not used currently; would be used to implement backrefs inner = regex[2] return self._sat_expr(inner) elif ty == BACKREF: raise NotImplementedError elif ty == CARET: assert len(regex) == 1 b = self._gen_bool_var() return (z3.StringVal(''), b, b, z3.BoolVal(False)) elif ty == DOLLAR: assert len(regex) == 1 b = self._gen_bool_var() return (z3.StringVal(''), b, z3.BoolVal(False), b) else: raise ValueError("Unknown regex_parser type '%s'" % repr(ty))
def spec_invariants(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) pn = util.FreshBitVec('pn', dt.pn_t) # # procs' page table, hvm and stack are # # 1) valid conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.And( is_pn_valid(kernelstate.procs[pid].page_table_root), is_pn_valid(kernelstate.procs[pid].hvm), is_pn_valid(kernelstate.procs[pid].stack))))) # 2) owned by that proc conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.Implies( is_status_live(kernelstate.procs[pid].state), z3.And( kernelstate.pages[kernelstate.procs[pid].page_table_root].owner == pid, kernelstate.pages[kernelstate.procs[pid].hvm].owner == pid, kernelstate.pages[kernelstate.procs[pid].stack].owner == pid))))) # 3) have the correct type conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.Implies( is_status_live(kernelstate.procs[pid].state), z3.And( kernelstate.pages[kernelstate.procs[pid].page_table_root].type == dt.page_type.PAGE_TYPE_X86_PML4, kernelstate.pages[kernelstate.procs[pid].hvm].type == dt.page_type.PAGE_TYPE_PROC_DATA, kernelstate.pages[kernelstate.procs[pid].stack].type == dt.page_type.PAGE_TYPE_PROC_DATA))))) ## # Sleeping PROC's ipc_page is a frame owned by that pid conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_SLEEPING, z3.And( is_pn_valid(kernelstate.procs[pid].ipc_page), kernelstate.pages[kernelstate.procs[pid] .ipc_page].type == dt.page_type.PAGE_TYPE_FRAME, kernelstate.pages[kernelstate.procs[pid].ipc_page].owner == pid))))) ## Non-zombie procs with use_io_bitmaps own their (valid) bitmap pages conj.append(z3.ForAll([pid], z3.Implies( z3.And( is_pid_valid(pid), kernelstate.procs[pid].use_io_bitmap, kernelstate.procs[pid].state != dt.proc_state.PROC_ZOMBIE), z3.And( is_pn_valid(kernelstate.procs[pid].io_bitmap_a), is_pn_valid(kernelstate.procs[pid].io_bitmap_b), kernelstate.pages[kernelstate.procs[pid].io_bitmap_a].owner == pid, kernelstate.pages[kernelstate.procs[pid].io_bitmap_b].owner == pid, kernelstate.pages[kernelstate.procs[pid].io_bitmap_a].type == dt.page_type.PAGE_TYPE_PROC_DATA, kernelstate.pages[kernelstate.procs[pid].io_bitmap_b].type == dt.page_type.PAGE_TYPE_PROC_DATA)))) # page has an owner <=> page is not free conj.append(z3.ForAll([pn], z3.Implies(is_pn_valid(pn), is_pid_valid(kernelstate.pages[pn].owner) == (kernelstate.pages[pn].type != dt.page_type.PAGE_TYPE_FREE)))) conj.append(z3.ForAll([pn], z3.Implies(is_pn_valid(pn), z3.Implies(kernelstate.pages[pn].type == dt.page_type.PAGE_TYPE_FREE, z3.Not(is_pid_valid(kernelstate.pages[pn].owner)))))) # a sleeping proc's ipc_fd is either invalid or empty conj.append(z3.ForAll([pid], z3.Implies(z3.And( is_pid_valid(pid), kernelstate.procs[pid].state == dt.proc_state.PROC_SLEEPING), z3.Or(z3.Not(is_fd_valid(kernelstate.procs[pid].ipc_fd)), z3.Not(is_fn_valid(kernelstate.procs[pid].ofile(kernelstate.procs[pid].ipc_fd))))))) ############## # Unused procs's refcount is all zero # conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), # z3.Implies(kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, # z3.And( # kernelstate.procs[pid].nr_pages(dt.NPAGE - 1) == z3.BitVecVal(0, dt.size_t)))))) # kernelstate.procs[pid].nr_children(dt.NPROC - 1) == z3.BitVecVal(0, dt.size_t), # kernelstate.procs[pid].nr_fds(dt.NOFILE - 1) == z3.BitVecVal(0, dt.size_t), # kernelstate.procs[pid].nr_devs(dt.NPCIDEV - 1) == z3.BitVecVal(0, dt.size_t)))))) # # unused procs don't have a parent # conj.append(z3.ForAll([pid], z3.Implies( # z3.And( # is_pid_valid(pid), # kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED), # kernelstate.procs[pid].ppid == z3.BitVecVal(0, dt.pid_t)))) # # unused procs don't have fds # conj.append(z3.ForAll([pid, fd], z3.Implies( # z3.And( # is_pid_valid(pid), # kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED), # z3.Not(is_fn_valid(kernelstate.procs[pid].ofile(fd)))))) # unused fn has refcount == 0 # conj.append(z3.ForAll([fn], z3.Implies(is_fn_valid(fn), # z3.Implies(kernelstate.files[fn].type == dt.file_type.FD_NONE, # kernelstate.files[fn].refcnt( # z3.Concat( # z3.BitVecVal(dt.NPROC - 1, dt.pid_t), # z3.BitVecVal(dt.NOFILE - 1, dt.fd_t))) == z3.BitVecVal(0, dt.size_t))))) ############## # disjointed-ness of memory regions conj.append(z3.And( z3.Extract(63, 40, z3.UDiv(kernelstate.pages_ptr_to_int, util.i64(4096)) + dt.NPAGES_PAGES) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.proc_table_ptr_to_int, util.i64(4096)) + dt.NPAGES_PROC_TABLE) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.page_desc_table_ptr_to_int, util.i64(4096)) + dt.NPAGES_PAGE_DESC_TABLE) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.file_table_ptr_to_int, util.i64(4096)) + dt.NPAGES_FILE_TABLE) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.devices_ptr_to_int,util.i64(4096)) + dt.NPAGES_DEVICES) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.dmapages_ptr_to_int,util.i64(4096)) + dt.NDMAPAGE) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.pages_ptr_to_int, util.i64(4096))) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.proc_table_ptr_to_int, util.i64(4096))) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.page_desc_table_ptr_to_int, util.i64(4096))) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.file_table_ptr_to_int, util.i64(4096))) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.devices_ptr_to_int, util.i64(4096))) == z3.BitVecVal(0, 24), z3.Extract(63, 40, z3.UDiv(kernelstate.dmapages_ptr_to_int, util.i64(4096))) == z3.BitVecVal(0, 24), z3.ULT(z3.UDiv(kernelstate.pages_ptr_to_int, util.i64(4096)) + dt.NPAGES_PAGES, z3.UDiv(kernelstate.proc_table_ptr_to_int, util.i64(4096))), z3.ULT(z3.UDiv(kernelstate.proc_table_ptr_to_int, util.i64(4096)) + dt.NPAGES_PROC_TABLE, z3.UDiv(kernelstate.page_desc_table_ptr_to_int, util.i64(4096))), z3.ULT(z3.UDiv(kernelstate.page_desc_table_ptr_to_int, util.i64(4096)) + dt.NPAGES_PAGE_DESC_TABLE, z3.UDiv(kernelstate.file_table_ptr_to_int, util.i64(4096))), z3.ULT(z3.UDiv(kernelstate.file_table_ptr_to_int, util.i64(4096)) + dt.NPAGES_FILE_TABLE, z3.UDiv(kernelstate.devices_ptr_to_int, util.i64(4096))), z3.ULT(z3.UDiv(kernelstate.devices_ptr_to_int, util.i64(4096)) + dt.NPCIDEV, z3.UDiv(kernelstate.dmapages_ptr_to_int, util.i64(4096))), z3.ULT(z3.UDiv(kernelstate.dmapages_ptr_to_int, util.i64(4096)) + dt.NDMAPAGE, z3.UDiv(dt.PCI_START, util.i64(4096))), )) # Current is a valid pid conj.append(is_pid_valid(kernelstate.current)) # Current is always running conj.append(kernelstate.procs[kernelstate.current].state == dt.proc_state.PROC_RUNNING), # A running proc must be current conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.Implies(kernelstate.procs[pid].state == dt.proc_state.PROC_RUNNING, pid == kernelstate.current)))) return z3.And(*conj)
def impl_invariants_py(ctx): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) pn = util.FreshBitVec('pn', dt.pn_t) fd = util.FreshBitVec('fd', dt.fd_t) # fn = util.FreshBitVec('fn', dt.fn_t) # embryos, runnable or running processes own the pages in their structs conj.append(z3.ForAll([pid], z3.Implies( z3.Or(util.global_field_element(ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_EMBRYO, util.global_field_element( ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_RUNNING, util.global_field_element( ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_RUNNABLE, util.global_field_element(ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_SLEEPING), z3.And( pn_has_owner_and_type(ctx, util.global_field_element( ctx, '@proc_table', 'page_table_root', pid), pid, dt.page_type.PAGE_TYPE_X86_PML4), pn_has_owner_and_type(ctx, util.global_field_element( ctx, '@proc_table', 'hvm', pid), pid, dt.page_type.PAGE_TYPE_PROC_DATA), pn_has_owner_and_type(ctx, util.global_field_element( ctx, '@proc_table', 'stack', pid), pid, dt.page_type.PAGE_TYPE_PROC_DATA), )))) # sleeping processes own their ipc_page conj.append(z3.ForAll([pid], z3.Implies(z3.And(is_pid_valid(pid), util.global_field_element(ctx, '@proc_table', 'state', pid) != dt.proc_state.PROC_ZOMBIE), z3.Implies(util.global_field_element(ctx, '@proc_table', 'use_io_bitmap', pid) != 0, z3.And( is_pn_valid(util.global_field_element(ctx, '@proc_table', 'io_bitmap_a', pid)), is_pn_valid(util.global_field_element(ctx, '@proc_table', 'io_bitmap_b', pid)), pn_has_owner_and_type(ctx, util.global_field_element(ctx, '@proc_table', 'io_bitmap_a', pid), pid, dt.page_type.PAGE_TYPE_PROC_DATA), pn_has_owner_and_type(ctx, util.global_field_element(ctx, '@proc_table', 'io_bitmap_b', pid), pid, dt.page_type.PAGE_TYPE_PROC_DATA)))))) # sleeping processes own their ipc_page conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.Implies(util.global_field_element(ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_SLEEPING, pn_has_owner_and_type(ctx, util.global_field_element(ctx, '@proc_table', 'ipc_page', pid), pid, dt.page_type.PAGE_TYPE_FRAME))))) conj.append(z3.ForAll([pid], z3.And( is_pn_valid(util.global_field_element( ctx, '@proc_table', 'page_table_root', pid)), is_pn_valid(util.global_field_element( ctx, '@proc_table', 'hvm', pid)), is_pn_valid(util.global_field_element(ctx, '@proc_table', 'stack', pid))))) # sleeping processes' ipc fd are empty if valid conj.append(z3.ForAll([pid], z3.Implies(is_pid_valid(pid), z3.Implies(util.global_field_element(ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_SLEEPING, z3.Implies(is_fd_valid(util.global_field_element(ctx, '@proc_table', 'ipc_fd', pid)), util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, util.global_field_element(ctx, '@proc_table', 'ipc_fd', pid))) == z3.BitVecVal(0, dt.fn_t)))))) conj.append(z3.ForAll([pid], z3.And( is_pn_valid(util.global_field_element( ctx, '@proc_table', 'page_table_root', pid)), is_pn_valid(util.global_field_element( ctx, '@proc_table', 'hvm', pid)), is_pn_valid(util.global_field_element(ctx, '@proc_table', 'stack', pid))))) # page has an owner <=> page is not free conj.append(z3.ForAll([pn], z3.Implies(is_pn_valid(pn), is_pid_valid(util.global_field_element(ctx, '@page_desc_table', 'pid', pn)) == (util.global_field_element(ctx, '@page_desc_table', 'type', pn) != dt.page_type.PAGE_TYPE_FREE)))) # unused procs have zero refcnt conj.append(z3.ForAll([pid], z3.Implies( z3.And( is_pid_valid(pid), util.global_field_element(ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_UNUSED), z3.And( util.global_field_element(ctx, '@proc_table', 'nr_children', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_fds', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_pages', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_dmapages', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_devs', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_ports', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_vectors', pid) == z3.BitVecVal(0, dt.size_t), util.global_field_element(ctx, '@proc_table', 'nr_intremaps', pid) == z3.BitVecVal(0, dt.size_t))))) # conj.append(z3.ForAll([pid, fd], z3.Implies(z3.And(is_pid_valid(pid), is_fd_valid(fd)), # z3.Implies( # util.global_field_element(ctx, '@proc_table', 'nr_fds', pid) == z3.BitVecVal(0, dt.size_t), # z3.Not(is_fn_valid(util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, fd)))))))) # # unused procs have zero fds # conj.append(z3.ForAll([pid, fd], z3.Implies(z3.And(is_pid_valid(pid), is_fd_valid(fd)), # z3.Implies( # util.global_field_element(ctx, '@proc_table', 'state', pid) == dt.proc_state.PROC_UNUSED, # util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, fd)) == z3.BitVecVal(0, dt.fn_t))))) # fds valid conj.append(z3.ForAll([pid, fd], z3.Implies(z3.And(is_pid_valid(pid), is_fd_valid(fd)), z3.Or( util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, fd)) == z3.BitVecVal(0, dt.fn_t), is_fn_valid(util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, fd))))))) # # FD_NONE's refcount is 0 # conj.append(z3.ForAll([fn], z3.Implies( # z3.And( # is_fn_valid(fn), # util.global_field_element(ctx, '@file_table', 'type', fn) == dt.file_type.FD_NONE), # util.global_field_element(ctx, '@file_table', 'refcnt', fn) == z3.BitVecVal(0, dt.size_t)))) # # FD never points to FD_NONE # conj.append(z3.ForAll([pid, fd], z3.Implies( # z3.And( # is_pid_valid(pid), # is_fd_valid(fd), # is_fn_valid(util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, fd)))), # util.global_field_element(ctx, '@file_table', 'type', # util.global_field_element(ctx, '@proc_table', 'ofile', pid, z3.ZeroExt(32, fd))) != dt.file_type.FD_NONE))) # page freelist is well formed conj.append(z3.ForAll([pn], z3.Implies(is_pn_valid(pn), z3.And( is_pn_valid(util.global_field_element(ctx, '@page_desc_table', ['link', 'prev'], pn)), is_pn_valid(util.global_field_element(ctx, '@page_desc_table', ['link', 'next'], pn)))))) # ready queue is well formed # don't use is_pid_valid as some ->prev and ->next are zeros conj.append(z3.ForAll([pid], z3.Implies(is_pid_bounded(pid), z3.And( is_pid_bounded(util.global_field_element(ctx, '@proc_table', ['ready', 'prev'], pid)), is_pid_bounded(util.global_field_element(ctx, '@proc_table', ['ready', 'next'], pid)))))) # Current is always a valid and running conj.append(is_pid_valid(util.global_value(ctx, '@current'))) conj.append(util.global_field_element(ctx, '@proc_table', 'state', util.global_value(ctx, '@current')) == dt.proc_state.PROC_RUNNING) return z3.And(*conj)
def comparable_coverability(petrinet, init, targets, prune=False, max_iter=None): global total_check_time global total_build_time global UUcomp global nbcomp global error # Verify if non coverable in CPN first if prune and non_coverable(petrinet, init, targets): print "non_coverable in Q" print "result find with non_coverable" return False # Otherwise, proceed with backward coverability def smallest_elems(x): return set(sorted(x, key=sum_norm)[:int(10 + 0.2 * len(x))]) solverQ, variables = build_cpn_solver(petrinet, init, targets=None, domain='N') transitions = get_transitions(petrinet) solverL,_ = build_limit_solver(transitions,init) _, _, target_vars = variables def comparaison_coverable(markings): global glitch global UUcomp global nbcomp global error nbcomp += 1 #print solverQ #print solverL resQ = check_cpn_coverability_z3(solverQ, target_vars, markings) resL = check_limit_coverability_z3(solverL, markings) if resQ and resL == False: print "qcover solver say cover and limit solver say not cover" print "impossible" print "error" #print markings error +=1 print exit(1) if resQ == False and resL: glitch +=1 return resQ init_marking = _omega_marking(init) basis = {tuple(constraint_vector(m)) for m in targets} precomputed = {} covered = in_upward(init_marking, basis) num_iter = 0 while not covered: if max_iter is not None and num_iter >= max_iter: return None # Unknown result else: num_iter += 1 # Compute prebasis print "step :",num_iter prebasis = pre_upward(petrinet, basis, precomputed) # Coverability pruning nbover = glitch pruned = {x for x in prebasis if prune and not comparaison_coverable([x])} print "nb over ", glitch-nbover print "prebasis size : ", len(prebasis) print "size of pruned :", len(pruned) prebasis.difference_update(pruned) for x in pruned: solverQ.add(z3.Or([target_vars[p] < x[p] for p in range(len(x))])) # Continue? if len(prebasis) == 0: break else: prebasis = smallest_elems(prebasis) merge_upward(basis, prebasis) covered = in_upward(init_marking, basis) print print "total build time :", total_build_time print "total check time :", total_check_time print "glitch: ", glitch print "error", error print "comparison", nbcomp return covered
return z3.ZeroExt(64 - 8, parse_byte(b)) return (pl(chars[0]) << 56) | (pl(chars[1]) << 48) | (pl(chars[2]) << 40) | (pl(chars[3]) << 32) | (pl(chars[4]) << 24) | (pl(chars[5]) << 16) | (pl(chars[6]) << 8) | (pl(chars[7])) print("sanity checking parse_byte function") print(s.check()) print(s.model().eval(z3.BitVecVal(int('aF', 16), 16))) for idx, c in enumerate(begin): s.add(flag[idx] == ord(c)) s.add(flag[-1] == ord('}')) for c in flag[5:-1]: # change our domain to allow 0 s.add(z3.Or( z3.And(c >= ord('0'), c <= ord('9')), z3.And(c >= ord('a'), c <= ord('f')), z3.And(c >= ord('A'), c <= ord('F')) )) target = 1140336659 # res = z3.BitVecVal(0, 32) # flag_len = len(flag) # for idx, c in enumerate(flag): # res = res + z3.ZeroExt(24, c) * (31**(flag_len - idx - 1)) # print(res) r3 = z3.BitVecVal(0, 32) for c in flag: r3 = r3 * 31 + z3.ZeroExt(24, c) s.add(r3 == target) # s.add(res == target)
Z = ZHolder() Z.Wrapbool = Unk.bool Z.Wrapint = Unk.int Z.Wrapstring = Unk.string Z.Wrapfunc = Unk.func Z.Wrapnone = Unk.none Z.Bool = Unk.tobool Z.Int = Unk.toint Z.String = Unk.tostring Z.Func = Unk.tofunc Z.Isbool = lambda x: Unk.is_bool(x) Z.Isint = lambda x: Unk.is_int(x) Z.Isstring = lambda x: Unk.is_string(x) Z.Isfunc = lambda x: Unk.is_func(x) Z.Istuple = lambda x: z3.Or(Unk.is_app(x), Unk.is__(x)) Z.Isnone = lambda x: Unk.is_none(x) Z.Isdefined = lambda x: z3.Not(Unk.is_undef(x)) Z.Isundefined = lambda x: Unk.is_undef(x) Z.Eq = lambda x, y: x == y Z.Neq = lambda x, y: x != y Z.Distinct = z3.Distinct Z.T = z3.Function('T', Unk, z3.BoolSort()) Z.F = z3.Function('F', Unk, z3.BoolSort()) Z.N = Unk.none Z.Length = z3.Length Z.Implies = z3.Implies Z.And = z3.And Z.Or = z3.Or Z.Not = z3.Not Z.Negate = lambda x: -x
i_value, bv_value3, value_relationship, True, True, bv_type='intle:32')) print("Is conversion precise for bit-vector:" + str(bv_value3) + " in integer domain:" + str(i_value)) print(explanation) #check given constraints that should make them precise i_value = i_y - 2 bv_value4 = yconcat + z3.BitVecVal(-2, 32) value_relationship = (z3.BV2Int(bv_value4) == i_value) i_condition = i_y > 6 bv_condition = yconcat > z3.BitVecVal(6, 32) print("Alas, can we prove that bit-vector: " + str(bv_value4) + " in integer domain: " + str(i_value) + " under constraints: " + str(i_condition) + " and " + str(bv_condition) + " is precise?") print("... wait for demonstration of timeout") (same, model, explanation) = ( bar2020.single_variable_bit_vector_domain_equals_integer_domain( i_y, y, variable_relationship, i_value, bv_value4, value_relationship, i_condition, bv_condition, bv_type='intle:32')) print(explanation) #example using logic synthesis constraint = z3.And(z3.Or(y > 6, y == 6), z3.Not(y == 6)) using_sis = bar2020.simplify_z3_boolean_using_logic_synthesis_approach(constraint) print("Using sis, we can simplify " + str(constraint) + " to " + str(using_sis))
def _sat_expr(self, x, r, i, l): if l not in self._len_set(r): return z3.BoolVal(False) if i + l > self.length: return z3.BoolVal(False) ty = r[0] if ty == regex_parser.EMPTY: return z3.BoolVal(True) elif ty == regex_parser.CHAR: return (x[i] == ord(r[1])) elif ty == regex_parser.DOT: expr = z3.BoolVal(False) for ch in regex_parser.CHARSET: expr = z3.Or(expr, x[i] == ord(ch)) return expr elif ty == regex_parser.STAR: # SAT(r*, i, l) = Union for l' in LEN(r): # [ SAT(r, i, l') && SAT(r*, i+l', l-l') ] if l == 0: return z3.BoolVal(True) else: expr = z3.BoolVal(False) for l1 in self._len_set(r[1]): expr = z3.Or( expr, z3.And(self._sat_expr(x, r[1], i, l1), self._sat_expr(x, r, i + l1, l - l1))) return expr elif ty == regex_parser.BAR: # SAT(r1 | r2, i, l) = SAT(r1, i, l) || SAT(r2, i, l) expr = z3.Or(self._sat_expr(x, r[1], i, l), self._sat_expr(x, r[2], i, l)) return expr elif ty == regex_parser.CONCAT: # SAT(r1 r2, i, l) = Union for l1 in LEN(r1): # [ SAT(r1, i, l1) && SAT(r2, i+l1, l-l1) ] expr = z3.BoolVal(False) for l1 in self._len_set(r[1]): expr = z3.Or( expr, z3.And(self._sat_expr(x, r[1], i, l1), self._sat_expr(x, r[2], i + l1, l - l1))) return expr elif ty == regex_parser.GROUP: idx = r[1] - 1 inner = r[2] if (idx + 1) in self.backrefs: expr = z3.And((self.p[idx] == i), self._sat_expr(x, inner, i, l)) self.possible_pos[idx].add(i) else: expr = self._sat_expr(x, inner, i, l) return expr elif ty == regex_parser.BACKREF: idx = r[1] - 1 expr = z3.BoolVal(False) for j in self.possible_pos[idx]: clause = (self.p[idx] == j) for k in range(l): clause = z3.And(clause, (x[i + k] == x[j + k])) expr = z3.Or(expr, clause) return expr elif ty == regex_parser.CARET: inner = r[1] if i == 0: return self._sat_expr(x, inner, i, l) else: return z3.BoolVal(False) elif ty == regex_parser.DOLLAR: inner = r[1] if i + l == self.length: return self._sat_expr(x, inner, i, l) else: return z3.BoolVal(False) else: raise ValueError("Unknown regex_parser type '%s'" % repr(ty))
'east', 'north', 'west', ) def _generate_cards_for_player(player): for suit in suits: for rank in ranks: yield z3.Int('%s_%s_%s' % (player.key, suit.key, rank.key)) def _cards_for_player(player): return list(_generate_cards_for_player(player)) hands = map(_cards_for_player, players) axioms = [] axioms += [z3.Or(card == 0, card == 1) for card in sum(hands, [])] axioms += [sum(cards) == 1 for cards in zip(*hands)] axioms += [sum(cards) == 13 for cards in hands] solver = z3.Solver() solver.add(axioms) solver.check() model = solver.model() for cards in hands: for card in cards: if z3.is_true(model.eval(card == 1)): print card
def int01(self, name): v = z3.Int(name) self.solver.add(z3.Or(v == 0, v == 1)) return v
def Or(*args): return z3.Or(*(args + (getCtx(), )))
def delta_x(self, other): delta_x = z3.BitVec(self.name + '-' + other.name + '_delta_x', self.fabric.cols) constraint = z3.Or(self.x == other.x << delta_x, other.x == self.x << delta_x) return constraint, delta_x
def _walk(a, i, c): if a.size() != self.options.physical_address_bits: raise Exception( f"walk expected a " f"{self.options.physical_address_bits}-bit PA, " f"but got an address of {a.size()} bits") hi, lo = self.vpn_bits[i] vpn_i = z3.Extract(hi, lo, va) possibly_n = i == 0 and self.pte_size == 8 if possibly_n: # offset is further constrained in the second `possibly_n` # block below offset = self.physical_address( z3.BitVec(f"{op_name}_walk_{i}_offset", 9)) else: offset = self.physical_address(vpn_i) # Calculate the PTE address pte_addr = a + offset * self.pte_size # Generate an Implicit Read read_name = f"{op_name}_walk_{i}" builder.read( meta, tid, read_name, "PT Walk", c, self.pte_size, pte_addr, False, False, reserve=True, implicit=True, satp_asid=self.asid, ) # Update translation_order nonlocal previous_implicit for prev_op, prev_condition in previous_implicit: builder.translation_order.update((prev_op, read_name), z3.And(c, prev_condition)) previous_implicit.append((read_name, c)) # Interpret the return value as a PTE of the appropriate size value = builder.return_value[read_name] if self.pte_size == 4: pte = pte32(value) elif self.pte_size == 8: pte = pte64(value) else: assert False # Fault if any of the reserved bits are set if self.pte_size == 8: custom = z3.Extract(63, 63, pte.value()) reserved = z3.Extract(61, 54, pte.value()) c = _fault_if("access", c, z3.Or(custom != 0, reserved != 0)) # Batch the page faults for better solver performance page_fault_conditions = [] # Check for NAPOT pages if possibly_n: # For Svnapot translations, the offset must either match the # original offset or be to a valid NAPOT PTE in the same region napot64k = z3.And( pte.n, z3.Extract(3, 0, pte.ppn) == z3.BitVecVal(0b1000, 4)) builder.fact( z3.Or( offset == self.physical_address(vpn_i), z3.And( napot64k, z3.Extract(8, 4, offset) == z3.Extract(8, 4, vpn_i), ), ), "Svnapot offset", ) # Fault if the offset points to an invalid NAPOT PTE page_fault_conditions.append(z3.And(pte.n, z3.Not(napot64k))) else: page_fault_conditions.append(pte.n) napot64k = False # Fault if not V page_fault_conditions.append(z3.Not(pte.v)) # Fault if W and not R page_fault_conditions.append(z3.And(pte.w, z3.Not(pte.r))) # Check R, W, X, U leaf = z3.Or(pte.r, pte.x) page_fault_conditions.append(z3.And(leaf, read, z3.Not(pte.r))) page_fault_conditions.append(z3.And(leaf, write, z3.Not(pte.w))) page_fault_conditions.append(z3.And(leaf, execute, z3.Not(pte.x))) page_fault_conditions.append(z3.And(user, z3.Not(pte.u))) # Fault if i == 0 and this is not a leaf PTE if i == 0: page_fault_conditions.append(z3.Not(leaf)) # Fault if this is a misaligned superpage for j in range(i): hi, lo = self.ppn_bits[j] ppn_j = z3.Extract(hi, lo, pte.value()) page_fault_conditions.append( z3.And(leaf, ppn_j != z3.BitVecVal(0, ppn_j.size())), ) # Fault if A and D are not set properly a_d_insufficient = z3.And( c, z3.Or( z3.And(leaf, z3.Not(pte.a)), z3.And(leaf, write, z3.Not(pte.d)), ), ) if self.options.hardware_a_d_bit_update: # That's it for page fault checks c = _fault_if("page", c, z3.Or(page_fault_conditions)) old_pte_value = pte.value() updated_pte_value = z3.Concat( z3.Extract(old_pte_value.size() - 1, 8, old_pte_value), z3.If(write, resize(1, 1), z3.Extract(7, 7, old_pte_value)), resize(1, 1), z3.Extract(5, 0, old_pte_value), ) write_name = f"{op_name}_walk_{i}_a_d" # We are assuming this SC always succeeds just as a way of # filtering out some of the space that needs to be explored builder.write( meta, tid, write_name, "A/D Update", a_d_insufficient, self.pte_size, pte_addr, updated_pte_value, aq=False, rl=False, conditional_dst="x0", implicit=True, satp_asid=self.asid, ) builder.implicit_pair.update((read_name, write_name), a_d_insufficient) builder.datadep.update((read_name, write_name), a_d_insufficient) for prev_op, prev_condition in previous_implicit: builder.translation_order.update( (prev_op, write_name), z3.And(c, prev_condition, a_d_insufficient), ) previous_implicit.append( (write_name, z3.And(c, a_d_insufficient))) pte_value = z3.If(a_d_insufficient, old_pte_value, updated_pte_value) else: page_fault_conditions.append(a_d_insufficient) # That's it for page fault checks c = _fault_if("page", c, z3.Or(page_fault_conditions)) pte_value = pte.value() # Update the PPN to account for PTE.N pte_size = pte_value.size() pte_value = z3.If( napot64k, z3.Concat( z3.Extract(pte_size - 1, 14, pte_value), z3.Extract(15, 12, va), z3.Extract(9, 0, pte_value), ), pte_value, ) # Generate the PTE from the PPNs and offsets pa_components = [] for j in range(self.levels - 1, i - 1, -1): hi, lo = self.ppn_bits[j] pa_components.append(z3.Extract(hi, lo, pte_value)) for j in range(i - 1, -1, -1): hi, lo = self.vpn_bits[j] pa_components.append(z3.Extract(hi, lo, va)) pa_components.append(z3.Extract(11, 0, va)) pa_leaf = self.physical_address(z3.Concat(pa_components)) # Fault if the calculated PA is out of range c = _fault_if( "access", c, z3.And(leaf, truncates(pa_leaf, self.options.physical_address_bits)), ) # Recurse to the next level, unless this is a leaf PTE if i == 0 or true(leaf): return pa_leaf, c else: hi = self.ppn_bits[-1][0] lo = self.ppn_bits[0][1] ppn = z3.Extract(hi, lo, pte_value) a = self.physical_address(z3.Concat(ppn, z3.BitVecVal(0, 12))) c = z3.And(c, z3.Not(leaf)) pa, c_walk = _walk(a, i - 1, c) return z3.If(leaf, pa_leaf, pa), z3.If(leaf, c, c_walk)
def delta_y(self, other): delta_y = z3.BitVec(self.name + '-' + other.name + '_delta_y', self.fabric.rows) constraint = z3.Or(self.y == other.y << delta_y, other.y == self.y << delta_y) return constraint, delta_y
def or_(ctx, *args): return z3.Or(*args)
def delta_fun(constant): if constant == 0: return self.y == other.y else: return z3.Or(self.y == other.y << constant, other.y == self.y << constant)
elif isinstance(e, AppExpr) and e.callee in functions: return functions[e.callee](*(map(to_z3, e.args))) elif (isinstance(e, AppExpr) and e.callee in relations and isinstance(r := relations[e.callee], z3.FuncDeclRef)): return r(*(map(to_z3, e.args))) elif isinstance(e, UnaryExpr) and e.op == 'NOT': return z3.Not(to_z3(e.arg)) elif isinstance(e, BinaryExpr) and e.op == 'EQUAL': return to_z3(e.arg1) == to_z3(e.arg2) else: assert False, e value = z3.Implies( z3.And(*(universes[s](v) for v, s in zip(z3_vs, self.prefix_names))), z3.And(*(z3.Or(*(z3.And(self.lit_vs[i, lit], to_z3(lit)) for lit in self.literals)) for i in range(self.n_clauses)))) if len(z3_vs) > 0: value = z3.ForAll(z3_vs, value) assertions.append(state_models_sep == value) return assertions, state_models_sep def sep_main(solver: Solver) -> str: prog = syntax.the_program print(f'\n[{datetime.now()}] [PID={os.getpid()}] Starting sep\n') safety = tuple( chain(*(as_clauses(inv.expr) for inv in prog.invs() if inv.is_safety))) # convert to CNF
def get_accelerations_from_z3(trans: [OmegaTransition], init_marking: np.array, timeout=1): time_start = time.time() trans_var = [] strictly_greater_constrain = [] dim = trans[0].get_dim() accelerations = [] marking = init_marking if init_marking is None: marking = [0] * dim solver = z3.Solver() for i in range(len(trans)): name = "t" + i.__str__() trans_var.append(z3.Int(name)) first = True for p in range(dim): if marking[p] == float("inf"): continue terms = [] for t in range(len(trans)): terms.append((trans[t].get_incidence())[p] * trans_var[t]) # terms = ([c * x for (c, x) in zip(constants, trans_var)]) sum = z3.Sum(terms) if first: temp = sum >= 0 first = False else: temp = z3.And(temp, sum >= 0) strictly_greater_constrain.append(sum > 0) solver.add(temp) solver.add(z3.Or(strictly_greater_constrain)) above_zero = [x >= 0 for x in trans_var] solver.add(above_zero) solver.add(z3.Sum(trans_var) <= 15) n = 0 while time.time() - time_start < timeout: if solver.check() != z3.sat: break sol = solver.model() new_acc = from_solution_to_acceleration(sol, trans_var, trans, dim) to_add_the_new_acc = True num_of_acc = len(accelerations) for i in range(num_of_acc): acc = accelerations[num_of_acc - i - 1] if new_acc > acc: accelerations.remove(acc) if new_acc <= acc: to_add_the_new_acc = False break if to_add_the_new_acc: accelerations.append(new_acc) par = z3.Int("c" + n.__str__()) n += 1 not_the_same_answer = ([y != par * sol[y] for y in trans_var]) solver.add(z3.Or(not_the_same_answer)) return accelerations
################################################################################ # # These dictionaries gives the Z3 translations of the built-in symbols, # built-in sorts, and Z3 functions for building constants of the built-in # sorts. # ################################################################################ _built_in_z3_funs = { eq.name: (lambda args, context: args[0] == args[1]), And.name: (lambda args, context: z3.And(args)), Or.name: (lambda args, context: z3.Or(args)), implies.name: (lambda args, context: z3.Implies(args[0], args[1], context)), Not.name: (lambda args, context: z3.Not(args[0], context)), add.name: (lambda args, context: args[0] + args[1]), mul.name: (lambda args, context: args[0] * args[1]), minus.name: (lambda args, context: args[0] - args[1]), div.name: (lambda args, context: args[0] / args[1]), power.name: (lambda args, context: pow(args[0], args[1])), uminus.name: (lambda args, context: -args[0]), absf.name: (lambda args, context: abs(args[0])), lt.name: (lambda args, context: args[0] < args[1]), le.name: (lambda args, context: args[0] <= args[1]) # these are not used # ne.name: (lambda args, context: args[0] != args[1]), # Sum.name: (lambda args, context: z3.Sum(args)),
def valid(self): valid_list = [] for member_name, _ in self.fields: member_hdr = self.resolve_reference(member_name) valid_list.append(member_hdr.isValid()) return z3.simplify(z3.Or(*valid_list))
def solve(foods): s = z3.Solver() # encode all ingredients and allergens ingredients_ = list(set(item for pair in foods for item in pair[0])) allergens_ = list(set(item for pair in foods for item in pair[1])) ingredients = dict((v, i) for i, v in enumerate(ingredients_)) allergens = dict((v, i) for i, v in enumerate(allergens_)) # we want to find out which ingredient is an allergen # we treat this as an MxN assignment problem # ie. solve for which ingredient can be possibly assigned as an allergen, while satisfying all input constrains assignments = z3.IntVector('allergen', len(allergens)) # program the valid range of our ingredient encodings for a in assignments: s.add(z3.And(a >= 0, a < len(ingredients))) # there can only be one possible ingredient assigned to an allergen s.add(z3.Distinct(assignments)) for i, a in foods: # program the all possible pairs of assignment for this food for a_ in a: food = [] for i_ in i: # encode the input constrain I = ingredients[i_] A = assignments[allergens[a_]] # one of these (allergen == ingredient) pair could be valid food.append(A == I) s.add(z3.Or(food)) # ensure that this food doesn't contain any other types of allergen food = [] not_a = set(allergens.keys()) - set(a) for i_, a_ in itertools.product(i, not_a): # encode the input constrain I = ingredients[i_] A = assignments[allergens[a_]] # not any other types of allergen # print(f"{(i_, a_)=}") food.append(I != A) s.add(z3.Or(food)) # are we asking the impossible? print(f"{s=}") print() r = s.check() print(f"{r=}") if r == z3.sat: # constrain satisfied, now we extract the solution from the model m = s.model() print(f"{m=}") # reverse the our integer encoding into string allergen = dict(enumerate(allergens_)) ingredient = dict(enumerate(ingredients_)) solution = [{'ingredient': ingredient[m.eval(a).as_long()], 'allergen': allergen[i]} for i, a in enumerate(assignments)] return solution
def expt_rules(): rules = collections.deque() solver = z3.Solver() solver.set('arith.nl', False) solver.add(hyps) def show(p): report('trying to show(', p, '):') report(' hypotheses = ', solver) solver.push() solver.add(z3.Not(p)) outcome = solver.check() s1 = ' the negation is ' + str(outcome) if(outcome == z3.unsat): report(s1, "; therefore the original claim is valid") elif(outcome == z3.sat): report(s1, "\n here's a counter-example to ", p, "\n ", solver.model()) elif(outcome == z3.unknown): report(s1, "; therefore, the original claim is undecided") else: report(s1, "; how'd that happen?") solver.pop() return outcome == z3.unsat def add_rule(p): report('add_rule(', p, ')') rules.append(p) solver.add(p) while(len(workQ) > 0): v = workQ.pop() x = v.children()[0] n = v.children()[1] report('rewriting expt(', x, ', ', n, ')') # Many of the rules below should have guards to ensure that we don't # accidentally say expt(x, n) is defined when x==0 and n < 0. # Rather that figuring out # all of the corner cases, I first check to # see if (x == 0) and (n < 0) is satisfiable. If so, this code just # throws an exception. I could probably work out a better error message # later. # Now that we know that expt(x, n) is well-defined, we still need to be careful. # Consider expt(x, n+m) where x==0, n==3, and m==(-2). In this case, expt(x, n+m) # is well-defined, but we can't conclude: # expt(x, n+m) == expt(x, n) * expt(x, m) # Rather than working out lots of side conditions (and probably making a mistake), # I just check to see if implies(hyps, x > 0), and then plunge ahead without fear. # Of course, this means I don't generate all of the rules that I could, but I'll # do that later if this simple version turns out to be useful. def expt_rewrite_const(x2, n2): if(n2 == 0): return z3.intVal(1) elif((0 < n2) and (n2 <= self.maxPowExpand)): add_rule(v == prod(map(lambda _: x2, range(n2)))) elif((-self.maxPowExpand <= n2) and (n2 < 0)): add_rule(v*prod(map(lambda _: x2, range(-n2))) == 1) if(not show(z3.Or(x != 0, n >= 0))): raise ExptRewriteFailure('possible attempt to raise 0 to a negative power') x_is_pos = show(x > 0) x_is_nz = x_is_pos or show(x != 0) x_is_z = (not x_is_nz) and show(x == 0) n_is_pos = show(n > 0) n_is_neg = (not n_is_pos) and show(n < 0) n_is_z = (not n_is_pos) and (not n_is_neg) and show(n == 0) if(n_is_z or x_is_z): if(n_is_z): add_rule(v == 1) elif(n_is_pos): add_rule(v == 0) else: add_rule(v == z3.If(n == 0, 1, 0)) continue elif(x_is_pos): x_lt_1 = show(x < 1) x_gt_1 = (not x_lt_1) and show(x > 1) if((not x_lt_1) and (not x_gt_1) and show(x == 1)): add_rule(v == 1) continue add_rule(v > 0) else: add_rule(z3.Implies(x > 0, v > 0)) if(x_is_nz): add_rule(z != 0) else: add_rule(z3.Implies(z3.Or(x != 0, n==0), v != 0)) if((x.decl().name() == '*') and (len(x.children()) > 1)): # expt(x0*x1*..., n) add_rule(v == prod(map(lambda y: xpt(y, n), x.children()))) elif((n.decl().name() == '+') and (len(n.children()) > 1)): # expt(x, n0+n1+...) add_rule(v == prod(map(lambda m: xpt(x, m), n.children()))) elif(n.decl().name() == '-'): nn = n.children() if(len(nn) == 0): pass # a variable named '-' elif(len(nn) == 1): # expt(x, -n) add_rule(z3.Implies(x != 0, v*xpt(x, nn[0]) == 1)) elif(len(nn) == 2): # expt(x, n-m) add_rule(z3.Implies(x != 0, v*xpt(x, nn[1]) == xpt(x, nn[0]))) else: RewriteExptFailure("unexpected: '-' expression with more than two children") elif(n.decl().name() == '*'): # expt(x, n0*n1*...) # check to see if n0 is integer constants and not "too big". # if so, replace it with repeated multiplication nn = n.children() if((len(nn) > 0) and not (longVal(nn[0]) is None)): if(len(nn) == 1): ex = x else: ex = xpt(x, prod(nn[1:])) expt_rewrite_const(ex, longVal(nn[0])) elif(not (longVal(n) is None)): expt_rewrite_const(x, longVal(n)) else: # we can't think of a way to simplify it if(x_lt_1 or x_gt_1): if(n_is_pos or n_is_neg): pass else: add_rule(z3.Implies(n == 0, v == 1)) else: if(n_is_pos or n_is_neg): add_rule(z3.Implies(x==1, v == 1)) else: add_rule(z3.Implies(z3.Or(x==1, n == 0), v == 1)) if(x_is_pos): if(x_lt_1): if(n_is_pos): add_rule(v <= x) elif(n_is_neg): add_rule(v*x >= 1) else: add_rule(z3.And( z3.Implies(n > 0, v <= x), z3.Implies(n < 0, v*x >= 1))) elif(x_gt_1): if(n_is_pos): add_rule(v >= x) elif(n_is_neg): add_rule(v*x <= 1) else: add_rule(z3.And( z3.Implies(n > 0, v >= x), z3.Implies(n < 0, v*x <= 1))) else: add_rule(z3.And( z3.Implies(z3.And(x < 1, n > 0), v <= x), z3.Implies(z3.And(x < 1, n < 0), v*x >= 1), z3.Implies(z3.And(x > 1, n > 0), v >= x), z3.Implies(z3.And(x > 1, n < 0), v*x <= 1))) return rules
def _z3expr(self, printable): return z3.Or(*[z3expr(a, printable) for a in self.args])
def z3_isalnum(ch): return z3.Or( z3.And(0x30 <= ch, ch <= 0x39), z3.And(0x41 <= ch, ch <= 0x5a), z3.And(0x61 <= ch, ch <= 0x7a), )
ast.Gt: lambda x, y: x > y, ast.Lt: lambda x, y: x < y, ast.LtE: lambda x, y: x <= y, ast.GtE: lambda x, y: x >= y } _binop_map = { ast.Add: lambda x, y: x + y, ast.Sub: lambda x, y: x - y, ast.Mult: lambda x, y: x * y, ast.Div: lambda x, y: x / y } _boolop_map = { ast.And: lambda x, y: z3.And(x, y), ast.Or: lambda x, y: z3.Or(x, y) } _unop_map = {ast.USub: lambda x: -x} class NodeVerifier(ast.NodeVisitor): """ Walks through the :py:class:`ast.AST` and generate constraints to be solved by z3. """ def __init__(self): """ Initialization of :py:class:`NodeVerifier`. """ self._precondition = [] self._declarations = []
def In(val, lst): assert len(lst) > 0, "List must be non-empty" return z3.Or(*[val == a for a in lst])