<commit_before>from sympy.core.facts import FactRules, FactKB
from sympy.core.core import BasicMeta

# This are the rules under which our assumptions function
#
# References
# ----------
#
# negative,     -- http://en.wikipedia.org/wiki/Negative_number
# nonnegative
#
# even, odd     -- http://en.wikipedia.org/wiki/Parity_(mathematics)
# imaginary     -- http://en.wikipedia.org/wiki/Imaginary_number
# composite     -- http://en.wikipedia.org/wiki/Composite_number
# finite        -- http://en.wikipedia.org/wiki/Finite
# infinitesimal -- http://en.wikipedia.org/wiki/Infinitesimal
# irrational    -- http://en.wikipedia.org/wiki/Irrational_number
# ...

_assume_rules = FactRules([

    'integer        ->  rational',
    'rational       ->  real',
    'real           ->  complex',
    'imaginary      ->  complex',
    'complex        ->  commutative',

    'odd            ==  integer & !even',
    'even           ==  integer & !odd',

    'real           ==  negative | zero | positive',

    'positive       ->  real & !negative & !zero',
    'negative       ->  real & !positive & !zero',

    'nonpositive    ==  real & !positive',
    'nonnegative    ==  real & !negative',

    'zero           ->  infinitesimal & even',

    'prime          ->  integer & positive',
    'composite      ==  integer & positive & !prime',

    'irrational     ==  real & !rational',

    'imaginary      ->  !real',


    '!bounded     ==  unbounded',
    'noninteger     ==  real & !integer',
    '!zero        ==  nonzero',

    # XXX do we need this ?
    'finite     ->  bounded',       # XXX do we need this?
    'finite     ->  !zero',         # XXX wrong?
    'infinitesimal ->  !finite',    # XXX is this ok?
])

_assume_defined = _assume_rules.defined_facts.copy()
_assume_defined.add('polar')
_assume_defined = frozenset(_assume_defined)

class StdFactKB(FactKB):
    """A FactKB specialised for the built-in rules

    This is the only kind of FactKB that Basic objects should use.
    """
    rules = _assume_rules

    def __init__(self, facts=None):
        if facts:
            self.deduce_all_facts(facts)

    def copy(self):
        return self.__class__(self)


class CycleDetected(Exception):
    """(internal) used to detect cycles when evaluating assumptions
       through prerequisites
    """
    pass

def as_property(fact):
    """Convert a fact name to the name of the corresponding property"""
    return 'is_%s' % fact

class WithAssumptions(BasicMeta):
    """Metaclass for classes with old-style assumptions"""
    __metaclass__ = BasicMeta

    def __new__(mcl, name, bases, attrdict):
        if not any(issubclass(base, AssumeMixin) for base in bases):
            bases = (AssumeMixin,) + bases
            if '__slots__' in attrdict:
                attrdict['__slots__'] += AssumeMixin._assume_slots
        return super(WithAssumptions, mcl).__new__(mcl, name, bases, attrdict)

    def __init__(cls, *args, **kws):
        BasicMeta.__init__(cls, *args, **kws)

        cls_premises = {}
        for k in _assume_defined:
            attrname = as_property(k)
            v = cls.__dict__.get(attrname, '')
            if isinstance(v, (bool, int, long, type(None))):
                if v is not None:
                    v = bool(v)
                cls_premises[k] = v

        cls._default_premises = {}
        for base in reversed(cls.__bases__):
            try:
                cls._default_premises.update(base._default_premises)
            except AttributeError:
                pass
        cls._default_premises.update(cls_premises)

        # deduce all consequences from default assumptions -- make it complete
        default_assumptions = StdFactKB(cls._default_premises)

        # and store completed set into cls -- this way we'll avoid rededucing
        # extensions of class default assumptions each time on instance
        # creation -- we keep it prededuced already.
        for k, v in default_assumptions.iteritems():
            setattr(cls, as_property(k), v)
        cls.default_assumptions = default_assumptions

        # protection e.g. for Initeger.is_even=F <- (Rational.is_integer=F)
        base_derived_premises = set()
        for base in cls.__bases__:
            try:
                base_derived_premises |= (set(base.default_assumptions) -
                                                set(base._default_premises))
            except AttributeError:
                continue        #not an assumption-aware class

        for fact in base_derived_premises:
            if as_property(fact) not in cls.__dict__:
                cls.add_property(fact)

        for fact in _assume_defined:
            if not hasattr(cls, as_property(fact)):
                cls.add_property(fact)

    def add_property(cls, fact):
        """Add to the class the automagic property corresponding to a fact."""

        def getit(self):
            try:
                return self._assumptions[fact]
            except KeyError:
                if self._assumptions is self.default_assumptions:
                    self._assumptions = self.default_assumptions.copy()
                return self._what_known_about(fact)

        getit.func_name = '%s__is_%s' % (cls.__name__, fact)
        setattr(cls, as_property(fact), property(getit))


