示例#1
0
def compile_app(self):
    args = [a.compile() for a in self.args]
    # handle action calls in rhs of assignment
    if expr_context and top_context and self.rep in top_context.actions:
        returns = top_context.actions[self.rep]
        if len(returns) != 1:
            raise IvyError(self, "wrong number of return values")
            # TODO: right now we can't do anything with multiple returns
            sorts = [find_sort(r.sort) for r in returns]
            ress = []
            for sort in sorts:
                res = ivy_logic.Symbol(
                    'loc:' + str(len(expr_context.local_syms)), sort)
                expr_context.local_syms.append(res)
                ress.append(res())
            expr_context.code.append(
                CallAction(*([ivy_ast.Atom(self.rep, args)] + ress)))
            return ivy_ast.Tuple(*ress)
        sort = find_sort(returns[0].sort)
        res = ivy_logic.Symbol('loc:' + str(len(expr_context.local_syms)),
                               sort)
        expr_context.local_syms.append(res)
        expr_context.code.append(CallAction(ivy_ast.Atom(self.rep, args), res))
        return res()
    return (ivy_logic.Equals if self.rep == '=' else
            ivy_logic.find_polymorphic_symbol(self.rep))(*args)
示例#2
0
def compile_defn(df):
    has_consts = any(not isinstance(p, ivy_ast.Variable)
                     for p in df.args[0].args)
    sig = ivy_logic.sig.copy() if has_consts else ivy_logic.sig
    with ivy_ast.ASTContext(df):
        with sig:
            for p in df.args[0].args:
                if not isinstance(p, ivy_ast.Variable):
                    compile_const(p, sig)
            if isinstance(df.args[1], ivy_ast.SomeExpr):
                ifval = df.args[1].if_value() or df.args[1].params()[0]
                elseval = df.args[1].else_value() or ifval
                eqn = ivy_ast.Forall(
                    df.args[1].params(),
                    ivy_ast.Atom(
                        '=', (df.args[0],
                              ivy_ast.Ite(df.args[1].fmla(), ifval, elseval))))
                fmla = sortify_with_inference(eqn)
                args = [list(fmla.variables)[0], fmla.body.args[1].args[0]]
                if df.args[1].if_value():
                    args.append(fmla.body.args[1].args[1])
                if df.args[1].else_value():
                    args.append(fmla.body.args[1].args[2])
                df = ivy_logic.Definition(fmla.body.args[0],
                                          ivy_logic.Some(*args))
            else:
                eqn = ivy_ast.Atom('=', (df.args[0], df.args[1]))
                eqn = sortify_with_inference(eqn)
                df = ivy_logic.Definition(eqn.args[0], eqn.args[1])
            return df
示例#3
0
def compile_inline_call(self, args):
    params, returns = top_context.actions[self.rep]
    if len(returns) != 1:
        raise IvyError(self, "wrong number of return values")
        # TODO: right now we can't do anything with multiple returns
        sorts = [cmpl_sort(r.sort) for r in returns]
        ress = []
        for sort in sorts:
            res = ivy_logic.Symbol('loc:' + str(len(expr_context.local_syms)),
                                   sort)
            expr_context.local_syms.append(res)
            ress.append(res())
        expr_context.code.append(
            CallAction(*([ivy_ast.Atom(self.rep, args)] + ress)))
        return ivy_ast.Tuple(*ress)
    sort = cmpl_sort(returns[0].sort)
    res = ivy_logic.Symbol('loc:' + str(len(expr_context.local_syms)), sort)
    expr_context.local_syms.append(res)
    with ASTContext(self):
        if len(params) != len(args):
            raise iu.IvyError(
                self,
                "wrong number of input parameters (got {}, expecting {})".
                format(len(args), len(params)))
        args = [
            sort_infer_contravariant(a, cmpl_sort(p.sort))
            for a, p in zip(args, params)
        ]
    expr_context.code.append(CallAction(ivy_ast.Atom(self.rep, args), res))
    return res()
示例#4
0
def compile_app(self):
    args = [a.compile() for a in self.args]
    # handle action calls in rhs of assignment
    if expr_context and top_context and self.rep in top_context.actions:
        params, returns = top_context.actions[self.rep]
        if len(returns) != 1:
            raise IvyError(self, "wrong number of return values")
            # TODO: right now we can't do anything with multiple returns
            sorts = [cmpl_sort(r.sort) for r in returns]
            ress = []
            for sort in sorts:
                res = ivy_logic.Symbol(
                    'loc:' + str(len(expr_context.local_syms)), sort)
                expr_context.local_syms.append(res)
                ress.append(res())
            expr_context.code.append(
                CallAction(*([ivy_ast.Atom(self.rep, args)] + ress)))
            return ivy_ast.Tuple(*ress)
        sort = cmpl_sort(returns[0].sort)
        res = ivy_logic.Symbol('loc:' + str(len(expr_context.local_syms)),
                               sort)
        expr_context.local_syms.append(res)
        with ASTContext(self):
            if len(params) != len(args):
                raise iu.IvyError(
                    self,
                    "wrong number of input parameters (got {}, expecting {})".
                    format(len(args), len(params)))
            args = [
                sort_infer(a, cmpl_sort(p.sort)) for a, p in zip(args, params)
            ]
        expr_context.code.append(CallAction(ivy_ast.Atom(self.rep, args), res))
        return res()
    return (ivy_logic.Equals if self.rep == '=' else
            ivy_logic.find_polymorphic_symbol(self.rep))(*args)
