Esempio n. 1
0
 def doReducedEvaluation(self, assumptions=USE_DEFAULTS, **kwargs):
     '''
     Only handles -0 = 0 or double negation.
     '''
     from proveit.logic import EvaluationError
     from ._theorems_ import negatedZero
     from proveit.number import zero
     if self.operand == zero:
         return negatedZero
     if isinstance(self.operand, Neg) and isIrreducibleValue(
             self.operand.operand):
         return self.doubleNegSimplification(assumptions)
     raise EvaluationError(self, assumptions)
Esempio n. 2
0
    def doReducedEvaluation(self, assumptions=USE_DEFAULTS):
        '''
        Derive and return this multiplication expression equated with an irreducible value.
        Handle the trivial case of a zero factor or do pairwise evaluation
        after simplifying negations and eliminating one factors.
        '''
        from ._theorems_ import multZeroLeft, multZeroRight, multZeroAny
        from proveit.logic import isIrreducibleValue, SimplificationError
        from proveit.number import zero
        
        # First check for any zero factors -- quickest way to do an evaluation.
        try:
            zeroIdx = self.operands.index(zero)
            if len(self.operands)==2:
                if zeroIdx==0:
                    return multZeroLeft.specialize({x:self.operands[1]}, assumptions=assumptions)
                else:
                    return multZeroRight.specialize({x:self.operands[0]}, assumptions=assumptions)
            Afactors = self.operands[:zeroIdx]
            Bfactors = self.operands[zeroIdx+1:]
            return multZeroAny.specialize({m:len(Afactors), n:len(Bfactors), AA:Afactors, BB:Bfactors}, assumptions=assumptions)
        except (ValueError, ProofFailure):
            pass # No such "luck" regarding a simple multiplication by zero.
        
        expr = self
        
        # A convenience to allow successive update to the equation via transitivities.
        # (starting with self=self).
        eq = TransRelUpdater(self, assumptions)
        
        # Simplify negations -- factor them out.
        expr = eq.update(expr.negSimplifications(assumptions))
        
        if not isinstance(expr, Mult):
            # The expression may have changed to a negation after doing
            # negSimplification.  Start the simplification of this new
            # expression fresh at this point.
            eq.update(expr.evaluation(assumptions))
            return eq.relation

        # Eliminate any factors of one.
        expr = eq.update(expr.oneEliminations(assumptions))
        
        if isIrreducibleValue(expr):
            return eq.relation # done
        
        if len(self.operands) > 2:
            eq.update(pairwiseEvaluation(expr, assumptions))
            return eq.relation

        raise SimplificationError("Unable to evaluate %s"%str(self))
Esempio n. 3
0
 def irreducibleValue(self):
     from proveit.number import zero
     return isIrreducibleValue(self.operand) and self.operand != zero
