Ejemplo n.º 1
0
def option_printer(state: State, s: SortDecl, elt: str, args: List[str]) -> str:
    assert len(args) == 2
    is_none_name, value_name = args
    is_none = get_relation(is_none_name)
    value = get_function(value_name)

    option_sort = UninterpretedSort(None, s.name)

    assert not is_none.mutable and not value.mutable and \
        is_none.arity == [option_sort] and value.arity == [option_sort]

    elt_sort = syntax.get_decl_from_sort(value.sort)

    none: Optional[str] = None
    for tup, b in state.rel_interp[is_none]:
        if b:
            assert none is None and len(tup) == 1
            none = tup[0]

    assert none is not None

    if elt == none:
        return 'None'
    else:
        the_value: Optional[str] = None
        for tup, res in state.func_interp[value]:
            assert len(tup) == 1
            if tup[0] == elt:
                assert the_value is None
                the_value = res
        assert the_value is not None

        return 'Some(%s)' % (logic.print_element(state, elt_sort, the_value))
Ejemplo n.º 2
0
def option_printer(struct: FirstOrderStructure, s: SortDecl, elt: str,
                   args: List[str]) -> str:
    assert len(args) == 2
    is_none_name, value_name = args
    is_none = get_relation(is_none_name)
    value = get_function(value_name)

    option_sort = UninterpretedSort(s.name)

    assert not is_none.mutable and not value.mutable and \
        is_none.arity == (option_sort,) and value.arity == (option_sort,)

    elt_sort = syntax.get_decl_from_sort(value.sort)

    none: Optional[str] = None
    for tup, b in struct.rel_interps[is_none].items():
        if b:
            assert none is None and len(tup) == 1
            none = tup[0]

    assert none is not None

    if elt == none:
        return 'None'
    else:
        the_value: Optional[str] = None
        for tup, res in struct.func_interps[value].items():
            assert len(tup) == 1
            if tup[0] == elt:
                assert the_value is None
                the_value = res
        assert the_value is not None

        return 'Some(%s)' % (print_element(struct, elt_sort, the_value))
Ejemplo n.º 3
0
def const_printer(state: State, s: SortDecl, elt: str, args: List[str]) -> str:
    prog = syntax.the_program
    for c in prog.constants():
        if syntax.get_decl_from_sort(c.sort) == s and state.const_interp[c] == elt:
            return c.name

    return elt
def functions_total_axioms(prog: syntax.Program) -> List[Expr]:
    res = []

    for func in prog.functions():
        # TODO: generation of part of the formula duplicated from relaxation_action_def.
        # TODO: would be best to beef up the expression-generation library
        names: List[str] = []
        params = []
        for arg_sort in func.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            params.append(syntax.SortedVar(name, arg_sort))
        ap_func = syntax.Apply(func.name,
                               tuple(syntax.Id(v.name) for v in params))

        name = prog.scope.fresh('y', also_avoid=names)

        ax = syntax.Forall(
            tuple(params),
            syntax.Exists((syntax.SortedVar(name, func.sort), ),
                          syntax.Eq(syntax.Id(name), ap_func)))
        with prog.scope.n_states(1):
            typechecker.typecheck_expr(prog.scope, ax, syntax.BoolSort)

        res.append(ax)

    return res
Ejemplo n.º 5
0
def print_element(struct: FirstOrderStructure, s: Union[SortDecl, syntax.Sort], elt: Element) -> str:
    if not isinstance(s, SortDecl):
        if isinstance(s, (syntax._BoolSort, syntax._IntSort)):
            return elt
        s = syntax.get_decl_from_sort(s)

    return try_printed_by(struct, s, elt) or elt
Ejemplo n.º 6
0
 def arbitrary_interp_c(c: ConstantDecl) -> Element:
     if isinstance(c.sort, syntax._BoolSort):
         return 'false'
     elif isinstance(c.sort, syntax._IntSort):
         return '0'
     assert isinstance(c.sort, syntax.UninterpretedSort)
     sort = c.sort
     return get_univ(syntax.get_decl_from_sort(sort))[0]