示例#5
0
def learnInv(mod):
    print "\n" * 2
    print "<plearn> Directed to learning Algorithm"
    global silent, module, numVarFS, featureset
    silent = True
    updatenvi(mod)
    module = mod
    while True:
        print "Checking Inductiveness of the Invariant"
        maxunv, isInvInd = icheck.isInvInductive(mod)
        print "Invariant is{} Inductive\n".format('' if isInvInd else ' NOT')
        if isInvInd:  # its Inductive so nothing to do
            silent = False
            checkInitialCond(mod)
            break
        # testfunc(mod)
        for actname in sorted(mod.public_actions):
            print "learning Invariant for action {}".format(actname)
            clf = Classifier()  # new classifier
            newInv = learnWeekestInv(mod, clf, actname)
            print "\n" * 2
            print "<plearn> new Invariant:", newInv
            a = raw_input('new Invariant learned, press enter to continue')
            print "\n" * 2
            numVarFS = {}  # resetting numVarFS
            featureset = []  # resetting featuerset
            if newInv != true_clauses():
                lf = ivy_ast.LabeledFormula(*[
                    ivy_ast.Atom('learnedInv' + actname),
                    logic.And(*newInv.fmlas)
                ])
                mod.labeled_conjs.append(
                    lf)  # modifying mod and module, obj are copied by refr.
                updatenvi(mod)  # takes care of numVarInv
示例#6
0
def compile_call(self):
    assert top_context
    ctx = ExprContext(lineno=self.lineno)
    name = self.args[0].rep
    if name not in top_context.actions:
        raise iu.IvyError(self, "call to unknown action: {}".format(name))
    with ctx:
        args = [a.cmpl() for a in self.args[0].args]
    params, returns = top_context.actions[name]
    if len(returns) != len(self.args) - 1:
        raise iu.IvyError(
            self,
            "wrong number of output parameters (got {}, expecting {})".format(
                len(self.args) - 1, len(returns)))
    if len(params) != len(args):
        raise iu.IvyError(
            self,
            "wrong number of input parameters (got {}, expecting {})".format(
                len(args), len(params)))
    with ASTContext(self):
        mas = [sort_infer(a, cmpl_sort(p.sort)) for a, p in zip(args, params)]


#        print self.args
    res = CallAction(*([ivy_ast.Atom(name, mas)] +
                       [a.cmpl() for a in self.args[1:]]))
    res.lineno = self.lineno
    ctx.code.append(res)
    res = ctx.extract()
    #    print "compiled call action: {}".format(res)
    return res
示例#7
0
 def cmpl(self):
     mas = [a.cmpl() for a in self.args[0].args]
     n = self.args[0].rep
     #        print self.args
     res = CallAction(*([ivy_ast.Atom(n, mas)] +
                        [a.cmpl() for a in self.args[1:]]))
     res.lineno = self.lineno
     #        print "compiled call action: {}".format(res)
     return res
示例#8
0
def compile_call(self):
    ctx = ExprContext(lineno=self.lineno)
    with ctx:
        mas = [a.cmpl() for a in self.args[0].args]
    n = self.args[0].rep
    #        print self.args
    res = CallAction(*([ivy_ast.Atom(n, mas)] +
                       [a.cmpl() for a in self.args[1:]]))
    res.lineno = self.lineno
    ctx.code.append(res)
    res = ctx.extract()
    #    print "compiled call action: {}".format(res)
    return res
示例#9
0
def expand_schemata(mod,sort_constants,funs):
    match = Match()
    res = []
    for s in mod.sig.sorts.values():
        if not il.is_function_sort(s):
            match.add(s,s)
    for name,lf in mod.schemata.iteritems():
        schema = lf.formula
        if any(name.startswith(pref) for pref in ['rec[','lep[','ind[']):
            continue
        conc = schema.args[-1]
        for m in match_schema_prems(list(schema.args[:-1]),sort_constants,funs,match):
#            iu.dbg('str_map(m)')
#            iu.dbg('conc')
            inst = apply_match(m,conc)
            res.append(ivy_ast.LabeledFormula(ivy_ast.Atom(name),inst))
    return res
示例#10
0
 def cmpl(self):
     return self
     mas = [a.cmpl() for a in self.args[0].args]
     n = self.args[0].rep
     return InstantiateAction(ivy_ast.Atom(n,mas))
示例#11
0
文件: ivy_proof.py 项目: hannesm/ivy
def fresh_label(goals):
    rn = iu.UniqueRenamer(used=[x.name for x in goals])
    return ia.Atom(rn(), [])
