Beispiel #1
0
 def concludeNegation(self, assumptions=USE_DEFAULTS):
     # Created by JML on 6/24/19
     from ._theorems_ import (trueAndFalseNegated, falseAndTrueNegated, 
                              falseAndFalseNegated, nandIfNeither, 
                              nandIfLeftButNotRight, nandIfRightButNotLeft)
     from proveit.logic import Not
     not_self = Not(self)
     if not_self in {trueAndFalseNegated.expr, falseAndTrueNegated.expr, falseAndFalseNegated.expr}:
         # should be disproven via one of the imported theorems as a simple special case
         return not_self.prove()
         # Prove that the conjunction is true by proving that one of its operands is false and then negate it.
     # In the first attempt, don't use automation to prove any of the operands so that
     # we don't waste time trying to prove operands when we already know one to be false
     for useAutomationForOperand in [False, True]:
         disprovenOperandIndices = []
         for _k, operand in enumerate(self.operands):
             try:
                 operand.disprove(assumptions, automation=useAutomationForOperand)
                 disprovenOperandIndices.append(_k)
                 # possible way to prove it
                 self.concludeViaExample(operand, assumptions=assumptions)  
             except ProofFailure:
                 pass
         if len(self.operands) == 2 and len(disprovenOperandIndices) > 0:
             # One or both of the two operands were known to be true (without automation).
             # Try a possibly simpler proof than concludeViaExample.
             try:
                 if len(disprovenOperandIndices) == 2:
                     return nandIfNeither.specialize({A: self.operands[0], B: self.operands[1]}, assumptions=assumptions)
                 elif disprovenOperandIndices[0] == 0:
                     return nandIfRightButNotLeft.specialize({A: self.operands[0], B: self.operands[1]}, assumptions=assumptions)
                 else:
                     return nandIfLeftButNotRight.specialize({A: self.operands[0], B: self.operands[1]}, assumptions=assumptions)
             except:
                 pass
         if len(disprovenOperandIndices) > 0:
             # Not(self) should have been proven via 
             # concludeViaExample above 
             try:
                 return not_self.prove(assumptions, automation=False)
             except:
                 # If it wasn't proven via concludeViaExample, let's
                 # call it again to raise the appropriate exception.
                 operand = self.operands[disprovenOperandIndices[0]]
                 return self.concludeViaExample(operand, assumptions=assumptions)
     raise ProofFailure(not_self, assumptions, 
                        "Unable to conclude the negated conjunction; "
                        "we could not disprove any of the conjunction "
                        "operands.")
Beispiel #2
0
    def conclude(self, **defaults_config):
        from proveit.logic import FALSE, Not, evaluation_or_simplification
        if is_irreducible_value(self.lhs) and is_irreducible_value(self.rhs):
            # prove that two irreducible values are not equal
            return self.lhs.not_equal(self.rhs)
        if self.lhs == FALSE or self.rhs == FALSE:
            try:
                # prove something is not false by proving it to be true
                return self.conclude_via_double_negation()
            except BaseException:
                pass
        if Not(Equals(self.lhs, self.rhs)).proven():
            # Conclude (x ≠ y) by knowing that Not(x = y) is true.
            return self.conclude_as_folded()

        # Try the standard Relation strategies -- evaluate or
        # simplify both sides.
        try:
            return Relation.conclude(self)
        except ProofFailure:
            # Both sides are already irreducible or simplified.
            pass

        if hasattr(self.lhs, 'not_equal'):
            # If there is a 'not_equal' method, use that.
            # The responsibility then shifts to that method for
            # determining what strategies should be attempted
            # (with the recommendation that it should not attempt
            # multiple non-trivial automation strategies).
            # A good practice is to try the 'conclude_as_folded'
            # strategy if it doesn't fall into any specially-handled
            # case.
            return self.lhs.not_equal(self.rhs)

        return self.conclude_as_folded()
Beispiel #3
0
 def sideEffects(self, knownTruth):
     '''
     Side-effect derivations to attempt automatically.
     '''
     from proveit.logic import Not
     if len(self.operands) == 2:
         if self.operands[1] == Not(self.operands[0]):
             # (A or not(A)) is an unfolded Boolean
             return  # stop to avoid infinite recursion.
     yield self.deriveInBool
Beispiel #4
0
 def side_effects(self, judgment):
     '''
     Side-effect derivations to attempt automatically.
     '''
     from proveit.logic import Not
     if self.operands.is_double():
         if self.operands[1] == Not(self.operands[0]):
             # (A or not(A)) is an unfolded Boolean
             return  # stop to avoid infinite recursion.
     yield self.derive_in_bool