Ejemplo n.º 7
0
def set_printer(state: State, s: SortDecl, elt: str, args: List[str]) -> str:
    assert len(args) == 1
    member_name = args[0]
    member = get_relation(member_name)

    assert len(member.arity) == 2 and not member.mutable
    set_sort = UninterpretedSort(None, s.name)
    assert member.arity[1] == set_sort
    item_sort = member.arity[0]
    item_sort_decl = syntax.get_decl_from_sort(item_sort)

    items: Set[str] = set()
    for tup, b in state.rel_interp[member]:
        assert len(tup) == 2
        item, set_id = tup
        if b and set_id == elt:
            items.add(item)

    return '{%s}' % (','.join(sorted(logic.print_element(state, item_sort_decl, x) for x in items)),)
Ejemplo n.º 8
0
def set_printer(struct: FirstOrderStructure, s: SortDecl, elt: str,
                args: List[str]) -> str:
    assert len(args) == 1
    member_name = args[0]
    member = get_relation(member_name)

    assert len(member.arity) == 2 and not member.mutable
    set_sort = UninterpretedSort(s.name)
    assert member.arity[1] == set_sort
    item_sort = member.arity[0]
    item_sort_decl = syntax.get_decl_from_sort(item_sort)

    items: Set[str] = set()
    for tup, b in struct.rel_interps[member].items():
        assert len(tup) == 2
        item, set_id = tup
        if b and set_id == elt:
            items.add(item)

    return '{' + ','.join(
        sorted(print_element(struct, item_sort_decl, x) for x in items)) + '}'
Ejemplo n.º 9
0
def log_printer(state: State, s: SortDecl, elt: str, args: List[str]) -> str:
    # args should at least hold an index total order and used relation
    assert len(args) > 1
    n_values = len(args) - 2

    index_le = get_relation(args[0])
    assert len(index_le.arity) == 2
    assert index_le.arity[0] == index_le.arity[1] and not index_le.mutable
    index_sort = syntax.get_decl_from_sort(index_le.arity[0])
    index_used = get_relation(args[1])

    def default_values() -> List[List[str]]: return [[] for x in range(n_values)]

    def assert_valid_rel_or_func(rel_or_func: Union[RelationDecl, FunctionDecl]) -> None:
        assert len(rel_or_func.arity) >= 2
        assert isinstance(rel_or_func.arity[0], UninterpretedSort)
        assert isinstance(rel_or_func.arity[1], UninterpretedSort)
        assert rel_or_func.arity[0].decl == s
        assert rel_or_func.arity[1].decl == index_sort

    entries: Dict[str, LogEntry] = {}
    for tup, b in state.rel_interp[index_used]:
        if not b:
            continue

        log, index = tup
        if log == elt and index not in entries:
            entries[index] = LogEntry(index, values=default_values())

    value_sorts: List[SortDecl] = []
    for idx, name in enumerate(args[2:]):
        if is_relation(name):
            val_rel = get_relation(name)
            assert_valid_rel_or_func(val_rel)
            value_sorts.append(syntax.get_decl_from_sort(val_rel.arity[2]))
            for tup, b in state.rel_interp[val_rel]:
                if not b:
                    continue

                log, index, value = tup
                if log == elt:
                    if index not in entries:
                        entries[index] = LogEntry(index, default_values())
                    entries[index].values[idx].append(value)
        else:
            val_func = get_function(name)
            assert_valid_rel_or_func(val_func)
            value_sorts.append(syntax.get_decl_from_sort(val_func.sort))
            for tup, res in state.func_interp[val_func]:
                log, index = tup
                if log == elt:
                    if index not in entries:
                        entries[index] = LogEntry(index, default_values())
                    entries[index].values[idx].append(res)

    # The printed value of an index is consistent with index_le, so the log
    # should be ordered in the same way.
    sorted_entries = sorted(entries.values(),
                            key=lambda e: get_ordinal(state, index_le, e.index))

    # A log is well-formed if it is empty or
    #  all entries have a single element for each value and the set of indexes
    #  has no gaps starting from zero.
    well_formed = ((not sorted_entries) or
                   (all(all(len(x) == 1 for x in e.values) for e in sorted_entries) and
                    get_ordinal(state, index_le, sorted_entries[-1].index) ==
                    len(sorted_entries) - 1))

    def value_to_str(vs: List[str], sort: SortDecl) -> str:
        return '%s |-> %s' % (
            sort.name,
            logic.print_element(state, sort, vs[0]) if len(vs) == 1 else
            '[%s]' % (', '.join(logic.print_element(state, sort, v) for v in vs)))

    def entry_to_str(e: LogEntry, wf: bool) -> str:
        entry_strs = [value_to_str(e.values[idx], sort) for idx, sort in enumerate(value_sorts)]
        if not wf:
            entry_strs.insert(0, 'index |-> %s' % logic.print_element(state, index_sort, e.index))
        return '[%s]' % (', '.join(entry_strs))

    return '<<%s>>' % (', '.join(entry_to_str(entry, well_formed) for entry in sorted_entries))
