示例#1
0
def split_hyps_at_visit (tags, split, restrs, visit):
	(l_details, r_details, eqs, _, _) = split
	(l_split, (l_seq_start, l_step), l_eqs) = l_details
	(r_split, (r_seq_start, r_step), r_eqs) = r_details

	(l_visit, r_visit) = split_visit_visits (tags, split, restrs, visit)
	(l_start, r_start) = split_visit_visits (tags, split, restrs, vc_num (0))
	(l_tag, r_tag) = tags

	def mksub (v):
		return lambda exp: logic.var_subst (exp, {('%i', word32T) : v},
			must_subst = False)
	def inst (exp):
		return logic.inst_eq_at_visit (exp, visit)
	zsub = mksub (mk_word32 (0))
	if visit.kind == 'Number':
		lsub = mksub (mk_word32 (visit.n))
	else:
		lsub = mksub (mk_plus (mk_var ('%n', word32T),
			mk_word32 (visit.n)))

	hyps = [(Hyp ('PCImp', l_visit, r_visit), 'pc imp'),
		(Hyp ('PCImp', l_visit, l_start), '%s pc imp' % l_tag),
		(Hyp ('PCImp', r_visit, r_start), '%s pc imp' % r_tag)]
	hyps += [(eq_hyp ((zsub (l_exp), l_start), (lsub (l_exp), l_visit),
				(l_split, r_split)), '%s const' % l_tag)
			for l_exp in l_eqs if inst (l_exp)]
	hyps += [(eq_hyp ((zsub (r_exp), r_start), (lsub (r_exp), r_visit),
				(l_split, r_split)), '%s const' % r_tag)
			for r_exp in r_eqs if inst (r_exp)]
	hyps += [(eq_hyp ((lsub (l_exp), l_visit), (lsub (r_exp), r_visit),
				(l_split, r_split)), 'eq')
			for (l_exp, r_exp) in eqs
			if inst (l_exp) and inst (r_exp)]
	return hyps
示例#2
0
def split_hyps_at_visit(tags, split, restrs, visit):
    (l_details, r_details, eqs, _, _) = split
    (l_split, (l_seq_start, l_step), l_eqs) = l_details
    (r_split, (r_seq_start, r_step), r_eqs) = r_details

    (l_visit, r_visit) = split_visit_visits(tags, split, restrs, visit)
    (l_start, r_start) = split_visit_visits(tags, split, restrs, vc_num(0))
    (l_tag, r_tag) = tags

    def mksub(v):
        return lambda exp: logic.var_subst(exp, {('%i', word32T): v},
                                           must_subst=False)

    def inst(exp):
        return logic.inst_eq_at_visit(exp, visit)

    zsub = mksub(mk_word32(0))
    if visit.kind == 'Number':
        lsub = mksub(mk_word32(visit.n))
    else:
        lsub = mksub(mk_plus(mk_var('%n', word32T), mk_word32(visit.n)))

    hyps = [(Hyp('PCImp', l_visit, r_visit), 'pc imp'),
            (Hyp('PCImp', l_visit, l_start), '%s pc imp' % l_tag),
            (Hyp('PCImp', r_visit, r_start), '%s pc imp' % r_tag)]
    hyps += [(eq_hyp((zsub(l_exp), l_start), (lsub(l_exp), l_visit),
                     (l_split, r_split)), '%s const' % l_tag)
             for l_exp in l_eqs if inst(l_exp)]
    hyps += [(eq_hyp((zsub(r_exp), r_start), (lsub(r_exp), r_visit),
                     (l_split, r_split)), '%s const' % r_tag)
             for r_exp in r_eqs if inst(r_exp)]
    hyps += [(eq_hyp((lsub(l_exp), l_visit), (lsub(r_exp), r_visit),
                     (l_split, r_split)), 'eq') for (l_exp, r_exp) in eqs
             if inst(l_exp) and inst(r_exp)]
    return hyps
示例#3
0
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))
示例#4
0
def build_compound_problem_with_links(call_stack, f):
    funs = [get_body_addrs_fun(addr) for addr in call_stack] + [f]
    (p, hyps, addr_map, tag_pairs) = build_compound_problem(funs)
    call_tags = zip(tag_pairs[:-1], tag_pairs[1:])
    call_hyps = [
        get_call_link_hyps(p, addr_map[n], from_tp, to_tp) for (n, (from_tp, to_tp)) in zip(call_stack, call_tags)
    ]
    wcet_hyps = []
    from rep_graph import eq_hyp

    for (entry, tag, _, inputs) in p.entries:
        entry_vis = ((entry, ()), tag)
        for f in target_objects.hooks("extra_wcet_assertions"):
            for assn in f(inputs):
                wcet_hyps.append(eq_hyp((assn, entry_vis), (syntax.true_term, entry_vis)))
    return (p, hyps + [h for hs in call_hyps for h in hs] + wcet_hyps, addr_map)