示例#12
0
 def scenario(self, scen):
     init_tokens = set(p.rep for p in scen.args[0].args)
     transs_by_action = defaultdict(list)
     for tr in scen.args[1:]:
         transs_by_action[tr.args[2].args[1].args[0].rep].append(tr)
     for (place_name, lineno) in scen.places():
         sym = find_symbol(place_name)
         iname = place_name + '[init]'
         iact = AssignAction(
             sym,
             ivy_logic.And() if
             (place_name in init_tokens) else ivy_logic.Or())
         iact.formal_params = []
         iact.formal_returns = []
         iact.lineno = scen.lineno
         self.mod.actions[iname] = iact
         self.mixin(
             ivy_ast.MixinAfterDef(ivy_ast.Atom(iname),
                                   ivy_ast.Atom('init')))
     for actname, trs in transs_by_action.iteritems():
         choices = []
         params = None
         afters = []
         for tr in trs:
             scmix = tr.args[2]
             is_after = isinstance(scmix, ivy_ast.ScenarioAfterMixin)
             df = scmix.args[1]
             body = compile_action_def(df, self.mod.sig)
             seq = []
             if not is_after:
                 for p in tr.args[0].args:
                     seq.append(AssumeAction(find_symbol(p.rep)))
                 for p in tr.args[0].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.Or()))
                 for p in tr.args[1].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.And()))
                 seq.append(body)
                 seq = Sequence(*seq)
             else:
                 for p in tr.args[0].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.Or()))
                 for p in tr.args[1].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.And()))
                 seq.append(body)
                 seq = Sequence(*seq)
                 seq = IfAction(
                     And(*[find_symbol(p.rep) for p in tr.args[0].args]),
                     seq)
             if params is None:
                 params = body.formal_params
                 returns = body.formal_returns
                 mixer = scmix.args[0]
                 mixee = scmix.args[1].args[0]
             else:
                 aparams = df.formal_params + df.formal_returns
                 subst = dict(zip(aparams, params + returns))
                 seq = substitute_constants_ast(seq, subst)
             seq.lineno = tr.lineno
             if not is_after:
                 choices.append(seq)
             else:
                 afters.append(seq)
         if choices:
             choice = BalancedChoice(choices)
             choice.lineno = choices[0].lineno
             choice.formal_params = params
             choice.formal_returns = returns
             self.mod.actions[mixer.rep] = choice
             self.mixin(ivy_ast.MixinBeforeDef(mixer, mixee))
         if afters:
             choice = Sequence(*afters)
             choice.lineno = afters[0].lineno
             choice.formal_params = params
             choice.formal_returns = returns
             self.mod.actions[mixer.rep] = choice
             self.mixin(ivy_ast.MixinAfterDef(mixer, mixee))
示例#13
0
def change(x, y):
    x = conditionalexp(ivy_ast.Atom('=', x.args[0].args[0], y.args[0].args[0]), x.args[0], y.args[1], x.args[1])
    return instantiate(x)