Ejemplo n.º 10
0
 def arbitrary_interp_f(f: FunctionDecl) -> FunctionInterp:
     doms = [get_univ(syntax.get_decl_from_sort(s)) for s in f.arity]
     image = get_univ(syntax.get_decl_from_sort(f.sort))[0]
     return dict.fromkeys(product(*doms), image)
Ejemplo n.º 11
0
 def arbitrary_interp_r(r: RelationDecl) -> RelationInterp:
     doms = [get_univ(syntax.get_decl_from_sort(s)) for s in r.arity]
     return dict.fromkeys(product(*doms), False)
Ejemplo n.º 12
0
def relaxation_action_def(prog: syntax.Program,
                          actives: Optional[Dict[syntax.SortDecl, syntax.RelationDecl]]=None,
                          fresh: bool=True)  \
                            -> syntax.DefinitionDecl:
    decrease_name = (prog.scope.fresh('decrease_domain') if fresh else 'decrease_domain')
    mods = []
    conjs: List[Expr] = []
    if actives is None:
        actives = active_rel_by_sort(prog)

    # a conjunct allowing each domain to decrease
    for sort in prog.sorts():
        name = prog.scope.fresh(sort.name[0].upper())
        ap = syntax.Apply(actives[sort].name, [syntax.Id(None, name)])
        expr = syntax.Forall([syntax.SortedVar(None, name, None)],
                             syntax.Implies(ap, syntax.Old(ap)))
        conjs.append(expr)
        mods.append(syntax.ModifiesClause(None, actives[sort].name))

    # constants are active
    for const in prog.constants():
        conjs.append(syntax.Apply(actives[syntax.get_decl_from_sort(const.sort)].name,
                                  [syntax.Id(None, const.name)]))

    # functions map active to active
    for func in prog.functions():
        names: List[str] = []
        func_conjs = []
        for arg_sort in func.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            func_conjs.append(syntax.Apply(actives[arg_sort_decl].name, [syntax.Id(None, name)]))
        ap_func = syntax.Old(syntax.Apply(func.name, [syntax.Id(None, name) for name in names]))
        active_func = syntax.Apply(actives[syntax.get_decl_from_sort(func.sort)].name, [ap_func])
        conjs.append(syntax.Forall([syntax.SortedVar(None, name, None) for name in names],
                                   syntax.Implies(syntax.And(*func_conjs), active_func)))

    # (relativized) axioms hold after relaxation
    for axiom in prog.axioms():
        if not syntax.is_universal(axiom.expr):
            conjs.append(syntax.relativize_quantifiers(actives, axiom.expr))

    # derived relations have the same interpretation on the active domain
    for rel in prog.derived_relations():
        names = []
        rel_conjs = []
        for arg_sort in rel.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            rel_conjs.append(syntax.Apply(actives[arg_sort_decl].name, [syntax.Id(None, name)]))
        ap_rel = syntax.Apply(rel.name, [syntax.Id(None, name) for name in names])
        conjs.append(syntax.Forall([syntax.SortedVar(None, name, None) for name in names],
                                   syntax.Implies(syntax.And(*rel_conjs),
                                                  syntax.Iff(ap_rel, syntax.Old(ap_rel)))))

    return syntax.DefinitionDecl(None, public=True, twostate=True, name=decrease_name,
                                           params=[], body=(mods, syntax.And(*conjs)))
