예제 #1
0
def to_prover_str(f):
    """ Return a string representation of f that can be parsed by Prover9. """
    def to_prover(f):
        """ Function assumes each op has at most two args. """
        if f.op == OP_TRUE:
            return '(TRUE | -TRUE)' # no constant for true?
        elif f.op == OP_FALSE:
            return '(TRUE & -TRUE)' # no constant for false?
        elif f.op == OP_NOT:
            return ('-({arg})'.format(arg=to_prover(f.args[0])))
        elif f.op == OP_AND:
            return ('({arg1} & {arg2})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_OR:
            return ('({arg1} | {arg2})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_IMPLIES:
            return ('({arg1} -> {arg2})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_IMPLIED_BY:
            return ('({arg2} -> {arg1})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_EQUIVALENT:
            return ('({arg1} <-> {arg2})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_EQUALS:
            return ('({arg1} = {arg2})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_NOTEQUALS:
            return ('({arg1} != {arg2})'
                    .format(arg1=to_prover(f.args[0]),
                            arg2=to_prover(f.args[1])))
        elif f.op == OP_FORALL:
            return ('all {var} ({arg})'
                    .format(var=to_prover(f.vars[0]),
                            arg=to_prover(f.args[0])))
        elif f.op == OP_EXISTS:
            return ('exists {var} ({arg})'
                    .format(var=to_prover(f.vars[0]),
                            arg=to_prover(f.args[0])))
        else:
            return str(f)
    # first make sure each op has at most two args and then use the helper.
    return to_prover(deepen(f))
예제 #2
0
def push_quants(f):
    """Return formula f' equivalent to f in which quantifiers have the smallest
    possible scope. Function assumes that each quantifier has only one variable
    and each operator has at most two arguments. Use deepen() to do that.

    """
    def pushquants(f):
    #    print('pushquant({0})'.format(f))
        if is_quantified(f):
            arg = f.args[0]
            if arg.op == OP_NOT:
                return ~pushquants(Quantifier(opposite(f.op), f.vars, arg.args[0]))
            elif is_quantified(arg):
                arg1 = pushquants(arg)
                # did pushquants have any effect?
                if arg1 == arg:
#                    # if no, see if changing the order of the quants has an effect
#                    arg2 = Quantifier(f.op, f.vars, arg.args[0])
#                    arg2_ = pushquants(arg2)
#                    if arg2 == arg2_:
#                        return Quantifier(f.op, f.vars, arg1)
#                    else:
#                        return Quantifier(arg.op, arg.vars, arg2_)
                    return Quantifier(f.op, f.vars, arg1)
                else:
                    return pushquants(Quantifier(f.op, f.vars, arg1))
            elif arg.op in [OP_AND, OP_OR]:
                arg1 = arg.args[0]
                arg2 = arg.args[1]
                variable = f.vars[0]
                if variable in fvars(arg1) and variable in fvars(arg2):
                    if ((arg.op == OP_AND and f.op == OP_FORALL) or
                        (arg.op == OP_OR and f.op == OP_EXISTS)):
                        return pushquants(Expr(arg.op,
                                          Quantifier(f.op, f.vars, arg1),
                                          Quantifier(f.op, f.vars, arg2)))
                    else:
                        return Quantifier(f.op, f.vars, pushquants(arg))
                if variable in fvars(arg1):
                    return pushquants(Expr(arg.op,
                                      Quantifier(f.op, f.vars, arg1), arg2))
                if variable in fvars(arg2):
                    return pushquants(Expr(arg.op, arg1,
                                           Quantifier(f.op, f.vars, arg2)))
                else:
                    get_log().warning('Dropped quantifier "{0} : {1}" from "{2}"'
                                      .format(f.op, f.vars, f))
                    return arg
            elif arg.op == OP_IMPLIES:
                arg1 = arg.args[0]
                arg2 = arg.args[1]
                variable = f.vars[0]
                if variable in fvars(arg1) and variable in fvars(arg2):
                    return Quantifier(f.op, f.vars, pushquants(arg))
                elif variable in fvars(arg1):
                    quant = opposite(f.op)
                    return (pushquants(Quantifier(quant, variable, arg1)) >>
                            pushquants(arg2))
                elif variable in fvars(arg2):
                    return (pushquants(arg1) >>
                            pushquants(Quantifier(f.op, variable, arg2)))
                else:
                    get_log().warning('Dropped quantifier "{0} : {1}" from "{2}"'
                                      .format(f.op, f.vars, f))
                    return (pushquants(arg1) >> pushquants(arg2))
            elif arg.op == OP_IMPLIED_BY:
                arg1 = arg.args[0]
                arg2 = arg.args[1]
                variable = f.vars[0]
                if variable in fvars(arg1) and variable in fvars(arg2):
                    return Quantifier(f.op, f.vars, pushquants(arg))
                elif variable in fvars(arg1):
                    return (pushquants(Quantifier(f.op, variable, arg1)) <<
                            pushquants(arg2))
                elif variable in fvars(arg2):
                    quant = opposite(f.op)
                    return (pushquants(arg1) <<
                            pushquants(Quantifier(quant, variable, arg2)))
                else:
                    get_log().warning('Dropped quantifier "{0} : {1}" from "{2}"'
                                      .format(f.op, f.vars, f))
                    return (pushquants(arg1) << pushquants(arg2))
            else:
                return Quantifier(f.op, f.vars[0], pushquants(f.args[0]))
        elif f.op == OP_NOT:
            return ~pushquants(f.args[0])
        elif f.op in BINARY_LOGIC_OPS:
            return Expr(f.op, *[pushquants(x) for x in f.args])
        else:
            return f

    return pushquants(deepen(f))
예제 #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))))