Beispiel #5
0
 def disprove(self, assumptions=USE_DEFAULTS, automation=USE_DEFAULTS):
     '''
     Attempt to prove the logical negation (Not) of this expression. 
     If successful, the KnownTruth is returned, otherwise an exception
     is raised.  By default, this simply calls prove on the negated
     expression. Override `concludeNegation` for automation specific to
     the type of expression being negated.      
     '''
     from proveit.logic import Not
     return Not(self).prove(assumptions=assumptions, automation=automation)
Beispiel #6
0
 def derive_via_boolean_equality(self, assumptions=USE_DEFAULTS):
     '''
     From A = TRUE derive A, or from A = FALSE derive Not(A).  This derivation
     is an automatic side-effect.
     Note, see derive_stmt_eq_true or Not.equate_negated_to_false for the reverse process.
     '''
     from proveit.logic import TRUE, FALSE
     from proveit.logic.booleans import eq_true_elim
     from proveit.logic import Not
     if self.rhs == TRUE:
         return eq_true_elim.instantiate({A: self.lhs},
                                         assumptions=assumptions)  # A
     elif self.rhs == FALSE:
         return Not(self.lhs).conclude_via_falsified_negation(
             assumptions=assumptions)  # Not(A)
Beispiel #7
0
 def deriveViaBooleanEquality(self, assumptions=USE_DEFAULTS):
     '''
     From A = TRUE derive A, or from A = FALSE derive Not(A).  This derivation
     is an automatic side-effect.
     Note, see deriveStmtEqTrue or Not.equateNegatedToFalse for the reverse process.
     '''
     from proveit.logic import TRUE, FALSE
     from proveit.logic.boolean._axioms_ import eqTrueElim
     from proveit.logic import Not
     if self.rhs == TRUE:
         return eqTrueElim.specialize({A: self.lhs},
                                      assumptions=assumptions)  # A
     elif self.rhs == FALSE:
         return Not(self.lhs).concludeViaFalsifiedNegation(
             assumptions=assumptions)  # Not(A)
Beispiel #8
0
    def side_effects(self, judgment):
        '''
        Side-effect derivations to attempt automatically.
        '''

        from proveit.logic import Not
        from proveit import ExprRange
        if self.operands.num_entries() == 0:
            return  # No side-effects needed for [And]().
        if self.operands.is_double():
            if self.operands[1] == Not(self.operands[0]):
                # (A or not(A)) is an unfolded Boolean
                return  # stop to avoid infinite recursion.
        yield self.derive_in_bool
        for _i, operand in enumerate(self.operands):
            if (isinstance(operand, ExprRange)
                    and self.operands.num_entries() == 1):
                yield lambda: self.derive_quantification()
            else:
                yield lambda: self.derive_any(_i)
Beispiel #9
0
def test():
        substitution.specialize({fx:Not(x), x:a, y:b}, assumptions=[Equals(a, b)])
        expr = Equals(a, Add(b, Frac(c, d), Exp(c, d)))
        gRepl = Lambda.globalRepl(expr, d)
        d_eq_y = Equals(d, y)
        d_eq_y.substitution(gRepl, assumptions=[d_eq_y])
        d_eq_y.substitution(expr, assumptions=[d_eq_y])
        d_eq_y.substitution(expr, assumptions=[d_eq_y]).proof()
        innerExpr = expr.innerExpr()
        innerExpr = innerExpr.rhs
        innerExpr = innerExpr.operands[1]
        innerExpr = innerExpr.denominator
        d_eq_y.substitution(innerExpr, assumptions=[d_eq_y])
        d_eq_y.substitution(expr.innerExpr().rhs.operands[2].exponent, assumptions=[d_eq_y])
        d_eq_y.subRightSideInto(gRepl, assumptions=[d_eq_y,expr])
        d_eq_y.subRightSideInto(expr, assumptions=[d_eq_y,expr])
        y_eq_d = Equals(y, d)
        y_eq_d.subLeftSideInto(gRepl, assumptions=[y_eq_d,expr])
        y_eq_d.subLeftSideInto(expr, assumptions=[y_eq_d,expr])
        y_eq_d.subLeftSideInto(expr, assumptions=[y_eq_d,expr]).proof()
        