Ejemplo n.º 13
0
        def go(expr: Expr, index: Optional[int]) -> Union[Element, bool]:
            assert index is None or 0 <= index < self.num_states

            def get_rel(d: RelationDecl) -> RelationInterp:
                if d.mutable:
                    assert index is not None
                    return self.rel_interps[index][d]
                else:
                    return self.immut_rel_interps[d]

            def get_const(d: ConstantDecl) -> Element:
                if d.mutable:
                    assert index is not None
                    return self.const_interps[index][d]
                else:
                    return self.immut_const_interps[d]

            def get_func(d: FunctionDecl) -> FunctionInterp:
                if d.mutable:
                    assert index is not None
                    return self.func_interps[index][d]
                else:
                    return self.immut_func_interps[d]

            # TODO: rewrite to use the new resolved expr without traversing with scope
            scope: syntax.Scope[Union[Element, bool]] = cast(
                syntax.Scope[Union[Element, bool]], syntax.the_program.scope)
            if isinstance(expr, syntax.Bool):
                return expr.val
            elif isinstance(expr, syntax.UnaryExpr):
                if expr.op == 'NEW':
                    assert index is not None
                    with scope.next_state_index():
                        return go(expr.arg, index=index + 1)
                elif expr.op == 'NOT':
                    return not go(expr.arg, index)
                else:
                    assert False, f'eval unknown operation {expr.op}'
            elif isinstance(expr, syntax.BinaryExpr):
                if expr.op == 'IMPLIES':
                    return not go(expr.arg1, index) or go(expr.arg2, index)
                elif expr.op in ['IFF', 'EQUAL']:
                    return go(expr.arg1, index) == go(expr.arg2, index)
                elif expr.op == 'NOTEQ':
                    return go(expr.arg1, index) != go(expr.arg2, index)
                else:
                    assert False, expr
            elif isinstance(expr, syntax.NaryExpr):
                assert expr.op in ['AND', 'OR', 'DISTINCT']
                if expr.op in ['AND', 'OR']:
                    p = all if expr.op == 'AND' else any
                    return p(go(arg, index) for arg in expr.args)
                else:
                    assert expr.op == 'DISTINCT'
                    return len(set(go(arg, index)
                                   for arg in expr.args)) == len(expr.args)
            elif isinstance(expr, syntax.AppExpr):
                args = tuple(
                    cast(Element, go(arg, index)) for arg in expr.args)
                assert all(isinstance(a, Element) for a in args)
                d = scope.get(expr.callee)
                if isinstance(d, RelationDecl):
                    return get_rel(d)[args]
                elif isinstance(d, FunctionDecl):
                    return get_func(d)[args]
                else:
                    assert False, f'{d}\n{expr}'
            elif isinstance(expr, syntax.QuantifierExpr):
                assert expr.quant in ['FORALL', 'EXISTS']
                p = all if expr.quant == 'FORALL' else any
                doms = [
                    self.univs[syntax.get_decl_from_sort(sv.sort)]
                    for sv in expr.binder.vs
                ]

                def one(q: syntax.QuantifierExpr, tup: Tuple[str,
                                                             ...]) -> bool:
                    with scope.in_scope(q.binder, list(tup)):
                        ans = go(q.body, index)
                        assert isinstance(ans, bool)
                        return ans

                return p(one(expr, t) for t in product(*doms))
            elif isinstance(expr, syntax.Id):
                a = scope.get(expr.name)
                # definitions are not supported
                assert (not isinstance(a, syntax.DefinitionDecl)
                        and not isinstance(a, syntax.FunctionDecl)
                        and a is not None)
                if isinstance(a, syntax.RelationDecl):
                    return get_rel(a)[()]
                elif isinstance(a, syntax.ConstantDecl):
                    return get_const(a)
                elif isinstance(a, tuple):
                    # bound variable introduced to scope
                    (bound_elem, ) = a
                    return bound_elem
                else:
                    assert isinstance(a, str) or isinstance(a, bool)
                    return a
            elif isinstance(expr, syntax.IfThenElse):
                branch = go(expr.branch, index)
                assert isinstance(branch, bool)
                return go(expr.then, index) if branch else go(expr.els, index)
            elif isinstance(expr, syntax.Let):
                val = go(expr.val, index)
                with scope.in_scope(expr.binder, [val]):
                    return go(expr.body, index)
            else:
                assert False, expr
