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 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 split_init_step_checks(p, restrs, hyps, split, tags=None): (_, _, _, n, _) = split if tags == None: tags = p.pairing.tags err_hyp = split_r_err_pc_hyp(p, split, restrs, tags=tags) hyps = [err_hyp] + hyps checks = [] for i in range(n): (l_visit, r_visit) = split_visit_visits(tags, split, restrs, vc_num(i)) lpc_hyp = pc_true_hyp(l_visit) # this trivial 'hyp' ensures the rep is built to include # the matching rhs visits when checking lhs consts rpc_triv_hyp = rep_graph.pc_triv_hyp(r_visit) vis_hyps = split_hyps_at_visit(tags, split, restrs, vc_num(i)) for (hyp, desc) in vis_hyps: checks.append((hyps + [lpc_hyp, rpc_triv_hyp], hyp, 'Induct check at visit %d: %s' % (i, desc))) return checks
def split_init_step_checks (p, restrs, hyps, split, tags = None): (_, _, _, n, _) = split if tags == None: tags = p.pairing.tags err_hyp = split_r_err_pc_hyp (p, split, restrs, tags = tags) hyps = [err_hyp] + hyps checks = [] for i in range (n): (l_visit, r_visit) = split_visit_visits (tags, split, restrs, vc_num (i)) lpc_hyp = pc_true_hyp (l_visit) # this trivial 'hyp' ensures the rep is built to include # the matching rhs visits when checking lhs consts rpc_triv_hyp = rep_graph.pc_triv_hyp (r_visit) vis_hyps = split_hyps_at_visit (tags, split, restrs, vc_num (i)) for (hyp, desc) in vis_hyps: checks.append ((hyps + [lpc_hyp, rpc_triv_hyp], hyp, 'Induct check at visit %d: %s' % (i, desc))) return checks
return non_r_err_pc_hyp(tags, restrs) restr_bump = 0 def get_proof_restr(n, (kind, (x, y))): return (n, mk_vc_opts([VisitCount(kind, i) for i in range(x, y + restr_bump)])) def restr_trivial_hyp(p, n, (kind, (x, y)), restrs): 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))
restrs = restr_others (p, ((r_split, vc), ) + restrs, 2) if tags == None: tags = p.pairing.tags return non_r_err_pc_hyp (tags, restrs) restr_bump = 0 def get_proof_restr (n, (kind, (x, y))): return (n, mk_vc_opts ([VisitCount (kind, i) for i in range (x, y + restr_bump)])) def restr_trivial_hyp (p, n, (kind, (x, y)), restrs): 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)
def get_necessary_split_opts (p, head, restrs, hyps, tags = None, iters = None): if not tags: tags = p.pairing.tags [l_tag, r_tag] = tags assert p.node_tags[head][0] == l_tag l_seq_vs = get_interesting_linear_series_exprs (p, head) if not l_seq_vs: return None r_seq_vs = {} for n in init_loops_to_split (p, restrs): if p.node_tags[n][0] == r_tag: vs = get_interesting_linear_series_exprs (p, n) r_seq_vs.update (vs) if not r_seq_vs: return None rep = rep_graph.mk_graph_slice (p, fast = True) def vis (n, i): if n != p.loop_id (n): i = i + 1 return (n, tuple ([(p.loop_id (n), vc_num (i))]) + restrs) smt = lambda expr, n, i: rep.to_smt_expr (expr, vis (n, i)) smt_pc = lambda n, i: rep.get_pc (vis (n, i)) # remove duplicates by concretising l_seq_vs = dict ([(smt (expr, n, 2), (kind, n, expr)) for n in l_seq_vs for (kind, expr) in l_seq_vs[n]]).values () r_seq_vs = dict ([(smt (expr, n, 2), (kind, n, expr)) for n in r_seq_vs for (kind, expr) in r_seq_vs[n]]).values () if iters == None: if [n for n in p.loop_body (head) if p.nodes[n].kind == 'Call']: iters = 5 else: iters = 8 r_seq_end = 1 + 2 * iters l_seq_end = 1 + iters l_seq_ineq = 1 + max ([1 << n for n in range (iters) if 1 << n <= iters]) hyps = hyps + [rep_graph.pc_triv_hyp ((vis (n, r_seq_end), r_tag)) for n in set ([n for (_, n, _) in r_seq_vs])] hyps = hyps + [rep_graph.pc_triv_hyp ((vis (n, l_seq_end), l_tag)) for n in set ([n for (_, n, _) in l_seq_vs])] ex_restrs = [(n, rep_graph.vc_upto (r_seq_end + 1)) for n in set ([p.loop_id (n) for (_, n, _) in r_seq_vs])] hyps = hyps + [check.non_r_err_pc_hyp (tags, restr_others (p, restrs + tuple (ex_restrs), 2))] necessary_split_opts_trace[:] = [] necessary_split_opts_long_trace[:] = [] for (kind, n, expr) in sorted (l_seq_vs): rel_r_seq_vs = [v for v in r_seq_vs if v[0] == kind] if not rel_r_seq_vs: necessary_split_opts_trace.append ((n, 'NoneRelevant')) continue m = {} eq = mk_eq (smt (expr, n, 1), smt (expr, n, l_seq_ineq)) ex_hyps = [rep_graph.pc_true_hyp ((vis (n, i), l_tag)) for i in range (1, l_seq_end + 1)] res = rep.test_hyp_whyps (eq, hyps + ex_hyps, model = m) necessary_split_opts_long_trace.append ((n, eq, hyps + ex_hyps, res, m, smt, smt_pc, (kind, n, expr), r_seq_vs, iters)) if not m: necessary_split_opts_trace.append ((n, None)) continue seq_eq = get_linear_seq_eq (rep, m, smt, smt_pc, (kind, n, expr), r_seq_vs, iters) necessary_split_opts_trace.append ((n, ('Seq', seq_eq))) if not seq_eq: continue ((n2, expr2), (l_start, l_step), (r_start, r_step)) = seq_eq eqs = [rep_graph.eq_hyp ((expr, (vis (n, l_start + (i * l_step)), l_tag)), (expr2, (vis (n2, r_start + (i * r_step)), r_tag))) for i in range (10) if l_start + (i * l_step) <= l_seq_end if r_start + (i * r_step) <= r_seq_end] eq = foldr1 (mk_and, map (rep.interpret_hyp, eqs)) if rep.test_hyp_whyps (eq, hyps): mk_i = lambda i: (l_start + (i * l_step), l_step) mk_j = lambda j: (r_start + (j * r_step), r_step) return [([mk_i (0)], [mk_j (0)]), ([mk_i (0), mk_i (1)], [mk_j (0), mk_j (1)])] n_vcs = entry_path_no_loops (rep, l_tag, m, head) path_hyps = [rep_graph.pc_true_hyp ((n_vc, l_tag)) for n_vc in n_vcs] if rep.test_hyp_whyps (eq, hyps + path_hyps): # immediate case split on difference between entry paths checks = [(hyps, eq_hyp, 'eq') for eq_hyp in eqs] return derive_case_split (rep, n_vcs, checks) necessary_split_opts_trace.append ((n, 'Seq check failed')) return None