# HG changeset patch
# User Nick Alexander <ncalexander@gmail.com>
# Date 1241589981 25200
# Node ID a602aebd86674ff278129bdda4e1514593b45de9
# Parent  3c76e25881323e281e5b69554bdaef0eb3ccd98a
[mq]: 5598-ncalexan-fixes-and-tests.patch

diff -r 3c76e2588132 -r a602aebd8667 sage/structure/parent.pyx
--- a/sage/structure/parent.pyx	Mon Mar 23 21:57:10 2009 -0700
+++ b/sage/structure/parent.pyx	Tue May 05 23:06:21 2009 -0700
@@ -16,6 +16,7 @@
     sage: gp(2) + gap(3)
     5      
 """
+
 cimport element
 cimport sage.categories.morphism as morphism
 cimport sage.categories.map as map
@@ -709,8 +710,43 @@
             self.register_conversion(mor)
         if embedding is not None:
             self.register_embedding(embedding)
+
+    def unset_coercions_used(self):
+        r"""
+        Pretend that this parent has never been interrogated by the
+        coercion model, so that it is safe to add coercions,
+        conversions, embeddings, and actions.
+
+        WARNING::
+
+            For internal use only!
+        """
+        self._coercions_used = False
+        import sage.structure.element
+        sage.structure.element.get_coercion_model().reset_cache()
             
     cpdef register_coercion(self, mor):
+        r"""
+        EXAMPLES::
+
+            sage: K.<a> = ZZ['a']
+            sage: L.<b> = ZZ['b']
+            sage: L_into_K = L.hom([-a]) # non-trivial automorphism
+            sage: K.unset_coercions_used()
+            sage: K.register_coercion(L_into_K)
+
+            sage: K(0) + b
+            -a
+            sage: a + b
+            0
+            sage: K(b) # check that convert calls coerce first; normally this is just a
+            -a
+
+            sage: L(0) + a in K # this goes through the coercion mechanism of K
+            True
+            sage: L(a) in L # this still goes through the convert mechanism of L
+            True
+        """
         assert not self._coercions_used, "coercions must all be registered up before use"
         if PY_TYPE_CHECK(mor, map.Map):
             if mor.codomain() is not self:
@@ -726,21 +762,91 @@
             raise TypeError, "coercions must be parents or maps (got %s)" % type(mor)
     
     cpdef register_action(self, action):
+        r"""
+        EXAMPLES::
+
+            sage: import sage.categories.action
+            sage: import operator
+
+            sage: class SymmetricGroupAction(sage.categories.action.Action):
+            ...       "Act on a multivariate polynomial ring by permuting the generators."
+            ...       def __init__(self, G, M, is_left=True):
+            ...           sage.categories.action.Action.__init__(self, G, M, is_left, operator.mul)
+            ...   
+            ...       def _call_(self, g, a):
+            ...           if not self.is_left():
+            ...               g, a = a, g
+            ...           D = {}
+            ...           for k, v in a.dict().items():
+            ...               nk = [0]*len(k)
+            ...               for i in range(len(k)):
+            ...                   nk[g(i+1)-1] = k[i]
+            ...               D[tuple(nk)] = v
+            ...           return a.parent()(D)
+
+            sage: R.<x, y, z> = QQ['x, y, z']
+            sage: G = SymmetricGroup(3)
+            sage: act = SymmetricGroupAction(G, R)
+            sage: t = x + 2*y + 3*z
+
+            sage: act(G((1, 2)), t)
+            2*x + y + 3*z
+            sage: act(G((2, 3)), t)
+            x + 3*y + 2*z
+            sage: act(G((1, 2, 3)), t)
+            3*x + y + 2*z
+
+            sage: R.unset_coercions_used()
+            sage: R.register_action(act)
+            sage: G((1, 2)) * t
+            2*x + y + 3*z
+
+            This should fail, since we haven't defined a right action::
+
+            sage: t * G((1, 2, 3))
+            Traceback (most recent call last):
+            ...
+            AttributeError: ...
+
+            Now let's make it work::
+
+            sage: R.unset_coercions_used()
+            sage: R.register_action(SymmetricGroupAction(G, R, is_left=False))
+
+            sage: t * G((1, 2, 3))
+            3*x + y + 2*z
+        """
         assert not self._coercions_used, "coercions must all be registered up before use"
         from sage.categories.action import Action
         if isinstance(action, Action):
             if action.actor() is self:
                 self._action_list.append(action)
-                self._action_list[action.domain(), action.operation(), action.is_left()] = action
+                self._action_hash[action.domain(), action.operation(), action.is_left()] = action
             elif action.domain() is self:
                 self._action_list.append(action)
-                self._action_list[action.actor(), action.operation(), not action.is_left()] = action
+                self._action_hash[action.actor(), action.operation(), not action.is_left()] = action
             else:
                 raise ValueError, "Action must involve self"
         else:
             raise TypeError, "actions must be actions"
             
     cpdef register_conversion(self, mor):
+        r"""
+        EXAMPLES::
+
+            sage: K.<a> = ZZ['a']
+            sage: M.<c> = ZZ['c']
+            sage: M_into_K = M.hom([a]) # trivial automorphism
+            sage: K.unset_coercions_used()
+            sage: K.register_conversion(M_into_K)
+
+            sage: K(c)
+            a
+            sage: K(0) + c
+            Traceback (most recent call last):
+            ...
+            TypeError: ...
+        """
         assert not self._coercions_used, "coercions must all be registered up before use"
         if isinstance(mor, map.Map):
             if mor.codomain() is not self:
@@ -757,6 +863,41 @@
             raise TypeError, "conversions must be parents or maps"
     
     cpdef register_embedding(self, embedding):
+        r"""
+        You're only allowed to assert one embedding per parent.  The
+        random nonsense below makes sure we can run this multiple times
+        easily.
+
+        EXAMPLES::
+
+            sage: x = QQ['x'].0
+            sage: t = abs(ZZ.random_element(10^6))
+            sage: K = NumberField(x^2 + 2*3*7*11, "a"+str(t))
+            sage: a = K.gen()
+            sage: K_into_MS = K.hom([a.matrix()])
+            sage: K.unset_coercions_used()
+            sage: K.register_embedding(K_into_MS)
+
+            sage: L = NumberField(x^2 + 2*3*7*11*19*31, "b"+str(abs(ZZ.random_element(10^6))))
+            sage: b = L.gen()
+            sage: L_into_MS = L.hom([b.matrix()])
+            sage: L.unset_coercions_used()
+            sage: L.register_embedding(L_into_MS)
+
+            sage: K.coerce_embedding()(a)
+            [   0    1]
+            [-462    0]
+            sage: L.coerce_embedding()(b)
+            [      0       1]
+            [-272118       0]
+
+            sage: a.matrix() * b
+            [-272118       0]
+            [      0    -462]
+            sage: a * b.matrix()
+            [-272118       0]
+            [      0    -462]
+        """
         assert not self._coercions_used, "coercions must all be registered up before use"
         assert self._embedding is None, "only one embedding allowed"
         if isinstance(embedding, map.Map):
