Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
def find_split_limit (p, n, restrs, hyps, kind, bound = 51, must_find = True,
		hints = [], use_rep = None):
	tag = p.node_tags[n][0]
	trace ('Finding split limit: %d (%s) %s' % (n, tag, restrs))
	trace ('  (restrs = %s)' % (restrs, ))
	trace ('  (hyps = %s)' % (hyps, ), push = 1)
	if use_rep == None:
		rep = mk_graph_slice (p, fast = True)
	else:
		rep = use_rep
	check_order = hints + [i for i in split_sample_set (bound)
		if i not in hints]
	for i in check_order:
		restrs2 = restrs + ((n, VisitCount (kind, i)), )
		pc = rep.get_pc ((n, restrs2))
		restrs3 = restr_others (p, restrs2, 2)
		epc = rep.get_pc (('Err', restrs3), tag = tag)
		hyp = mk_implies (mk_not (epc), mk_not (pc))
		if rep.test_hyp_whyps (hyp, hyps):
			trace ('split limit found: %d' % i, push = -1)
			return i

	trace ('No split limit found for %d (%s).' % (n, tag), push = -1)
	if must_find:
		assert not 'split limit found'
	return None
Ejemplo n.º 3
0
def find_case_split (p, head, restrs, hyps, tags = None):
	# are there multiple paths to the loop head 'head' and can we
	# restrict to one of them?
	preds = set ()
	frontier = list (set ([n2 for n in p.loop_body (head)
		for n2 in p.preds[n] if p.loop_id (n2) != head]))
	while frontier:
		n2 = frontier.pop ()
		if n2 in preds:
			continue
		preds.add (n2)
		frontier.extend (p.preds[n2])
	divs = [n2 for n2 in preds if len (set ([n3
		for n3 in p.nodes[n2].get_conts ()
			if n3 in preds or n3 == head])) > 1
		if n2 not in p.loop_data]

	trace ('find_case_split: possible divs %s.' % divs)

	rep = mk_graph_slice (p)
	err_restrs = restr_others (p, restrs, 2)
	if tags:
		l_tag, r_tag = tags
	else:
		l_tag, r_tag = p.pairing.tags
	hvis_restrs = tuple ([(head, rep_graph.vc_num (0))]) + restrs
	
	lhyps = hyps + [rep_graph.pc_false_hyp ((('Err', err_restrs), r_tag)),
		rep_graph.pc_true_hyp (((head, hvis_restrs),
			p.node_tags[head][0]))]

	# for this to be a usable case split, both paths must be possible
	for div in divs:
		dhyps = lhyps + [rep_graph.pc_true_hyp (((div, restrs),
			p.node_tags[div][0]))]
		assert p.nodes[div].kind == 'Cond'
		(_, env) = rep.get_node_pc_env ((div, restrs))
		c = to_smt_expr (p.nodes[div].cond, env, rep.solv)
		if (rep.test_hyp_whyps (c, dhyps)
				or rep.test_hyp_whyps (mk_not (c), dhyps)):
			continue
		trace ("attempting case split at %d" % div)
		sides = [n for n in p.nodes[div].get_conts ()
			if n not in p.loop_data
			if p.preds[n] == [div]]
		if not sides:
			trace ("skipping case split, no notable succ")
		n = sides[0]
		return ('CaseSplit', (n, p.node_tags[n][0]))
	trace ('find_case_split: no case splits possible')
	return (None, ())
Ejemplo n.º 4
0
def tryLoopBound(p_n,
                 p,
                 bounds,
                 rep,
                 restrs=None,
                 hints=None,
                 kind='Number',
                 bin_return=False,
                 hyps=None):
    if restrs == None:
        restrs = ()
    if hints == None:
        hints = []
    if hyps == None:
        hyps = []
    tag = p.node_tags[p_n][0]
    from stack_logic import default_n_vc
    print 'trying bound: %s' % bounds
    ret_bounds = []
    for (index, i) in enumerate(bounds):
        print 'testing %d' % i
        restrs2 = restrs + ((p_n, VisitCount(kind, i)), )
        try:
            pc = rep.get_pc((p_n, restrs2))
        except:
            print 'get_pc failed'
            if bin_return:
                return False
            else:
                return -1
        #print 'got rep_.get_pc'
        restrs3 = restr_others(p, restrs2, 2)
        epc = rep.get_pc(('Err', restrs3), tag=tag)
        hyp = mk_implies(mk_not(epc), mk_not(pc))
        hyps = hyps + noHaltHyps(p_n, p)

        #hyps = []
        #print 'calling test_hyp_whyps'
        if rep.test_hyp_whyps(hyp, hyps):
            print 'p_n %d: split limit found: %d' % (p_n, i)
            if bin_return:
                return True
            return index
    if bin_return:
        return False
    print 'loop bound not found!'
    return -1
    assert False, 'failed to find loop bound for p_n %d' % p_n
