def single_loop_induct_step_checks(p, restrs, hyps, tag, split, n, eqs, eqs_assume=None): if eqs_assume == None: eqs_assume = [] details = (split, (0, 1), eqs_assume + eqs) cont = split_visit_one_visit(tag, details, restrs, vc_offs(n)) hyps = ([pc_true_hyp(cont)] + hyps + [ h for i in range(n) for (h, _) in loop_eq_hyps_at_visit(tag, split, eqs_assume + eqs, restrs, vc_offs(i)) ]) return [ (hyps, hyp, 'Induct check (%s) at inductive step for %d' % (desc, split)) for ( hyp, desc) in loop_eq_hyps_at_visit(tag, split, eqs, restrs, vc_offs(n)) ]
def get_uniform_loop_vc(p, n): l_id = p.loop_id(n) assert l_id != None, n if n == l_id: restrs = tuple([(l_id, rep_graph.vc_offs(0))]) else: restrs = tuple([(l_id, rep_graph.vc_offs(1))]) restrs = search.restr_others_both(p, restrs, 2, 2) return restrs
def default_n_vc_cases(p, n): head = p.loop_id(n) general = [(n2, rep_graph.vc_options([0], [1])) for n2 in p.loop_heads() if n2 != head] if head: return [(n, tuple(general + [(head, rep_graph.vc_num(1))])), (n, tuple(general + [(head, rep_graph.vc_offs(1))]))] specific = [(head, rep_graph.vc_offs(1)) for _ in [1] if head] return [(n, tuple(general + specific))]
def default_n_vc_cases(p, n): head = p.loop_id(n) general = [(n2, rep_graph.vc_options([0], [1])) for n2 in p.loop_heads() if n2 != head] if head: return [ (n, tuple(general + [(head, rep_graph.vc_num(1))])), (n, tuple(general + [(head, rep_graph.vc_offs(1))])), ] specific = [(head, rep_graph.vc_offs(1)) for _ in [1] if head] return [(n, tuple(general + specific))]
def linear_eq_induct_step_checks(p, restrs, hyps, tag, split, eqs_assume, eqs): details = (split, (0, 1), eqs_assume + eqs) cont = split_visit_one_visit(tag, details, restrs, vc_offs(1)) hyps = ( [pc_true_hyp(cont)] + hyps + [h for (h, _) in linear_eq_hyps_at_visit(tag, split, eqs_assume + eqs, restrs, vc_offs(0))] ) return [ (hyps, hyp, "Induct check (%s) at inductive step for %d" % (desc, split)) for (hyp, desc) in linear_eq_hyps_at_visit(tag, split, eqs, restrs, vc_offs(1)) ]
def linear_eq_induct_step_checks (p, restrs, hyps, tag, split, eqs): details = (split, (0, 1), eqs) cont = split_visit_one_visit (tag, details, restrs, vc_offs (1)) # the 'trivial' hyp here ensures the representation includes a loop # of the rhs when proving const equations on the lhs hyps = ([pc_true_hyp (cont)] + hyps + [h for (h, _) in linear_eq_hyps_at_visit (tag, split, eqs, restrs, vc_offs (0))]) return [(hyps, hyp, 'Induct check (%s) at inductive step for %d' % (desc, split)) for (hyp, desc) in linear_eq_hyps_at_visit (tag, split, eqs, restrs, vc_offs (1))]
def split_loop_hyps (tags, split, restrs, exit): ((r_split, _, _), _, _, n, _) = split (l_visit, _) = split_visit_visits (tags, split, restrs, vc_offs (n - 1)) (l_cont, _) = split_visit_visits (tags, split, restrs, vc_offs (n)) (l_tag, r_tag) = tags l_enter = pc_true_hyp (l_visit) l_exit = pc_false_hyp (l_cont) if exit: hyps = [l_enter, l_exit] else: hyps = [l_enter] return hyps + [hyp for offs in map (vc_offs, range (n)) for (hyp, _) in split_hyps_at_visit (tags, split, restrs, offs)]
def get_n_offset_successes (rep, sp, step, restrs): loop = rep.p.loop_body (sp) ns = [n for n in loop if rep.p.nodes[n].kind == 'Call'] succs = [] for i in range (step): for n in ns: vc = vc_offs (i + 1) if n == sp: vc = vc_offs (i) n_vc = (n, restrs + tuple ([(sp, vc)])) (_, _, succ) = rep.get_func (n_vc) pc = rep.get_pc (n_vc) succs.append (syntax.mk_implies (pc, succ)) return succs
def get_induct_eq_hyp(p, split, restrs, n): details = (split, (0, 1), []) (tag, _) = p.node_tags[split] visit = split_visit_one_visit(tag, details, restrs, vc_offs(0)) from syntax import mk_var, word32T, mk_word32 return eq_hyp((mk_var("%n", word32T), visit), (mk_word32(n), visit), (split, 0))
def test (n): assert n > 10 hyp = get_induct_eq_hyp (p, split, restrs, n - 2) visit = ((split, vc_offs (2)), ) + restrs continue_to_split_guess = rep.get_pc ((split, visit)) return rep.test_hyp_whyps (syntax.mk_not (continue_to_split_guess), [hyp] + l_hyps + hyps)
def split_loop_hyps(tags, split, restrs, exit): ((r_split, _, _), _, _, n, _) = split (l_visit, _) = split_visit_visits(tags, split, restrs, vc_offs(n - 1)) (l_cont, _) = split_visit_visits(tags, split, restrs, vc_offs(n)) (l_tag, r_tag) = tags l_enter = pc_true_hyp(l_visit) l_exit = pc_false_hyp(l_cont) if exit: hyps = [l_enter, l_exit] else: hyps = [l_enter] return hyps + [ hyp for offs in map(vc_offs, range(n)) for (hyp, _) in split_hyps_at_visit(tags, split, restrs, offs) ]
def test(n): assert n > 10 hyp = check.mk_loop_counter_eq_hyp(p, split, restrs, n - 2) visit = ((split, vc_offs(2)), ) + restrs continue_to_split_guess = rep.get_pc((split, visit)) return rep.test_hyp_whyps(syntax.mk_not(continue_to_split_guess), [hyp] + l_hyps + hyps)
def single_loop_rev_induct_base_checks(p, restrs, hyps, tag, split, n_bound, eqs_assume, pred): details = (split, (0, 1), eqs_assume) cont = split_visit_one_visit(tag, details, restrs, vc_offs(1)) n_hyp = mk_loop_counter_eq_hyp(p, split, restrs, n_bound) split_details = (None, details, None, 1, 1) non_err = split_r_err_pc_hyp(p, split_details, restrs) hyps = (hyps + [n_hyp, pc_true_hyp(cont), non_err] + [ h for (h, _) in loop_eq_hyps_at_visit(tag, split, eqs_assume, restrs, vc_offs(0)) ]) goal = rep_graph.true_if_at_hyp(pred, cont) return [(hyps, goal, 'Pred true at %d check.' % n_bound)]
def split_induct_step_checks (p, restrs, hyps, split, tags = None): ((l_split, _, _), _, _, n, _) = split if tags == None: tags = p.pairing.tags err_hyp = split_r_err_pc_hyp (p, split, restrs, tags = tags) (cont, r_cont) = split_visit_visits (tags, split, restrs, vc_offs (n)) # the 'trivial' hyp here ensures the representation includes a loop # of the rhs when proving const equations on the lhs hyps = ([err_hyp, pc_true_hyp (cont), rep_graph.pc_triv_hyp (r_cont)] + hyps + split_loop_hyps (tags, split, restrs, exit = False)) return [(hyps, hyp, 'Induct check (%s) at inductive step for %d' % (desc, l_split)) for (hyp, desc) in split_hyps_at_visit (tags, split, restrs, vc_offs (n))]
def single_loop_rev_induct_checks(p, restrs, hyps, tag, split, eqs_assume, pred): details = (split, (0, 1), eqs_assume) curr = split_visit_one_visit(tag, details, restrs, vc_offs(1)) cont = split_visit_one_visit(tag, details, restrs, vc_offs(2)) split_details = (None, details, None, 1, 1) non_err = split_r_err_pc_hyp(p, split_details, restrs) true_next = rep_graph.true_if_at_hyp(pred, cont) hyps = (hyps + [pc_true_hyp(curr), true_next, non_err] + [ h for (h, _) in loop_eq_hyps_at_visit( tag, split, eqs_assume, restrs, vc_offs(1), use_if_at=True) ]) goal = rep_graph.true_if_at_hyp(pred, curr) return [(hyps, goal, 'Pred reverse step.')]
def split_induct_step_checks(p, restrs, hyps, split, tags=None): ((l_split, _, _), _, _, n, _) = split if tags == None: tags = p.pairing.tags err_hyp = split_r_err_pc_hyp(p, split, restrs, tags=tags) (cont, r_cont) = split_visit_visits(tags, split, restrs, vc_offs(n)) # the 'trivial' hyp here ensures the representation includes a loop # of the rhs when proving const equations on the lhs hyps = ( [err_hyp, pc_true_hyp(cont), rep_graph.pc_triv_hyp(r_cont)] + hyps + split_loop_hyps(tags, split, restrs, exit=False)) return [(hyps, hyp, 'Induct check (%s) at inductive step for %d' % (desc, l_split)) for (hyp, desc) in split_hyps_at_visit(tags, split, restrs, vc_offs(n))]
def get_linear_series_hyps(p, split, restrs, hyps): eqs = get_linear_series_eqs(p, split, restrs, hyps) (tag, _) = p.node_tags[split] hyps = [ h for (h, _) in linear_eq_hyps_at_visit(tag, split, eqs, restrs, vc_offs(0)) ] return hyps
def split_visit_one_visit (tag, details, restrs, visit): if details == None: return None (split, (seq_start, step), eqs) = details # the split point sequence at low numbers ('Number') is offset # by the point the sequence starts. At symbolic offsets we ignore # that, instead having the loop counter for the two sequences # be the same number of iterations after the sequence start. if visit.kind == 'Offset': visit = vc_offs (visit.n * step) else: visit = vc_num (seq_start + (visit.n * step)) visit = ((split, ((split, visit), ) + restrs), tag) return visit
def split_visit_one_visit(tag, details, restrs, visit): if details == None: return None (split, (seq_start, step), eqs) = details # the split point sequence at low numbers ('Number') is offset # by the point the sequence starts. At symbolic offsets we ignore # that, instead having the loop counter for the two sequences # be the same number of iterations after the sequence start. if visit.kind == 'Offset': visit = vc_offs(visit.n * step) else: visit = vc_num(seq_start + (visit.n * step)) visit = ((split, ((split, visit), ) + restrs), tag) return visit
def get_linear_series_hyps(p, split, restrs, hyps): k = ("linear_series_hyps", split, restrs, tuple(hyps)) if k in p.cached_analysis: return p.cached_analysis[k] cands = search.mk_seq_eqs(p, split, 1, with_rodata=False) cands += candidate_additional_eqs(p, split) (tag, _) = p.node_tags[split] rep = rep_graph.mk_graph_slice(p, fast=True) def do_checks(eqs_assume, eqs): checks = linear_eq_induct_step_checks( p, restrs, hyps, tag, split, eqs_assume, eqs ) + linear_eq_induct_base_checks(p, restrs, hyps, tag, split, eqs) groups = check.proof_check_groups(checks) for group in groups: (res, _) = check.test_hyp_group(rep, group) if not res: return False return True eqs = [] failed = [] while cands: cand = cands.pop() if do_checks(eqs, [cand]): eqs.append(cand) failed.reverse() cands = failed + cands failed = [] else: failed.append(cand) assert do_checks([], eqs) hyps = [h for (h, _) in linear_eq_hyps_at_visit(tag, split, eqs, restrs, vc_offs(0))] p.cached_analysis[k] = hyps return hyps
def mk_loop_counter_eq_hyp(p, split, restrs, n): details = (split, (0, 1), []) (tag, _) = p.node_tags[split] visit = split_visit_one_visit(tag, details, restrs, vc_offs(0)) return eq_hyp((mk_var('%n', word32T), visit), (mk_word32(n), visit), (split, 0))
restr = (n, VisitCount (kind, y - 1)) return rep_graph.pc_triv_hyp (((n, (restr, ) + restrs), p.node_tags[n][0])) def proof_restr_checks (n, (kind, (x, y)), p, restrs, hyps): restr = get_proof_restr (n, (kind, (x, y))) ncerr_hyp = non_r_err_pc_hyp (p.pairing.tags, restr_others (p, (restr, ) + restrs, 2)) hyps = [ncerr_hyp] + hyps def visit (vc): return ((n, ((n, vc), ) + restrs), p.node_tags[n][0]) # this cannot be more uniform because the representation of visit # at offset 0 is all a bit odd, with n being the only node so visited: if kind == 'Offset': min_vc = vc_offs (max (0, x - 1)) elif x > 1: min_vc = vc_num (x - 1) else: min_vc = None if min_vc: init_check = [(hyps, pc_true_hyp (visit (min_vc)), 'Check of restr min %d %s for %d' % (x, kind, n))] else: init_check = [] # if we can reach node n with (y - 1) visits to n, then the next # node will have y visits to n, which we are disallowing # thus we show that this visit is impossible top_vc = VisitCount (kind, y - 1) top_check = (hyps, pc_false_hyp (visit (top_vc)),
return rep_graph.pc_triv_hyp(((n, (restr, ) + restrs), p.node_tags[n][0])) def proof_restr_checks(n, (kind, (x, y)), p, restrs, hyps): restr = get_proof_restr(n, (kind, (x, y))) ncerr_hyp = non_r_err_pc_hyp(p.pairing.tags, restr_others(p, (restr, ) + restrs, 2)) hyps = [ncerr_hyp] + hyps def visit(vc): return ((n, ((n, vc), ) + restrs), p.node_tags[n][0]) # this cannot be more uniform because the representation of visit # at offset 0 is all a bit odd, with n being the only node so visited: if kind == 'Offset': min_vc = vc_offs(max(0, x - 1)) elif x > 1: min_vc = vc_num(x - 1) else: min_vc = None if min_vc: init_check = [(hyps, pc_true_hyp(visit(min_vc)), 'Check of restr min %d %s for %d' % (x, kind, n))] else: init_check = [] # if we can reach node n with (y - 1) visits to n, then the next # node will have y visits to n, which we are disallowing # thus we show that this visit is impossible top_vc = VisitCount(kind, y - 1) top_check = (hyps, pc_false_hyp(visit(top_vc)),