示例#5
0
def ident_callables (fname, callees, idents):
	from solver import to_smt_expr, smt_expr
	from syntax import mk_not, mk_and, true_term

	auto_callables = dict ([((ident, f, true_term), True)
		for ident in idents.get (fname, [true_term])
		for f in callees if f not in idents])

	if not [f for f in callees if f in idents]:
		return auto_callables

	fun = functions[fname]
	p = fun.as_problem (problem.Problem, name = 'Target')
	check_ns = [(n, ident, cond) for n in p.nodes
		if p.nodes[n].kind == 'Call'
		if p.nodes[n].fname in idents
		for (ident, cond) in ident_conds (p.nodes[n].fname, idents)]

	p.do_analysis ()
	assert check_ns

	rep = rep_graph.mk_graph_slice (p, fast = True)
	err_hyp = rep_graph.pc_false_hyp ((default_n_vc (p, 'Err'), 'Target'))

	callables = auto_callables
	nhyps = mk_not_callable_hyps (p)

	for (ident, cond) in ident_conds (fname, idents):
		renames = p.entry_exit_renames (tags = ['Target'])
		cond = syntax.rename_expr (cond, renames['Target_IN'])
		entry = p.get_entry ('Target')
		e_vis = ((entry, ()), 'Target')
		hyps = [err_hyp, rep_graph.eq_hyp ((cond, e_vis),
				(true_term, e_vis))]

		for (n, ident2, cond2) in check_ns:
			k = (ident, p.nodes[n].fname, ident2)
			(inp_env, _, _) = rep.get_func (default_n_vc (p, n))
			pc = rep.get_pc (default_n_vc (p, n))
			cond2 = to_smt_expr (cond2, inp_env, rep.solv)
			if rep.test_hyp_whyps (mk_not (mk_and (pc, cond2)),
					hyps + nhyps):
				callables[k] = False
			else:
				callables[k] = True
	return callables
示例#6
0
def inst_eqs(p, restrs, eqs, tag_map={}):
    addr_map = {}
    if not tag_map:
        tag_map = dict([(tag, tag) for tag in p.tags()])
    for (pair_tag, p_tag) in tag_map.iteritems():
        addr_map[pair_tag + '_IN'] = ((p.get_entry(p_tag), ()), p_tag)
        addr_map[pair_tag + '_OUT'] = (('Ret', restrs), p_tag)
    renames = p.entry_exit_renames(tag_map.values())
    for (pair_tag, p_tag) in tag_map.iteritems():
        renames[pair_tag + '_IN'] = renames[p_tag + '_IN']
        renames[pair_tag + '_OUT'] = renames[p_tag + '_OUT']
    hyps = []
    for (lhs, rhs) in eqs:
        vals = [(rename_expr(x, renames[x_addr]), addr_map[x_addr])
                for (x, x_addr) in (lhs, rhs)]
        hyps.append(eq_hyp(vals[0], vals[1]))
    return hyps
示例#7
0
def inst_eqs (p, restrs, eqs, tag_map = {}):
	addr_map = {}
	if not tag_map:
		tag_map = dict ([(tag, tag) for tag in p.tags ()])
	for (pair_tag, p_tag) in tag_map.iteritems ():
		addr_map[pair_tag + '_IN'] = ((p.get_entry (p_tag), ()), p_tag)
		addr_map[pair_tag + '_OUT'] = (('Ret', restrs), p_tag)
	renames = p.entry_exit_renames (tag_map.values ())
	for (pair_tag, p_tag) in tag_map.iteritems ():
		renames[pair_tag + '_IN'] = renames[p_tag + '_IN']
		renames[pair_tag + '_OUT'] = renames[p_tag + '_OUT']
	hyps = []
	for (lhs, rhs) in eqs:
		vals = [(rename_expr (x, renames[x_addr]), addr_map[x_addr])
			for (x, x_addr) in (lhs, rhs)]
		hyps.append (eq_hyp (vals[0], vals[1]))
	return hyps