Ejemplo n.º 5
0
def loop_no_match_unroll (rep, restrs, hyps, split, other_tag, unroll):
	p = rep.p
	assert p.node_tags[split][0] != other_tag
	restr = ((split, vc_num (unroll)), )
	restrs2 = restr_others (p, restr + restrs, 2)
	loop_cond = rep.get_pc ((split, restr + restrs))
	ret_cond = rep.get_pc (('Ret', restrs2), tag = other_tag)
	# loop should be reachable
	if rep.test_hyp_whyps (mk_not (loop_cond), hyps):
		trace ('Loop weak at %d (unroll count %d).' %
			(split, unroll))
		return True
	# reaching the loop should imply reaching a loop on the other side
	hyp = mk_not (mk_and (loop_cond, ret_cond))
	if not rep.test_hyp_whyps (hyp, hyps):
		trace ('Loop independent at %d (unroll count %d).' %
			(split, unroll))
		return True
	return False
Ejemplo n.º 6
0
def tryLoopBound(p_n, p, bounds, rep, restrs=None, hints=None, kind="Number", bin_return=False, hyps=None):
    if restrs == None:
        restrs = ()
    if hints == None:
        hints = []
    if hyps == None:
        hyps = []
    tag = p.node_tags[p_n][0]
    from stack_logic import default_n_vc

    print "trying bound: %s" % bounds
    ret_bounds = []
    for (index, i) in enumerate(bounds):
        print "testing %d" % i
        restrs2 = restrs + ((p_n, VisitCount(kind, i)),)
        try:
            pc = rep.get_pc((p_n, restrs2))
        except:
            print "get_pc failed"
            if bin_return:
                return False
            else:
                return -1
        # print 'got rep_.get_pc'
        restrs3 = restr_others(p, restrs2, 2)
        epc = rep.get_pc(("Err", restrs3), tag=tag)
        hyp = mk_implies(mk_not(epc), mk_not(pc))
        hyps = hyps + noHaltHyps(p_n, p)

        # hyps = []
        # print 'calling test_hyp_whyps'
        if rep.test_hyp_whyps(hyp, hyps):
            print "p_n %d: split limit found: %d" % (p_n, i)
            if bin_return:
                return True
            return index
    if bin_return:
        return False
    print "loop bound not found!"
    return -1
    assert False, "failed to find loop bound for p_n %d" % p_n
Ejemplo n.º 7
0
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])
Ejemplo n.º 8
0
def build_proof_rec_with_restrs (split_points, kind, searcher, p, restrs,
		hyps, must_find = True, name = "problem"):
	if not split_points:
		return build_proof_rec (searcher, p, restrs, hyps, name = name)

	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]

	if p.loop_id (sp):
		lim_pair = get_proof_split_limit (p, sp, restrs, use_hyps,
			kind, must_find = must_find)
	else:
		lim_pair = get_proof_visit_restr (p, sp, restrs, use_hyps,
			kind, must_find = must_find)

	if not lim_pair:
		assert not must_find
		return build_proof_rec_with_restrs (split_points[1:],
			kind, searcher, p, restrs, hyps, must_find = must_find,
			name = name)

	(min_v, max_v) = lim_pair
	if kind == 'Number':
		vc_opts = rep_graph.vc_options (range (min_v, max_v), [])
	else:
		vc_opts = rep_graph.vc_options ([], range (min_v, max_v))

	restrs = restrs + ((sp, vc_opts), )
	subproof = build_proof_rec_with_restrs (split_points[1:],
		kind, searcher, p, restrs, hyps, must_find = must_find,
		name = name)

	return ProofNode ('Restr', (sp, (kind, (min_v, max_v))), [subproof])
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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