def relaxation_action_def(prog: syntax.Program,
                          actives: Optional[Dict[syntax.SortDecl,
                                                 syntax.RelationDecl]] = None,
                          fresh: bool = True) -> syntax.DefinitionDecl:
    decrease_name = (prog.scope.fresh('decrease_domain')
                     if fresh else 'decrease_domain')
    mods: Tuple[syntax.ModifiesClause, ...] = ()
    conjs: List[Expr] = []
    if actives is None:
        actives = active_rel_by_sort(prog)

    # a conjunct allowing each domain to decrease
    new_mods, new_conjs = relax_actives_action_chunk(prog.scope, actives)
    mods += new_mods
    conjs += new_conjs

    # constants are active
    for const in prog.constants():
        conjs.append(
            syntax.New(
                syntax.Apply(
                    actives[syntax.get_decl_from_sort(const.sort)].name,
                    (syntax.Id(const.name), ))))

    # functions map active to active
    for func in prog.functions():
        names: List[str] = []
        func_conjs = []
        for arg_sort in func.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            func_conjs.append(
                syntax.New(
                    syntax.Apply(actives[arg_sort_decl].name,
                                 (syntax.Id(name), ))))
        ap_func = syntax.Apply(func.name,
                               tuple(syntax.Id(name) for name in names))
        name = prog.scope.fresh('y', also_avoid=names)
        active_func = syntax.Let(
            syntax.SortedVar(name, func.sort), ap_func,
            syntax.New(
                syntax.Apply(
                    actives[syntax.get_decl_from_sort(func.sort)].name,
                    (syntax.Id(name), ))))
        conjs.append(
            syntax.Forall(
                tuple(syntax.SortedVar(name, None) for name in names),
                syntax.Implies(syntax.And(*func_conjs), active_func)))

    # (relativized) axioms hold after relaxation
    for axiom in prog.axioms():
        if not syntax.is_universal(axiom.expr):
            conjs.append(syntax.relativize_quantifiers(actives, axiom.expr))

    # derived relations have the same interpretation on the active domain
    for rel in prog.derived_relations():
        names = []
        rel_conjs = []
        for arg_sort in rel.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            rel_conjs.append(
                syntax.Apply(actives[arg_sort_decl].name, (syntax.Id(name), )))
        ap_rel = syntax.Apply(rel.name,
                              tuple(syntax.Id(name) for name in names))
        conjs.append(
            syntax.Forall(
                tuple(syntax.SortedVar(name, None) for name in names),
                syntax.Implies(syntax.And(*rel_conjs),
                               syntax.Iff(syntax.New(ap_rel), ap_rel))))

    return syntax.DefinitionDecl(is_public_transition=True,
                                 num_states=2,
                                 name=decrease_name,
                                 params=(),
                                 mods=mods,
                                 expr=syntax.And(*conjs))