def get_safety() -> List[Expr]: prog = syntax.the_program safety: List[Expr] if utils.args.safety is not None: the_inv: Optional[InvariantDecl] = None for inv in prog.invs(): if inv.name == utils.args.safety: the_inv = inv if the_inv is not None: safety = [the_inv.expr] else: try: oldcount = utils.error_count e = syntax.close_free_vars(parser.parse_expr( utils.args.safety)) with prog.scope.n_states(1): typechecker.typecheck_expr(prog.scope, e, syntax.BoolSort) assert oldcount == utils.error_count, 'errors in parsing or typechecking' safety = [e] except Exception as e: print(e) utils.print_error_and_exit( None, f'--safety received string "{utils.args.safety}", ' 'which is neither the name of an invariant/safety property ' 'nor does it parse and typecheck as an expression') else: safety = [s.expr for s in prog.safeties()] return safety
def verify(s: Solver) -> None: old_count = utils.error_count prog = syntax.the_program a = prog.the_automaton() if a is None: if utils.args.automaton == 'only': utils.print_error_and_exit( None, "--automaton='only' requires the file to declare an automaton") elif utils.args.automaton != 'no': check_automaton_full(s, a) if utils.args.automaton != 'only': init_res = logic.check_init(s) tr_res = logic.check_transitions(s) res = init_res or tr_res if res is not None and utils.args.json: json_cex: Optional[JSON] = json_counterexample(res) else: json_cex = None obj: JSON = {} obj['version'] = 1 obj['subcommand'] = utils.args.subcommand obj['is_inductive'] = json_cex is None if json_cex is not None: obj['counterexample'] = json_cex json.dump(obj, sys.stdout, indent=4) if utils.error_count == old_count: utils.logger.always_print('all ok!') else: utils.logger.always_print('program has errors.')
def __init__(self, solver: Solver) -> None: self.solver = solver prog = syntax.the_program if utils.args.automaton: automaton = prog.the_automaton() if automaton is None: utils.print_error_and_exit( None, 'updr --automaton requires the file to ' 'declare an automaton') else: the_phase = 'the_phase' pcs: List[syntax.PhaseComponent] = [] for t in prog.transitions(): pcs.append( syntax.PhaseTransitionDecl(None, t.name, None, the_phase)) for inv in prog.safeties(): pcs.append(inv) automaton = AutomatonDecl(None, [ syntax.InitPhaseDecl(None, the_phase), syntax.PhaseDecl(None, the_phase, pcs) ]) automaton.resolve(prog.scope) self.automaton = PhaseAutomaton(automaton) self.fs: List[Frame] = [] self.push_cache: List[Dict[Phase, Set[Expr]]] = [] self.counter = 0 self.predicates: List[Expr] = [] self.state_count = 0
def bmc_trace(prog: syntax.Program, trace: syntax.TraceDecl, s: Solver, sat_checker: Callable[[Solver, List[str]], Optional[logic.Trace]], log: bool = False) -> Optional[logic.Trace]: n_states = len(list(trace.transitions())) + 1 if log: print('%s states' % (n_states, )) keys = ['state%2d' % i for i in range(n_states)] for k in keys: s.get_translator( k) # initialize all the keys before pushing a solver stack frame with s: lator = s.get_translator(keys[0]) if len(trace.components) > 0 and not isinstance( trace.components[0], syntax.AssertDecl): for init in prog.inits(): s.add(lator.translate_expr(init.expr)) i = 0 for c in trace.components: if isinstance(c, syntax.AssertDecl): if c.expr is None: if i != 0: utils.print_error_and_exit( c.tok, 'assert init is only allowed in the first state') for init in prog.inits(): s.add( s.get_translator(keys[i]).translate_expr( init.expr)) else: s.add(s.get_translator(keys[i]).translate_expr(c.expr)) else: te: syntax.TransitionExpr = c.transition if isinstance(te, syntax.AnyTransition): logic.assert_any_transition(s, str(i), keys[i + 1], keys[i], allow_stutter=True) else: l = [] for call in te.calls: tid = z3.Bool( logic.get_transition_indicator( str(i), call.target)) l.append(tid) s.add(tid == translate_transition_call( s, keys[i + 1], keys[i], call)) s.add(z3.Or(*l)) i += 1 return sat_checker(s, keys)
def bmc_trace(prog: syntax.Program, trace: syntax.TraceDecl, s: Solver, sat_checker: Callable[[Solver, int], Optional[logic.Trace]], log: bool = False) -> Optional[logic.Trace]: n_states = len(list(trace.transitions())) + 1 if log: print('%s states' % (n_states, )) lator = s.get_translator(n_states) with s.new_frame(): if len(trace.components) > 0 and not isinstance( trace.components[0], syntax.AssertDecl): for init in prog.inits(): s.add(lator.translate_expr(init.expr)) i = 0 for c in trace.components: if isinstance(c, syntax.AssertDecl): if c.expr is None: if i != 0: utils.print_error_and_exit( c.span, 'assert init is only allowed in the first state') for init in prog.inits(): assert i == 0 s.add(lator.translate_expr(init.expr)) else: s.add(lator.translate_expr(New(c.expr, i))) else: te: syntax.TransitionExpr = c.transition if isinstance(te, syntax.AnyTransition): logic.assert_any_transition(s, lator, i, allow_stutter=True) else: l = [] for call in te.calls: tid = z3.Bool( logic.get_transition_indicator( str(i), call.target)) l.append(tid) s.add( z3.Implies( tid, translate_transition_call(s, lator, i, call))) s.add(z3.Or(*l)) i += 1 return sat_checker(s, n_states)
def trace(s: Solver) -> None: prog = syntax.the_program if len(list(prog.traces())) > 0: utils.logger.always_print('finding traces:') for trace in prog.traces(): n_states = len(list(trace.transitions())) + 1 print('%s states' % (n_states,)) keys = ['state%2d' % i for i in range(n_states)] for k in keys: s.get_translator(k) # initialize all the keys before pushing a solver stack frame with s: lator = s.get_translator(keys[0]) if len(trace.components) > 0 and not isinstance(trace.components[0], syntax.AssertDecl): for init in prog.inits(): s.add(lator.translate_expr(init.expr)) i = 0 for c in trace.components: if isinstance(c, syntax.AssertDecl): if c.expr is None: if i != 0: utils.print_error_and_exit(c.tok, 'assert init is only allowed in the first state') for init in prog.inits(): s.add(s.get_translator(keys[i]).translate_expr(init.expr)) else: s.add(s.get_translator(keys[i]).translate_expr(c.expr)) else: te: syntax.TransitionExpr = c.transition if isinstance(te, syntax.AnyTransition): logic.assert_any_transition(s, str(i), keys[i + 1], keys[i], allow_stutter=True) else: l = [] for call in te.calls: tid = z3.Bool(logic.get_transition_indicator(str(i), call.target)) l.append(tid) s.add(tid == translate_transition_call(s, keys[i + 1], keys[i], call)) s.add(z3.Or(*l)) i += 1 res = logic.check_unsat([], s, keys) if (res == z3.sat) != trace.sat: utils.print_error(trace.tok, 'trace declared %s but was %s!' % ('sat' if trace.sat else 'unsat', res))
def __init__(self, solver: Solver) -> None: self.solver = solver prog = syntax.the_program if utils.args.automaton: automaton = prog.the_automaton() if automaton is None: utils.print_error_and_exit( None, 'updr --automaton requires the file to ' 'declare an automaton') else: the_phase = 'the_phase' pcs: List[syntax.PhaseComponent] = [] for t in prog.transitions(): pcs.append( syntax.PhaseTransitionDecl(None, t.name, None, the_phase)) for inv in prog.safeties(): pcs.append(inv) automaton = AutomatonDecl(None, [ syntax.InitPhaseDecl(None, the_phase), syntax.PhaseDecl(None, the_phase, pcs) ]) automaton.resolve(prog.scope) self.automaton = PhaseAutomaton(automaton) self.fs: List[Frame] = [] self.push_cache: List[Dict[Phase, Set[Expr]]] = [] self.counter = 0 self.predicates: List[Expr] = [] self.state_count = 0 self.inductive_invariant: Set[int] = set( ) # indices into predicates of currently inductive predicates self.human_invariant = tuple( itertools.chain(*(syntax.as_clauses(inv.expr) for inv in prog.invs() if not inv.is_safety))) # convert to CNF self.human_invariant_to_predicate: Dict[int, int] = dict( ) # dict mapping index of human_invariant to index of predicates self.human_invariant_proved: Set[int] = set( ) # indices into human_invariant that are implied by the current inductive_invariant self.human_invariant_implies: Set[int] = set( ) # indices into predicates of predicates that are implied by the human invariant self._first_frame()
def verify(s: Solver) -> None: old_count = utils.error_count prog = syntax.the_program a = prog.the_automaton() if a is None: if utils.args.automaton == 'only': utils.print_error_and_exit(None, "--automaton='only' requires the file to declare an automaton") elif utils.args.automaton != 'no': check_automaton_full(s, a) if utils.args.automaton != 'only': logic.check_init(s) logic.check_transitions(s) if utils.error_count == old_count: utils.logger.always_print('all ok!') else: utils.logger.always_print('program has errors.')
'semi-linear'), ] for e_str, prop_name in thm_expr_strs: e = logic.parse_and_typecheck_expr(e_str, close_free_vars=True) th = syntax.TheoremDecl(name=None, expr=e, num_states=0) if (m := logic.check_theorem(th, solve, verbose=False)) is not None: utils.error_count += 1 utils.logger.always_print( f'warning: relation {order_name} is not {prop_name}') utils.logger.always_print(f'info: try adding "axiom {e_str}"') utils.logger.always_print('info: see counterexample below') sortdecl.annotations = () utils.logger.always_print(str(m)) if utils.error_count > old_error_count: utils.print_error_and_exit( None, f'ordered_by_printer: relation {order_name} is not a total order. aborting...' ) ordinal = get_ordinal(struct.rel_interps[order], elt) return f'{sortdecl.name}{ordinal}' def set_printer(struct: FirstOrderStructure, s: SortDecl, elt: str, args: List[str]) -> str: assert len(args) == 1 member_name = args[0] member = get_relation(member_name) assert len(member.arity) == 2 and not member.mutable set_sort = UninterpretedSort(s.name) assert member.arity[1] == set_sort item_sort = member.arity[0]