Beispiel #10
0
 def concludeBooleanEquality(self, assumptions=USE_DEFAULTS):
     '''
     Prove and return self of the form (A=TRUE) assuming A, A=FALSE assuming Not(A), [Not(A)=FALSE] assuming A.
     '''
     from proveit.logic import TRUE, FALSE, Not
     from proveit.logic.boolean._axioms_ import eqTrueIntro
     if self.rhs == TRUE:
         return eqTrueIntro.specialize({A: self.lhs},
                                       assumptions=assumptions)
     elif self.rhs == FALSE:
         if isinstance(self.lhs, Not):
             return self.lhs.evaluation(assumptions=assumptions)
         else:
             return Not(self.lhs).equateNegatedToFalse(assumptions)
     elif self.lhs == TRUE or self.lhs == FALSE:
         return Equals(
             self.rhs,
             self.lhs).prove(assumptions).deriveReversed(assumptions)
     raise ProofFailure(
         self, assumptions,
         "May only conclude via boolean equality if one side of the equality is TRUE or FALSE"
     )
Beispiel #11
0
 def conclude_boolean_equality(self, assumptions=USE_DEFAULTS):
     '''
     Prove and return self of the form (A=TRUE) assuming A, A=FALSE assuming Not(A), [Not(A)=FALSE] assuming A.
     '''
     from proveit.logic import TRUE, FALSE, Not
     from proveit.logic.booleans import eq_true_intro
     if self.rhs == TRUE:
         return eq_true_intro.instantiate({A: self.lhs},
                                          assumptions=assumptions)
     elif self.rhs == FALSE:
         if isinstance(self.lhs, Not):
             evaluation = self.lhs.evaluation(assumptions=assumptions)
             if evaluation.rhs == self.rhs:
                 return evaluation
         else:
             return Not(self.lhs).equate_negated_to_false(assumptions)
     elif self.lhs == TRUE or self.lhs == FALSE:
         return Equals(self.rhs, self.lhs).conclude_boolean_equality(
             assumptions).derive_reversed(assumptions)
     raise ProofFailure(
         self, assumptions,
         "May only conclude via boolean equality if one side of the equality is TRUE or FALSE"
     )
