Пример #1
0
 def replace_quants(self, ex, domain):
     """
     Apply the closed domain assumption to the expression
      - Domain = union([e.free()|e.constants() for e in all_expressions])
      - translate "exists x.P" to "(z=d1 | z=d2 | ... ) & P.replace(x,z)" OR
                  "P.replace(x, d1) | P.replace(x, d2) | ..."
      - translate "all x.P" to "P.replace(x, d1) & P.replace(x, d2) & ..."
     :param ex: ``Expression``
     :param domain: set of {Variable}s
     :return: ``Expression``
     """
     if isinstance(ex, AllExpression):
         conjuncts = [
             ex.term.replace(ex.variable, VariableExpression(d))
             for d in domain
         ]
         conjuncts = [self.replace_quants(c, domain) for c in conjuncts]
         return reduce(lambda x, y: x & y, conjuncts)
     elif isinstance(ex, BooleanExpression):
         return ex.__class__(
             self.replace_quants(ex.first, domain),
             self.replace_quants(ex.second, domain),
         )
     elif isinstance(ex, NegatedExpression):
         return -self.replace_quants(ex.term, domain)
     elif isinstance(ex, ExistsExpression):
         disjuncts = [
             ex.term.replace(ex.variable, VariableExpression(d))
             for d in domain
         ]
         disjuncts = [self.replace_quants(d, domain) for d in disjuncts]
         return reduce(lambda x, y: x | y, disjuncts)
     else:
         return ex
Пример #2
0
    def assumptions(self):
        """
        - Domain = union([e.free()|e.constants() for e in all_expressions])
        - if "d1 = d2" cannot be proven from the premises, then add "d1 != d2"
        """
        assumptions = self._command.assumptions()

        domain = list(get_domain(self._command.goal(), assumptions))

        # build a dictionary of obvious equalities
        eq_sets = SetHolder()
        for a in assumptions:
            if isinstance(a, EqualityExpression):
                av = a.first.variable
                bv = a.second.variable
                # put 'a' and 'b' in the same set
                eq_sets[av].add(bv)

        new_assumptions = []
        for i, a in enumerate(domain):
            for b in domain[i + 1:]:
                # if a and b are not already in the same equality set
                if b not in eq_sets[a]:
                    newEqEx = EqualityExpression(VariableExpression(a),
                                                 VariableExpression(b))
                    if Prover9().prove(newEqEx, assumptions):
                        # we can prove that the names are the same entity.
                        # remember that they are equal so we don't re-check.
                        eq_sets[a].add(b)
                    else:
                        # we can't prove it, so assume unique names
                        new_assumptions.append(-newEqEx)

        return assumptions + new_assumptions
Пример #3
0
    def _attempt_proof_all(self, current, context, agenda, accessible_vars, atoms, debug):
        try:
            current._used_vars
        except AttributeError:
            current._used_vars = set()

        #if there are accessible_vars on the path
        if accessible_vars:
            # get the set of bound variables that have not be used by this AllExpression
            bv_available = accessible_vars - current._used_vars

            if bv_available:
                variable_to_use = list(bv_available)[0]
                debug.line('--> Using \'%s\'' % variable_to_use, 2)
                current._used_vars |= set([variable_to_use])
                agenda.put(current.term.replace(current.variable, variable_to_use), context)
                agenda[Categories.ALL].add((current,context))
                return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

            else:
                #no more available variables to substitute
                debug.line('--> Variables Exhausted', 2)
                current._exhausted = True
                agenda[Categories.ALL].add((current,context))
                return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

        else:
            new_unique_variable = VariableExpression(unique_variable())
            debug.line('--> Using \'%s\'' % new_unique_variable, 2)
            current._used_vars |= set([new_unique_variable])
            agenda.put(current.term.replace(current.variable, new_unique_variable), context)
            agenda[Categories.ALL].add((current,context))
            agenda.mark_alls_fresh()
            return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)
Пример #4
0
 def _attempt_proof_some(self, current, context, agenda, accessible_vars,
                         atoms, debug):
     new_unique_variable = VariableExpression(unique_variable())
     agenda.put(current.term.replace(current.variable, new_unique_variable),
                context)
     agenda.mark_alls_fresh()
     return self._attempt_proof(
         agenda, accessible_vars | set([new_unique_variable]), atoms,
         debug + 1)
Пример #5
0
 def _make_antecedent(self, predicate, signature):
     """
     Return an application expression with 'predicate' as the predicate
     and 'signature' as the list of arguments.
     """
     antecedent = predicate
     for v in signature:
         antecedent = antecedent(VariableExpression(v))
     return antecedent