示例#8
0
def build_compound_problem_with_links(call_stack, f):
    funs = [get_body_addrs_fun(addr) for addr in call_stack] + [f]
    (p, hyps, addr_map, tag_pairs) = build_compound_problem(funs)
    call_tags = zip(tag_pairs[:-1], tag_pairs[1:])
    call_hyps = [
        get_call_link_hyps(p, addr_map[n], from_tp, to_tp)
        for (n, (from_tp, to_tp)) in zip(call_stack, call_tags)
    ]
    wcet_hyps = []
    from rep_graph import eq_hyp
    for (entry, tag, _, inputs) in p.entries:
        entry_vis = ((entry, ()), tag)
        for f in target_objects.hooks('extra_wcet_assertions'):
            for assn in f(inputs):
                wcet_hyps.append(
                    eq_hyp((assn, entry_vis), (syntax.true_term, entry_vis)))
    return (p, hyps + [h for hs in call_hyps
                       for h in hs] + wcet_hyps, addr_map)
示例#9
0
def ident_callables(fname, callees, idents):
    from solver import to_smt_expr, smt_expr
    from syntax import mk_not, mk_and, true_term

    auto_callables = dict([((ident, f, true_term), True)
                           for ident in idents.get(fname, [true_term])
                           for f in callees if f not in idents])

    if not [f for f in callees if f in idents]:
        return auto_callables

    fun = functions[fname]
    p = fun.as_problem(problem.Problem, name='Target')
    check_ns = [(n, ident, cond) for n in p.nodes if p.nodes[n].kind == 'Call'
                if p.nodes[n].fname in idents
                for (ident, cond) in ident_conds(p.nodes[n].fname, idents)]

    p.do_analysis()
    assert check_ns

    rep = rep_graph.mk_graph_slice(p, fast=True)
    err_hyp = rep_graph.pc_false_hyp((default_n_vc(p, 'Err'), 'Target'))

    callables = auto_callables
    nhyps = mk_not_callable_hyps(p)

    for (ident, cond) in ident_conds(fname, idents):
        renames = p.entry_exit_renames(tags=['Target'])
        cond = syntax.rename_expr(cond, renames['Target_IN'])
        entry = p.get_entry('Target')
        e_vis = ((entry, ()), 'Target')
        hyps = [err_hyp, rep_graph.eq_hyp((cond, e_vis), (true_term, e_vis))]

        for (n, ident2, cond2) in check_ns:
            k = (ident, p.nodes[n].fname, ident2)
            (inp_env, _, _) = rep.get_func(default_n_vc(p, n))
            pc = rep.get_pc(default_n_vc(p, n))
            cond2 = to_smt_expr(cond2, inp_env, rep.solv)
            if rep.test_hyp_whyps(mk_not(mk_and(pc, cond2)), hyps + nhyps):
                callables[k] = False
            else:
                callables[k] = True
    return callables
示例#10
0
def leaf_condition_checks(p, restrs, hyps):
    '''checks of the final refinement conditions'''
    nrerr_pc_hyp = non_r_err_pc_hyp(p.pairing.tags, restrs)
    hyps = [nrerr_pc_hyp] + hyps
    [l_tag, r_tag] = p.pairing.tags

    nlerr_pc = pc_false_hyp((('Err', restrs), l_tag))
    # this 'hypothesis' ensures that the representation is built all
    # the way to Ret. in particular this ensures that function relations
    # are available to use in proving single-side equalities
    ret_eq = eq_hyp((true_term, (('Ret', restrs), l_tag)),
                    (true_term, (('Ret', restrs), r_tag)))

    ### TODO: previously we considered the case where 'Ret' was unreachable
    ### (as a result of unsatisfiable hyps) and proved a simpler property.
    ### we might want to restore this
    (_, out_eqs) = p.pairing.eqs
    checks = [(hyps + [nlerr_pc, ret_eq], hyp, 'Leaf eq check')
              for hyp in inst_eqs(p, restrs, out_eqs)]
    return [(hyps + [ret_eq], nlerr_pc, 'Leaf path-cond imp')] + checks