Beispiel #12
0
    def decorated_prover(*args, **kwargs):
        from proveit import Expression, Judgment, InnerExpr
        from proveit.logic import Equals
        if (kwargs.get('preserve_all', False)
                and len(kwargs.get('replacements', tuple())) > 0):
            raise ValueError(
                "Adding 'replacements' and setting 'preserve_all' "
                "to True are incompatible settings.")
        preserve_expr = kwargs.pop('preserve_expr', None)
        if len(args) > 0:
            _self = args[0]
            if isinstance(_self, Judgment) or isinstance(_self, InnerExpr):
                # Include the assumptions of the Judgment or InnerExpr
                assumptions = kwargs.get('assumptions', None)
                if assumptions is None:
                    assumptions = defaults.assumptions
                if not _self.assumptions_set.issubset(assumptions):
                    assumptions = tuple(assumptions) + _self.assumptions
                    kwargs['assumptions'] = assumptions
            if is_conclude_method:
                # If the method starts with conclude 'conclude', we must
                # preserve _self.
                if (not isinstance(_self, Expression)
                        and hasattr(_self, 'expr')):
                    preserve_expr = _self.expr
                else:
                    preserve_expr = _self
        defaults_to_change = set(kwargs.keys()).intersection(
            defaults.__dict__.keys())
        # Check to see if there are any unexpected keyword
        # arguments.
        for key in kwargs.keys():
            if key in defaults_to_change: continue
            if key not in sig.parameters:
                raise TypeError(
                    "%s got an unexpected keyword argument '%s' which "
                    "is not an attribute of proveit.defaults" % (func, key))

        def public_attributes_dict(obj):
            # Return a dictionary of public attributes and values of
            # an object.
            return {
                key: val
                for key, val in obj.__dict__.items() if key[0] != '_'
            }

        exprs_to_replace = set()
        if 'replacements' in kwargs:
            for replacement in kwargs['replacements']:
                if not isinstance(replacement, Judgment):
                    raise TypeError("The 'replacements' must be Judgments")
                if not isinstance(replacement.expr, Equals):
                    raise TypeError(
                        "The 'replacements' must be equality Judgments")
                exprs_to_replace.add(replacement.expr.lhs)

        # Make sure a preserved expression isn't also being replaced.
        if 'preserved_exprs' in kwargs:
            # Make sure a preserved expression isn't also
            # being replaced.
            preserved_exprs = kwargs['preserved_exprs']
            if not exprs_to_replace.isdisjoint(preserved_exprs):
                raise ValueError(
                    "Cannot simultaneously replace and preserve these "
                    "expression: %s" %
                    exprs_to_replace.intersection(preserved_exprs))

        if preserve_expr is not None:
            # Make sure this preserved expression isn't also being replaced.
            if preserve_expr in exprs_to_replace:
                raise ValueError(
                    "Cannot simultaneously replace and preserve %s" %
                    preserve_expr)
            # Preserve the 'preserve_expr'.
            if ('preserved_exprs' in defaults_to_change
                    or preserve_expr not in defaults.preserved_exprs):
                if 'preserved_exprs' in kwargs:
                    kwargs['preserved_exprs'].add(preserve_expr)
                else:
                    defaults_to_change.add('preserved_exprs')
                    kwargs['preserved_exprs'] = (
                        defaults.preserved_exprs.union({preserve_expr}))

        def checked_truth(proven_truth):
            # Check that the proven_truth is a Judgment and has
            # appropriate assumptions.
            if proven_truth is None and is_conclude_method:
                return proven_truth  # we'll raise an exception later.
            if not isinstance(proven_truth, Judgment):
                raise TypeError("@prover method %s is expected to return "
                                "a proven Judgment, not %s of type %s." %
                                (func, proven_truth, proven_truth.__class__))
            if not proven_truth.is_applicable():
                raise TypeError("@prover method %s returned a Judgment, "
                                "%s, that is not proven under the active "
                                "assumptions: %s" %
                                (func, proven_truth, defaults.assumptions))
            return proven_truth

        if len(defaults_to_change) > 0:
            # Temporarily reconfigure defaults with
            with defaults.temporary() as temp_defaults:
                if 'assumptions' in defaults_to_change:
                    # Set 'assumptions' first (before turning off
                    # 'automation', for example, so that the
                    # side-effects will be processed).
                    key = 'assumptions'
                    setattr(temp_defaults, key, kwargs[key])
                for key in defaults_to_change:
                    if key != 'assumptions':
                        # Temporarily alter a default:
                        setattr(temp_defaults, key, kwargs[key])
                kwargs.update(public_attributes_dict(defaults))
                proven_truth = checked_truth(func(*args, **kwargs))
        else:
            # No defaults reconfiguration.
            kwargs.update(public_attributes_dict(defaults))
            proven_truth = checked_truth(func(*args, **kwargs))

        if is_conclude_method:
            self = args[0]
            if isinstance(self, Expression):
                expr = self
            elif hasattr(self, 'expr'):
                expr = self.expr
            else:
                raise TypeError(
                    "The @prover method %s beginning with 'conclude' "
                    "expected to be a method for an Expression type "
                    "or the object must have an 'expr' attribute." % func)
            if proven_truth is None:
                raise ValueError("@prover method %s is not implemented "
                                 "for %s." % (func, expr))
            if func.__name__.startswith('conclude_negation'):
                from proveit.logic import Not
                not_expr = Not(expr)
                if proven_truth.expr != not_expr:
                    raise ValueError(
                        "@prover method %s whose name starts with "
                        "'conclude_negation' must prove %s "
                        "but got %s." % (func, not_expr, proven_truth))
                # Match the style of not_self.
                return proven_truth.with_matching_style(not_expr)
            else:
                if proven_truth.expr != expr:
                    raise ValueError(
                        "@prover method %s whose name starts with "
                        "'conclude' must prove %s but got "
                        "%s." % (func, expr, proven_truth))
                # Match the style of self.
                return proven_truth.with_matching_style(expr)
        return proven_truth
Beispiel #13
0
true_conclusion = Forall(A, Implies(A, TRUE))

in_bool_equiv = Forall(
    A, Equals(in_bool(A), Or(Equals(A, TRUE), Equals(A, FALSE))))

true_is_bool = in_bool(TRUE)

false_is_bool = in_bool(FALSE)

unfold_forall_over_bool = Forall(
    P, Implies(Forall(A, PofA, domain=Boolean), And(PofTrue, PofFalse)))

in_bool_if_true = Forall(A, in_bool(A), conditions=[A])

in_bool_if_false = Forall(A, in_bool(A), conditions=[Not(A)])

# This weak form requires B to be a Boolean
by_cases_weak = Forall((A, B),
                       B,
                       domain=Boolean,
                       conditions=[Implies(A, B),
                                   Implies(Not(A), B)])