示例#14
0
文件: ivy_check.py 项目: odedp/ivy
def check_isolate():
    mod = im.module
    if mod.isolate_proof is not None:
        pc = ivy_proof.ProofChecker(
            mod.labeled_axioms + mod.assumed_invariants, mod.definitions,
            mod.schemata)
        model = itmp.normal_program_from_module(im.module)
        prop = ivy_ast.LabeledFormula(ivy_ast.Atom('safety'), lg.And())
        subgoal = ivy_ast.LabeledFormula(ivy_ast.Atom('safety'),
                                         itmp.TemporalModels(model, lg.And()))
        #        print 'subgoal = {}'.format(subgoal)
        subgoals = [subgoal]
        subgoals = pc.admit_proposition(prop, mod.isolate_proof, subgoals)
        check_subgoals(subgoals)
        return

    ifc.check_fragment()
    with im.module.theory_context():
        global check_lineno
        check_lineno = act.checked_assert.get()
        if check_lineno == "":
            check_lineno = None
    #    print 'check_lineno: {}'.format(check_lineno)
        check = not opt_summary.get()
        subgoalmap = dict((x.id, y) for x, y in im.module.subgoals)
        axioms = [m for m in mod.labeled_axioms if m.id not in subgoalmap]
        schema_instances = [
            m for m in mod.labeled_axioms if m.id in subgoalmap
        ]
        if axioms:
            print "\n    The following properties are assumed as axioms:"
            for lf in axioms:
                print pretty_lf(lf)

        if mod.definitions:
            print "\n    The following definitions are used:"
            for lf in mod.definitions:
                print pretty_lf(lf)

        if (mod.labeled_props
                or schema_instances) and not checked_action.get():
            print "\n    The following properties are to be checked:"
            if check:
                for lf in schema_instances:
                    print pretty_lf(lf) + " [proved by axiom schema]"
                ag = ivy_art.AnalysisGraph()
                clauses1 = lut.true_clauses(annot=act.EmptyAnnotation())
                pre = itp.State(value=clauses1)
                props = [x for x in im.module.labeled_props if not x.temporal]
                props = [
                    p for p in props if not (p.id in subgoalmap and p.explicit)
                ]
                fcs = ([(ConjAssumer if prop.assumed or prop.id in subgoalmap
                         else ConjChecker)(prop) for prop in props])
                check_fcs_in_state(mod, ag, pre, fcs)
            else:
                for lf in schema_instances + mod.labeled_props:
                    print pretty_lf(lf)

        # after checking properties, make them axioms, except temporals
        im.module.labeled_axioms.extend(p for p in im.module.labeled_props
                                        if not p.temporal)
        im.module.update_theory()

        if mod.labeled_inits:
            print "\n    The following properties are assumed initially:"
            for lf in mod.labeled_inits:
                print pretty_lf(lf)
        if mod.labeled_conjs:
            print "\n    The inductive invariant consists of the following conjectures:"
            for lf in mod.labeled_conjs:
                print pretty_lf(lf)

        apply_conj_proofs(mod)

        if mod.isolate_info is not None and mod.isolate_info.implementations:
            print "\n    The following action implementations are present:"
            for mixer, mixee, action in sorted(
                    mod.isolate_info.implementations, key=lambda x: x[0]):
                print "        {}implementation of {}".format(
                    pretty_lineno(action), mixee)

        if mod.isolate_info is not None and mod.isolate_info.monitors:
            print "\n    The following action monitors are present:"
            for mixer, mixee, action in sorted(mod.isolate_info.monitors,
                                               key=lambda x: x[0]):
                print "        {}monitor of {}".format(pretty_lineno(action),
                                                       mixee)

        # if mod.actions:
        #     print "\n    The following actions are present:"
        #     for actname,action in sorted(mod.actions.iteritems()):
        #         print "        {}{}".format(pretty_lineno(action),actname)

        if mod.initializers:
            print "\n    The following initializers are present:"
            for actname, action in sorted(mod.initializers,
                                          key=lambda x: x[0]):
                print "        {}{}".format(pretty_lineno(action), actname)

        if mod.labeled_conjs and not checked_action.get():
            print "\n    Initialization must establish the invariant"
            if check:
                with itp.EvalContext(check=False):
                    ag = ivy_art.AnalysisGraph(initializer=lambda x: None)
                    check_conjs_in_state(mod, ag, ag.states[0])
            else:
                print ''

        if mod.initializers:
            print "\n    Any assertions in initializers must be checked",
            if check:
                ag = ivy_art.AnalysisGraph(initializer=lambda x: None)
                fail = itp.State(expr=itp.fail_expr(ag.states[0].expr))
                check_safety_in_state(mod, ag, fail)

        checked_actions = get_checked_actions()

        if checked_actions and mod.labeled_conjs:
            print "\n    The following set of external actions must preserve the invariant:"
            for actname in sorted(checked_actions):
                action = act.env_action(actname)
                print "        {}{}".format(pretty_lineno(action), actname)
                if check:
                    ag = ivy_art.AnalysisGraph()
                    pre = itp.State()
                    pre.clauses = get_conjs(mod)
                    with itp.EvalContext(check=False):  # don't check safety
                        #                    post = ag.execute(action, pre, None, actname)
                        post = ag.execute(action, pre)
                    check_conjs_in_state(mod, ag, post, indent=12)
                else:
                    print ''

        callgraph = defaultdict(list)
        for actname, action in mod.actions.iteritems():
            for called_name in action.iter_calls():
                callgraph[called_name].append(actname)

        some_assumps = False
        for actname, action in mod.actions.iteritems():
            assumptions = [
                sub for sub in action.iter_subactions()
                if isinstance(sub, act.AssumeAction)
            ]
            if assumptions:
                if not some_assumps:
                    print "\n    The following program assertions are treated as assumptions:"
                    some_assumps = True
                callers = callgraph[actname]
                if actname in mod.public_actions:
                    callers.append("the environment")
                prettyname = actname[4:] if actname.startswith(
                    'ext:') else actname
                prettycallers = [
                    c[4:] if c.startswith('ext:') else c for c in callers
                ]
                print "        in action {} when called from {}:".format(
                    prettyname, ','.join(prettycallers))
                for sub in assumptions:
                    print "            {}assumption".format(pretty_lineno(sub))

        tried = set()
        some_guarants = False
        for actname, action in mod.actions.iteritems():
            guarantees = [
                sub for sub in action.iter_subactions()
                if isinstance(sub, (act.AssertAction, act.Ranking))
            ]
            if check_lineno is not None:
                guarantees = [
                    sub for sub in guarantees if sub.lineno == check_lineno
                ]
            if guarantees:
                if not some_guarants:
                    print "\n    The following program assertions are treated as guarantees:"
                    some_guarants = True
                callers = callgraph[actname]
                if actname in mod.public_actions:
                    callers.append("the environment")
                prettyname = actname[4:] if actname.startswith(
                    'ext:') else actname
                prettycallers = [
                    c[4:] if c.startswith('ext:') else c for c in callers
                ]
                print "        in action {} when called from {}:".format(
                    prettyname, ','.join(prettycallers))
                roots = set(iu.reachable([actname], lambda x: callgraph[x]))
                for sub in guarantees:
                    print "            {}guarantee".format(pretty_lineno(sub)),
                    if check and any(
                            r in roots and (r, sub.lineno) not in tried
                            for r in checked_actions):
                        print_dots()
                        old_checked_assert = act.checked_assert.get()
                        act.checked_assert.value = sub.lineno
                        some_failed = False
                        for root in checked_actions:
                            if root in roots:
                                tried.add((root, sub.lineno))
                                action = act.env_action(root)
                                ag = ivy_art.AnalysisGraph()
                                pre = itp.State()
                                pre.clauses = get_conjs(mod)
                                with itp.EvalContext(check=False):
                                    post = ag.execute(action, prestate=pre)
                                fail = itp.State(expr=itp.fail_expr(post.expr))
                                if not check_safety_in_state(
                                        mod, ag, fail, report_pass=False):
                                    some_failed = True
                                    break
                        if not some_failed:
                            print 'PASS'
                        act.checked_assert.value = old_checked_assert
                    else:
                        print ""

        check_temporals()
