Esempio n. 1
0
def pnf(f):
    """ Return a copy of formula f in a Prenex Normal Form. """
    return flatten(pull_quants(nnf(f)))
Esempio n. 2
0
def miniscope(f):
    """ Return a normalised copy of f with the minimu scope of quantifiers. """
    return flatten(push_quants(nnf(f)))
Esempio n. 3
0
def pull_quants(f):
    """ Pull out quantifiers to the front of the formula f.
    The function assumes that all operators have at most two arguments
    and all quantifiers have at most one variable
    (this can be achieved using the function deepen()).
    Also, each variabl name can be used only once per formula.

    """
    def rename_and_pull(f, quant, old_var1, old_var2, arg1, arg2):
        """ Helper function that renames given variable in a formula. """
        # when both variables are to be renamed, re-use the variable name
        # eg. (forall x: P(x) & forall y: Q(y)) <-> (forall x: P(x) & Q(x))
        new_var = None
        if old_var1: # rename left?
            new_var = variant(old_var1, fvars(f))
            a1 = subst({old_var1: new_var}, arg1)
        else:
            a1 = arg1
        if old_var2: # rename right?
            if not new_var:
                new_var = variant(old_var2, fvars(f))
            a2 = subst({old_var2: new_var}, arg2)
        else:
            a2 = arg2
        return Quantifier(quant, new_var, pullquants(Expr(f.op, a1 , a2)))

    def pullquants(f):
    #    print('pullquants({0})'.format(str(f)))
        if f.op == OP_AND:
            arg1 = pullquants(f.args[0])
            arg2 = pullquants(f.args[1])
            if arg1.op == OP_FORALL and arg2.op == OP_FORALL:
                return rename_and_pull(f, OP_FORALL,
                                       arg1.vars[0], arg2.vars[0],
                                       arg1.args[0], arg2.args[0])
            elif is_quantified(arg1):
                return rename_and_pull(f, arg1.op,
                                       arg1.vars[0], None,
                                       arg1.args[0], arg2)
            elif is_quantified(arg2):
                return rename_and_pull(f, arg2.op,
                                       None, arg2.vars[0],
                                       arg1, arg2.args[0])
            else:
                return (arg1 & arg2)
        elif f.op == OP_OR:
            arg1 = pullquants(f.args[0])
            arg2 = pullquants(f.args[1])
            if arg1.op == OP_EXISTS and arg2.op == OP_EXISTS:
                return rename_and_pull(f, OP_EXISTS,
                                       arg1.vars[0], arg2.vars[0],
                                       arg1.args[0], arg2.args[0])
            elif is_quantified(arg1):
                return rename_and_pull(f, arg1.op,
                                       arg1.vars[0], None,
                                       arg1.args[0], arg2)
            elif is_quantified(arg2):
                return rename_and_pull(f, arg2.op,
                                       None, arg2.vars[0],
                                       arg1, arg2.args[0])
            else:
                return (arg1 | arg2)
        elif f.op == OP_IMPLIES:
            arg1 = pullquants(f.args[0])
            arg2 = pullquants(f.args[1])
            if is_quantified(arg1):
                return rename_and_pull(f, opposite(arg1.op),
                                       arg1.vars[0], None,
                                       arg1.args[0], arg2)
            elif is_quantified(arg2):
                return rename_and_pull(f, arg2.op,
                                       None, arg2.vars[0],
                                       arg1, arg2.args[0])
            else:
                return (arg1 >> arg2)
        elif f.op == OP_IMPLIED_BY:
            arg1 = pullquants(f.args[0])
            arg2 = pullquants(f.args[1])
            if is_quantified(arg1):
                return rename_and_pull(f, arg1.op,
                                       arg1.vars[0], None,
                                       arg1.args[0], arg2)
            elif is_quantified(arg2):
                return rename_and_pull(f, opposite(arg2.op),
                                       None, arg2.vars[0],
                                       arg1, arg2.args[0])
            else:
                return (arg1 << arg2)
        elif f.op == OP_EQUIVALENT:
            arg1 = pullquants(f.args[0])
            arg2 = pullquants(f.args[1])
            return pullquants((arg1 >> arg2) & (arg1 << arg2))
        elif f.op == OP_NOT:
            arg = pullquants(f.args[0])
            if is_quantified(arg):
                return Quantifier(opposite(arg.op), f.vars, ~(arg.args[0]))
            else:
                return (~arg)
        else:
            return f

    return flatten(pullquants(unique_vars(deepen(f))))