Esempio n. 1
0
    def _union_if_not_exclusive(
        self, other: Holding, context: ContextRegister
    ) -> Optional[Holding]:
        if self.decided is other.decided is False:
            if self.rule.implies(other.rule, context=context):
                return other
            if other.rule.implies(self.rule, context=context.reversed()):
                return self
            return None

        if not self.decided or not other.decided:
            return None
        if self.rule_valid != other.rule_valid:
            return None

        if self.rule_valid is False:
            # If a Rule with input A present is not valid
            # and a Rule with input A absent is also not valid
            # then a version of the Rule with input A
            # omitted is also not valid.
            raise NotImplementedError(
                "The union operation is not yet implemented for Holdings "
                "that assert a Rule is not valid."
            )

        new_rule = self.rule.union(other.rule, context=context)
        if not new_rule:
            return None
        return self.evolve({"rule": new_rule, "exclusive": False})
Esempio n. 2
0
    def implies(
        self, other: Optional[Comparable], context: ContextRegister = None
    ) -> bool:
        r"""
        Test for implication.

        See :meth:`.Procedure.implies_all_to_all`
        and :meth:`.Procedure.implies_all_to_some` for
        explanations of how ``inputs``, ``outputs``,
        and ``despite`` :class:`.Factor`\s affect implication.

        :param other:
            A :class:`Holding` to compare to self, or a :class:`.Rule` to
            convert into such a :class:`Holding` and then compare

        :returns:
            whether ``self`` implies ``other``
        """
        if other is None:
            return True
        if isinstance(other, (Rule, Procedure)):
            other = Holding(rule=other)
        if not isinstance(other, self.__class__):
            if hasattr(other, "implied_by"):
                if context:
                    context = context.reversed()
                return other.implied_by(self, context=context)
            return False
        return any(
            explanation is not None
            for explanation in self.explanations_implication(other, context)
        )
Esempio n. 3
0
 def _likely_context_from_implication(
         self, other: Comparable,
         context: ContextRegister) -> Optional[ContextRegister]:
     new_context = None
     if self.implies(other, context=context) or other.implies(
             self, context=context.reversed()):
         new_context = self._update_context_from_factors(other, context)
     if new_context and new_context != context:
         return new_context
     return None
Esempio n. 4
0
    def explanations_contradiction(
        self, other: Factor, context: ContextRegister = None
    ) -> Iterator[Explanation]:
        r"""
        Find context matches that would result in a contradiction with other.

        Works by testing whether ``self`` would imply ``other`` if
        ``other`` had an opposite value for ``rule_valid``.

        This method takes three main paths depending on
        whether the holdings ``self`` and ``other`` assert that
        rules are decided or undecided.

        A ``decided`` :class:`Rule` can never contradict
        a previous statement that any :class:`Rule` was undecided.

        If rule A implies rule B, then a holding that B is undecided
        contradicts a prior :class:`Rule` deciding that
        rule A is valid or invalid.

        :param other:
            The :class:`.Factor` to be compared to self. Unlike with
            :meth:`~Holding.contradicts`\, this method cannot be called
            with an :class:`.Opinion` for `other`.

        :returns:
            a generator yielding :class:`.ContextRegister`\s that cause a
            contradiction.
        """

        if context is None:
            context = ContextRegister()
        if isinstance(other, Procedure):
            other = Rule(procedure=other)
        if isinstance(other, Rule):
            other = Holding(rule=other)
        if isinstance(other, self.__class__):
            yield from self._explanations_contradiction_of_holding(other, context)
        elif isinstance(other, Factor):
            yield from []  # no possible contradiction
        elif hasattr(other, "explanations_contradiction"):
            if context:
                context = context.reversed()
            yield from other.explanations_contradiction(self, context=context)
        else:
            raise TypeError(
                f"'Contradicts' test not implemented for types "
                f"{self.__class__} and {other.__class__}."
            )
Esempio n. 5
0
 def union_from_explanation_allow_contradiction(
         self, other: ComparableGroup,
         context: ContextRegister) -> ComparableGroup:
     result = self + other.new_context(context.reversed())
     result = result.drop_implied_factors()
     return result
Esempio n. 6
0
 def _trigger_addition(self, other: Procedure, context: ContextRegister):
     """Add two Procedures, given that they have already been found to be addable."""
     triggered_procedure = other.new_context(context.reversed())
     new_outputs = [*self.outputs, *triggered_procedure.outputs]
     unique_new_outputs = tuple({key: None for key in new_outputs})
     return self.evolve({"outputs": unique_new_outputs})