Пример #6
0
def clausify(expression):
    """
    Skolemize, clausify, and standardize the variables apart.
    """
    clause_list = []
    for clause in _clausify(skolemize(expression)):
        for free in clause.free():
            if is_indvar(free.name):
                newvar = VariableExpression(unique_variable())
                clause = clause.replace(free, newvar)
        clause_list.append(clause)
    return clause_list
Пример #7
0
    def find_answers(self, verbose=False):
        self.prove(verbose)

        answers = set()
        answer_ex = VariableExpression(Variable(ResolutionProver.ANSWER_KEY))
        for clause in self._clauses:
            for term in clause:
                if isinstance(term, ApplicationExpression) and\
                   term.function == answer_ex and\
                   not isinstance(term.argument, IndividualVariableExpression):
                    answers.add(term.argument)
        return answers
Пример #8
0
 def _attempt_proof_app(self, current, context, agenda, accessible_vars, atoms, debug):
     f, args = current.uncurry()
     for i, arg in enumerate(args):
         if not TableauProver.is_atom(arg):
             ctx = f
             nv = Variable('X%s' % _counter.get())
             for j,a in enumerate(args):
                 ctx = (ctx(VariableExpression(nv)) if i == j else ctx(a))
             if context:
                 ctx = context(ctx).simplify()
             ctx = LambdaExpression(nv, ctx)
             agenda.put(arg, ctx)
             return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
     raise Exception('If this method is called, there must be a non-atomic argument')
Пример #9
0
    def assumptions(self):
        assumptions = self._command.assumptions()

        predicates = self._make_predicate_dict(assumptions)

        new_assumptions = []
        for p in predicates:
            predHolder = predicates[p]
            new_sig = self._make_unique_signature(predHolder)
            new_sig_exs = [VariableExpression(v) for v in new_sig]

            disjuncts = []

            # Turn the signatures into disjuncts
            for sig in predHolder.signatures:
                equality_exs = []
                for v1, v2 in zip(new_sig_exs, sig):
                    equality_exs.append(EqualityExpression(v1, v2))
                disjuncts.append(reduce(lambda x, y: x & y, equality_exs))

            # Turn the properties into disjuncts
            for prop in predHolder.properties:
                # replace variables from the signature with new sig variables
                bindings = {}
                for v1, v2 in zip(new_sig_exs, prop[0]):
                    bindings[v2] = v1
                disjuncts.append(prop[1].substitute_bindings(bindings))

            # make the assumption
            if disjuncts:
                # disjuncts exist, so make an implication
                antecedent = self._make_antecedent(p, new_sig)
                consequent = reduce(lambda x, y: x | y, disjuncts)
                accum = ImpExpression(antecedent, consequent)
            else:
                # nothing has property 'p'
                accum = NegatedExpression(self._make_antecedent(p, new_sig))

            # quantify the implication
            for new_sig_var in new_sig[::-1]:
                accum = AllExpression(new_sig_var, accum)
            new_assumptions.append(accum)

        return assumptions + new_assumptions
Пример #10
0
    def __setitem__(self, variable, binding):
        """
        A binding is consistent with the dict if its variable is not already bound, OR if its
        variable is already bound to its argument.

        :param variable: ``Variable`` The variable to bind
        :param binding: ``Expression`` The atomic to which 'variable' should be bound
        :raise BindingException: If the variable cannot be bound in this dictionary
        """
        assert isinstance(variable, Variable)
        assert isinstance(binding, Expression)

        try:
            existing = self[variable]
        except KeyError:
            existing = None

        if not existing or binding == existing:
            self.d[variable] = binding
        elif isinstance(binding, IndividualVariableExpression):
            # Since variable is already bound, try to bind binding to variable
            try:
                existing = self[binding.variable]
            except KeyError:
                existing = None

            binding2 = VariableExpression(variable)

            if not existing or binding2 == existing:
                self.d[binding.variable] = binding2
            else:
                raise BindingException(
                    "Variable %s already bound to another " "value" % (variable)
                )
        else:
            raise BindingException(
                "Variable %s already bound to another " "value" % (variable)
            )
Пример #11
0
 def make_VariableExpression(self, name):
     return VariableExpression(name)
