Ticket #3738: 3738-12-explain-div.patch

File 3738-12-explain-div.patch, 9.6 KB (added by robertwb, 11 years ago)
  • sage/categories/action.pyx

    # HG changeset patch
    # User Robert Bradshaw <robertwb@math.washington.edu>
    # Date 1217396919 25200
    # Node ID 91f7fe5627603bd4107657a6a7f7fc80cefc1f24
    # Parent  b8e2bb71c71cd7b9ebaf01a27a661f718669ee2f
    Handle analysis of division correctly.
    
    diff -r b8e2bb71c71c -r 91f7fe562760 sage/categories/action.pyx
    a b cdef class Action(Functor): 
    9696        return self.S
    9797       
    9898    def domain(self):
    99         return self.codomain()
     99        return self.S
    100100       
    101101    def left_domain(self):
    102102        if self._is_left:
    cdef class InverseAction(Action): 
    142142                self._action = action
    143143                return
    144144            else:
    145                 K = G.fraction_field()
     145                K = G._pseudo_fraction_field()
    146146                Action.__init__(self, K, action.S, action._is_left)
    147147                self._action = action
    148148                return
    cdef class InverseAction(Action): 
    160160                a = self.S_precomposition(a)
    161161            return self._action._call_(a, ~b)
    162162           
     163    def codomain(self):
     164        return self._action.codomain()
     165
    163166    def __invert__(self):
    164167        return self._action
    165168
    cdef class PrecomposedAction(Action): 
    200203        elif not self._is_left and self.left_precomposition is not None:
    201204            return self.left_precomposition.domain()
    202205        else:
    203             return self.codomain()
     206            return self._action.domain()
     207           
     208    def codomain(self):
     209        return self._action.codomain()
    204210   
    205211    def __invert__(self):
    206212        return PrecomposedAction(~self._action, self.left_precomposition, self.right_precomposition)
  • sage/structure/coerce.pxd

    diff -r b8e2bb71c71c -r 91f7fe562760 sage/structure/coerce.pxd
    a b cdef class CoercionModel_cache_maps(Coer 
    2525
    2626    cdef readonly _exception_stack
    2727    cdef bint _exceptions_cleared
    28    
    29  No newline at end of file
     28   
     29    cdef TripleDict _division_parents
     30    cpdef analyse(self, xp, yp, op=*)
     31    cpdef Parent division_parent(self, Parent parent)
  • sage/structure/coerce.pyx

    diff -r b8e2bb71c71c -r 91f7fe562760 sage/structure/coerce.pyx
    a b cdef class CoercionModel_cache_maps(Coer 
    191191        self._coercion_maps = TripleDict(lookup_dict_size, threshold=lookup_dict_threshold)
    192192        # This MUST be a mapping to actions.
    193193        self._action_maps = TripleDict(lookup_dict_size, threshold=lookup_dict_threshold)
     194        # This is a mapping from Parents to Parents, storing the result of division in the given parent.
     195        self._division_parents = TripleDict(lookup_dict_size, threshold=lookup_dict_threshold)
    194196
    195197    def get_cache(self):
    196198        """
    cdef class CoercionModel_cache_maps(Coer 
    393395            sage: parent(QQ(1) + float(1))
    394396            <type 'float'>
    395397           
    396         NOTE: This function is accurate only in so far as analyze is kept in
     398
     399        Special care is taken to deal with division:
     400       
     401            sage: cm.explain(ZZ, ZZ, operator.div)
     402            Identical parents, arithmetic performed immediately.
     403            Result lives in Rational Field
     404            Rational Field
     405
     406            sage: cm.explain(ZZ['x'], QQ['x'], operator.div)
     407            Coercion on left operand via
     408                Call morphism:
     409                  From: Univariate Polynomial Ring in x over Integer Ring
     410                  To:   Univariate Polynomial Ring in x over Rational Field
     411            Arithmetic performed after coercions.
     412            Result lives in Fraction Field of Univariate Polynomial Ring in x over Rational Field
     413            Fraction Field of Univariate Polynomial Ring in x over Rational Field
     414
     415            sage: cm.explain(int, ZZ, operator.div)
     416            Coercion on left operand via
     417                Native morphism:
     418                  From: Set of Python objects of type 'int'
     419                  To:   Integer Ring
     420            Arithmetic performed after coercions.
     421            Result lives in Rational Field
     422            Rational Field
     423
     424            sage: cm.explain(ZZ['x'], ZZ, operator.div)
     425            Action discovered.
     426                Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring
     427                with precomposition on right by Natural morphism:
     428                  From: Integer Ring
     429                  To:   Rational Field
     430            Result lives in Univariate Polynomial Ring in x over Rational Field
     431            Univariate Polynomial Ring in x over Rational Field
     432
     433        NOTE: This function is accurate only in so far as analyse is kept in
    397434              sync with the \code{bin_op} and \code{canonical_coercion} which
    398435              are kept seperate for maximal efficiency.
    399436        """
    400         all, res = self.analyze(xp, yp, op)
     437        all, res = self.analyse(xp, yp, op)
    401438        indent = " "*4
    402439        if verbosity >= 2:
    403440            print "\n".join([s if isinstance(s, str) else indent+(repr(s).replace("\n", "\n"+indent)) for s in all])
    cdef class CoercionModel_cache_maps(Coer 
    410447                print "Result lives in", res
    411448        return res
    412449
    413     def analyze(self, xp, yp, op=operator.mul):
     450    cpdef analyse(self, xp, yp, op=mul):
    414451        """
    415452        Emulate the process of doing arithmetic between xp and yp, returning
    416453        a list of steps and the parent that the result will live in. The
    cdef class CoercionModel_cache_maps(Coer 
    420457       
    421458        EXAMPLES:
    422459            sage: cm = sage.structure.element.get_coercion_model()
    423             sage: steps, res = cm.analyze(GF(7), ZZ)
     460            sage: steps, res = cm.analyse(GF(7), ZZ)
    424461            sage: print steps
    425462            ['Coercion on right operand via', Natural morphism:
    426463              From: Integer Ring
    cdef class CoercionModel_cache_maps(Coer 
    431468            <type 'sage.rings.integer_mod.Integer_to_IntegerMod'>
    432469            sage: f(100)
    433470            2
    434         """
     471            """
    435472        self._exceptions_cleared = False
    436473        if not PY_TYPE_CHECK(xp, type) and not PY_TYPE_CHECK(xp, Parent):
    437474            xp = parent_c(xp)
    cdef class CoercionModel_cache_maps(Coer 
    441478        all = []
    442479        if xp is yp:
    443480            all.append("Identical parents, arithmetic performed immediately." % xp)
     481            if op is div and PY_TYPE_CHECK(xp, Parent):
     482                xp = self.division_parent(xp)
    444483            return all, xp
    445484        if xp == yp:
    446485            all.append("Equal but distinct parents.")
    cdef class CoercionModel_cache_maps(Coer 
    466505                    raise RuntimeError, ("BUG in coercion model: codomains not equal!", x_mor, y_mor)
    467506                res = y_mor.codomain()
    468507            all.append("Arithmetic performed after coercions.")
     508            if op is div and PY_TYPE_CHECK(res, Parent):
     509                res = self.division_parent(res)
    469510            return all, res
    470511               
    471512        if PY_TYPE_CHECK(yp, Parent) and xp in [int, long, float, complex, bool]:
    cdef class CoercionModel_cache_maps(Coer 
    473514            if mor is not None:
    474515                all.append("Coercion on numeric left operand via")
    475516                all.append(mor)
     517                if op is div and PY_TYPE_CHECK(yp, Parent):
     518                    yp = self.division_parent(yp)
    476519                return all, yp
    477520            all.append("Left operand is numeric, will attempt conversion in both directions.")
    478521        elif type(xp) is type:
    cdef class CoercionModel_cache_maps(Coer 
    483526            if mor is not None:
    484527                all.append("Coercion on numeric right operand via")
    485528                all.append(mor)
     529                if op is div and PY_TYPE_CHECK(xp, Parent):
     530                    xp = self.division_parent(xp)
    486531                return all, xp
    487532            all.append("Right operand is numeric, will attempt conversion in both directions.")
    488533        elif type(yp) is type:
    cdef class CoercionModel_cache_maps(Coer 
    492537            all.append("Will try _r_action and _l_action")
    493538           
    494539        return all, None
     540       
     541    cpdef Parent division_parent(self, Parent parent):
     542        r"""
     543        Deduces where the result of division in parent lies by calculating
     544        the inverse of \code{parent.one_element()} or \code{parent.an_element()}.
     545       
     546        The result is cached.
     547       
     548        EXAMPLES:
     549            sage: cm = sage.structure.element.get_coercion_model()
     550            sage: cm.division_parent(ZZ)
     551            Rational Field
     552            sage: cm.division_parent(QQ)
     553            Rational Field
     554            sage: cm.division_parent(ZZ['x'])
     555            Fraction Field of Univariate Polynomial Ring in x over Integer Ring
     556            sage: cm.division_parent(GF(41))
     557            Finite Field of size 41
     558            sage: cm.division_parent(Integers(100))
     559            Ring of integers modulo 100
     560            sage: cm.division_parent(SymmetricGroup(5))
     561            Symmetric group of order 5! as a permutation group
     562        """
     563        try:
     564            return self._division_parents.get(parent, None, None)
     565        except KeyError:
     566            pass
     567        try:
     568            ret = parent_c(~parent.one_element())
     569        except:
     570            self._record_exception()
     571            ret = parent_c(~parent.an_element())
     572        self._division_parents.set(parent, None, None, ret)
     573        return ret
    495574       
    496575   
    497576    cpdef bin_op(self, x, y, op):