示例#11
0
def leaf_condition_checks (p, restrs, hyps):
	'''checks of the final refinement conditions'''
	nrerr_pc_hyp = non_r_err_pc_hyp (p.pairing.tags, restrs)
	hyps = [nrerr_pc_hyp] + hyps
	[l_tag, r_tag] = p.pairing.tags

	nlerr_pc = pc_false_hyp ((('Err', restrs), l_tag))
	# this 'hypothesis' ensures that the representation is built all
	# the way to Ret. in particular this ensures that function relations
	# are available to use in proving single-side equalities
	ret_eq = eq_hyp ((true_term, (('Ret', restrs), l_tag)),
		(true_term, (('Ret', restrs), r_tag)))

	### TODO: previously we considered the case where 'Ret' was unreachable
	### (as a result of unsatisfiable hyps) and proved a simpler property.
	### we might want to restore this
	(_, out_eqs) = p.pairing.eqs
	checks = [(hyps + [nlerr_pc, ret_eq], hyp, 'Leaf eq check') for hyp in
		inst_eqs (p, restrs, out_eqs)]
	return [(hyps + [ret_eq], nlerr_pc, 'Leaf path-cond imp')] + checks
示例#12
0
def loop_eq_hyps_at_visit(tag, split, eqs, restrs, visit_num, use_if_at=False):
    details = (split, (0, 1), eqs)
    visit = split_visit_one_visit(tag, details, restrs, visit_num)
    start = split_visit_one_visit(tag, details, restrs, vc_num(0))

    def mksub(v):
        return lambda exp: logic.var_subst(exp, {('%i', word32T): v},
                                           must_subst=False)

    zsub = mksub(mk_word32(0))
    if visit_num.kind == 'Number':
        isub = mksub(mk_word32(visit_num.n))
    else:
        isub = mksub(mk_plus(mk_var('%n', word32T), mk_word32(visit_num.n)))

    hyps = [(Hyp('PCImp', visit, start), '%s pc imp' % tag)]
    hyps += [(eq_hyp((zsub(exp), start), (isub(exp), visit), (split, 0),
                     use_if_at=use_if_at), '%s const' % tag) for exp in eqs
             if logic.inst_eq_at_visit(exp, visit_num)]

    return hyps
示例#13
0
def linear_eq_hyps_at_visit (tag, split, eqs, restrs, visit_num):
    details = (split, (0, 1), eqs)
    visit = split_visit_one_visit (tag, details, restrs, visit_num)
    start = split_visit_one_visit (tag, details, restrs, vc_num (0))
    from syntax import mk_word32, mk_plus, mk_var, word32T

    def mksub (v):
            return lambda exp: logic.var_subst (exp, {('%i', word32T) : v},
                    must_subst = False)
    zsub = mksub (mk_word32 (0))
    if visit_num.kind == 'Number':
            isub = mksub (mk_word32 (visit_num.n))
    else:
            isub = mksub (mk_plus (mk_var ('%n', word32T),
                    mk_word32 (visit_num.n)))

    hyps = [(Hyp ('PCImp', visit, start), '%s pc imp' % tag)]
    hyps += [(eq_hyp ((zsub (exp), start), (isub (exp), visit),
                            (split, 0)), '%s const' % tag)
                    for exp in eqs if logic.inst_eq_at_visit (exp, visit_num)]

    return hyps
示例#14
0
def add_recursion_ident (f, group, idents, extra_unfolds):
	from syntax import mk_eq, mk_implies, mk_var
	p = problem.Problem (None, name = 'Recursion Test')
	chain = []
	tag = 'fun0'
	p.add_entry_function (functions[f], tag)
	p.do_analysis ()
	assns = []
	recursion_last_assns[0] = assns

	while True:
		res = find_unknown_recursion (p, group, idents, tag, assns,
			extra_unfolds)
		if res == None:
			break
		if p.nodes[res].fname not in group:
			problem.inline_at_point (p, res)
			continue
		fname = p.nodes[res].fname
		chain.append (fname)
		tag = 'fun%d' % len (chain)
		(args, _, entry) = p.add_entry_function (functions[fname], tag)
		p.do_analysis ()
		assns += function_link_assns (p, res, tag)
	if chain == []:
		return None
	recursion_trace.append ('  created fun chain %s' % chain)
	word_args = [(i, mk_var (s, typ))
		for (i, (s, typ)) in enumerate (args)
		if typ.kind == 'Word']
	rep = rep_graph.mk_graph_slice (p, fast = True)
	(_, env) = rep.get_node_pc_env ((entry, ()))

	m = {}
	res = rep.test_hyp_whyps (syntax.false_term, assns, model = m)
	assert m

	if find_unknown_recursion (p, group, idents, tag, [], []) == None:
		idents.setdefault (fname, [])
		idents[fname].append (syntax.true_term)
		recursion_trace.append ('      found final ident for %s' % fname)
		return syntax.true_term
	assert word_args
	recursion_trace.append ('      scanning for ident for %s' % fname)
	for (i, arg) in word_args:
		(nm, typ) = functions[fname].inputs[i]
		arg_smt = solver.to_smt_expr (arg, env, rep.solv)
		val = search.eval_model_expr (m, rep.solv, arg_smt)
		if not rep.test_hyp_whyps (mk_eq (arg_smt, val), assns):
			recursion_trace.append ('      discarded %s = 0x%x, not stable' % (nm, val.val))
			continue
		entry_vis = ((entry, ()), tag)
		ass = rep_graph.eq_hyp ((arg, entry_vis), (val, entry_vis))
		res = find_unknown_recursion (p, group, idents, tag,
				assns + [ass], [])
		if res:
			fname2 = p.nodes[res].fname
			recursion_trace.append ('      discarded %s, allows recursion to %s' % (nm, fname2))
			continue
		eq = syntax.mk_eq (mk_var (nm, typ), val)
		idents.setdefault (fname, [])
		idents[fname].append (eq)
		recursion_trace.append ('    found ident for %s: %s' % (fname, eq))
		return eq
	assert not "identifying assertion found"