# This is a stronger form that does not require B to be a Boolean
by_cases = Forall(A,
                  Forall(B, B, conditions=[Implies(A, B),
                                           Implies(Not(A), B)]),
                  domain=Boolean)

fold_forall_over_bool = Forall(P,
Beispiel #14
0
trueConclusion = Forall(A, Implies(A, TRUE))

inBoolEquiv = Forall(A, Equals(inBool(A), Or(Equals(A, TRUE), Equals(A,
                                                                     FALSE))))

trueInBool = inBool(TRUE)

falseInBool = inBool(FALSE)

unfoldForallOverBool = Forall(
    P, Implies(Forall(A, PofA, domain=Booleans), And(PofTrue, PofFalse)))

inBoolIfTrue = Forall(A, inBool(A), conditions=[A])

inBoolIfFalse = Forall(A, inBool(A), conditions=[Not(A)])

# This weak form requires B to be a Boolean
byCasesWeak = Forall((A, B),
                     B,
                     domain=Booleans,
                     conditions=[Implies(A, B),
                                 Implies(Not(A), B)])

# This is a stronger form that does not require B to be a Boolean
byCases = Forall(A,
                 Forall(B, B, conditions=[Implies(A, B),
                                          Implies(Not(A), B)]),
                 domain=Booleans)

foldForallOverBool = Forall(P,
Beispiel #15
0
    def conclude_negation(self, **defaults_config):
        # Created by JML on 6/24/19
        from . import (true_and_false_negated, false_and_true_negated,
                       false_and_false_negated, nand_if_neither,
                       nand_if_left_but_not_right, nand_if_right_but_not_left)
        from proveit.logic import Not, FALSE
        not_self = Not(self)
        if not_self in {
                true_and_false_negated.expr, false_and_true_negated.expr,
                false_and_false_negated.expr
        }:
            # should be disproven via one of the imported theorems as a
            # simple special case
            return not_self.prove()
            # Prove that the conjunction is true by proving that one of
            # its operands is false and then negate it.
        # In the first attempt, don't use automation to prove any of the
        # operands so that
        # we don't waste time trying to prove operands when we already
        # know one to be false
        use_automation_possibilities = ([False, True]
                                        if defaults.automation else [False])
        if self.operands.contains_range():
            if self.operands.num_entries() == 1:
                # Just a single ExprRange.  Conclude the negation
                # through an evaluation which will equate it to
                # a universal quantification.
                evaluation = self.evaluation()
                if evaluation.rhs == FALSE:
                    return self.disprove()
                raise ProofFailure(
                    Not(self), defaults.assumptions,
                    "Expected evaluation to be FALSE, got %s" % evaluation)
            # Group each ExprRange operand, call conclude_negation,
            # then disassociate the ExprRange operands.
            return prove_via_grouping_ranges(
                self, lambda expr, **kwargs: expr.conclude_negation(**kwargs))

        for use_automation_for_operand in use_automation_possibilities:
            disproven_operand_indices = []
            for _k, operand in enumerate(self.operands):
                try:
                    operand.disprove(automation=use_automation_for_operand)
                    disproven_operand_indices.append(_k)
                    # possible way to prove it
                    self.conclude_negation_via_example(operand)
                except Exception:
                    pass
            if self.operands.is_double(
            ) and len(disproven_operand_indices) > 0:
                # One or both of the two operands were known to be true
                # (without automation).
                # Try a possibly simpler proof than
                # conclude_negation_via_example.
                try:
                    if len(disproven_operand_indices) == 2:
                        return nand_if_neither.instantiate({
                            A: self.operands[0],
                            B: self.operands[1]
                        })
                    elif disproven_operand_indices[0] == 0:
                        return nand_if_right_but_not_left.instantiate({
                            A:
                            self.operands[0],
                            B:
                            self.operands[1]
                        })
                    else:
                        return nand_if_left_but_not_right.instantiate({
                            A:
                            self.operands[0],
                            B:
                            self.operands[1]
                        })
                except BaseException:
                    pass
            if len(disproven_operand_indices) > 0:
                # Not(self) should have been proven via
                # conclude_negation_via_example above
                try:
                    return not_self.prove(automation=False)
                except BaseException:
                    # If it wasn't proven via
                    # conclude_negation_via_example, let's
                    # call it again to raise the appropriate exception.
                    operand = self.operands[disproven_operand_indices[0]]
                    return self.conclude_negation_via_example(operand)
        raise ProofFailure(
            not_self, defaults.assumptions,
            "Unable to conclude the negated conjunction; "
            "we could not disprove any of the conjunction "
            "operands.")