class AssumeMixin(object):
    """ Define default assumption methods.

    AssumeMeths should be used to derive Basic class only.

    All symbolic objects have assumption attributes that can be accessed via
    .is_<assumption name> attribute.

    Assumptions determine certain properties of symbolic objects. Assumptions
    can have 3 possible values: True, False, None.  None is returned when it is
    impossible to say something about the property. For example, a Symbol is
    not know beforehand to be positive.<commit_msg>Create class PropertyManager to handle class-level assumptions.<commit_after>from sympy.core.facts import FactRules, FactKB
from sympy.core.core import BasicMeta

# This are the rules under which our assumptions function
#
# References
# ----------
#
# negative,     -- http://en.wikipedia.org/wiki/Negative_number
# nonnegative
#
# even, odd     -- http://en.wikipedia.org/wiki/Parity_(mathematics)
# imaginary     -- http://en.wikipedia.org/wiki/Imaginary_number
# composite     -- http://en.wikipedia.org/wiki/Composite_number
# finite        -- http://en.wikipedia.org/wiki/Finite
# infinitesimal -- http://en.wikipedia.org/wiki/Infinitesimal
# irrational    -- http://en.wikipedia.org/wiki/Irrational_number
# ...

_assume_rules = FactRules([

    'integer        ->  rational',
    'rational       ->  real',
    'real           ->  complex',
    'imaginary      ->  complex',
    'complex        ->  commutative',

    'odd            ==  integer & !even',
    'even           ==  integer & !odd',

    'real           ==  negative | zero | positive',

    'positive       ->  real & !negative & !zero',
    'negative       ->  real & !positive & !zero',

    'nonpositive    ==  real & !positive',
    'nonnegative    ==  real & !negative',

    'zero           ->  infinitesimal & even',

    'prime          ->  integer & positive',
    'composite      ==  integer & positive & !prime',

    'irrational     ==  real & !rational',

    'imaginary      ->  !real',


    '!bounded     ==  unbounded',
    'noninteger     ==  real & !integer',
    '!zero        ==  nonzero',

    # XXX do we need this ?
    'finite     ->  bounded',       # XXX do we need this?
    'finite     ->  !zero',         # XXX wrong?
    'infinitesimal ->  !finite',    # XXX is this ok?
])

_assume_defined = _assume_rules.defined_facts.copy()
_assume_defined.add('polar')
_assume_defined = frozenset(_assume_defined)

class StdFactKB(FactKB):
    """A FactKB specialised for the built-in rules

    This is the only kind of FactKB that Basic objects should use.
    """
    rules = _assume_rules

    def __init__(self, facts=None):
        if facts:
            self.deduce_all_facts(facts)

    def copy(self):
        return self.__class__(self)

class CycleDetected(Exception):
    """(internal) used to detect cycles when evaluating assumptions
       through prerequisites
    """
    pass

def as_property(fact):
    """Convert a fact name to the name of the corresponding property"""
    return 'is_%s' % fact

class PropertyManager(StdFactKB):
    """This object is responsible for ensuring the consistency of class
    properties obeying a set of logic rules."""
    def __init__(self, cls):
        local_defs = {}
        for k in _assume_defined:
            attrname = as_property(k)
            v = cls.__dict__.get(attrname, '')
            if isinstance(v, (bool, int, long, type(None))):
                if v is not None:
                    v = bool(v)
                local_defs[k] = v

        defs = {}
        for base in reversed(cls.__bases__):
            try:
                defs.update(base.default_assumptions.definitions)
            except AttributeError:
                pass
        defs.update(local_defs)

        self.definitions = defs
        self.deduce_all_facts(defs)

    def copy(self):
        return StdFactKB(self)


class WithAssumptions(BasicMeta):
    """Metaclass for classes with old-style assumptions"""
    __metaclass__ = BasicMeta

    def __new__(mcl, name, bases, attrdict):
        if not any(issubclass(base, AssumeMixin) for base in bases):
            bases = (AssumeMixin,) + bases
            if '__slots__' in attrdict:
                attrdict['__slots__'] += AssumeMixin._assume_slots
        return super(WithAssumptions, mcl).__new__(mcl, name, bases, attrdict)

    def __init__(cls, *args, **kws):
        BasicMeta.__init__(cls, *args, **kws)

        default_assumptions = PropertyManager(cls)
        cls.default_assumptions = default_assumptions

        # Put definite results directly into the class dict, for speed
        for k, v in default_assumptions.iteritems():
            setattr(cls, as_property(k), v)

        # protection e.g. for Integer.is_even=F <- (Rational.is_integer=F)
        derived_from_bases = set()
        for base in cls.__bases__:
            try:
                derived_from_bases |= set(base.default_assumptions)
            except AttributeError:
                continue        #not an assumption-aware class
        for fact in derived_from_bases - set(default_assumptions):
            if as_property(fact) not in cls.__dict__:
                cls.add_property(fact)

        # Finally, add any missing automagic property (e.g. for Basic)
        for fact in _assume_defined:
            if not hasattr(cls, as_property(fact)):
                cls.add_property(fact)

    def add_property(cls, fact):
        """Add to the class the automagic property corresponding to a fact."""

        def getit(self):
            try:
                return self._assumptions[fact]
            except KeyError:
                if self._assumptions is self.default_assumptions:
                    self._assumptions = self.default_assumptions.copy()
                return self._what_known_about(fact)

        getit.func_name = '%s__is_%s' % (cls.__name__, fact)
        setattr(cls, as_property(fact), property(getit))


class AssumeMixin(object):
    """ Define default assumption methods.

    AssumeMeths should be used to derive Basic class only.

    All symbolic objects have assumption attributes that can be accessed via
    .is_<assumption name> attribute.

    Assumptions determine certain properties of symbolic objects. Assumptions
    can have 3 possible values: True, False, None.  None is returned when it is
    impossible to say something about the property. For example, a Symbol is
    not know beforehand to be positive.
{'fraction_non_alphanumeric': 0.10164018016486785, 'fraction_numerical': 0.0001699668564629897, 'mean_word_length': 2.2267617219632574, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2101566', 'n_tokens_mistral': 3500, 'n_tokens_neox': 3310, 'n_words': 928}