示例#15
0
def field_reference_action(actname, args, top):
    nformals = len(top_context.actions[actname][0])
    return compile_inline_call(ivy_ast.Atom(actname, []),
                               pull_args(args, nformals, actname, top))
示例#16
0
def action_app(action, arg):
    return ia.Atom(action, [arg])
示例#17
0
def create_isolate(iso, mod=None, **kwargs):

    mod = mod or im.module

    # treat initializers as exports
    after_inits = mod.mixins["init"]
    del mod.mixins["init"]
    mod.exports.extend(
        ivy_ast.ExportDef(ivy_ast.Atom(a.mixer()), ivy_ast.Atom(''))
        for a in after_inits)

    # check all mixin declarations

    for name, mixins in mod.mixins.iteritems():
        for mixin in mixins:
            with ASTContext(mixins):
                action1, action2 = (lookup_action(mixin, mod, a.relname)
                                    for a in mixin.args)

    # check all the delagate declarations

    for dl in mod.delegates:
        lookup_action(dl.args[0], mod, dl.delegated())
        if dl.delegee() and dl.delegee() not in mod.hierarchy:
            raise iu.IvyError(dl.args[1],
                              "{} is not a module instance".format(name))

    # check all the export declarations
    for exp in mod.exports:
        expname = exp.args[0].rep
        if expname not in mod.actions:
            raise iu.IvyError(exp, "undefined action: {}".format(expname))

    # create the import actions, if requested

    extra_with = []
    extra_strip = {}
    if create_imports.get():
        newimps = []
        for imp in mod.imports:
            if imp.args[1].rep == '':
                impname = imp.args[0].rep
                if impname not in mod.actions:
                    raise iu.IvyError(imp,
                                      "undefined action: {}".format(impname))
                action = mod.actions[impname]
                if not (type(action) == ia.Sequence and not action.args):
                    raise iu.IvyError(
                        imp,
                        "cannot import implemented action: {}".format(impname))
                extname = 'imp__' + impname
                call = ia.CallAction(
                    *([ivy_ast.Atom(extname, action.formal_params)] +
                      action.formal_returns))
                call.formal_params = action.formal_params
                call.formal_returns = action.formal_returns
                call.lineno = action.lineno
                mod.actions[impname] = call
                mod.actions[extname] = action
                newimps.append(
                    ivy_ast.ImportDef(ivy_ast.Atom(extname), imp.args[1]))
                extra_with.append(ivy_ast.Atom(impname))
                #                    extra_with.append(ivy_ast.Atom(extname))
                if iso and iso in mod.isolates:
                    ps = mod.isolates[iso].params()
                    extra_strip[impname] = [a.rep for a in ps]
                    extra_strip[extname] = [a.rep for a in ps]
            else:
                newimps.append(imp)
        mod.imports = newimps

    mixers = set()
    for ms in mod.mixins.values():
        for m in ms:
            mixers.add(m.mixer())

    # Determine the mixin order (as a side effect on module.mixins)

    get_mixin_order(iso, mod)

    # Construct an isolate

    if iso:
        isolate_component(mod,
                          iso,
                          extra_with=extra_with,
                          extra_strip=extra_strip)
    else:
        if mod.isolates and cone_of_influence.get():
            raise iu.IvyError(None, 'no isolate specified on command line')
        # apply all the mixins in no particular order
        for name, mixins in mod.mixins.iteritems():
            for mixin in mixins:
                action1, action2 = (lookup_action(mixin, mod, a.relname)
                                    for a in mixin.args)
                mixed = ia.apply_mixin(mixin, action1, action2)
                mod.actions[mixin.args[1].relname] = mixed
        # find the globally exported actions (all if none specified, for compat)
        if mod.exports:
            mod.public_actions.clear()
            for e in mod.exports:
                if not e.scope():  # global export
                    mod.public_actions.add(e.exported())
        else:
            for a in mod.actions:
                mod.public_actions.add(a)

    # Create one big external action if requested

    for name in mod.public_actions:
        mod.actions[name].label = name
    ext = kwargs['ext'] if 'ext' in kwargs else ext_action.get()
    if ext is not None:
        ext_acts = [mod.actions[x] for x in sorted(mod.public_actions)]
        ext_act = ia.EnvAction(*ext_acts)
        mod.public_actions.add(ext)
        mod.actions[ext] = ext_act

    # Check native interpretations of symbols

    slv.check_compat()

    # Make concept spaces from the conjecture

    for i, cax in enumerate(mod.labeled_conjs):
        fmla = cax.formula
        csname = 'conjecture:' + str(i)
        variables = list(lu.used_variables_ast(fmla))
        sort = ivy_logic.RelationSort([v.sort for v in variables])
        sym = ivy_logic.Symbol(csname, sort)
        space = ics.NamedSpace(ivy_logic.Literal(0, fmla))
        mod.concept_spaces.append((sym(*variables), space))

    ith.check_theory()

    # get rid of useless actions

    cone = get_mod_cone(mod)
    if cone_of_influence.get():
        for a in list(mod.actions):
            if a not in cone:
                del mod.actions[a]
    else:
        for a in list(mod.actions):
            if a not in cone and not a.startswith('ext:') and a not in mixers:
                ea = 'ext:' + a
                if ea in mod.actions and ea not in cone:
                    if ia.has_code(mod.actions[a]):
                        iu.warn(mod.actions[a],
                                "action {} is never called".format(a))

    fix_initializers(mod, after_inits)

    # show the compiled code if requested

    if show_compiled.get():
        ivy_printer.print_module(mod)
