def setup_split_search (rep, head, restrs, hyps, i_opts, j_opts, unfold_limit = None, tags = None): p = rep.p if not tags: tags = p.pairing.tags if unfold_limit == None: unfold_limit = max ([start + (2 * step) + 1 for (start, step) in i_opts + j_opts]) trace ('Split search at %d, unfold limit %d.' % (head, unfold_limit)) l_tag, r_tag = tags loop_elts = [(n, start, step) for n in p.splittable_points (head) for (start, step) in i_opts] init_to_split = init_loops_to_split (p, restrs) r_to_split = [n for n in init_to_split if p.node_tags[n][0] == r_tag] cand_r_loop_elts = [(n2, start, step) for n in r_to_split for n2 in p.splittable_points (n) for (start, step) in j_opts] err_restrs = restr_others (p, tuple ([(sp, vc_upto (unfold_limit)) for sp in r_to_split]) + restrs, 1) nrerr_pc = mk_not (rep.get_pc (('Err', err_restrs), tag = r_tag)) def get_pc (n, k): head = p.loop_id (n) assert head in init_to_split if n != head: k += 1 restrs2 = restrs + ((head, vc_num (k)), ) return rep.get_pc ((n, restrs2)) for n in r_to_split: get_pc (n, unfold_limit) get_pc (head, unfold_limit) premise = foldr1 (mk_and, [nrerr_pc] + map (rep.interpret_hyp, hyps)) premise = logic.weaken_assert (premise) knowledge = SearchKnowledge (rep, 'search at %d (unfold limit %d)' % (head, unfold_limit), restrs, hyps, tags, (loop_elts, cand_r_loop_elts)) knowledge.premise = premise last_knowledge[0] = knowledge # make sure the representation is in sync rep.test_hyp_whyps (true_term, hyps) # make sure all mem eqs are being tracked mem_vs = [v for v in knowledge.v_ids if v[0].typ == builtinTs['Mem']] for (i, v) in enumerate (mem_vs): for v2 in mem_vs[:i]: for pred in expand_var_eqs (knowledge, (v, v2)): smt_expr (pred, {}, rep.solv) for v in knowledge.v_ids: for pred in expand_var_eqs (knowledge, (v, 'Const')): smt_expr (pred, {}, rep.solv) return knowledge
def add_loop_bound_restrs_hyps(p, restrs, hyps, split, bound, ctxt): # time this for diagnostic reasons start = time.time() # vc_options([concrete numbers], [offsets]) hyps = hyps + get_linear_series_hyps(p, split, restrs, hyps) hyps = list(set(hyps)) if bound == None or bound >= 10: restrs = restrs + ((split, rep_graph.vc_options([0], [1])),) else: restrs = restrs + ((split, rep_graph.vc_upto(bound + 1)),) end = time.time() save_extra_timing("LoopBoundRestrHyps", ctxt, end - start) return (restrs, hyps)
def add_loop_bound_restrs_hyps(p, restrs, hyps, split, bound, ctxt): # time this for diagnostic reasons start = time.time() #vc_options([concrete numbers], [offsets]) hyps = hyps + get_linear_series_hyps(p, split, restrs, hyps) hyps = list(set(hyps)) if bound == None or bound >= 10: restrs = restrs + ((split, rep_graph.vc_options([0], [1])), ) else: restrs = restrs + ((split, rep_graph.vc_upto(bound + 1)), ) end = time.time() save_extra_timing('LoopBoundRestrHyps', ctxt, end - start) return (restrs, hyps)
def build_proof_rec_with_restrs (split_points, kind, searcher, p, restrs, hyps): sp = split_points[0] use_hyps = list (hyps) if p.node_tags[sp][0] != p.pairing.tags[1]: nrerr_hyp = check.non_r_err_pc_hyp (p.pairing.tags, restr_others (p, restrs, 2)) use_hyps = use_hyps + [nrerr_hyp] limit = find_split_limit (p, sp, restrs, use_hyps, kind) # double-check this limit with a rep constructed without the 'fast' flag limit = find_split_limit (p, sp, restrs, use_hyps, kind, hints = [limit, limit + 1], use_rep = mk_graph_slice (p)) if kind == 'Number': vc_opts = vc_upto (limit + 1) else: vc_opts = vc_offset_upto (limit + 1) restrs = restrs + ((sp, vc_opts), ) if len (split_points) == 1: subproof = build_proof_rec (searcher, p, restrs, hyps) else: subproof = build_proof_rec_with_restrs (split_points[1:], kind, searcher, p, restrs, hyps) return ProofNode ('Restr', (sp, (kind, (0, limit + 1))), [subproof])
def restr_others(p, restrs, n): extras = [(sp, vc_upto(n)) for sp in loops_to_split(p, restrs)] return restrs + tuple(extras)
def find_split (rep, head, restrs, hyps, i_opts, j_opts, unfold_limit, tags = None): p = rep.p if tags: l_tag, r_tag = tags else: l_tag, r_tag = p.pairing.tags loop_elts = [(n, start, step) for n in p.loop_data[head][1] if p.loop_splittables[n] for (start, step) in i_opts] init_to_split = init_loops_to_split (p, restrs) r_to_split = [n for n in init_to_split if p.node_tags[n][0] == r_tag] cand_r_loop_elts = [(n2, start, step) for n in r_to_split for n2 in p.loop_data[n][1] if p.loop_splittables[n2] for (start, step) in j_opts] err_restrs = restr_others (p, tuple ([(sp, vc_upto (unfold_limit)) for sp in r_to_split]) + restrs, 1) nrerr_pc = mk_not (rep.get_pc (('Err', err_restrs), tag = r_tag)) def get_pc (n, k): head = p.loop_id (n) assert head in init_to_split if n != head: k += 1 restrs2 = restrs + ((head, vc_num (k)), ) return rep.get_pc ((n, restrs2)) for n in r_to_split: get_pc (n, unfold_limit) get_pc (head, unfold_limit) premise = foldr1 (mk_and, [nrerr_pc] + map (rep.interpret_hyp, hyps)) premise = logic.weaken_assert (premise) knowledge = (rep, (restrs, loop_elts, cand_r_loop_elts, premise), init_knowledge_pairs (rep, loop_elts, cand_r_loop_elts), set ()) last_knowledge[0] = knowledge # make sure the representation is in sync rep.test_hyp_whyps (true_term, hyps) # make sure all mem eqs are being tracked (_, _, (pairs, vs), _) = knowledge mem_vs = [v for v in vs if v[0].typ == builtinTs['Mem']] for (i, v) in enumerate (mem_vs): for v2 in mem_vs[:i]: for pred in expand_var_eqs (knowledge, (v, v2)): smt_expr (pred, {}, rep.solv) for v in vs: for pred in expand_var_eqs (knowledge, (v, 'Const')): smt_expr (pred, {}, rep.solv) # start the process with a model add_model (knowledge, [mk_not (get_pc (head, unfold_limit))]) num_eqs = 3 while True: trace ('Search at unfold limit %d' % unfold_limit) trace ('Computing live pairings') pair_eqs = [(pair, mk_pairing_v_eqs (knowledge, pair)) for pair in sorted (pairs) if pairs[pair][0] != 'Failed'] endorsed = [(pair, eqs) for (pair, eqs) in pair_eqs if eqs != None] trace (' ... %d live pairings, %d endorsed' % (len (pair_eqs), len (endorsed))) for (pair, eqs) in endorsed: split = v_eqs_to_split (p, pair, eqs, restrs, hyps, tags = tags) if split == None: pairs[pair] = ('Failed', 'SplitWeak', eqs) continue if check_split_induct (p, restrs, hyps, split, tags = tags): trace ('Tested v_eqs!') return ('Split', split) else: pairs[pair] = ('Failed', 'InductFailed', eqs) u_eqs = unknown_eqs (knowledge, num_eqs) if not u_eqs: trace (('Exhausted split candidates for loop at %d,' + ' unfold limit %d') % (head, unfold_limit)) fails = [it for it in pairs.items () if it[1][0] == 'Failed'] fails10 = fails[:10] trace (' %d of %d failed pairings:' % (len (fails10), len (fails))) last_failed_pairings.append (fails) del last_failed_pairings[:-10] for f in fails: trace (' %s' % (f,)) ind_fails = [it for it in fails if str (it[1][1]) == 'InductFailed'] if ind_fails: trace ( 'Inductive failures!') for f in ind_fails: trace (' %s' % (f,)) return (None, ind_fails) add_model_wrapper (knowledge, u_eqs) num_eqs = 4 - num_eqs # oscillate between 3, 1
def restr_others (p, restrs, n): extras = [(sp, vc_upto (n)) for sp in loops_to_split (p, restrs)] return restrs + tuple (extras)
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