Пример #12
0
def skolemize(expression, univ_scope=None, used_variables=None):
    """
    Skolemize the expression and convert to conjunctive normal form (CNF)
    """
    if univ_scope is None:
        univ_scope = set()
    if used_variables is None:
        used_variables = set()

    if isinstance(expression, AllExpression):
        term = skolemize(expression.term,
                         univ_scope | set([expression.variable]),
                         used_variables | set([expression.variable]))
        return term.replace(
            expression.variable,
            VariableExpression(unique_variable(ignore=used_variables)))
    elif isinstance(expression, AndExpression):
        return skolemize(expression.first, univ_scope, used_variables) &\
               skolemize(expression.second, univ_scope, used_variables)
    elif isinstance(expression, OrExpression):
        return to_cnf(skolemize(expression.first, univ_scope, used_variables),
                      skolemize(expression.second, univ_scope, used_variables))
    elif isinstance(expression, ImpExpression):
        return to_cnf(skolemize(-expression.first, univ_scope, used_variables),
                      skolemize(expression.second, univ_scope, used_variables))
    elif isinstance(expression, IffExpression):
        return to_cnf(skolemize(-expression.first, univ_scope, used_variables),
                      skolemize(expression.second, univ_scope, used_variables)) &\
               to_cnf(skolemize(expression.first, univ_scope, used_variables),
                      skolemize(-expression.second, univ_scope, used_variables))
    elif isinstance(expression, EqualityExpression):
        return expression
    elif isinstance(expression, NegatedExpression):
        negated = expression.term
        if isinstance(negated, AllExpression):
            term = skolemize(-negated.term, univ_scope,
                             used_variables | set([negated.variable]))
            if univ_scope:
                return term.replace(negated.variable,
                                    skolem_function(univ_scope))
            else:
                skolem_constant = VariableExpression(
                    unique_variable(ignore=used_variables))
                return term.replace(negated.variable, skolem_constant)
        elif isinstance(negated, AndExpression):
            return to_cnf(
                skolemize(-negated.first, univ_scope, used_variables),
                skolemize(-negated.second, univ_scope, used_variables))
        elif isinstance(negated, OrExpression):
            return skolemize(-negated.first, univ_scope, used_variables) &\
                   skolemize(-negated.second, univ_scope, used_variables)
        elif isinstance(negated, ImpExpression):
            return skolemize(negated.first, univ_scope, used_variables) &\
                   skolemize(-negated.second, univ_scope, used_variables)
        elif isinstance(negated, IffExpression):
            return to_cnf(skolemize(-negated.first, univ_scope, used_variables),
                          skolemize(-negated.second, univ_scope, used_variables)) &\
                   to_cnf(skolemize(negated.first, univ_scope, used_variables),
                          skolemize(negated.second, univ_scope, used_variables))
        elif isinstance(negated, EqualityExpression):
            return expression
        elif isinstance(negated, NegatedExpression):
            return skolemize(negated.term, univ_scope, used_variables)
        elif isinstance(negated, ExistsExpression):
            term = skolemize(-negated.term,
                             univ_scope | set([negated.variable]),
                             used_variables | set([negated.variable]))
            return term.replace(
                negated.variable,
                VariableExpression(unique_variable(ignore=used_variables)))
        elif isinstance(negated, ApplicationExpression):
            return expression
        else:
            raise Exception('\'%s\' cannot be skolemized' % expression)
    elif isinstance(expression, ExistsExpression):
        term = skolemize(expression.term, univ_scope,
                         used_variables | set([expression.variable]))
        if univ_scope:
            return term.replace(expression.variable,
                                skolem_function(univ_scope))
        else:
            skolem_constant = VariableExpression(
                unique_variable(ignore=used_variables))
            return term.replace(expression.variable, skolem_constant)
    elif isinstance(expression, ApplicationExpression):
        return expression
    else:
        raise Exception('\'%s\' cannot be skolemized' % expression)