Esempio n. 4
0
    def deduceEnumProperSubset(self,
                               subset_indices=None,
                               subset=None,
                               assumptions=USE_DEFAULTS):
        '''
        Deduce that this Set expression has as a proper subset the
        set specified by either (a) the indices in the subset_indices 
        list OR (b) the Set specified by subset (but not both).
        For example, both
        {a, b, c, d}.deduceEnumSubset(subset_indices=[1, 3]) and
        {a, b, c, d}.deduceEnumSubset(subset=Set(b, d))
        return |– {b, d} subset {a, b, c, d} (assuming the appropriate
        knowledge about either a or c (or both) not being elements of
        the subset {b, d}).
        This proper subset method is more complex than the analogous
        method for improper subsets. As with the improper subset case,
        this process is complicated by the fact that the Set class
        allows for multiplicity of elements without it actually
        representing a multi-set (thus, for example, {a, a} = {a}).
        Subset deductions are based on the support sets (i.e. the sets
        with all multiplicities reduced to 1) for the self
        and subsets supplied. The process is further complicated by
        the fact that elements in one set might not *appear* to be in
        the other set but might be *equal* to elements in the other set,
        making it challenging to confirm the proper subset relationship.
        '''

        from proveit.logic import Set

        # Before bothering with much processing, quickly check that:
        # (1) user has specified subset_indices OR subset but not both;
        # (2) if only subset specification, it has the correct form;
        # (3) if only subset_indices, they are plausible.
        if subset_indices is None and subset is None:
            raise ValueError("Need to specify the desired subset by "
                             "specifying the list of indices (subset_indices) "
                             "OR an actual subset (in the form of an "
                             "enumerated set using Set()).")
        if subset_indices is not None and subset is not None:
            raise ValueError("Need to specify the desired subset by "
                             "specifying the list of indices (subset_indices) "
                             "OR an actual subset, but NOT both.")
        if subset is not None and not isinstance(subset, Set):
            raise ValueError("Specified subset {} does not appear to be a "
                             "valid Set object.".format(subset))
        self_list = list(self.operands)
        valid_indices_list = list(range(0, len(self.operands)))

        if subset_indices is not None:
            # We must have had subset=None, so check validity of the
            # indices and use them to create a subset Set
            self._check_subset_indices_weak(valid_indices_list,
                                            subset_indices,
                                            proper_subset=True)
            subset_list_from_indices = [self_list[i] for i in subset_indices]
            subset_from_indices = Set(*subset_list_from_indices)
            subset = subset_from_indices

        # Reformat assumptions if necessary. Among other things,
        # convert any assumptions=None to assumptions=()
        assumptions = defaults.checkedAssumptions(assumptions)

        # We should now have a subset Set, either explicitly provided
        # as an argument or derived from the subset_indices.
        subset_list = list(subset.operands)

        # Try to make some appropriate substitutions into the subset,
        # and reduce the subset, all to make later processing (such as
        # finding a superset element not also in the subset) easier.
        # This seems like a lot of extra code, but should execute
        # fairly quickly because it doesn't depend on automation --
        # just some list searches and theorem specializations.
        from proveit.logic import Equals, isIrreducibleValue
        from proveit import TransRelUpdater
        temp_subset = subset
        eq_temp = TransRelUpdater(temp_subset, assumptions)
        # perform substitutions to irreducible values when possible
        for elem in set(temp_subset.operands):
            if elem in Equals.knownEqualities:
                for kt in Equals.knownEqualities[elem]:
                    if set(kt.assumptions).issubset(set(assumptions)):
                        if (kt.lhs == elem and isIrreducibleValue(kt.rhs)
                                and kt.lhs != kt.rhs):
                            temp_subset = eq_temp.update(
                                temp_subset.elem_substitution(
                                    elem=elem,
                                    sub_elem=kt.rhs,
                                    assumptions=assumptions))
                            break
        # reduce multiplicities
        temp_subset = eq_temp.update(temp_subset.reduction(assumptions))
        subset = temp_subset
        subset_list = list(subset.operands)
        subset_to_subset_subbed_reduced_kt = eq_temp.relation
        # subset_was_substituted = True

        # ================================================= #
        # LATER do that same process for the superset self? #
        # ================================================= #

        # We now have a SUBSTITUTED and REDUCED subset Set.
        # A subset generated from the subset_indices will automatically
        # be a plausible subset (b/c it derived from the superset self
        # elements). If the subset was originally supplied as
        # an argument, however, we now check if it is a plausible
        # subset of self: it should only have elements found in self
        # or elements somehow proven to be equal to elements in self.
        if subset_indices == None:  # i.e. subset provided explicitly by user
            # then substituted, reduced subset might not be a subset
            error_elem_candidates = set()
            error_elem_equivalences_dict = dict()
            for elem in set(subset_list):
                if elem not in set(self_list):
                    error_elem_candidates.add(elem)
            if len(error_elem_candidates) > 0:
                # We have candidates in the supposed subset that do not
                # literally appear in the supposed superset self, but
                # the candidates might be known to be 'Equal' to
                # appropriate values, so we check just a little more
                # assiduously before returning an error message
                error_elems = error_elem_candidates.copy()
                # from proveit.logic import Equals
                for elem in error_elem_candidates:
                    for super_elem in set(self_list):
                        if Equals(elem,
                                  super_elem).proven(assumptions=assumptions):
                            error_elems.discard(elem)
                            break  # b/c we just need 1 instance
                if len(error_elems) > 0:
                    raise ValueError(
                        "Specified subset {0} does not appear to be a "
                        "subset of the original set {1}. The following "
                        "elements appear in the requested subset Set but "
                        "not in the original Set: {2}.".format(
                            subset, self, error_elems))

        # Furthermore, we need to check that at least one superset
        # elem does not appear in the proposed proper subset.
        # This is not a proof, just a superficial check that
        # there at least APPEAR to be elements in self that do not
        # appear in the subset (but we can be fooled by variables).
        # Those candidates will then be checked more carefully later
        # using the reduced forms of the sets.
        non_subset_elem_candidates = set()
        non_subset_elem_remaining = set()
        non_subset_elem_proven = None
        non_subset_elem_index = None
        non_subset_elem_kt = None
        for elem in set(self_list):
            if elem not in set(subset_list):
                non_subset_elem_candidates.add(elem)
                non_subset_elem_remaining.add(elem)
        # if no candidate elements, raise an error
        if len(non_subset_elem_candidates) == 0:
            raise ValueError(
                "Specified subset {0} does not appear to be a proper "
                "subset of the original set {1}. All of the superset "
                "elements appear in the specified subset.".format(
                    subset, self))
        # but if we have candidates, see if at least one can be proven
        # to not be in the subset
        else:
            from proveit.logic import Equals, NotEquals, NotInSet
            for elem in non_subset_elem_candidates:
                for subset_elem in set(subset_list):
                    if Equals(elem,
                              subset_elem).proven(assumptions=assumptions):
                        non_subset_elem_remaining.discard(elem)
                        break
            # that might have reduced the set of remaining candidates
            # so now check if there are any remaining. If not, raise
            # an error; if so, try proving one of the remaining
            # candidates really is not in the subset
            if len(non_subset_elem_remaining) == 0:
                raise ValueError("In calling Set.deduceEnumProperSubset(), "
                                 "the self superset {0} does not appear to "
                                 "have any elements outside of the requested "
                                 "subset {1}.".format(self, subset))
            else:
                for elem in non_subset_elem_remaining:
                    try:
                        non_subset_elem_kt = NotInSet(
                            elem, subset).prove(assumptions=assumptions)
                        non_subset_elem_proven = elem
                        break
                    except:
                        pass

            if non_subset_elem_proven is None:
                raise ValueError(
                    "Failed to prove that the supposed Self superset {0} "
                    "has any elements not already contained in the "
                    "supposed proper subset {1}. Notice that this might "
                    "be because the sets have unassigned variables".format(
                        self, subset))

        # Derive the reduced form of the self superset Set. We could
        # have done this earlier, but delayed until after param
        # checking. The eventual (proper) subset relationship will be
        # based on the reduced forms of the specified Sets.
        self_to_support_kt = self.reduction(assumptions=assumptions)
        self_reduced = self_to_support_kt.rhs
        self_reduced_list = list(self_reduced.operands)
        # while we're here, get the index of the non_subset_elem_proven
        non_subset_elem_index = self_reduced_list.index(non_subset_elem_proven)

        # For convenience, convert the subset_list to indices
        # of the self_reduced_list. Because of earlier checks, the
        # subset_list should contain only items in
        # self_reduced_list but not all the items in self_reduced_list.
        subset_indices_list = ([
            self_reduced_list.index(elem) for elem in subset_list
        ])

        full_indices_list = list(range(0, len(self_reduced_list)))

        # construct the complement of the subset_indices_list,
        # to use in the eventual construction of the necessary
        # permutation of the self superset Set.
        remaining_indices = list(full_indices_list)  # clone
        for elem in subset_indices_list:
            remaining_indices.remove(elem)
        # then also remove the index for the non_subset_elem_proven
        remaining_indices.remove(non_subset_elem_index)

        # establish the desired order for eventual thm application
        new_order = (subset_indices_list + [non_subset_elem_index] +
                     remaining_indices)
        # find superset permutation needed for thm application
        supersetPermRelation = generic_permutation(self_reduced,
                                                   new_order,
                                                   assumptions=assumptions)
        # construct the desired list of subset elems
        desired_subset_list = subset_list
        # construct the desired complement list of elems
        desired_complement_list = [non_subset_elem_proven]
        for elem in remaining_indices:
            desired_complement_list.append(self_reduced_list[elem])

        # Organize info for theorem specialization
        # then specialize.
        from ._theorems_ import properSubsetOfSuperset
        from proveit.number import num
        m, n, a, b, c = properSubsetOfSuperset.allInstanceVars()
        a_sub = desired_subset_list
        b_sub = desired_complement_list[0]
        c_sub = desired_complement_list[1:]
        m_sub, n_sub = num(len(a_sub)), num(len(c_sub))
        subset_of_permuted_superset = properSubsetOfSuperset.specialize(
            {
                m: m_sub,
                n: n_sub,
                a: a_sub,
                b: b_sub,
                c: c_sub
            },
            assumptions=assumptions)

        # We now have
        # |- subset_subbed_reduced \propersubset superset_reduced.
        # We back-sub to get the original subset as a proper subset of
        # the original superset (self):
        # (1) Replace permuted reduced superset with unpermuted reduced
        #     superset:
        reduced_subset_of_reduced_superset = (
            supersetPermRelation.subLeftSideInto(subset_of_permuted_superset,
                                                 assumptions=assumptions))
        # (2) Replace reduced superset with original superset:
        reduced_subset_of_orig_superset = (self_to_support_kt.subLeftSideInto(
            reduced_subset_of_reduced_superset, assumptions=assumptions))
        # (3) Replace the substituted, reduced subset with the original
        #     subset (might be trivial if subsitution and reduction
        #     were essentially identities):
        orig_subset_of_orig_superset = (
            subset_to_subset_subbed_reduced_kt.subLeftSideInto(
                reduced_subset_of_orig_superset, assumptions=assumptions))

        return orig_subset_of_orig_superset