示例#18
0
def l2s(mod, temporal_goal):
    # modify mod in place

    # module pass helper funciton
    def mod_pass(transform):
        mod.labeled_conjs = [transform(x) for x in mod.labeled_conjs]
        # TODO: what about axioms and properties?
        for a in mod.public_actions:
            action = mod.actions[a]
            new_action = transform(action)
            new_action.lineno = action.lineno
            new_action.formal_params = action.formal_params
            new_action.formal_returns = action.formal_returns
            mod.actions[a] = new_action
        mod.initializers = [(x, transform(y)) for x, y in mod.initializers]

    l2s_waiting = lg.Const('l2s_waiting', lg.Boolean)
    l2s_frozen = lg.Const('l2s_frozen', lg.Boolean)
    l2s_saved = lg.Const('l2s_saved', lg.Boolean)
    l2s_error = lg.Const('l2s_error', lg.Boolean)
    l2s_d = lambda sort: lg.Const('l2s_d', lg.FunctionSort(sort, lg.Boolean))
    l2s_a = lambda sort: lg.Const('l2s_a', lg.FunctionSort(sort, lg.Boolean))
    l2s_w = lambda vs, t: lg.NamedBinder('l2s_w', vs, t)
    l2s_s = lambda vs, t: lg.NamedBinder('l2s_s', vs, t)
    l2s_g = lambda vs, t: lg.NamedBinder('l2s_g', vs, t)
    old_l2s_g = lambda vs, t: lg.NamedBinder('old_l2s_g', vs, t)

    # add conjectures about monitor state
    conjs = [
        lg.Or(l2s_waiting, l2s_frozen, l2s_saved),
        lg.Or(lg.Not(l2s_waiting), lg.Not(l2s_frozen)),
        lg.Or(lg.Not(l2s_waiting), lg.Not(l2s_saved)),
        lg.Or(lg.Not(l2s_frozen), lg.Not(l2s_saved)),
    ]
    for f in conjs:
        c = ast.LabeledFormula(ast.Atom('l2s_internal'), f)
        c.lineno = temporal_goal.lineno
        mod.labeled_conjs.append(c)

    # add conjecture that we are not in the error state (this is
    # instead of using an assertion. see below)
    c = ast.LabeledFormula(ast.Atom('not_l2s_error'), lg.Not(l2s_error))
    c.lineno = temporal_goal.lineno
    mod.labeled_conjs.append(c)

    #print ilu.used_symbols_asts(mod.labeled_conjs)
    #print '='*40
    #print list(ilu.named_binders_asts(mod.labeled_conjs))

    # some normalization

    # We first convert all temporal operators to named binders, so
    # it's possible to normalize them. Otherwise we won't have the
    # connection betweel (globally p(X)) and (globally p(Y)). Note
    # that we replace them even inside named binders.
    l2s_gs = set()

    def _l2s_g(vs, t):
        vs = tuple(vs)
        res = l2s_g(vs, t)
        l2s_gs.add((vs, t))
        return res

    replace_temporals_by_l2s_g = lambda ast: ilu.replace_temporals_by_named_binder_g_ast(
        ast, _l2s_g)
    mod_pass(replace_temporals_by_l2s_g)
    not_temporal_goal = replace_temporals_by_l2s_g(
        lg.Not(temporal_goal.formula))
    if debug.get():
        print "=" * 80 + "\nafter replace_temporals_by_named_binder_g_ast" + "\n" * 3
        print "=" * 80 + "\nl2s_gs:"
        for vs, t in sorted(l2s_gs):
            print vs, t
        print "=" * 80 + "\n" * 3
        print_module(mod)
        print "=" * 80 + "\n" * 3

    # now we normalize all named binders
    mod_pass(ilu.normalize_named_binders)
    if debug.get():
        print "=" * 80 + "\nafter normalize_named_binders" + "\n" * 3
        print_module(mod)
        print "=" * 80 + "\n" * 3

    # TODO: what about normalizing temporal_goal? - temporal_goal
    # should not contain any named binders except for temporal
    # properties, so it is normalized by construction

    # construct the monitor related building blocks

    uninterpreted_sorts = [
        s for s in mod.sig.sorts.values() if type(s) is lg.UninterpretedSort
    ]
    reset_a = [
        AssignAction(l2s_a(s)(v),
                     l2s_d(s)(v)) for s in uninterpreted_sorts
        for v in [lg.Var('X', s)]
    ]
    add_consts_to_d = [
        AssignAction(l2s_d(s)(c), lg.true) for s in uninterpreted_sorts
        for c in mod.sig.symbols.values() if c.sort == s
    ]
    # TODO: maybe add all ground terms, not just consts (if stratified)
    # TODO: add conjectures that constants are in d and a

    # figure out which l2s_w and l2s_s are used in conjectures
    named_binders_conjs = defaultdict(
        list)  # dict mapping names to lists of (vars, body)
    for b in ilu.named_binders_asts(mod.labeled_conjs):
        named_binders_conjs[b.name].append((b.variables, b.body))
    named_binders_conjs = defaultdict(
        list, ((k, sorted(list(set(v))))
               for k, v in named_binders_conjs.iteritems()))
    to_wait = [
    ]  # list of (variables, term) corresponding to l2s_w in conjectures
    to_wait += named_binders_conjs['l2s_w']
    to_save = [
    ]  # list of (variables, term) corresponding to l2s_s in conjectures
    to_save += named_binders_conjs['l2s_s']

    if debug.get():
        print "=" * 40 + "\nto_wait:\n"
        for vs, t in to_wait:
            print vs, t
            # print list(ilu.variables_ast(t)) == list(vs)
            # print
        print "=" * 40

    save_state = [AssignAction(l2s_s(vs, t)(*vs), t) for vs, t in to_save]
    done_waiting = [forall(vs, lg.Not(l2s_w(vs, t)(*vs))) for vs, t in to_wait]
    reset_w = [
        AssignAction(
            l2s_w(vs, t)(*vs), lg.And(*(l2s_d(v.sort)(v) for v in vs)))
        for vs, t in to_wait
    ]
    update_w = [
        AssignAction(
            l2s_w(vs, t)(*vs),
            lg.And(
                l2s_w(vs, t)(*vs), lg.Not(t),
                replace_temporals_by_l2s_g(lg.Not(lg.Globally(ilu.negate(t)))))
            # ($l2s_w.  phi) waits until ( phi | globally ~phi), but
            # ($l2s_w. ~phi) waits until (~phi | globally  phi) (i.e., we avoid "globally ~~phi" here)
            # note this adds to l2s_gs
        ) for vs, t in to_wait
    ]
    if debug.get():
        print "=" * 40 + "\nupdate_w:\n"
        for x in update_w:
            print x
            print
        print "=" * 40

    fair_cycle = [l2s_saved]
    fair_cycle += done_waiting
    # projection of relations
    fair_cycle += [
        lg.ForAll(
            vs,
            lg.Implies(lg.And(*(l2s_a(v.sort)(v)
                                for v in vs)), lg.Iff(l2s_s(vs, t)(*vs), t)))
        if len(vs) > 0 else lg.Iff(l2s_s(vs, t), t) for vs, t in to_save
        if (t.sort == lg.Boolean or isinstance(t.sort, lg.FunctionSort)
            and t.sort.range == lg.Boolean)
    ]
    # projection of functions and constants
    fair_cycle += [
        forall(
            vs,
            lg.Implies(
                lg.And(*([l2s_a(v.sort)(v) for v in vs] + [
                    lg.Or(l2s_a(t.sort)(l2s_s(vs, t)(*vs)),
                          l2s_a(t.sort)(t))
                ])), lg.Eq(l2s_s(vs, t)(*vs), t))) for vs, t in to_save
        if (isinstance(t.sort, lg.UninterpretedSort)
            or isinstance(t.sort, lg.FunctionSort)
            and isinstance(t.sort.range, lg.UninterpretedSort))
    ]
    if debug.get():
        print "=" * 40 + "\nfair_cycle:\n"
        for x in fair_cycle:
            print x
            print
        print "=" * 40
    # TODO: figure out why AssertAction doesn't work properly
    def assert_no_fair_cycle(a):
        # comment and uncomment the following lines to debug:
        # res = AssertAction(lg.Not(lg.And(*fair_cycle)))
        # res = AssertAction(lg.false)
        # res.lineno = temporal_goal.lineno
        # res.lineno = a.lineno
        res = AssignAction(l2s_error, lg.And(*fair_cycle))
        return res

    monitor_edge = lambda s1, s2: [
        AssumeAction(s1),
        AssignAction(s1, lg.false),
        AssignAction(s2, lg.true),
    ]
    change_monitor_state = [
        ChoiceAction(
            # waiting -> frozen
            Sequence(*(monitor_edge(l2s_waiting, l2s_frozen) +
                       [AssumeAction(x) for x in done_waiting] + reset_a)),
            # frozen -> saved
            Sequence(*(monitor_edge(l2s_frozen, l2s_saved) + save_state +
                       reset_w)),
            # stay in same state (self edge)
            Sequence(),
        )
    ]

    # tableau construction
    to_g = []  # list of (variables, formula)
    to_g += sorted(list(l2s_gs))
    if debug.get():
        print '=' * 40 + "\nto_g:\n"
        for vs, t in to_g:
            print vs, t, '\n'
        print '=' * 40
    assume_g_axioms = [
        AssumeAction(forall(vs, lg.Implies(l2s_g(vs, t)(*vs), t)))
        for vs, t in to_g
    ]
    update_g = [
        a for vs, t in to_g for a in [
            HavocAction(l2s_g(vs, t)(*vs)),
            AssumeAction(
                forall(vs, lg.Implies(
                    old_l2s_g(vs, t)(*vs),
                    l2s_g(vs, t)(*vs)))),
            AssumeAction(
                forall(
                    vs,
                    lg.Implies(lg.And(lg.Not(old_l2s_g(vs, t)(
                        *vs)), t), lg.Not(l2s_g(vs, t)(*vs))))),
        ]
    ]

    # now patch the module actions with monitor and tableau

    if debug.get():
        print "public_actions:", mod.public_actions
    for a in mod.public_actions:
        action = mod.actions[a]
        add_params_to_d = [
            AssignAction(l2s_d(p.sort)(p), lg.true)
            for p in action.formal_params
        ]
        new_action = concat_actions(*(
            # TODO: check this with Sharon
            assume_g_axioms + change_monitor_state + add_params_to_d +
            update_g + [action] + assume_g_axioms + add_consts_to_d +
            update_w + [assert_no_fair_cycle(action)]))
        new_action.lineno = action.lineno
        new_action.formal_params = action.formal_params
        new_action.formal_returns = action.formal_returns
        mod.actions[a] = new_action

    l2s_init = [
        AssignAction(l2s_waiting, lg.true),
        AssignAction(l2s_frozen, lg.false),
        AssignAction(l2s_saved, lg.false),
        AssignAction(l2s_error, lg.false),
    ]
    l2s_init += add_consts_to_d
    l2s_init += reset_w
    l2s_init += assume_g_axioms
    l2s_init += [AssumeAction(not_temporal_goal)]
    mod.initializers.append(('l2s_init', Sequence(*l2s_init)))

    if debug.get():
        print "=" * 80 + "\nafter patching actions" + "\n" * 3
        print_module(mod)
        print "=" * 80 + "\n" * 3

    # now replace all named binders by fresh relations

    named_binders = defaultdict(
        list)  # dict mapping names to lists of (vars, body)
    for b in ilu.named_binders_asts(
            chain(
                mod.labeled_conjs,
                mod.actions.values(),
                (y for x, y in mod.initializers),
            )):
        named_binders[b.name].append(b)
    # sort named binders according to a consistent order
    named_binders = defaultdict(
        list, ((k,
                list(
                    sorted(
                        set(v),
                        key=lambda x:
                        (len(x.variables), str(x.variables), str(x.body)),
                    ))) for k, v in named_binders.iteritems()))
    # make sure old_l2s_g is consistent with l2s_g, so that
    # old_l2s_g_X is really old l2s_g_X after the substitution
    assert len(named_binders['l2s_g']) == len(named_binders['old_l2s_g'])
    assert named_binders['old_l2s_g'] == [
        lg.NamedBinder('old_l2s_g', b.variables, b.body)
        for b in named_binders['l2s_g']
    ]
    subs = dict((b, lg.Const('{}_{}'.format(k, i), b.sort))
                for k, v in named_binders.iteritems() for i, b in enumerate(v))
    if debug.get():
        print "=" * 80 + "\nsubs:" + "\n" * 3
        for k in sorted(named_binders.keys()):
            v = named_binders[k]
            for i, b in enumerate(v):
                print '{}_{}'.format(k, i), ' : ', b
        print "=" * 80 + "\n" * 3
    mod_pass(lambda ast: ilu.replace_named_binders_ast(ast, subs))

    if debug.get():
        print "=" * 80 + "\nafter replace_named_binders" + "\n" * 3
        print_module(mod)
        print "=" * 80 + "\n" * 3