Пример #13
0
    def _attempt_proof_n_app(self, current, context, agenda, accessible_vars, atoms, debug):
        f, args = current.term.uncurry()
        for i, arg in enumerate(args):
            if not TableauProver.is_atom(arg):
                ctx = f
                nv = Variable('X%s' % _counter.get())
                for j,a in enumerate(args):
                    if i==j:
                    ctx = (ctx(VariableExpression(nv)) if i == j else ctx(a))
                if context:
                    #combine new context with existing
                    ctx = context(ctx).simplify()
                ctx = LambdaExpression(nv, -ctx)
                agenda.put(-arg, ctx)
                return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)
        raise Exception('If this method is called, there must be a non-atomic argument')

    def _attempt_proof_n_eq(self, current, context, agenda, accessible_vars, atoms, debug):
        ###########################################################################
        # Since 'current' is of type '~(a=b)', the path is closed if 'a' == 'b'
        ###########################################################################
        if current.term.first == current.term.second:
            debug.line('CLOSED', 1)
            return True

        agenda[Categories.N_EQ].add((current,context))
        current._exhausted = True
        return self._attempt_proof(agenda, accessible_vars|set([current.term.first, current.term.second]), atoms, debug+1)

    def _attempt_proof_d_neg(self, current, context, agenda, accessible_vars, atoms, debug):
        agenda.put(current.term.term, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_n_all(self, current, context, agenda, accessible_vars, atoms, debug):
        agenda[Categories.EXISTS].add((ExistsExpression(current.term.variable, -current.term.term), context))
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_n_some(self, current, context, agenda, accessible_vars, atoms, debug):
        agenda[Categories.ALL].add((AllExpression(current.term.variable, -current.term.term), context))
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_and(self, current, context, agenda, accessible_vars, atoms, debug):
        agenda.put(current.first, context)
        agenda.put(current.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_n_or(self, current, context, agenda, accessible_vars, atoms, debug):
        agenda.put(-current.term.first, context)
        agenda.put(-current.term.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_n_imp(self, current, context, agenda, accessible_vars, atoms, debug):
        agenda.put(current.term.first, context)
        agenda.put(-current.term.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_or(self, current, context, agenda, accessible_vars, atoms, debug):
        new_agenda = agenda.clone()
        agenda.put(current.first, context)
        new_agenda.put(current.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
                self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_imp(self, current, context, agenda, accessible_vars, atoms, debug):
        new_agenda = agenda.clone()
        agenda.put(-current.first, context)
        new_agenda.put(current.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
                self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_n_and(self, current, context, agenda, accessible_vars, atoms, debug):
        new_agenda = agenda.clone()
        agenda.put(-current.term.first, context)
        new_agenda.put(-current.term.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
                self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_iff(self, current, context, agenda, accessible_vars, atoms, debug):
        new_agenda = agenda.clone()
        agenda.put(current.first, context)
        agenda.put(current.second, context)
        new_agenda.put(-current.first, context)
        new_agenda.put(-current.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
                self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_n_iff(self, current, context, agenda, accessible_vars, atoms, debug):
        new_agenda = agenda.clone()
        agenda.put(current.term.first, context)
        agenda.put(-current.term.second, context)
        new_agenda.put(-current.term.first, context)
        new_agenda.put(current.term.second, context)
        return self._attempt_proof(agenda, accessible_vars, atoms, debug+1) and \
                self._attempt_proof(new_agenda, accessible_vars, atoms, debug+1)

    def _attempt_proof_eq(self, current, context, agenda, accessible_vars, atoms, debug):
        #########################################################################
        # Since 'current' is of the form '(a = b)', replace ALL free instances
        # of 'a' with 'b'
        #########################################################################
        agenda.put_atoms(atoms)
        agenda.replace_all(current.first, current.second)
        accessible_vars.discard(current.first)
        agenda.mark_neqs_fresh();
        return self._attempt_proof(agenda, accessible_vars, set(), debug+1)

    def _attempt_proof_some(self, current, context, agenda, accessible_vars, atoms, debug):
        new_unique_variable = VariableExpression(unique_variable())
        agenda.put(current.term.replace(current.variable, new_unique_variable), context)
        agenda.mark_alls_fresh()
        return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)

    def _attempt_proof_all(self, current, context, agenda, accessible_vars, atoms, debug):
        try:
            current._used_vars
        except AttributeError:
            current._used_vars = set()

        #if there are accessible_vars on the path
        if accessible_vars:
            # get the set of bound variables that have not be used by this AllExpression
            bv_available = accessible_vars - current._used_vars

            if bv_available:
                variable_to_use = list(bv_available)[0]
                debug.line('--> Using \'%s\'' % variable_to_use, 2)
                current._used_vars |= set([variable_to_use])
                agenda.put(current.term.replace(current.variable, variable_to_use), context)
                agenda[Categories.ALL].add((current,context))
                return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

            else:
                #no more available variables to substitute
                debug.line('--> Variables Exhausted', 2)
                current._exhausted = True
                agenda[Categories.ALL].add((current,context))
                return self._attempt_proof(agenda, accessible_vars, atoms, debug+1)

        else:
            new_unique_variable = VariableExpression(unique_variable())
            debug.line('--> Using \'%s\'' % new_unique_variable, 2)
            current._used_vars |= set([new_unique_variable])
            agenda.put(current.term.replace(current.variable, new_unique_variable), context)
            agenda[Categories.ALL].add((current,context))
            agenda.mark_alls_fresh()
            return self._attempt_proof(agenda, accessible_vars|set([new_unique_variable]), atoms, debug+1)

    @staticmethod
    def is_atom(e):
        if isinstance(e, NegatedExpression):
            e = e.term

        if isinstance(e, ApplicationExpression):
            for arg in e.args:
                if not TableauProver.is_atom(arg):
                    return False
            return True
        elif isinstance(e, AbstractVariableExpression) or \
             isinstance(e, LambdaExpression):
            return True
        else:
            return False