示例#1
0
def _standardize_quantified_variables(node: syntax.Node,
                                      state: syntax.WalkState) -> syntax.Node:
    """Standardizes quantified variables by giving them unique names.

    :param node: The node to rewrite.
    :param state: Rewriting state.
    :returns: Rewritten node.

    Rewrites expressions of type:

    - `*x: A(x)` into `*var_1: A(var_1)`,
    - `?x: A(x)` into `?var_1: A(var_1)`.
    """

    seen: List[syntax.Node] = state.context.setdefault('seen', [])
    replaced: syntax.T_Substitution = state.context.setdefault('replaced', {})

    # todo: replaced would not work with nested quantified formulas that
    #  reuse the same symbol, but actually never mind - it's a corner case
    #  I don't want to fiddle with now

    if node in seen:
        return node

    if node.is_quantified():
        old = node.get_quantified_variable().value
        if old.startswith('_'):
            return node  # already renamed

        new = _new_variable_name()
        qtype = node.get_quantifier_type()
        quant = syntax.make_quantifier(qtype, new)
        rv = syntax.make_formula(quant, node.children)

        replaced[new] = node.get_quantified_variable()
        state.stack.append((old, new))
        seen.append(rv)
        return rv

    elif node.is_variable():
        # reversed, because we want to rename symbol to the last seen value.
        # Example: We want to rewrite `?x, ?x: x` into `?a: ?b: b`.
        for old, new in reversed(state.stack):
            if old == node.value:
                rv = syntax.make_variable(new)
                seen.append(rv)
                return rv

        return node

    else:
        return node
示例#2
0
def _skolemize(node: syntax.Node, state: syntax.WalkState) -> syntax.Node:
    """Skolemizes expressions and drops quantifiers.

    :param node: The node to rewrite.
    :param state: Rewriting state.
    :returns: Rewritten node.

    Rewrites expressions of type:

    - `?x: x` into `C1`,
    - `*a: a & ?x: x` into `a & F1(a)`,
    - `*a: a & ?x: x & *b: b & ?y: y` into `a & F1(a) & b & F2(a, b)`,
    """

    if not state.stack:
        state.stack.extend([[], []])

    # enclosing universally quantified variables
    universal: List[str] = state.stack[0]
    replacements: List[Tuple[str, syntax.Node]] = state.stack[1]

    replaced: syntax.T_Substitution = state.context.setdefault('replaced', {})

    if node.is_quantified():
        qtype = node.get_quantifier_type()
        if qtype == syntax.UNIVERSAL_QUANTIFIER:
            qv = node.get_quantified_variable()
            universal.append(qv.value)
        else:
            assert qtype == syntax.EXISTENTIAL_QUANTIFIER

            # store what to replace (actual replacement happens in the
            # elif branch below)

            qv = node.get_quantified_variable()
            old = qv.value

            if universal:
                name = _new_function_name()
                new = syntax.make_function(name, *universal)
            else:
                name = _new_constant_name()
                new = syntax.make_constant(name)

            replaced[new.value] = qv

            replacements.append((old, new))

        # drop quantifiers
        children = node.children
        assert len(children) == 1
        return children[0]

    elif node.is_variable():
        for old, new in replacements:
            if old == node.value:
                return copy.deepcopy(new)
        return node

    else:
        return node