示例#15
0
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))
示例#16
0
def init_true_hyp(p, tag, expr):
    n = p.get_entry(tag)
    vis = ((n, ()), tag)
    assert expr.typ == syntax.boolT, expr
    return rep_graph.eq_hyp((expr, vis), (syntax.true_term, vis))
示例#17
0
def add_recursion_ident(f, group, idents, extra_unfolds):
    from syntax import mk_eq, mk_implies, mk_var
    p = problem.Problem(None, name='Recursion Test')
    chain = []
    tag = 'fun0'
    p.add_entry_function(functions[f], tag)
    p.do_analysis()
    assns = []
    recursion_last_assns[0] = assns

    while True:
        res = find_unknown_recursion(p, group, idents, tag, assns,
                                     extra_unfolds)
        if res == None:
            break
        if p.nodes[res].fname not in group:
            problem.inline_at_point(p, res)
            continue
        fname = p.nodes[res].fname
        chain.append(fname)
        tag = 'fun%d' % len(chain)
        (args, _, entry) = p.add_entry_function(functions[fname], tag)
        p.do_analysis()
        assns += function_link_assns(p, res, tag)
    if chain == []:
        return None
    recursion_trace.append('  created fun chain %s' % chain)
    word_args = [(i, mk_var(s, typ)) for (i, (s, typ)) in enumerate(args)
                 if typ.kind == 'Word']
    rep = rep_graph.mk_graph_slice(p, fast=True)
    (_, env) = rep.get_node_pc_env((entry, ()))

    m = {}
    res = rep.test_hyp_whyps(syntax.false_term, assns, model=m)
    assert m

    if find_unknown_recursion(p, group, idents, tag, [], []) == None:
        idents.setdefault(fname, [])
        idents[fname].append(syntax.true_term)
        recursion_trace.append('      found final ident for %s' % fname)
        return syntax.true_term
    assert word_args
    recursion_trace.append('      scanning for ident for %s' % fname)
    for (i, arg) in word_args:
        (nm, typ) = functions[fname].inputs[i]
        arg_smt = solver.to_smt_expr(arg, env, rep.solv)
        val = search.eval_model_expr(m, rep.solv, arg_smt)
        if not rep.test_hyp_whyps(mk_eq(arg_smt, val), assns):
            recursion_trace.append('      discarded %s = 0x%x, not stable' %
                                   (nm, val.val))
            continue
        entry_vis = ((entry, ()), tag)
        ass = rep_graph.eq_hyp((arg, entry_vis), (val, entry_vis))
        res = find_unknown_recursion(p, group, idents, tag, assns + [ass], [])
        if res:
            fname2 = p.nodes[res].fname
            recursion_trace.append(
                '      discarded %s, allows recursion to %s' % (nm, fname2))
            continue
        eq = syntax.mk_eq(mk_var(nm, typ), val)
        idents.setdefault(fname, [])
        idents[fname].append(eq)
        recursion_trace.append('    found ident for %s: %s' % (fname, eq))
        return eq
    assert not "identifying assertion found"
示例#18
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