# HG changeset patch
# User Simon King <simon.king@nuigalway.ie>
# Date 1279718741 -3600
# Node ID 1a7c8feb901dd09ff8ee1d2fd34135c3e72665ad
# Parent  b4e473888eb985231e9429a532c937ce0040b073
#8800: Full doc test coverage of sage/categories/functor and sage/categories/pushout; fixing a multitude of bugs related with coercion. Putting it into the reference manual.

diff -r b4e473888eb9 -r 1a7c8feb901d doc/en/reference/categories.rst
--- a/doc/en/reference/categories.rst	Tue Mar 08 15:10:11 2011 +0100
+++ b/doc/en/reference/categories.rst	Wed Jul 21 14:25:41 2010 +0100
@@ -13,6 +13,7 @@
    sage/categories/homset
    sage/categories/morphism
    sage/categories/functor
+   sage/categories/pushout
 
 Functorial constructions
 ========================
diff -r b4e473888eb9 -r 1a7c8feb901d doc/en/reference/coercion.rst
--- a/doc/en/reference/coercion.rst	Tue Mar 08 15:10:11 2011 +0100
+++ b/doc/en/reference/coercion.rst	Wed Jul 21 14:25:41 2010 +0100
@@ -586,14 +586,14 @@
     sage: CC.construction()
     (AlgebraicClosureFunctor, Real Field with 53 bits of precision)
     sage: RR.construction()
-    (CompletionFunctor, Rational Field)
+    (Completion[+Infinity], Rational Field)
     sage: QQ.construction()
     (FractionField, Integer Ring)
     sage: ZZ.construction()  # None
    
     sage: Qp(5).construction()
-    (CompletionFunctor, Rational Field)
-    sage: QQ.completion(5, 100)
+    (Completion[5], Rational Field)
+    sage: QQ.completion(5, 100, {})
     5-adic Field with capped relative precision 100
     sage: c, R = RR.construction()
     sage: a = CC.construction()[0]
@@ -608,7 +608,7 @@
     (FractionField, Univariate Polynomial Ring in x over Complex Double Field),
     (Poly[x], Complex Double Field),
     (AlgebraicClosureFunctor, Real Double Field),
-    (CompletionFunctor, Rational Field),
+    (Completion[+Infinity], Rational Field),
     (FractionField, Integer Ring)]
 
 Given Parents R and S, such that there is no coercion either from R to
diff -r b4e473888eb9 -r 1a7c8feb901d sage/categories/functor.pyx
--- a/sage/categories/functor.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/categories/functor.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -9,7 +9,8 @@
 
 - Robert Bradshaw (2007-06-23): Pyrexify
 
-- Simon King (2010-04-30): more examples, several bug fixes, re-implementation of the default call method,
+- Simon King (2010-04-30): more examples, several bug fixes,
+  re-implementation of the default call method,
   making functors applicable to morphisms (not only to objects)
 
 """
@@ -44,16 +45,18 @@
       Instead, one should implement three methods, which are composed in the
       default call method:
 
-      - ``_coerce_into_domain(self, x)``: Return an object of ``self``'s domain,
-        corresponding to ``x``, or raise a ``TypeError``.
+      - ``_coerce_into_domain(self, x)``: Return an object of ``self``'s
+        domain, corresponding to ``x``, or raise a ``TypeError``.
 
         - Default: Raise ``TypeError`` if ``x`` is not in ``self``'s domain.
         
-      - ``_apply_functor(self, x)``: Apply ``self`` to an object ``x`` of ``self``'s domain.
+      - ``_apply_functor(self, x)``: Apply ``self`` to an object ``x`` of
+        ``self``'s domain.
 
         - Default: Conversion into ``self``'s codomain.
 
-      - ``_apply_functor_to_morphism(self, f)``: Apply ``self`` to a morphism ``f`` in ``self``'s domain.
+      - ``_apply_functor_to_morphism(self, f)``: Apply ``self`` to a morphism
+        ``f`` in ``self``'s domain.
         - Default: Return ``self(f.domain()).hom(f,self(f.codomain()))``.
 
     EXAMPLES::
@@ -76,9 +79,9 @@
         sage: is_Functor(I)
         True
 
-    Note that by default, an instance of the class Functor is coercion from the
-    domain into the codomain. The above subclasses overloaded this behaviour. Here
-    we illustrate the default::
+    Note that by default, an instance of the class Functor is coercion
+    from the domain into the codomain. The above subclasses overloaded
+    this behaviour. Here we illustrate the default::
 
         sage: from sage.categories.functor import Functor
         sage: F = Functor(Rings(),Fields())
@@ -89,9 +92,9 @@
         sage: F(GF(2))
         Finite Field of size 2
 
-    Functors are not only about the objects of a category, but also about their
-    morphisms. We illustrate it, again, with the coercion functor from rings
-    to fields.
+    Functors are not only about the objects of a category, but also about
+    their morphisms. We illustrate it, again, with the coercion functor
+    from rings to fields.
 
     ::
 
@@ -108,6 +111,27 @@
           From: Fraction Field of Univariate Polynomial Ring in x over Integer Ring
           To:   Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
           Defn: x |--> a + b
+        sage: F(f)(1/x)
+        1/(a + b)
+
+    We can also apply a polynomial ring construction functor to our homomorphism. The
+    result is a homomorphism that is defined on the base ring::
+
+        sage: F = QQ['t'].construction()[0]
+        sage: F
+        Poly[t]
+        sage: F(f)
+        Ring morphism:
+          From: Univariate Polynomial Ring in t over Univariate Polynomial Ring in x over Integer Ring
+          To:   Univariate Polynomial Ring in t over Multivariate Polynomial Ring in a, b over Rational Field
+          Defn: Induced from base ring by
+                Ring morphism:
+                  From: Univariate Polynomial Ring in x over Integer Ring
+                  To:   Multivariate Polynomial Ring in a, b over Rational Field
+                  Defn: x |--> a + b
+        sage: p = R1['t']('(-x^2 + x)*t^2 + (x^2 - x)*t - 4*x^2 - x + 1')
+        sage: F(f)(p)
+        (-a^2 - 2*a*b - b^2 + a + b)*t^2 + (a^2 + 2*a*b + b^2 - a - b)*t - 4*a^2 - 8*a*b - 4*b^2 - a - b + 1
 
     """
     def __init__(self, domain, codomain):
@@ -133,7 +157,7 @@
         
     def _apply_functor(self, x):
         """
-        Apply the functor to an object of ``self``'s domain
+        Apply the functor to an object of ``self``'s domain.
 
         NOTE:
 
@@ -153,13 +177,13 @@
 
     def _apply_functor_to_morphism(self, f):
         """
-        Apply the functor to a morphism between two objects of ``self``'s domain
+        Apply the functor to a morphism between two objects of ``self``'s domain.
 
         NOTE:
 
-        Each subclass of :class:`Functor` should overload this method. By default,
-        this method coerces into the codomain, without checking whether the
-        argument belongs to the domain.
+        Each subclass of :class:`Functor` should overload this method. By
+        default, this method coerces into the codomain, without checking
+        whether the argument belongs to the domain.
 
         TESTS::
 
@@ -169,7 +193,8 @@
             sage: f = k.hom([-a-4])
             sage: R.<t> = k[]
             sage: fR = R.hom(f,R)
-            sage: fF = F(fR); fF
+            sage: fF = F(fR)         # indirect doctest
+            sage: fF
             Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Finite Field in a of size 5^2
               Defn: Induced from base ring by
                     Ring endomorphism of Univariate Polynomial Ring in t over Finite Field in a of size 5^2
@@ -187,15 +212,16 @@
 
     def _coerce_into_domain(self, x):
         """
-        Interprete the argument as an object of self's domain
+        Interprete the argument as an object of self's domain.
 
         NOTE:
 
-        Each subclass of :class:`Functor` should overload this method. It should return
-        an object of self's domain, and should raise a ``TypeError`` if this is impossible.
+        A subclass of :class:`Functor` may overload this method. It should
+        return an object of self's domain, and should raise a ``TypeError``
+        if this is impossible.
 
-        By default, the argument will not be changed, but a ``TypeError`` will be raised if
-        the argument does not belong to the domain.
+        By default, the argument will not be changed, but a ``TypeError``
+        will be raised if the argument does not belong to the domain.
 
         TEST::
 
@@ -208,7 +234,6 @@
             ...
             TypeError: x (=Integer Ring) is not in Category of fields
 
-        
         """
         if not (x in  self.__domain):
             raise TypeError, "x (=%s) is not in %s"%(x, self.__domain)
@@ -229,7 +254,8 @@
         """
         NOTE:
 
-        Implement _coerce_into_domain and _apply_functor when subclassing Functor.
+        Implement _coerce_into_domain, _apply_functor and 
+        _apply_functor_to_morphism when subclassing Functor.
         
         TESTS:
  
@@ -397,28 +423,32 @@
         """
         NOTE:
 
-        It is tested whether the second argument belongs to the class of forgetful functors
-        and has the same domain and codomain as self. If the second argument is a functor
-        of a different class but happens to be a forgetful functor, both arguments will
+        It is tested whether the second argument belongs to the class
+        of forgetful functors and has the same domain and codomain as
+        self. If the second argument is a functor of a different class
+        but happens to be a forgetful functor, both arguments will
         still be considered as being *different*.
 
         TEST::
 
             sage: F1 = ForgetfulFunctor(FiniteFields(),Fields())
 
-        This is to test against a bug occuring in a previous version (see ticket 8800)::
+        This is to test against a bug occuring in a previous version
+        (see ticket 8800)::
 
             sage: F1 == QQ #indirect doctest
             False
 
-        We now compare with the fraction field functor, that has a different domain:
+        We now compare with the fraction field functor, that has a
+        different domain::
         
             sage: F2 = QQ.construction()[0]
             sage: F1 == F2 #indirect doctest
             False
 
         """
-        if not isinstance(other, self.__class__):
+        from sage.categories.pushout import IdentityConstructionFunctor
+        if not isinstance(other, (self.__class__,IdentityConstructionFunctor)):
             return -1
         if self.domain() == other.domain() and \
            self.codomain() == other.codomain():
@@ -445,6 +475,16 @@
         ...
         TypeError: x (=Integer Ring) is not in Category of fields
 
+    TESTS::
+
+        sage: R = IdentityFunctor(Rings())
+        sage: P, _ = QQ['t'].construction()
+        sage: R == P
+        False
+        sage: P == R
+        False
+        sage: R == QQ
+        False
     """
     def __init__(self, C):
         """
@@ -485,6 +525,8 @@
     
     def _apply_functor(self, x):
         """
+        Apply the functor to an object of ``self``'s domain.
+        
         TESTS::
 
             sage: fields = Fields()
@@ -533,8 +575,8 @@
 
     OUTPUT:
 
-    A functor that returns the corresponding object of ``D`` for any element of ``C``,
-    by forgetting the extra structure.
+    A functor that returns the corresponding object of ``D`` for
+    any element of ``C``, by forgetting the extra structure.
 
     ASSUMPTION:
 
@@ -567,5 +609,4 @@
     if not domain.is_subcategory(codomain):
         raise ValueError, "Forgetful functor not supported for domain %s"%domain
     return ForgetfulFunctor_generic(domain, codomain)
-    
 
diff -r b4e473888eb9 -r 1a7c8feb901d sage/categories/pushout.py
--- a/sage/categories/pushout.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/categories/pushout.py	Wed Jul 21 14:25:41 2010 +0100
@@ -1,4 +1,7 @@
-from functor import Functor
+"""
+Coercion via Construction Functors.
+"""
+from functor import Functor, IdentityFunctor_generic
 from basic import *
 
 from sage.structure.parent import CoercionException
@@ -6,13 +9,141 @@
 # TODO, think through the rankings, and override pushout where necessary. 
 
 class ConstructionFunctor(Functor):
-
+    """
+    Base class for construction functors.
+
+    A construction functor is a functorial algebraic construction,
+    such as the construction of a matrix ring over a given ring
+    or the fraction field of a given ring.
+
+    In addition to the class :class:`~sage.categories.functor.Functor`,
+    construction functors provide rules for combining and merging
+    constructions. This is an important part of Sage's coercion model,
+    namely the pushout of two constructions: When a polynomial ``p`` in
+    a variable ``x`` with integer coefficients is added to a rational
+    number ``q``, then Sage finds that the parents ``ZZ['x']`` and
+    ``QQ`` are obtained from ``ZZ`` by applying a polynomial ring
+    construction respectively the fraction field construction. Each
+    construction functor has an attribute ``rank``, and the rank of
+    the polynomial ring construction is higher than the rank of the
+    fraction field construction. This means that the pushout of ``QQ``
+    and ``ZZ['x']``, and thus a common parent in which ``p`` and ``q``
+    can be added, is ``QQ['x']``, since the construction functor with
+    a lower rank is applied first.
+
+    ::
+
+        sage: F1, R = QQ.construction()
+        sage: F1
+        FractionField
+        sage: R
+        Integer Ring
+        sage: F2, R = (ZZ['x']).construction()
+        sage: F2
+        Poly[x]
+        sage: R
+        Integer Ring
+        sage: F3 = F2.pushout(F1)
+        sage: F3
+        Poly[x](FractionField(...))
+        sage: F3(R)
+        Univariate Polynomial Ring in x over Rational Field
+        sage: from sage.categories.pushout import pushout
+        sage: P.<x> = ZZ[]
+        sage: pushout(QQ,P)
+        Univariate Polynomial Ring in x over Rational Field
+        sage: ((x+1) + 1/2).parent()
+        Univariate Polynomial Ring in x over Rational Field
+
+    When composing two construction functors, they are sometimes
+    merged into one, as is the case in the Quotient construction::
+
+        sage: Q15, R = (ZZ.quo(15*ZZ)).construction()
+        sage: Q15
+        QuotientFunctor
+        sage: Q35, R = (ZZ.quo(35*ZZ)).construction()
+        sage: Q35
+        QuotientFunctor
+        sage: Q15.merge(Q35)
+        QuotientFunctor
+        sage: Q15.merge(Q35)(ZZ)
+        Ring of integers modulo 5
+
+    Functors can not only be applied to objects, but also to morphisms in the
+    respective categories. For example::
+
+        sage: P.<x,y> = ZZ[]
+        sage: F = P.construction()[0]; F
+        MPoly[x,y]
+        sage: A.<a,b> = GF(5)[]
+        sage: f = A.hom([a+b,a-b],A)
+        sage: F(A)
+        Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5
+        sage: F(f)
+        Ring endomorphism of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5
+          Defn: Induced from base ring by
+                Ring endomorphism of Multivariate Polynomial Ring in a, b over Finite Field of size 5
+                  Defn: a |--> a + b
+                        b |--> a - b
+        sage: F(f)(F(A)(x)*a)
+        (a + b)*x
+
+    """
     def __mul__(self, other):
+        """
+        Compose construction functors to a composit construction functor, unless one of them is the identity.
+
+        NOTE:
+
+        The product is in functorial notation, i.e., when applying the product to an object
+        then the second factor is applied first.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: F = QQ.construction()[0]
+            sage: P = ZZ['t'].construction()[0]
+            sage: F*P
+            FractionField(Poly[t](...))
+            sage: P*F
+            Poly[t](FractionField(...))
+            sage: (F*P)(ZZ)
+            Fraction Field of Univariate Polynomial Ring in t over Integer Ring
+            sage: I*P is P
+            True
+            sage: F*I is F
+            True
+
+        """
         if not isinstance(self, ConstructionFunctor) and not isinstance(other, ConstructionFunctor):
             raise CoercionException, "Non-constructive product"
+        if isinstance(other,IdentityConstructionFunctor):
+            return self
+        if isinstance(self,IdentityConstructionFunctor):
+            return other
         return CompositeConstructionFunctor(other, self)
         
     def pushout(self, other):
+        """
+        Composition of two construction functors, ordered by their ranks.
+
+        NOTE:
+        
+        - This method seems not to be used in the coercion model.
+
+        - By default, the functor with smaller rank is applied first.
+
+        TESTS::
+
+            sage: F = QQ.construction()[0]
+            sage: P = ZZ['t'].construction()[0]
+            sage: F.pushout(P)
+            Poly[t](FractionField(...))
+            sage: P.pushout(F)
+            Poly[t](FractionField(...))
+
+        """
         if self.rank > other.rank:
             return self * other
         else:
@@ -20,39 +151,149 @@
             
     def __cmp__(self, other):
         """
-        Equality here means that they are mathematically equivalent, though they may have specific implementation data. 
-        See the \code{merge} function. 
+        Equality here means that they are mathematically equivalent, though they may have
+        specific implementation data. This method will usually be overloaded in subclasses.
+        by default, only the types of the functors are compared. Also see the \code{merge}
+        function.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: F = QQ.construction()[0]
+            sage: P = ZZ['t'].construction()[0]
+            sage: I == F        # indirect doctest
+            False
+            sage: I == I        # indirect doctest
+            True
+
         """
         return cmp(type(self), type(other))
         
     def __str__(self):
+        """
+        NOTE:
+
+        By default, it returns the name of the construction functor's class.
+        Usually, this method will be overloaded.
+
+        TEST::
+
+            sage: F = QQ.construction()[0]
+            sage: F                  # indirect doctest
+            FractionField
+            sage: Q = ZZ.quo(2).construction()[0]
+            sage: Q                  # indirect doctest
+            QuotientFunctor
+
+        """
         s = str(type(self))
         import re
         return re.sub("<.*'.*\.([^.]*)'>", "\\1", s)
         
     def __repr__(self):
+        """
+        NOTE:
+
+        By default, it returns the name of the construction functor's class.
+        Usually, this method will be overloaded.
+
+        TEST::
+
+            sage: F = QQ.construction()[0]
+            sage: F                  # indirect doctest
+            FractionField
+            sage: Q = ZZ.quo(2).construction()[0]
+            sage: Q                  # indirect doctest
+            QuotientFunctor
+
+        """
         return str(self)
         
     def merge(self, other):
+        """
+        Merge ``self`` with another construction functor, or return None.
+
+        NOTE:
+
+        The default is to merge only if the two functors coincide. But this
+        may be overloaded for subclasses, such as the quotient functor.
+
+        EXAMPLES::
+
+            sage: F = QQ.construction()[0]
+            sage: P = ZZ['t'].construction()[0]
+            sage: F.merge(F)
+            FractionField
+            sage: F.merge(P)
+            sage: P.merge(F)
+            sage: P.merge(P)
+            Poly[t]
+
+        """
         if self == other:
             return self
         else:
             return None
             
     def commutes(self, other):
+        """
+        Determine whether ``self`` commutes with another construction functor.
+
+        NOTE:
+
+        By default, ``False`` is returned in all cases (even if the two
+        functors are the same, since in this case :meth:`merge` will apply
+        anyway). So far there is no construction functor that overloads
+        this method. Anyway, this method only becomes relevant if two 
+        construction functors have the same rank.
+
+        EXAMPLES::
+
+            sage: F = QQ.construction()[0]
+            sage: P = ZZ['t'].construction()[0]
+            sage: F.commutes(P)
+            False
+            sage: P.commutes(F)
+            False
+            sage: F.commutes(F)
+            False
+        
+        """
         return False
 
     def expand(self):
+        """
+        Decompose ``self`` into a list of construction functors.
+
+        NOTE:
+
+        The default is to return the list only containing ``self``.
+
+        EXAMPLE::
+
+            sage: F = QQ.construction()[0]
+            sage: F.expand()
+            [FractionField]
+            sage: Q = ZZ.quo(2).construction()[0]
+            sage: Q.expand()
+            [QuotientFunctor]
+            sage: P = ZZ['t'].construction()[0]
+            sage: FP = F*P
+            sage: FP.expand()
+            [FractionField, Poly[t]]
+
+        """
         return [self]
 
         
 class CompositeConstructionFunctor(ConstructionFunctor):
     """
-    A Construction Functor composed by other Construction Functors
+    A Construction Functor composed by other Construction Functors.
 
     INPUT:
 
-    ``F1,F2,...``: A list of Construction Functors. The result is the
+    ``F1, F2,...``: A list of Construction Functors. The result is the
     composition ``F1`` followed by ``F2`` followed by ...
 
     EXAMPLES::
@@ -61,6 +302,8 @@
         sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0])
         sage: F
         Poly[y](FractionField(Poly[x](FractionField(...))))
+        sage: F == loads(dumps(F))
+        True
         sage: F == CompositeConstructionFunctor(*F.all)
         True
         sage: F(GF(2)['t'])
@@ -92,13 +335,15 @@
 
     def _apply_functor_to_morphism(self, f):
         """
+        Apply the functor to an object of ``self``'s domain.
+        
         TESTS::
 
             sage: from sage.categories.pushout import CompositeConstructionFunctor
             sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0])
             sage: R.<a,b> = QQ[]
             sage: f = R.hom([a+b, a-b])
-            sage: F(f) # indirect doctest
+            sage: F(f)           # indirect doctest
             Ring endomorphism of Univariate Polynomial Ring in y over Fraction Field of Univariate Polynomial Ring in x over Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
               Defn: Induced from base ring by
                     Ring endomorphism of Fraction Field of Univariate Polynomial Ring in x over Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
@@ -116,12 +361,14 @@
 
     def _apply_functor(self, R):
         """
+        Apply the functor to an object of ``self``'s domain.
+        
         TESTS::
         
             sage: from sage.categories.pushout import CompositeConstructionFunctor
             sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0])
             sage: R.<a,b> = QQ[]
-            sage: F(R) # indirect doctest
+            sage: F(R)       # indirect doctest
             Univariate Polynomial Ring in y over Fraction Field of Univariate Polynomial Ring in x over Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
 
         """
@@ -146,7 +393,12 @@
             
     def __mul__(self, other):
         """
-        Convention: ``(F1*F2)(X) == F1(F2(X))``.
+        Compose construction functors to a composit construction functor, unless one of them is the identity.
+
+        NOTE:
+
+        The product is in functorial notation, i.e., when applying the product to an object
+        then the second factor is applied first.
 
         EXAMPLES::
 
@@ -159,6 +411,8 @@
         """
         if isinstance(self, CompositeConstructionFunctor):
             all = [other] + self.all
+        elif isinstance(other,IdentityConstructionFunctor):
+            return self
         else:
             all = other.all + [self]
         return CompositeConstructionFunctor(*all)
@@ -201,37 +455,188 @@
 
         
 class IdentityConstructionFunctor(ConstructionFunctor):
-
+    """
+    A construction functor that is the identity functor.
+
+    TESTS::
+
+        sage: from sage.categories.pushout import IdentityConstructionFunctor
+        sage: I = IdentityConstructionFunctor()
+        sage: I(RR) is RR
+        True
+        sage: I == loads(dumps(I))
+        True
+
+    """
     rank = -100
 
     def __init__(self):
-        Functor.__init__(self, Sets(), Sets())
-    def _apply_functor(self, R):
-        return R
+        """
+        TESTS::
+
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: IdentityFunctor(Sets()) == I
+            True
+            sage: I(RR) is RR
+            True
+
+        """
+        ConstructionFunctor.__init__(self, Sets(), Sets())
+
+    def _apply_functor(self, x):
+        """
+        Return the argument unaltered.
+        
+        TESTS::
+
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: I(RR) is RR      # indirect doctest
+            True
+        """
+        return x
+
+    def _apply_functor_to_morphism(self, f):
+        """
+        Return the argument unaltered.
+        
+        TESTS::
+
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: f = ZZ['t'].hom(['x'],QQ['x'])
+            sage: I(f) is f      # indirect doctest
+            True
+        """
+        return f
+
+    def __cmp__(self, other):
+        """
+        TESTS::
+        
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: I == IdentityFunctor(Sets())     # indirect doctest
+            True
+            sage: I == QQ.construction()[0]
+            False
+
+        """
+        c = cmp(type(self),type(other))
+        if c:
+            from sage.categories.functor import IdentityFunctor_generic
+            if isinstance(other,IdentityFunctor_generic):
+               return 0
+        return c
+
     def __mul__(self, other):
+        """
+        Compose construction functors to a composit construction functor, unless one of them is the identity.
+
+        NOTE:
+
+        The product is in functorial notation, i.e., when applying the product to an object
+        then the second factor is applied first.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import IdentityConstructionFunctor
+            sage: I = IdentityConstructionFunctor()
+            sage: F = QQ.construction()[0]
+            sage: P = ZZ['t'].construction()[0]
+            sage: I*F is F     # indirect doctest
+            True
+            sage: F*I is F
+            True
+            sage: I*P is P
+            True
+            sage: P*I is P
+            True
+
+        """
         if isinstance(self, IdentityConstructionFunctor):
             return other
         else:
             return self
 
 
-
-
 class PolynomialFunctor(ConstructionFunctor):
-
+    """
+    Construction functor for univariate polynomial rings.
+
+    EXAMPLE:
+
+        sage: P = ZZ['t'].construction()[0]
+        sage: P(GF(3))
+        Univariate Polynomial Ring in t over Finite Field of size 3
+        sage: P == loads(dumps(P))
+        True
+        sage: R.<x,y> = GF(5)[]
+        sage: f = R.hom([x+2*y,3*x-y],R)
+        sage: P(f)((x+y)*P(R).0)
+        (-x + y)*t
+
+    """
     rank = 9
 
     def __init__(self, var, multi_variate=False):
+        """
+        TESTS::
+
+            sage: from sage.categories.pushout import PolynomialFunctor
+            sage: P = PolynomialFunctor('x')
+            sage: P(GF(3))
+            Univariate Polynomial Ring in x over Finite Field of size 3
+
+        There is an optional parameter ``multi_variate``, but 
+        apparently it is not used::
+
+            sage: Q = PolynomialFunctor('x',multi_variate=True)
+            sage: Q(ZZ)
+            Univariate Polynomial Ring in x over Integer Ring
+            sage: Q == P
+            True
+
+        """
         from rings import Rings
         Functor.__init__(self, Rings(), Rings())
         self.var = var
         self.multi_variate = multi_variate
 
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TEST::
+
+            sage: P = ZZ['x'].construction()[0]
+            sage: P(GF(3))      # indirect doctest
+            Univariate Polynomial Ring in x over Finite Field of size 3
+
+        """
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         return PolynomialRing(R, self.var)
 
     def __cmp__(self, other):
+        """
+        TESTS::
+
+            sage: from sage.categories.pushout import MultiPolynomialFunctor
+            sage: Q = MultiPolynomialFunctor(('x',),'lex')
+            sage: P = ZZ['x'].construction()[0]
+            sage: P
+            Poly[x]
+            sage: Q
+            MPoly[x]
+            sage: P == Q
+            True
+            sage: P == loads(dumps(P))
+            True
+            sage: P == QQ.construction()[0]
+            False
+
+        """
         c = cmp(type(self), type(other))
         if c == 0:
             c = cmp(self.var, other.var)
@@ -240,6 +645,25 @@
         return c
 
     def merge(self, other):
+        """
+        Merge ``self`` with another construction functor, or return None.
+        
+        NOTE:
+
+        Internally, the merging is delegated to the merging of
+        multipolynomial construction functors. But in effect,
+        this does the same as the default implementation, that
+        returns ``None`` unless the to-be-merged functors coincide.
+
+        EXAMPLE::
+
+            sage: P = ZZ['x'].construction()[0]
+            sage: Q = ZZ['y','x'].construction()[0]
+            sage: P.merge(Q)
+            sage: P.merge(P) is P
+            True
+
+        """
         if isinstance(other, MultiPolynomialFunctor):
             return other.merge(self)
         elif self == other:
@@ -248,18 +672,46 @@
             return None
 
     def __str__(self):
+        """
+        TEST::
+
+            sage: P = ZZ['x'].construction()[0]
+            sage: P       # indirect doctest
+            Poly[x]
+
+        """
         return "Poly[%s]" % self.var
 
 class MultiPolynomialFunctor(ConstructionFunctor):
     """
     A constructor for multivariate polynomial rings.
+
+    EXAMPLES::
+
+        sage: P.<x,y> = ZZ[]
+        sage: F = P.construction()[0]; F
+        MPoly[x,y]
+        sage: A.<a,b> = GF(5)[]
+        sage: F(A)
+        Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5
+        sage: f = A.hom([a+b,a-b],A)
+        sage: F(f)
+        Ring endomorphism of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5
+          Defn: Induced from base ring by
+                Ring endomorphism of Multivariate Polynomial Ring in a, b over Finite Field of size 5
+                  Defn: a |--> a + b
+                        b |--> a - b
+        sage: F(f)(F(A)(x)*a)
+        (a + b)*x
+
     """
     
     rank = 9
 
     def __init__(self, vars, term_order):
         """
-        EXAMPLES: 
+        EXAMPLES::
+        
             sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None)
             sage: F
             MPoly[x,y]
@@ -274,15 +726,18 @@
 
     def _apply_functor(self, R):
         """
-        EXAMPLES:
+        Apply the functor to an object of ``self``'s domain.
+        
+        EXAMPLES::
+        
             sage: R.<x,y,z> = QQ[]
             sage: F = R.construction()[0]; F
             MPoly[x,y,z]
             sage: type(F)
             <class 'sage.categories.pushout.MultiPolynomialFunctor'>
-            sage: F(ZZ)
+            sage: F(ZZ)          # indirect doctest
             Multivariate Polynomial Ring in x, y, z over Integer Ring
-            sage: F(RR)
+            sage: F(RR)          # indirect doctest
             Multivariate Polynomial Ring in x, y, z over Real Field with 53 bits of precision
         """
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
@@ -290,11 +745,14 @@
 
     def __cmp__(self, other):
         """
-        EXAMPLES: 
+        EXAMPLES::
+        
             sage: F = ZZ['x,y,z'].construction()[0]
             sage: G = QQ['x,y,z'].construction()[0]
             sage: F == G
             True
+            sage: G == loads(dumps(G))
+            True
             sage: G = ZZ['x,y'].construction()[0]
             sage: F == G
             False
@@ -311,12 +769,15 @@
         If two MPoly functors are given in a row, form a single MPoly functor
         with all of the variables. 
         
-        EXAMPLES:
+        EXAMPLES::
+        
             sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None)
             sage: G = sage.categories.pushout.MultiPolynomialFunctor(['t'], None)
             sage: G*F
             MPoly[x,y,t]
         """
+        if isinstance(other,IdentityConstructionFunctor):
+            return self
         if isinstance(other, MultiPolynomialFunctor):
             if self.term_order != other.term_order:
                 raise CoercionException, "Incompatible term orders (%s,%s)." % (self.term_order, other.term_order)
@@ -331,7 +792,10 @@
 
     def merge(self, other):
         """
-        EXAMPLES:
+        Merge ``self`` with another construction functor, or return None.
+        
+        EXAMPLES::
+        
             sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None)
             sage: G = sage.categories.pushout.MultiPolynomialFunctor(['t'], None)
             sage: F.merge(G) is None
@@ -346,13 +810,17 @@
 
     def expand(self):
         """
-        EXAMPLES: 
+        Decompose ``self`` into a list of construction functors.
+        
+        EXAMPLES::
+        
             sage: F = QQ['x,y,z,t'].construction()[0]; F
             MPoly[x,y,z,t]
             sage: F.expand()
             [MPoly[t], MPoly[z], MPoly[y], MPoly[x]]
             
-        Now an actual use case:
+        Now an actual use case::
+        
             sage: R.<x,y,z> = ZZ[]
             sage: S.<z,t> = QQ[]
             sage: x+t
@@ -376,7 +844,8 @@
 
     def __str__(self):
         """
-        EXAMPLES:
+        TEST::
+        
             sage: QQ['x,y,z,t'].construction()[0]
             MPoly[x,y,z,t]
         """
@@ -386,10 +855,11 @@
 
 class InfinitePolynomialFunctor(ConstructionFunctor):
     """
-    A Construction Functor for Infinite Polynomial Rings (see :mod:`~sage.rings.polynomial.infinite_polynomial_ring`)
+    A Construction Functor for Infinite Polynomial Rings (see :mod:`~sage.rings.polynomial.infinite_polynomial_ring`).
     
     AUTHOR: 
-       -- Simon King
+
+    -- Simon King
 
     This construction functor is used to provide uniqueness of infinite polynomial rings as parent structures.
     As usual, the construction functor allows for constructing pushouts.
@@ -443,7 +913,7 @@
         CoercionException: Overlapping variables (('a', 'b'),['a_3', 'a_1']) are incompatible
 
     Since the construction functors are actually used to construct infinite polynomial rings, the following
-    result is no surprise:
+    result is no surprise::
 
         sage: C.<a,b> = InfinitePolynomialRing(B); C
         Infinite polynomial ring in a, b over Multivariate Polynomial Ring in x, y over Rational Field
@@ -455,7 +925,7 @@
 
     `X` and `Y` have an overlapping generators `x_\\ast, y_\\ast`. Since the default lexicographic order is
     used in both rings, it gives rise to isomorphic sub-monoids in both `X` and `Y`. They are merged in the
-    pushout, which also yields a common parent for doing arithmetic.
+    pushout, which also yields a common parent for doing arithmetic::
 
         sage: P = sage.categories.pushout.pushout(Y,X); P
         Infinite polynomial ring in w, x, y, z over Rational Field
@@ -476,7 +946,7 @@
         """
         TEST::
 
-            sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F # indirect doc test
+            sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F # indirect doctest
             InfPoly{[a,b,x], "degrevlex", "sparse"} 
             sage: F == loads(dumps(F))
             True
@@ -490,15 +960,31 @@
         self._imple = implementation
 
     def _apply_functor_to_morphism(self, f):
-        raise NotImplementedError
+        """
+        Morphisms for inifinite polynomial rings are not implemented yet.
+
+        TEST::
+
+            sage: P.<x,y> = QQ[]
+            sage: R.<alpha> = InfinitePolynomialRing(P)
+            sage: f = P.hom([x+y,x-y],P)
+            sage: R.construction()[0](f)     # indirect doctest
+            Traceback (most recent call last):
+            ...
+            NotImplementedError: Morphisms for inifinite polynomial rings are not implemented yet.
+            
+        """
+        raise NotImplementedError, "Morphisms for inifinite polynomial rings are not implemented yet."
 
     def _apply_functor(self, R):
         """
+        Apply the functor to an object of ``self``'s domain.
+        
         TEST::
 
             sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F
             InfPoly{[a,b,x], "degrevlex", "sparse"}
-            sage: F(QQ['t']) # indirect doc test
+            sage: F(QQ['t']) # indirect doctest
             Infinite polynomial ring in a, b, x over Univariate Polynomial Ring in t over Rational Field
 
         """
@@ -509,7 +995,7 @@
         """
         TEST::
 
-            sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F # indirect doc test
+            sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F # indirect doctest
             InfPoly{[a,b,x], "degrevlex", "sparse"} 
 
         """
@@ -519,9 +1005,9 @@
         """
         TEST::
 
-            sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F # indirect doc test
+            sage: F = sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'degrevlex','sparse'); F # indirect doctest
             InfPoly{[a,b,x], "degrevlex", "sparse"} 
-            sage: F == loads(dumps(F)) # indirect doc test
+            sage: F == loads(dumps(F)) # indirect doctest
             True
             sage: F == sage.categories.pushout.InfinitePolynomialFunctor(['a','b','x'],'deglex','sparse')
             False
@@ -534,6 +1020,13 @@
 
     def __mul__(self, other):
         """
+        Compose construction functors to a composit construction functor, unless one of them is the identity.
+
+        NOTE:
+
+        The product is in functorial notation, i.e., when applying the product to an object
+        then the second factor is applied first.
+
         TESTS::
 
             sage: F1 = QQ['a','x_2','x_1','y_3','y_2'].construction()[0]; F1
@@ -551,6 +1044,8 @@
             InfPoly{[x,y], "degrevlex", "dense"}(FractionField(...))
 
         """
+        if isinstance(other,IdentityConstructionFunctor):
+            return self
         if isinstance(other, self.__class__): # 
             INT = set(self._gens).intersection(other._gens)
             if INT:
@@ -684,33 +1179,11 @@
             if self._imple != other._imple:
                 return InfinitePolynomialFunctor(self._gens, self._order, 'dense')
             return self
-##         if isinstance(other, PolynomialFunctor) or isinstance(other, MultiPolynomialFunctor):
-##             # For merging, we don't care about the orders
-## ##            if isinstance(other, MultiPolynomialFunctor) and self._order!=other.term_order.name():
-## ##                return None
-##             # We only merge if other's variables can all be interpreted in self.
-##             if isinstance(other, PolynomialFunctor):
-##                 if other.var.count('_')!=1:
-##                     return None
-##                 g,n = other.var.split('_')
-##                 if not ((g in self._gens) and n.isdigit()):
-##                     return None
-##                 # other merges into self!
-##                 return self
-##             # Now, other is MultiPolynomial
-##             for v in other.vars:
-##                 if v.count('_')!=1:
-##                     return None
-##                 g,n = v.split('_')
-##                 if not ((g in self._gens) and n.isdigit()):
-##                     return None
-##             # other merges into self!
-##             return self
         return None
 
     def expand(self):
         """
-        Decompose the functor `F` into sub-functors, whose product returns `F`
+        Decompose the functor `F` into sub-functors, whose product returns `F`.
 
         EXAMPLES::
 
@@ -735,59 +1208,252 @@
 
 
 class MatrixFunctor(ConstructionFunctor):
-
+    """
+    A construction functor for matrices over rings.
+
+    EXAMPLES::
+
+        sage: MS = MatrixSpace(ZZ,2, 3)
+        sage: F = MS.construction()[0]; F
+        MatrixFunctor
+        sage: MS = MatrixSpace(ZZ,2)
+        sage: F = MS.construction()[0]; F
+        MatrixFunctor
+        sage: P.<x,y> = QQ[]
+        sage: R = F(P); R
+        Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field
+        sage: f = P.hom([x+y,x-y],P); F(f)
+        Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field
+          Defn: Induced from base ring by
+                Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field
+                  Defn: x |--> x + y
+                        y |--> x - y
+        sage: M = R([x,y,x*y,x+y])
+        sage: F(f)(M)
+        [    x + y     x - y]
+        [x^2 - y^2       2*x]
+
+    """
     rank = 10
 
     def __init__(self, nrows, ncols, is_sparse=False):
-#        if nrows == ncols:
-#            Functor.__init__(self, Rings(), RingModules()) # takes a base ring
-#        else:
-#            Functor.__init__(self, Rings(), MatrixAlgebras()) # takes a base ring
-        # We must distinguish two cases: 
-        # If nrows=ncols, the result is a ring. Otherwise,
-        # it is just a commutative additive group.
-        if nrows==ncols:
-            Functor.__init__(self, Rings(), Rings())
+        """
+        TEST::
+
+            sage: from sage.categories.pushout import MatrixFunctor
+            sage: F = MatrixFunctor(2,3)
+            sage: F == MatrixSpace(ZZ,2,3).construction()[0]
+            True
+            sage: F.codomain()
+            Category of commutative additive groups
+            sage: R = MatrixSpace(ZZ,2,2).construction()[0]
+            sage: R.codomain()
+            Category of rings
+            sage: F(ZZ)
+            Full MatrixSpace of 2 by 3 dense matrices over Integer Ring
+            sage: F(ZZ) in F.codomain()
+            True
+            sage: R(GF(2))
+            Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 2
+            sage: R(GF(2)) in R.codomain()
+            True
+        """
+        if nrows == ncols:
+            Functor.__init__(self, Rings(), Rings()) # Algebras() takes a base ring
         else:
-            Functor.__init__(self,Rings(), CommutativeAdditiveGroups())
+            # Functor.__init__(self, Rings(), MatrixAlgebras()) # takes a base ring
+            Functor.__init__(self, Rings(), CommutativeAdditiveGroups()) # not a nice solution, but the best we can do.
         self.nrows = nrows
         self.ncols = ncols
         self.is_sparse = is_sparse
+
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TEST:
+
+        The following is a test against a bug discussed at ticket #8800
+
+            sage: F = MatrixSpace(ZZ,2,3).construction()[0]
+            sage: F(RR)         # indirect doctest
+            Full MatrixSpace of 2 by 3 dense matrices over Real Field with 53 bits of precision
+            sage: F(RR) in F.codomain()
+            True
+
+        """
         from sage.matrix.matrix_space import MatrixSpace
         return MatrixSpace(R, self.nrows, self.ncols, sparse=self.is_sparse)
+
     def __cmp__(self, other):
+        """
+        TEST::
+        
+            sage: F = MatrixSpace(ZZ,2,3).construction()[0]
+            sage: F == loads(dumps(F))
+            True
+            sage: F == MatrixSpace(ZZ,2,2).construction()[0]
+            False
+
+        """
         c = cmp(type(self), type(other))
         if c == 0:
             c = cmp((self.nrows, self.ncols), (other.nrows, other.ncols))
         return c
+
     def merge(self, other):
+        """
+        Merging is only happening if both functors are matrix functors of the same dimension.
+        The result is sparse if and only if both given functors are sparse.
+
+        EXAMPLE::
+
+            sage: F1 = MatrixSpace(ZZ,2,2).construction()[0]
+            sage: F2 = MatrixSpace(ZZ,2,3).construction()[0]
+            sage: F3 = MatrixSpace(ZZ,2,2,sparse=True).construction()[0]
+            sage: F1.merge(F2)
+            sage: F1.merge(F3)
+            MatrixFunctor
+            sage: F13 = F1.merge(F3)
+            sage: F13.is_sparse
+            False
+            sage: F1.is_sparse
+            False
+            sage: F3.is_sparse
+            True
+            sage: F3.merge(F3).is_sparse
+            True
+
+        """
         if self != other:
             return None
         else:
             return MatrixFunctor(self.nrows, self.ncols, self.is_sparse and other.is_sparse)
 
 class LaurentPolynomialFunctor(ConstructionFunctor):
-
+    """
+    Construction functor for Laurent polynomial rings.
+
+    EXAMPLES::
+
+        sage: L.<t> = LaurentPolynomialRing(ZZ)
+        sage: F = L.construction()[0]
+        sage: F
+        LaurentPolynomialFunctor
+        sage: F(QQ)
+        Univariate Laurent Polynomial Ring in t over Rational Field
+        sage: K.<x> = LaurentPolynomialRing(ZZ)
+        sage: F(K)
+        Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in x over Integer Ring
+        sage: P.<x,y> = ZZ[]
+        sage: f = P.hom([x+2*y,3*x-y],P)
+        sage: F(f)
+        Ring endomorphism of Univariate Laurent Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Integer Ring
+          Defn: Induced from base ring by
+                Ring endomorphism of Multivariate Polynomial Ring in x, y over Integer Ring
+                  Defn: x |--> x + 2*y
+                        y |--> 3*x - y
+        sage: F(f)(x*F(P).gen()^-2+y*F(P).gen()^3)
+        (3*x - y)*t^3 + (x + 2*y)*t^-2
+
+    """
     rank = 9
     
     def __init__(self, var, multi_variate=False):
+        """
+        INPUT:
+
+        - ``var``, a string or a list of strings
+        - ``multi_variate``, optional bool, default ``False`` if ``var`` is a string
+          and ``True`` otherwise: If ``True``, application to a Laurent polynomial
+          ring yields a multivariate Laurent polynomial ring.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import LaurentPolynomialFunctor
+            sage: F1 = LaurentPolynomialFunctor('t')
+            sage: F2 = LaurentPolynomialFunctor('s', multi_variate=True)
+            sage: F3 = LaurentPolynomialFunctor(['s','t'])
+            sage: F1(F2(QQ))
+            Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in s over Rational Field
+            sage: F2(F1(QQ))
+            Multivariate Laurent Polynomial Ring in t, s over Rational Field
+            sage: F3(QQ)
+            Multivariate Laurent Polynomial Ring in s, t over Rational Field
+
+        """
         Functor.__init__(self, Rings(), Rings())
+        if not isinstance(var, (basestring,tuple,list)):
+            raise TypeError, "variable name or list of variable names expected"
         self.var = var
-        self.multi_variate = multi_variate
+        self.multi_variate = multi_variate or not isinstance(var, basestring)
+
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TESTS::
+
+            sage: from sage.categories.pushout import LaurentPolynomialFunctor
+            sage: F1 = LaurentPolynomialFunctor('t')
+            sage: F2 = LaurentPolynomialFunctor('s', multi_variate=True)
+            sage: F3 = LaurentPolynomialFunctor(['s','t'])
+            sage: F1(F2(QQ))          # indirect doctest
+            Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in s over Rational Field
+            sage: F2(F1(QQ))
+            Multivariate Laurent Polynomial Ring in t, s over Rational Field
+            sage: F3(QQ)
+            Multivariate Laurent Polynomial Ring in s, t over Rational Field
+
+        """
         from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, is_LaurentPolynomialRing
         if self.multi_variate and is_LaurentPolynomialRing(R):
             return LaurentPolynomialRing(R.base_ring(), (list(R.variable_names()) + [self.var]))
         else:
             from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
             return LaurentPolynomialRing(R, self.var)
+
     def __cmp__(self, other):
+        """
+        TESTS::
+
+            sage: from sage.categories.pushout import LaurentPolynomialFunctor
+            sage: F1 = LaurentPolynomialFunctor('t')
+            sage: F2 = LaurentPolynomialFunctor('t', multi_variate=True)
+            sage: F3 = LaurentPolynomialFunctor(['s','t'])
+            sage: F1 == F2
+            True
+            sage: F1 == loads(dumps(F1))
+            True
+            sage: F1 == F3
+            False
+            sage: F1 == QQ.construction()[0]
+            False
+
+        """
         c = cmp(type(self), type(other))
         if c == 0:
             c = cmp(self.var, other.var)
         return c
+
     def merge(self, other):
+        """
+        Two Laurent polynomial construction functors merge if the variable names coincide.
+        The result is multivariate if one of the arguments is multivariate.
+
+        EXAMPLE::
+
+            sage: from sage.categories.pushout import LaurentPolynomialFunctor
+            sage: F1 = LaurentPolynomialFunctor('t')
+            sage: F2 = LaurentPolynomialFunctor('t', multi_variate=True)
+            sage: F1.merge(F2)
+            LaurentPolynomialFunctor
+            sage: F1.merge(F2)(LaurentPolynomialRing(GF(2),'a'))
+            Multivariate Laurent Polynomial Ring in a, t over Finite Field of size 2
+            sage: F1.merge(F1)(LaurentPolynomialRing(GF(2),'a'))
+            Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in a over Finite Field of size 2
+
+        """
         if self == other or isinstance(other, PolynomialFunctor) and self.var == other.var:
             return LaurentPolynomialFunctor(self.var, (self.multi_variate or other.multi_variate))
         else:
@@ -795,179 +1461,1250 @@
 
         
 class VectorFunctor(ConstructionFunctor):
-
-    rank = 10 # ranking of functor, not rank of module
+    """
+    A construction functor for free modules over commutative rings.
+
+    EXAMPLE::
+
+        sage: F = (ZZ^3).construction()[0]
+        sage: F
+        VectorFunctor
+        sage: F(GF(2)['t'])
+        Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL)
+        
+
+    """
+    rank = 10 # ranking of functor, not rank of module.
+    # This coincides with the rank of the matrix construction functor, but this is OK since they can not both be applied in any order
 
     def __init__(self, n, is_sparse=False, inner_product_matrix=None):
-#        Functor.__init__(self, Rings(), FreeModules()) # takes a base ring
-        #This is a bad choice, since the input must be a commutative ring, and
-        #the output belongs to the category of commutative additive groups
-        #Functor.__init__(self, Objects(), Objects())
-        Functor.__init__(self,CommutativeRings(),CommutativeAdditiveGroups())
+        """
+        INPUT:
+
+        - ``n``, the rank of the to-be-created modules (non-negative integer)
+        - ``is_sparse`` (optional bool, default ``False``), create sparse implementation of modules
+        - ``inner_product_matrix``: ``n`` by ``n`` matrix, used to compute inner products in the
+          to-be-created modules
+
+        TEST::
+
+            sage: from sage.categories.pushout import VectorFunctor
+            sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9)))
+            sage: F1.domain()
+            Category of commutative rings
+            sage: F1.codomain()
+            Category of commutative additive groups
+            sage: M1 = F1(ZZ)
+            sage: M1.is_sparse()
+            False
+            sage: v = M1([3, 2, 1])
+            sage: v*Matrix(3,3,range(9))*v.column()
+            (96)
+            sage: v.inner_product(v)
+            96
+            sage: F2 = VectorFunctor(3, is_sparse=True)
+            sage: M2 = F2(QQ); M2; M2.is_sparse()
+            Sparse vector space of dimension 3 over Rational Field
+            True
+
+        """
+#        Functor.__init__(self, Rings(), FreeModules()) # FreeModules() takes a base ring
+#        Functor.__init__(self, Objects(), Objects())   # Object() makes no sence, since FreeModule raises an error, e.g., on Set(['a',1]).
+        ## FreeModule requires a commutative ring. Thus, we have
+        Functor.__init__(self, CommutativeRings(), CommutativeAdditiveGroups())
         self.n = n
         self.is_sparse = is_sparse
         self.inner_product_matrix = inner_product_matrix
+
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TESTS::
+
+            sage: from sage.categories.pushout import VectorFunctor
+            sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9)))
+            sage: M1 = F1(ZZ)   # indirect doctest
+            sage: M1.is_sparse()
+            False
+            sage: v = M1([3, 2, 1])
+            sage: v*Matrix(3,3,range(9))*v.column()
+            (96)
+            sage: v.inner_product(v)
+            96
+            sage: F2 = VectorFunctor(3, is_sparse=True)
+            sage: M2 = F2(QQ); M2; M2.is_sparse()
+            Sparse vector space of dimension 3 over Rational Field
+            True
+            sage: v = M2([3, 2, 1])
+            sage: v.inner_product(v)
+            14
+
+        """
         from sage.modules.free_module import FreeModule
         return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix)
+
+    def _apply_functor_to_morphism(self, f):
+        """
+        This is not implemented yet.
+
+        TEST::
+
+            sage: F = (ZZ^3).construction()[0]
+            sage: P.<x,y> = ZZ[]
+            sage: f = P.hom([x+2*y,3*x-y],P)
+            sage: F(f)       # indirect doctest
+            Traceback (most recent call last):
+            ...
+            NotImplementedError: Can not create induced morphisms of free modules yet
+        """
+        ## TODO: Implement this!
+        raise NotImplementedError, "Can not create induced morphisms of free modules yet"
+
     def __cmp__(self, other):
+        """
+        Only the rank of the to-be-created modules is compared, *not* the inner product matrix.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import VectorFunctor
+            sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9)))
+            sage: F2 = (ZZ^3).construction()[0]
+            sage: F1 == F2
+            True
+            sage: F1(QQ) == F2(QQ)
+            True
+            sage: F1(QQ).inner_product_matrix() == F2(QQ).inner_product_matrix()
+            False
+            sage: F1 == loads(dumps(F1))
+            True
+        """
         c = cmp(type(self), type(other))
         if c == 0:
             c = cmp(self.n, other.n)
         return c
+
     def merge(self, other):
+        """
+        Two constructors of free modules merge, if the module ranks coincide. If both
+        have explicitly given inner product matrices, they must coincide as well.
+
+        EXAMPLE:
+
+        Two modules without explicitly given inner product allow coercion::
+
+            sage: M1 = QQ^3
+            sage: P.<t> = ZZ[]
+            sage: M2 = FreeModule(P,3)
+            sage: M1([1,1/2,1/3]) + M2([t,t^2+t,3])     # indirect doctest
+            (t + 1, t^2 + t + 1/2, 10/3)
+
+        If only one summand has an explicit inner product, the result will be provided
+        with it::
+
+            sage: M3 = FreeModule(P,3, inner_product_matrix = Matrix(3,3,range(9)))
+            sage: M1([1,1/2,1/3]) + M3([t,t^2+t,3])
+            (t + 1, t^2 + t + 1/2, 10/3)
+            sage: (M1([1,1/2,1/3]) + M3([t,t^2+t,3])).parent().inner_product_matrix()
+            [0 1 2]
+            [3 4 5]
+            [6 7 8]
+
+        If both summands have an explicit inner product (even if it is the standard
+        inner product), then the products must coincide. The only difference between
+        ``M1`` and ``M4`` in the following example is the fact that the default
+        inner product was *explicitly* requested for ``M4``. It is therefore not
+        possible to coerce with a different inner product::
+
+            sage: M4 = FreeModule(QQ,3, inner_product_matrix = Matrix(3,3,1))
+            sage: M4 == M1
+            True
+            sage: M4.inner_product_matrix() == M1.inner_product_matrix()
+            True
+            sage: M4([1,1/2,1/3]) + M3([t,t^2+t,3])      # indirect doctest
+            Traceback (most recent call last):
+            ...
+            TypeError: unsupported operand parent(s) for '+': 'Ambient quadratic space of dimension 3 over Rational Field
+            Inner product matrix:
+            [1 0 0]
+            [0 1 0]
+            [0 0 1]' and 'Ambient free quadratic module of rank 3 over the integral domain Univariate Polynomial Ring in t over Integer Ring
+            Inner product matrix:
+            [0 1 2]
+            [3 4 5]
+            [6 7 8]'
+
+        """
         if self != other:
             return None
+        if self.inner_product_matrix is None:
+            return VectorFunctor(self.n, self.is_sparse and other.is_sparse, other.inner_product_matrix)
+        if other.inner_product_matrix is None:
+            return VectorFunctor(self.n, self.is_sparse and other.is_sparse, self.inner_product_matrix)
+        # At this point, we know that the user wants to take care of the inner product.
+        # So, we only merge if both coincide:
+        if self.inner_product_matrix != other.inner_product_matrix:
+            return None
         else:
-            return VectorFunctor(self.n, self.is_sparse and other.is_sparse)
-
+            return VectorFunctor(self.n, self.is_sparse and other.is_sparse, self.inner_product_matrix)
 
 class SubspaceFunctor(ConstructionFunctor):
+    """
+    Constructing a subspace of an ambient free module, given by a basis.
+
+    NOTE:
+
+    This construction functor keeps track of the basis. It can only be applied
+    to free modules into which this basis coerces.
+
+    EXAMPLES::
+
+        sage: M = ZZ^3
+        sage: S = M.submodule([(1,2,3),(4,5,6)]); S
+        Free module of degree 3 and rank 2 over Integer Ring
+        Echelon basis matrix:
+        [1 2 3]
+        [0 3 6]
+        sage: F = S.construction()[0]
+        sage: F(GF(2)^3)
+        Vector space of degree 3 and dimension 2 over Finite Field of size 2
+        User basis matrix:
+        [1 0 1]
+        [0 1 0]
+
+    """
     rank = 11 # ranking of functor, not rank of module
+
     def __init__(self, basis):
-#        Functor.__init__(self, FreeModules(), FreeModules()) # takes a base ring
-        #Functor.__init__(self, Objects(), Objects())
+        """
+        INPUT:
+
+        ``basis``: a list of elements of a free module.
+
+        TEST::
+
+            sage: from sage.categories.pushout import SubspaceFunctor
+            sage: M = ZZ^3
+            sage: F = SubspaceFunctor([M([1,2,3]),M([4,5,6])])
+            sage: F(GF(5)^3)
+            Vector space of degree 3 and dimension 2 over Finite Field of size 5
+            User basis matrix:
+            [1 2 3]
+            [4 0 1]
+        """
+##        Functor.__init__(self, FreeModules(), FreeModules()) # takes a base ring
+##        Functor.__init__(self, Objects(), Objects())   # is too general
         ## It seems that the category of commutative additive groups
         ## currently is the smallest base ring free category that
         ## contains in- and output
-        Functor.__init__(self, CommutativeAdditiveGroups(),CommutativeAdditiveGroups())
+        Functor.__init__(self, CommutativeAdditiveGroups(), CommutativeAdditiveGroups())
         self.basis = basis
+
     def _apply_functor(self, ambient):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TESTS::
+
+            sage: M = ZZ^3
+            sage: S = M.submodule([(1,2,3),(4,5,6)]); S
+            Free module of degree 3 and rank 2 over Integer Ring
+            Echelon basis matrix:
+            [1 2 3]
+            [0 3 6]
+            sage: F = S.construction()[0]
+            sage: F(GF(2)^3)    # indirect doctest
+            Vector space of degree 3 and dimension 2 over Finite Field of size 2
+            User basis matrix:
+            [1 0 1]
+            [0 1 0]
+        """
         return ambient.span_of_basis(self.basis)
+
+    def _apply_functor_to_morphism(self, f):
+        """
+        This is not implemented yet.
+
+        TEST::
+
+            sage: F = (ZZ^3).span([(1,2,3),(4,5,6)]).construction()[0]
+            sage: P.<x,y> = ZZ[]
+            sage: f = P.hom([x+2*y,3*x-y],P)
+            sage: F(f)      # indirect doctest
+            Traceback (most recent call last):
+            ...
+            NotImplementedError: Can not create morphisms of free sub-modules yet
+        """
+        raise NotImplementedError, "Can not create morphisms of free sub-modules yet"
+
     def __cmp__(self, other):
+        """
+        TEST::
+
+            sage: F1 = (GF(5)^3).span([(1,2,3),(4,5,6)]).construction()[0]
+            sage: F2 = (ZZ^3).span([(1,2,3),(4,5,6)]).construction()[0]
+            sage: F3 = (QQ^3).span([(1,2,3),(4,5,6)]).construction()[0]
+            sage: F4 = (ZZ^3).span([(1,0,-1),(0,1,2)]).construction()[0]
+            sage: F1 == loads(dumps(F1))
+            True
+
+        The ``span`` method automatically transforms the given basis into
+        echelon form. The bases look like that::
+
+            sage: F1.basis
+            [
+            (1, 0, 4),
+            (0, 1, 2)
+            ]
+            sage: F2.basis
+            [
+            (1, 2, 3),
+            (0, 3, 6)
+            ]
+            sage: F3.basis
+            [
+            (1, 0, -1),
+            (0, 1, 2)
+            ]
+            sage: F4.basis
+            [
+            (1, 0, -1),
+            (0, 1, 2)
+            ]
+
+
+        The basis of ``F2`` is modulo 5 different from the other bases.
+        So, we have::
+
+            sage: F1 != F2 != F3
+            True
+
+        The bases of ``F1``, ``F3`` and ``F4`` are the same modulo 5; however,
+        there is no coercion from ``QQ^3`` to ``GF(5)^3``. Therefore, we have::
+
+            sage: F1 == F3
+            False
+
+        But there are coercions from ``ZZ^3`` to ``QQ^3`` and ``GF(5)^3``, thus::
+
+            sage: F1 == F4 == F3
+            True
+
+        """
         c = cmp(type(self), type(other))
         if c == 0:
             c = cmp(self.basis, other.basis)
         return c
+
     def merge(self, other):
+        """
+        Two Subspace Functors are merged into a construction functor of the sum of two subspaces.
+
+        EXAMPLE::
+
+            sage: M = GF(5)^3
+            sage: S1 = M.submodule([(1,2,3),(4,5,6)])
+            sage: S2 = M.submodule([(2,2,3)])
+            sage: F1 = S1.construction()[0]
+            sage: F2 = S2.construction()[0]
+            sage: F1.merge(F2)
+            SubspaceFunctor
+            sage: F1.merge(F2)(GF(5)^3) == S1+S2
+            True
+            sage: F1.merge(F2)(GF(5)['t']^3)
+            Free module of degree 3 and rank 3 over Univariate Polynomial Ring in t over Finite Field of size 5
+            User basis matrix:
+            [1 0 0]
+            [0 1 0]
+            [0 0 1]
+
+        TEST::
+
+            sage: P.<t> = ZZ[]
+            sage: S1 = (ZZ^3).submodule([(1,2,3),(4,5,6)])
+            sage: S2 = (Frac(P)^3).submodule([(t,t^2,t^3+1),(4*t,0,1)])
+            sage: v = S1([0,3,6]) + S2([2,0,1/(2*t)]); v   # indirect doctest
+            (2, 3, (12*t + 1)/(2*t))
+            sage: v.parent()
+            Vector space of degree 3 and dimension 3 over Fraction Field of Univariate Polynomial Ring in t over Integer Ring
+            User basis matrix:
+            [1 0 0]
+            [0 1 0]
+            [0 0 1]
+
+        """
         if isinstance(other, SubspaceFunctor):
-            return SubspaceFunctor(self.basis + other.basis) # TODO: remove linear dependencies
+            # in order to remove linear dependencies, and in
+            # order to test compatibility of the base rings,
+            # we try to construct a sample submodule
+            if not other.basis:
+                return self
+            if not self.basis:
+                return other
+            try:
+                P = pushout(self.basis[0].parent().ambient_module(),other.basis[0].parent().ambient_module())
+            except CoercionException:
+                return None
+            S = P.submodule(self.basis+other.basis).echelonized_basis()
+            return SubspaceFunctor(S)
         else:
             return None
 
-        
 class FractionField(ConstructionFunctor):
-    
+    """
+    Construction functor for fraction fields.
+
+    EXAMPLE::
+
+        sage: F = QQ.construction()[0]
+        sage: F(GF(5)) is GF(5)
+        True
+        sage: F(ZZ['t'])
+        Fraction Field of Univariate Polynomial Ring in t over Integer Ring
+        sage: P.<x,y> = QQ[]
+        sage: f = P.hom([x+2*y,3*x-y],P)
+        sage: F(f)
+        Ring endomorphism of Fraction Field of Multivariate Polynomial Ring in x, y over Rational Field
+          Defn: x |--> x + 2*y
+                y |--> 3*x - y
+        sage: F(f)(1/x)
+        1/(x + 2*y)
+        sage: F == loads(dumps(F))
+        True
+
+    """
     rank = 5
     
     def __init__(self):
+        """
+        TEST::
+
+            sage: from sage.categories.pushout import FractionField
+            sage: F = FractionField()
+            sage: F
+            FractionField
+            sage: F(ZZ['t'])
+            Fraction Field of Univariate Polynomial Ring in t over Integer Ring
+        """
         Functor.__init__(self, Rings(), Fields())
+
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TEST::
+
+            sage: F = QQ.construction()[0]
+            sage: F(GF(5)['t'])      # indirect doctest
+            Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 5
+        """
         return R.fraction_field()
         
-    
-class LocalizationFunctor(ConstructionFunctor):
-    
-    rank = 6
-    
-    def __init__(self, t):
-        Functor.__init__(self, Rings(), Rings())
-        self.t = t
-    def _apply_functor(self, R):
-        return R.localize(t)
-    def __cmp__(self, other):
-        c = cmp(type(self), type(other))
-        if c == 0:
-            c = cmp(self.t, other.t)
-        return c
-    
+
+# This isn't used anywhere in Sage, and so I remove it (Simon King, 2010-05)
+# 
+#class LocalizationFunctor(ConstructionFunctor):
+#    
+#    rank = 6
+#    
+#    def __init__(self, t):
+#        Functor.__init__(self, Rings(), Rings())
+#        self.t = t
+#    def _apply_functor(self, R):
+#        return R.localize(t)
+#    def __cmp__(self, other):
+#        c = cmp(type(self), type(other))
+#        if c == 0:
+#            c = cmp(self.t, other.t)
+#        return c
     
 class CompletionFunctor(ConstructionFunctor):
-    
+    """
+    Completion of a ring with respect to a given prime (including infinity).
+
+    EXAMPLES::
+
+        sage: R = Zp(5)
+        sage: R
+        5-adic Ring with capped relative precision 20
+        sage: F1 = R.construction()[0]
+        sage: F1
+        Completion[5]
+        sage: F1(ZZ) is R
+        True
+        sage: F1(QQ)
+        5-adic Field with capped relative precision 20
+        sage: F2 = RR.construction()[0]
+        sage: F2
+        Completion[+Infinity]
+        sage: F2(QQ) is RR
+        True
+        sage: P.<x> = ZZ[]
+        sage: Px = P.completion(x) # currently the only implemented completion of P
+        sage: Px
+        Power Series Ring in x over Integer Ring
+        sage: F3 = Px.construction()[0]
+        sage: F3(GF(3)['x'])
+        Power Series Ring in x over Finite Field of size 3
+
+    TEST::
+
+        sage: R1.<a> = Zp(5,prec=20)[]
+        sage: R2 = Qp(5,prec=40)
+        sage: R2(1) + a
+        (1 + O(5^20))*a + (1 + O(5^40))
+        sage: 1/2 + a
+        (1 + O(5^20))*a + (3 + 2*5 + 2*5^2 + 2*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 2*5^8 + 2*5^9 + 2*5^10 + 2*5^11 + 2*5^12 + 2*5^13 + 2*5^14 + 2*5^15 + 2*5^16 + 2*5^17 + 2*5^18 + 2*5^19 + O(5^20))
+
+    """
     rank = 4
-    
+
     def __init__(self, p, prec, extras=None):
+        """
+        INPUT:
+
+        - ``p``: A prime number, the generator of a univariate polynomial ring, or ``+Infinity``
+        - ``prec``: an integer, yielding the precision in bits. Note that
+          if ``p`` is prime then the ``prec`` is the *capped* precision,
+          while it is the *set* precision if ``p`` is ``+Infinity``.
+        - ``extras`` (optional dictionary): Information on how to print elements, etc.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import CompletionFunctor
+            sage: F1 = CompletionFunctor(5,100)
+            sage: F1(QQ)
+            5-adic Field with capped relative precision 100
+            sage: F1(ZZ)
+            5-adic Ring with capped relative precision 100
+            sage: F2 = RR.construction()[0]
+            sage: F2
+            Completion[+Infinity]
+            sage: F2.extras
+            {'sci_not': False, 'rnd': 'RNDN'}
+
+        """
         Functor.__init__(self, Rings(), Rings())
         self.p = p
         self.prec = prec
         self.extras = extras
+
+    def __str__(self):
+        """
+        TEST::
+
+            sage: Zp(7).construction()  # indirect doctest
+            (Completion[7], Integer Ring)
+        """
+        return 'Completion[%s]'%repr(self.p)
+
     def _apply_functor(self, R):
-        return R.completion(self.p, self.prec, self.extras)
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TEST::
+
+            sage: R = Zp(5)
+            sage: F1 = R.construction()[0]
+            sage: F1(ZZ) is R  # indirect doctest
+            True
+            sage: F1(QQ)
+            5-adic Field with capped relative precision 20
+
+        """
+        try:
+            if self.extras is None:
+                try:
+                    return R.completion(self.p, self.prec)
+                except TypeError:
+                    return R.completion(self.p, self.prec, {})
+            return R.completion(self.p, self.prec, self.extras)
+        except (NotImplementedError,AttributeError):
+            if R.construction() is None:
+                raise NotImplementedError, "Completion is not implemented for %s"%R.__class__
+            F, BR = R.construction()
+            M = self.merge(F) or F.merge(self)
+            if M is not None:
+                return M(BR)
+            if self.commutes(F) or F.commutes(self):
+                return F(self(BR))
+            raise NotImplementedError, "Don't know how to apply %s to %s"%(repr(self),repr(R))
+
     def __cmp__(self, other):
+        """
+        NOTE:
+
+        Only the prime used in the completion is relevant to comparison
+        of Completion functors, although the resulting rings also take
+        the precision into account.
+
+        TEST::
+
+            sage: R1 = Zp(5,prec=30)
+            sage: R2 = Zp(5,prec=40)
+            sage: F1 = R1.construction()[0]
+            sage: F2 = R2.construction()[0]
+            sage: F1 == loads(dumps(F1))    # indirect doctest
+            True
+            sage: F1==F2
+            True
+            sage: F1(QQ)==F2(QQ)
+            False
+            sage: R3 = Zp(7)
+            sage: F3 = R3.construction()[0]
+            sage: F1==F3
+            False
+        """
         c = cmp(type(self), type(other))
         if c == 0:
             c = cmp(self.p, other.p)
         return c
+
     def merge(self, other):
+        """
+        Two Completion functors are merged, if they are equal. If the precisions of
+        both functors coincide, then a Completion functor is returned that results
+        from updating the ``extras`` dictionary of ``self`` by ``other.extras``.
+        Otherwise, if the completion is at infinity then merging does not increase
+        the set precision, and if the completion is at a finite prime, merging
+        does not decrease the capped precision.
+
+        EXAMPLE::
+
+            sage: R1.<a> = Zp(5,prec=20)[]
+            sage: R2 = Qp(5,prec=40)
+            sage: R2(1)+a         # indirect doctest
+            (1 + O(5^20))*a + (1 + O(5^40))
+            sage: R3 = RealField(30)
+            sage: R4 = RealField(50)
+            sage: R3(1) + R4(1)   # indirect doctest
+            2.0000000
+            sage: (R3(1) + R4(1)).parent()
+            Real Field with 30 bits of precision
+
+        """ 
+        if self!=other:
+            return None
         if self.p == other.p:
+            from sage.all import Infinity
             if self.prec == other.prec:
                 extras = self.extras.copy()
                 extras.update(other.extras)
                 return CompletionFunctor(self.p, self.prec, extras)
-            elif self.prec < other.prec:
+            elif (self.p==Infinity and self.prec<other.prec) or (self.p<Infinity and self.prec>other.prec):
                 return self
             else: # self.prec > other.prec
                 return other
         else:
             return None
-    
+##   Completion has a lower rank than FractionField
+##   and is thus applied first. However, fact is that
+##   both commute. This is used in the call method,
+##   since some fraction fields have no completion method
+##   implemented.
+
+    def commutes(self,other):
+        """
+        Completion commutes with fraction fields.
+
+        EXAMPLE::
+
+            sage: F1 = Qp(5).construction()[0]
+            sage: F2 = QQ.construction()[0]
+            sage: F1.commutes(F2)
+            True
+
+        TEST:
+
+        The fraction field ``R`` in the example below has no completion
+        method. But completion commutes with the fraction field functor,
+        and so it is tried internally whether applying the construction
+        functors in opposite order works. It does:: 
+
+            sage: P.<x> = ZZ[]
+            sage: C = P.completion(x).construction()[0]
+            sage: R = FractionField(P)
+            sage: hasattr(R,'completion')
+            False
+            sage: C(R) is Frac(C(P))
+            True
+            sage: F = R.construction()[0]
+            sage: (C*F)(ZZ['x']) is (F*C)(ZZ['x'])
+            True
+
+        """
+        return isinstance(other,(FractionField,CompletionFunctor))
     
 class QuotientFunctor(ConstructionFunctor):
-    
+    """
+    Construction functor for quotient rings.
+
+    NOTE:
+
+    The functor keeps track of variable names.
+
+    EXAMPLE::
+
+        sage: P.<x,y> = ZZ[]
+        sage: Q = P.quo([x^2+y^2]*P)
+        sage: F = Q.construction()[0]
+        sage: F(QQ['x','y'])
+        Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2)
+        sage: F(QQ['x','y']) == QQ['x','y'].quo([x^2+y^2]*QQ['x','y'])
+        True
+        sage: F(QQ['x','y','z'])
+        Traceback (most recent call last):
+        ...
+        CoercionException: Can not apply this quotient functor to Multivariate Polynomial Ring in x, y, z over Rational Field
+        sage: F(QQ['y','z'])
+        Traceback (most recent call last):
+        ...
+        TypeError: not a constant polynomial
+    """
     rank = 7
     
-    def __init__(self, I, as_field=False):
+    def __init__(self, I, names=None, as_field=False):
+        """
+        INPUT:
+
+        - ``I``, an ideal (the modulus)
+        - ``names`` (optional string or list of strings), the names for the quotient ring generators
+        - ``as_field`` (optional bool, default false), return the quotient ring as field (if available).
+
+        TESTS::
+
+            sage: from sage.categories.pushout import QuotientFunctor
+            sage: P.<t> = ZZ[]
+            sage: F = QuotientFunctor([5+t^2]*P)
+            sage: F(P)
+            Univariate Quotient Polynomial Ring in tbar over Integer Ring with modulus t^2 + 5
+            sage: F(QQ['t'])
+            Univariate Quotient Polynomial Ring in tbar over Rational Field with modulus t^2 + 5
+            sage: F = QuotientFunctor([5+t^2]*P,names='s')
+            sage: F(P)
+            Univariate Quotient Polynomial Ring in s over Integer Ring with modulus t^2 + 5
+            sage: F(QQ['t'])
+            Univariate Quotient Polynomial Ring in s over Rational Field with modulus t^2 + 5
+            sage: F = QuotientFunctor([5]*ZZ,as_field=True)
+            sage: F(ZZ)
+            Finite Field of size 5
+            sage: F = QuotientFunctor([5]*ZZ)
+            sage: F(ZZ)
+            Ring of integers modulo 5
+
+        """
         Functor.__init__(self, Rings(), Rings()) # much more general...
         self.I = I
+        if names is None:
+            self.names = None
+        elif isinstance(names, basestring):
+            self.names = (names,)
+        else:
+            self.names = tuple(names)
         self.as_field = as_field
+
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TESTS::
+
+            sage: P.<x,y> = ZZ[]
+            sage: Q = P.quo([2+x^2,3*x+y^2])
+            sage: F = Q.construction()[0]; F
+            QuotientFunctor
+            sage: F(QQ['x','y'])     # indirect doctest
+            Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + 2, y^2 + 3*x)
+
+        Note that the ``quo()`` method of a field returns the integer zero.
+        The quotient construction functor, when applied to a field, returns
+        the trivial ring::
+
+            sage: F = ZZ.quo([5]*ZZ).construction()[0]
+            sage: F(QQ) is Integers(1)
+            True
+            sage: QQ.quo(5) is int(0)
+            True
+
+        """
         I = self.I
+        from sage.all import QQ
+        if not I.is_zero():
+            from sage.rings.field import is_Field
+            if is_Field(R):
+                from sage.all import Integers
+                return Integers(1)
         if I.ring() != R:
-            I.base_extend(R)
-        Q = R.quo(I)
+            if I.ring().has_coerce_map_from(R):
+                R = I.ring()
+            else:
+                R = pushout(R,I.ring().base_ring())
+                I = [R(1)*t for t in I.gens()]*R
+        try:
+            Q = R.quo(I,names=self.names)
+        except IndexError: # That may happen!
+            raise CoercionException, "Can not apply this quotient functor to %s"%R
         if self.as_field and hasattr(Q, 'field'):
             Q = Q.field()
         return Q
+
     def __cmp__(self, other):
+        """
+        The types, the names and the moduli are compared.
+
+        TESTS::
+
+            sage: P.<x> = QQ[]
+            sage: F = P.quo([(x^2+1)^2*(x^2-3),(x^2+1)^2*(x^5+3)]).construction()[0]
+            sage: F == loads(dumps(F))
+            True
+            sage: P2.<x,y> = QQ[]
+            sage: F == P2.quo([(x^2+1)^2*(x^2-3),(x^2+1)^2*(x^5+3)]).construction()[0]
+            False
+            sage: P3.<x> = ZZ[]
+            sage: F == P3.quo([(x^2+1)^2*(x^2-3),(x^2+1)^2*(x^5+3)]).construction()[0]
+            True
+        """
         c = cmp(type(self), type(other))
         if c == 0:
+            c = cmp(self.names, other.names)
+        if c == 0:
             c = cmp(self.I, other.I)
         return c
+
     def merge(self, other):
+        """
+        Two quotient functors with coinciding names are merged by taking the gcd of their moduli.
+
+        EXAMPLE::
+
+            sage: P.<x> = QQ[]
+            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
+            sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)])
+            sage: from sage.categories.pushout import pushout
+            sage: pushout(Q1,Q2)    # indirect doctest
+            Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^4 + 2*x^2 + 1
+
+        The following was fixed in trac ticket #8800::
+
+            sage: pushout(GF(5), Integers(5))
+            Finite Field of size 5
+
+        """
+        if type(self)!=type(other):
+            return None
+        if self.names != other.names:
+            return None
         if self == other:
-            return self
+            if self.as_field == other.as_field:
+                return self
+            return QuotientFunctor(self.I, names=self.names, as_field=True) # one of them yields a field!
         try:
             gcd = self.I + other.I
         except (TypeError, NotImplementedError):
-            return None
+            try:
+                gcd = self.I.gcd(other.I)
+            except (TypeError, NotImplementedError):
+                return None
         if gcd.is_trivial() and not gcd.is_zero():
             # quotient by gcd would result in the trivial ring/group/...
             # Rather than create the zero ring, we claim they can't be merged
             # TODO: Perhaps this should be detected at a higher level...
             raise TypeError, "Trivial quotient intersection."
-        return QuotientFunctor(gcd)
+        # GF(p) has a coercion from Integers(p). Hence, merging should
+        # yield a field if either self or other yields a field.
+        return QuotientFunctor(gcd, names=self.names, as_field=self.as_field or other.as_field)
 
 class AlgebraicExtensionFunctor(ConstructionFunctor):
-    
+    """
+    Algebraic extension (univariate polynomial ring modulo principal ideal).
+
+    EXAMPLE::
+
+        sage: K.<a> = NumberField(x^3+x^2+1)
+        sage: F = K.construction()[0]
+        sage: F(ZZ['t'])
+        Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in t over Integer Ring with modulus a^3 + a^2 + 1
+
+    Note that, even if a field is algebraically closed, the algebraic
+    extension will be constructed as the quotient of a univariate
+    polynomial ring::
+
+        sage: F(CC)
+        Univariate Quotient Polynomial Ring in a over Complex Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000
+        sage: F(RR)
+        Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000
+
+    Note that the construction functor of a number field applied to
+    the integers returns an order (not necessarily maximal) of that
+    field, similar to the behaviour of ``ZZ.extension(...)``::
+
+        sage: F(ZZ)
+        Order in Number Field in a with defining polynomial x^3 + x^2 + 1
+
+    This also holds for non-absolute number fields::
+
+        sage: K.<a,b> = NumberField([x^3+x^2+1,x^2+x+1])
+        sage: F = K.construction()[0]
+        sage: O = F(ZZ); O
+        Relative Order in Number Field in a with defining polynomial x^3 + x^2 + 1 over its base field
+
+    Unfortunately, the relative number field is not a unique parent::
+
+        sage: O.ambient() is K
+        False
+        sage: O.ambient() == K
+        True
+
+    """
     rank = 3
     
-    def __init__(self, poly, name, elt=None, embedding=None):
+    def __init__(self, polys, names, embeddings, cyclotomic=None):
+        """
+        INPUT:
+
+        - ``polys``: a list of polynomials
+        - ``names``: a list of strings of the same length as the
+          list ``polys``
+        - ``embeddings``: a list of approximate complex values,
+          determining an embedding of the generators into the
+          complex field, or ``None`` for each generator whose
+          embedding is not prescribed.
+        - ``cyclotomic``: optional integer. If it is provided,
+          application of the functor to the rational field yields
+          a cyclotomic field, rather than just a number field.
+
+        REMARK:
+
+        Currently, an embedding can only be provided for the last
+        generator, and only when the construction functor is applied
+        to the rational field. There will be no error when constructing
+        the functor, but when applying it.
+
+        TESTS::
+
+            sage: from sage.categories.pushout import AlgebraicExtensionFunctor
+            sage: P.<x> = ZZ[]
+            sage: F1 = AlgebraicExtensionFunctor([x^3 - x^2 + 1], ['a'], [None])
+            sage: F2 = AlgebraicExtensionFunctor([x^3 - x^2 + 1], ['a'], [0])
+            sage: F1==F2
+            False
+            sage: F1(QQ)
+            Number Field in a with defining polynomial x^3 - x^2 + 1
+            sage: F1(QQ).coerce_embedding()
+            sage: F2(QQ).coerce_embedding()
+            Generic morphism:
+              From: Number Field in a with defining polynomial x^3 - x^2 + 1
+              To:   Real Lazy Field
+              Defn: a -> -0.7548776662466928?
+            sage: F1(QQ)==F2(QQ)
+            False
+            sage: F1(GF(5))
+            Univariate Quotient Polynomial Ring in a over Finite Field of size 5 with modulus a^3 + 4*a^2 + 1
+            sage: F2(GF(5))
+            Traceback (most recent call last):
+            ...
+            NotImplementedError: ring extension with prescripted embedding is not implemented
+
+        When applying a number field constructor to the ring of
+        integers, an order (not necessarily maximal) of that field is
+        returned, similar to the behaviour of ``ZZ.extension``::
+
+            sage: F1(ZZ)
+            Order in Number Field in a with defining polynomial x^3 - x^2 + 1
+
+        The cyclotomic fields form a special case of number fields
+        with prescribed embeddings::
+
+            sage: C = CyclotomicField(8)
+            sage: F,R = C.construction()
+            sage: F
+            AlgebraicExtensionFunctor
+            sage: R
+            Rational Field
+            sage: F(R)
+            Cyclotomic Field of order 8 and degree 4
+            sage: F(ZZ)
+            Maximal Order in Cyclotomic Field of order 8 and degree 4
+
+        """ 
         Functor.__init__(self, Rings(), Rings())
-        self.poly = poly
-        self.name = name
-        self.elt = elt
-        self.embedding = embedding
+        if not (isinstance(polys,(list,tuple)) and isinstance(names,(list,tuple)) and isinstance(embeddings,(list,tuple))):
+            raise ValueError, "Arguments must be lists or tuples"
+        if not (len(names)==len(polys)==len(embeddings)):
+            raise ValueError, "The three arguments must be of the same length"
+        self.polys = list(polys)
+        self.names = list(names)
+        self.embeddings = list(embeddings)
+        self.cyclotomic = int(cyclotomic) if cyclotomic is not None else None
+
     def _apply_functor(self, R):
-        return R.extension(self.poly, self.name, embedding=self.embedding)
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TESTS::
+
+            sage: K.<a>=NumberField(x^3+x^2+1)
+            sage: F = K.construction()[0]
+            sage: F(ZZ)       # indirect doctest
+            Order in Number Field in a with defining polynomial x^3 + x^2 + 1
+            sage: F(ZZ['t'])  # indirect doctest
+            Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in t over Integer Ring with modulus a^3 + a^2 + 1
+            sage: F(RR)       # indirect doctest
+            Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000
+        """
+        from sage.all import QQ, ZZ, CyclotomicField
+        if self.cyclotomic:
+            if R==QQ:
+                return CyclotomicField(self.cyclotomic)
+            if R==ZZ:
+                return CyclotomicField(self.cyclotomic).maximal_order()
+        if len(self.polys) == 1:
+            return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0])
+        return R.extension(self.polys, self.names, embedding=self.embeddings)
+
     def __cmp__(self, other):
+        """
+        TEST::
+
+            sage: K.<a>=NumberField(x^3+x^2+1)
+            sage: F = K.construction()[0]
+            sage: F == loads(dumps(F))
+            True
+        """
         c = cmp(type(self), type(other))
         if c == 0:
-            c = cmp(self.poly, other.poly)
+            c = cmp(self.polys, other.polys)
         if c == 0:
-            c = cmp(self.embedding, other.embedding)
+            c = cmp(self.embeddings, other.embeddings)
         return c
 
+    def merge(self,other):
+        """
+        Merging with another :class:`AlgebraicExtensionFunctor`.
+
+        INPUT:
+
+        ``other`` -- Construction Functor.
+
+        OUTPUT:
+
+        - If ``self==other``, ``self`` is returned.
+        - If ``self`` and ``other`` are simple extensions
+          and both provide an embedding, then it is tested
+          whether one of the number fields provided by
+          the functors coerces into the other; the functor
+          associated with the target of the coercion is
+          returned. Otherwise, the construction functor
+          associated with the pushout of the codomains
+          of the two embeddings is returned, provided that
+          it is a number field.
+        - Otherwise, None is returned.
+          
+        REMARK:
+
+        Algebraic extension with embeddings currently only
+        works when applied to the rational field. This is
+        why we use the admittedly strange rule above for
+        merging.
+
+        TESTS::
+
+            sage: P.<x> = QQ[]
+            sage: L.<b> = NumberField(x^8-x^4+1, embedding=CDF.0)
+            sage: M1.<c1> = NumberField(x^2+x+1, embedding=b^4-1)
+            sage: M2.<c2> = NumberField(x^2+1, embedding=-b^6)
+            sage: M1.coerce_map_from(M2)
+            sage: M2.coerce_map_from(M1)
+            sage: c1+c2; parent(c1+c2)    #indirect doctest
+            -b^6 + b^4 - 1
+            Number Field in b with defining polynomial x^8 - x^4 + 1
+            sage: from sage.categories.pushout import pushout
+            sage: pushout(M1['x'],M2['x'])
+            Univariate Polynomial Ring in x over Number Field in b with defining polynomial x^8 - x^4 + 1
+
+        In the previous example, the number field ``L`` becomes the pushout
+        of ``M1`` and ``M2`` since both are provided with an embedding into
+        ``L``, *and* since ``L`` is a number field. If two number fields
+        are embedded into a field that is not a numberfield, no merging
+        occurs::
+
+            sage: K.<a> = NumberField(x^3-2, embedding=CDF(1/2*I*2^(1/3)*sqrt(3) - 1/2*2^(1/3)))
+            sage: L.<b> = NumberField(x^6-2, embedding=1.1)
+            sage: L.coerce_map_from(K)
+            sage: K.coerce_map_from(L)
+            sage: pushout(K,L)
+            Traceback (most recent call last):
+            ...
+            CoercionException: ('Ambiguous Base Extension', Number Field in a with defining polynomial x^3 - 2, Number Field in b with defining polynomial x^6 - 2)
+
+        """
+        if not isinstance(other,AlgebraicExtensionFunctor):
+            return None
+        if self == other:
+            return self
+        # This method is supposed to be used in pushout(),
+        # *after* expanding the functors. Hence, we can
+        # assume that both functors have a single variable.
+        # But for being on the safe side...:
+        if len(self.names)!=1 or len(other.names)!=1:
+            return None
+##       We don't accept a forgetful coercion, since, together
+##       with bidirectional coercions between two embedded
+##       number fields, it would yield to contradictions in
+##       the coercion system.
+#        if self.polys==other.polys and self.names==other.names:
+#            # We have a forgetful functor:
+#            if self.embeddings==[None]:
+#                return self
+#            if  other.embeddings==[None]:
+#                return other
+        # ... or we may use the given embeddings:
+        if self.embeddings!=[None] and other.embeddings!=[None]:
+            from sage.all import QQ
+            KS = self(QQ)
+            KO = other(QQ)
+            if KS.has_coerce_map_from(KO):
+                return self
+            if KO.has_coerce_map_from(KS):
+                return other
+            # nothing else helps, hence, we move to the pushout of the codomains of the embeddings
+            try:
+                P = pushout(self.embeddings[0].parent(), other.embeddings[0].parent())
+                from sage.rings.number_field.number_field import is_NumberField
+                if is_NumberField(P):
+                    return P.construction()[0]
+            except CoercionException:
+                return None
+
+    def __mul__(self, other):
+        """
+        Compose construction functors to a composit construction functor, unless one of them is the identity.
+
+        NOTE:
+
+        The product is in functorial notation, i.e., when applying the product to an object
+        then the second factor is applied first.
+
+        TESTS::
+
+            sage: P.<x> = QQ[]
+            sage: K.<a> = NumberField(x^3-5,embedding=0)
+            sage: L.<b> = K.extension(x^2+a)
+            sage: F,R = L.construction()
+            sage: prod(F.expand())(R) == L #indirect doctest
+            True
+
+        """
+        if isinstance(other,IdentityConstructionFunctor):
+            return self
+        if isinstance(other, AlgebraicExtensionFunctor):
+            if set(self.names).intersection(other.names):
+                raise CoercionException, "Overlapping names (%s,%s)" % (self.names, other.names)
+            return AlgebraicExtensionFunctor(self.polys+other.polys, self.names+other.names, self.embeddings+other.embeddings)
+        elif isinstance(other, CompositeConstructionFunctor) \
+              and isinstance(other.all[-1], AlgebraicExtensionFunctor):
+            return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1])
+        else:
+            return CompositeConstructionFunctor(other, self)
+
+    def expand(self):
+        """
+        Decompose the functor `F` into sub-functors, whose product returns `F`.
+
+        EXAMPLES::
+
+            sage: P.<x> = QQ[]
+            sage: K.<a> = NumberField(x^3-5,embedding=0)
+            sage: L.<b> = K.extension(x^2+a)
+            sage: F,R = L.construction()
+            sage: prod(F.expand())(R) == L
+            True
+            sage: K = NumberField([x^2-2, x^2-3],'a')
+            sage: F, R = K.construction()
+            sage: F
+            AlgebraicExtensionFunctor
+            sage: L = F.expand(); L
+            [AlgebraicExtensionFunctor, AlgebraicExtensionFunctor]
+            sage: L[-1](QQ)
+            Number Field in a1 with defining polynomial x^2 - 3
+        """
+        if len(self.polys)==1:
+            return [self]
+        return [AlgebraicExtensionFunctor([self.polys[i]], [self.names[i]], [self.embeddings[i]]) for i in range(len(self.polys))]
+
 class AlgebraicClosureFunctor(ConstructionFunctor):
-
+    """
+    Algebraic Closure.
+
+    EXAMPLE::
+
+        sage: F = CDF.construction()[0]
+        sage: F(QQ)
+        Algebraic Field
+        sage: F(RR)
+        Complex Field with 53 bits of precision
+        sage: F(F(QQ)) is F(QQ)
+        True
+
+    """
     rank = 3
 
     def __init__(self):
+        """
+        TEST::
+
+            sage: from sage.categories.pushout import AlgebraicClosureFunctor
+            sage: F = AlgebraicClosureFunctor()
+            sage: F(QQ)
+            Algebraic Field
+            sage: F(RR)
+            Complex Field with 53 bits of precision
+            sage: F == loads(dumps(F))
+            True
+
+        """
         Functor.__init__(self, Rings(), Rings())
+
     def _apply_functor(self, R):
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TEST::
+
+            sage: F = CDF.construction()[0]
+            sage: F(QQ)       # indirect doctest
+            Algebraic Field
+        """
+        if hasattr(R,'construction'):
+            c = R.construction()
+            if c is not None and c[0]==self:
+                return R
         return R.algebraic_closure()
+
     def merge(self, other):
-        # Algebraic Closure subsumes Algebraic Extension
-        return self
+        """
+        Mathematically, Algebraic Closure subsumes Algebraic Extension.
+        However, it seems that people do want to work with algebraic
+        extensions of ``RR``. Therefore, we dont merge with algebraic extension.
+
+        TEST::
+
+            sage: K.<a>=NumberField(x^3+x^2+1)
+            sage: CDF.construction()[0].merge(K.construction()[0]) is None
+            True
+            sage: CDF.construction()[0].merge(CDF.construction()[0])
+            AlgebraicClosureFunctor
+
+        """
+        if self==other:
+            return self
+        return None
+        # Mathematically, Algebraic Closure subsumes Algebraic Extension.
+        # However, it seems that people do want to work with
+        # algebraic extensions of RR (namely RR/poly*RR). So, we don't do:
+        # if isinstance(other,AlgebraicExtensionFunctor):
+        #     return self
 
 class PermutationGroupFunctor(ConstructionFunctor):
 
@@ -976,7 +2713,7 @@
     def __init__(self, gens):
         """
         EXAMPLES::
-            
+
             sage: from sage.categories.pushout import PermutationGroupFunctor
             sage: PF = PermutationGroupFunctor([PermutationGroupElement([(1,2)])]); PF
             PermutationGroupFunctor[(1,2)]
@@ -987,15 +2724,15 @@
     def __repr__(self):
         """
         EXAMPLES::
-        
+
             sage: P1 = PermutationGroup([[(1,2)]])
             sage: PF, P = P1.construction()
             sage: PF
-            PermutationGroupFunctor[(1,2)]        
+            PermutationGroupFunctor[(1,2)]
         """
         return "PermutationGroupFunctor%s"%self.gens()
 
-    def _apply_functor(self, R):
+    def __call__(self, R):
         """
         EXAMPLES::
 
@@ -1017,11 +2754,13 @@
             [(1,2)]
         """
         return self._gens
-    
+
     def merge(self, other):
         """
+        Merge ``self`` with another construction functor, or return None.
+        
         EXAMPLES::
-        
+
             sage: P1 = PermutationGroup([[(1,2)]])
             sage: PF1, P = P1.construction()
             sage: P2 = PermutationGroup([[(1,3)]])
@@ -1032,91 +2771,168 @@
         if self.__class__ != other.__class__:
             return None
         return PermutationGroupFunctor(self.gens() + other.gens())
-        
-def BlackBoxConstructionFunctor(ConstructionFunctor):
-
+
+class BlackBoxConstructionFunctor(ConstructionFunctor):
+    """
+    Construction functor obtained from any callable object.
+
+    EXAMPLES::
+
+        sage: from sage.categories.pushout import BlackBoxConstructionFunctor
+        sage: FG = BlackBoxConstructionFunctor(gap)
+        sage: FS = BlackBoxConstructionFunctor(singular)
+        sage: FG
+        BlackBoxConstructionFunctor
+        sage: FG(ZZ)
+        Integers
+        sage: FG(ZZ).parent()
+        Gap
+        sage: FS(QQ['t'])
+        //   characteristic : 0
+        //   number of vars : 1
+        //        block   1 : ordering lp
+        //                  : names    t
+        //        block   2 : ordering C
+        sage: FG == FS
+        False
+        sage: FG == loads(dumps(FG))
+        True
+    """
     rank = 100
 
     def __init__(self, box):
+        """
+        TESTS::
+            sage: from sage.categories.pushout import BlackBoxConstructionFunctor
+            sage: FG = BlackBoxConstructionFunctor(gap)
+            sage: FM = BlackBoxConstructionFunctor(maxima)
+            sage: FM == FG
+            False
+            sage: FM == loads(dumps(FM))
+            True
+        """
+        ConstructionFunctor.__init__(self,Objects(),Objects())
         if not callable(box):
             raise TypeError, "input must be callable"
         self.box = box
+
     def _apply_functor(self, R):
-        return box(R)
+        """
+        Apply the functor to an object of ``self``'s domain.
+        
+        TESTS::
+
+            sage: from sage.categories.pushout import BlackBoxConstructionFunctor
+            sage: f = lambda x: x^2
+            sage: F = BlackBoxConstructionFunctor(f)
+            sage: F(ZZ)           # indirect doctest
+            Ambient free module of rank 2 over the principal ideal domain Integer Ring
+
+        """
+        return self.box(R)
+
     def __cmp__(self, other):
-        return self.box == other.box
-        
-        
+        """
+        TESTS::
+            sage: from sage.categories.pushout import BlackBoxConstructionFunctor
+            sage: FG = BlackBoxConstructionFunctor(gap)
+            sage: FM = BlackBoxConstructionFunctor(maxima)
+            sage: FM == FG       # indirect doctest
+            False
+            sage: FM == loads(dumps(FM))
+            True
+        """
+        c = cmp(type(self), type(other))
+        if c == 0:
+            c = cmp(self.box, other.box)
+        #return self.box == other.box
+        return c
+
 def pushout(R, S):
-    """
+    r"""
     Given a pair of Objects R and S, try and construct a 
     reasonable object $Y$ and return maps such that 
     canonically $R \leftarrow Y \rightarrow S$. 
     
-    ALGORITHM: 
-       This incorporates the idea of functors discussed Sage Days 4. 
-       Every object $R$ can be viewed as an initial object and 
-       a series of functors (e.g. polynomial, quotient, extension, 
-       completion, vector/matrix, etc.). Call the series of 
-       increasingly-simple rings (with the associated functors) 
-       the "tower" of $R$. The \code{construction} method is used to
-       create the tower. 
-       
-       Given two objects $R$ and $S$, try and find a common initial
-       object $Z$. If the towers of $R$ and $S$ meet, let $Z$ be their
-       join. Otherwise, see if the top of one coerces naturally into
-       the other. 
-       
-       Now we have an initial object and two \emph{ordered} lists of 
-       functors to apply. We wish to merge these in an unambiguous order, 
-       popping elements off the top of one or the other tower as we 
-       apply them to $Z$. 
-       
-       - If the functors are distinct types, there is an absolute ordering 
-           given by the rank attribute. Use this. 
-       - Otherwise:
-          - If the tops are equal, we (try to) merge them.
-          - If \emph{exactly} one occurs lower in the other tower
-              we may unambiguously apply the other (hoping for a later merge).
-          - If the tops commute, we can apply either first.
-          - Otherwise fail due to ambiguity.
+    ALGORITHM:
+    
+    This incorporates the idea of functors discussed Sage Days 4. 
+    Every object $R$ can be viewed as an initial object and 
+    a series of functors (e.g. polynomial, quotient, extension, 
+    completion, vector/matrix, etc.). Call the series of 
+    increasingly-simple rings (with the associated functors) 
+    the "tower" of $R$. The \code{construction} method is used to
+    create the tower. 
+
+    Given two objects $R$ and $S$, try and find a common initial
+    object $Z$. If the towers of $R$ and $S$ meet, let $Z$ be their
+    join. Otherwise, see if the top of one coerces naturally into
+    the other. 
+
+    Now we have an initial object and two \emph{ordered} lists of 
+    functors to apply. We wish to merge these in an unambiguous order, 
+    popping elements off the top of one or the other tower as we 
+    apply them to $Z$. 
+
+    - If the functors are distinct types, there is an absolute ordering 
+      given by the rank attribute. Use this.
+
+    - Otherwise:
+
+      - If the tops are equal, we (try to) merge them.
+
+      - If \emph{exactly} one occurs lower in the other tower
+        we may unambiguously apply the other (hoping for a later merge).
+
+      - If the tops commute, we can apply either first.
+
+      - Otherwise fail due to ambiguity.
               
     EXAMPLES:
-        Here our "towers" are $R = Complete_7(Frac(\Z)$ and $Frac(Poly_x(\Z))$, which give us $Frac(Poly_x(Complete_7(Frac(\Z)))$
-            sage: from sage.categories.pushout import pushout
-            sage: pushout(Qp(7), Frac(ZZ['x']))
-            Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20
-            
-        Note we get the same thing with
-            sage: pushout(Zp(7), Frac(QQ['x']))
-            Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20
-            sage: pushout(Zp(7)['x'], Frac(QQ['x']))
-            Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20            
-
-        Note that polynomial variable ordering must be unambiguously determined. 
-            sage: pushout(ZZ['x,y,z'], QQ['w,z,t'])
-            Traceback (most recent call last):
-            ...
-            CoercionException: ('Ambiguous Base Extension', Multivariate Polynomial Ring in x, y, z over Integer Ring, Multivariate Polynomial Ring in w, z, t over Rational Field)
-            sage: pushout(ZZ['x,y,z'], QQ['w,x,z,t'])
-            Multivariate Polynomial Ring in w, x, y, z, t over Rational Field
-
-        Some other examples
-            sage: pushout(Zp(7)['y'], Frac(QQ['t'])['x,y,z'])
-            Multivariate Polynomial Ring in x, y, z over Fraction Field of Univariate Polynomial Ring in t over 7-adic Field with capped relative precision 20
-            sage: pushout(ZZ['x,y,z'], Frac(ZZ['x'])['y'])
-            Multivariate Polynomial Ring in y, z over Fraction Field of Univariate Polynomial Ring in x over Integer Ring
-            sage: pushout(MatrixSpace(RDF, 2, 2), Frac(ZZ['x']))
-            Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in x over Real Double Field
-            sage: pushout(ZZ, MatrixSpace(ZZ[['x']], 3, 3))
-            Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring
-            sage: pushout(QQ['x,y'], ZZ[['x']])
-            Univariate Polynomial Ring in y over Power Series Ring in x over Rational Field
-            sage: pushout(Frac(ZZ['x']), QQ[['x']])
-            Laurent Series Ring in x over Rational Field
-
-    AUTHORS: 
-       -- Robert Bradshaw
+    
+    Here our "towers" are $R = Complete_7(Frac(\ZZ)$ and $Frac(Poly_x(\ZZ))$,
+    which give us $Frac(Poly_x(Complete_7(Frac(\ZZ)))$::
+
+        sage: from sage.categories.pushout import pushout
+        sage: pushout(Qp(7), Frac(ZZ['x']))
+        Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20
+
+    Note we get the same thing with
+    ::
+    
+        sage: pushout(Zp(7), Frac(QQ['x']))
+        Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20
+        sage: pushout(Zp(7)['x'], Frac(QQ['x']))
+        Fraction Field of Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 20            
+
+    Note that polynomial variable ordering must be unambiguously determined.
+    ::
+    
+        sage: pushout(ZZ['x,y,z'], QQ['w,z,t'])
+        Traceback (most recent call last):
+        ...
+        CoercionException: ('Ambiguous Base Extension', Multivariate Polynomial Ring in x, y, z over Integer Ring, Multivariate Polynomial Ring in w, z, t over Rational Field)
+        sage: pushout(ZZ['x,y,z'], QQ['w,x,z,t'])
+        Multivariate Polynomial Ring in w, x, y, z, t over Rational Field
+
+    Some other examples::
+    
+        sage: pushout(Zp(7)['y'], Frac(QQ['t'])['x,y,z'])
+        Multivariate Polynomial Ring in x, y, z over Fraction Field of Univariate Polynomial Ring in t over 7-adic Field with capped relative precision 20
+        sage: pushout(ZZ['x,y,z'], Frac(ZZ['x'])['y'])
+        Multivariate Polynomial Ring in y, z over Fraction Field of Univariate Polynomial Ring in x over Integer Ring
+        sage: pushout(MatrixSpace(RDF, 2, 2), Frac(ZZ['x']))
+        Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in x over Real Double Field
+        sage: pushout(ZZ, MatrixSpace(ZZ[['x']], 3, 3))
+        Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring
+        sage: pushout(QQ['x,y'], ZZ[['x']])
+        Univariate Polynomial Ring in y over Power Series Ring in x over Rational Field
+        sage: pushout(Frac(ZZ['x']), QQ[['x']])
+        Laurent Series Ring in x over Rational Field
+
+    AUTHORS:
+    
+    -- Robert Bradshaw
     """
     if R is S or R == S:
         return R
@@ -1218,7 +3034,7 @@
                     elif Sc[-1] in Rc:
                         all = Rc.pop() * all
                     # If, perchance, the two functors commute, then we may do them in any order. 
-                    elif Rc[-1].commutes(Sc[-1]):
+                    elif Rc[-1].commutes(Sc[-1]) or Sc[-1].commutes(Rc[-1]):
                         all = Sc.pop() * Rc.pop() * all
                     else:
                         # try and merge (default merge is failure for unequal functors)
@@ -1244,22 +3060,24 @@
 
     
 def pushout_lattice(R, S):
-    """
-    Given a pair of Objects R and S, try and construct a 
+    r"""
+    Given a pair of Objects $R$ and $S$, try and construct a 
     reasonable object $Y$ and return maps such that 
     canonically $R \leftarrow Y \rightarrow S$. 
     
-    ALGORITHM: 
-       This is based on the model that arose from much discussion at Sage Days 4. 
-       Going up the tower of constructions of $R$ and $S$ (e.g. the reals
-       come from the rationals come from the integers) try and find a 
-       common parent, and then try and fill in a lattice with these 
-       two towers as sides with the top as the common ancestor and 
-       the bottom will be the desired ring. 
+    ALGORITHM:
+    
+    This is based on the model that arose from much discussion at Sage Days 4. 
+    Going up the tower of constructions of $R$ and $S$ (e.g. the reals
+    come from the rationals come from the integers) try and find a 
+    common parent, and then try and fill in a lattice with these 
+    two towers as sides with the top as the common ancestor and 
+    the bottom will be the desired ring. 
+
+    See the code for a specific worked-out example. 
        
-       See the code for a specific worked-out example. 
-       
-    EXAMPLES: 
+    EXAMPLES::
+
         sage: from sage.categories.pushout import pushout_lattice
         sage: A, B = pushout_lattice(Qp(7), Frac(ZZ['x']))
         sage: A.codomain()
@@ -1271,7 +3089,9 @@
         Identity endomorphism of Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring
        
     AUTHOR: 
-       -- Robert Bradshaw
+
+    - Robert Bradshaw
+
     """
     R_tower = construction_tower(R)
     S_tower = construction_tower(S)
@@ -1357,8 +3177,15 @@
                         lattice[i+1,j+1] = Rc[i](lattice[i,j+1])
                         Sc[j] = None # force us to use pre-applied Sc[i]
             except (AttributeError, NameError):
-                print i, j
-                pp(lattice)
+                # print i, j
+                # pp(lattice)
+                for i in range(100):
+                    for j in range(100):
+                        try:
+                            R = lattice[i,j]
+                            print i, j, R
+                        except KeyError:
+                            break
                 raise CoercionException, "%s does not support %s" % (lattice[i,j], 'F')
             
     # If we are successful, we should have something that looks like this.
@@ -1397,19 +3224,39 @@
     return R_map, S_map
     
     
-def pp(lattice):
+## def pp(lattice):
+##     """
+##     Used in debugging to print the current lattice.
+##     """
+##     for i in range(100):
+##         for j in range(100):
+##             try:
+##                 R = lattice[i,j]
+##                 print i, j, R
+##             except KeyError:
+##                 break
+
+def construction_tower(R):
     """
-    Used in debugging to print the current lattice.
+    An auxiliary function that is used in :func:`pushout` and :func:`pushout_lattice`.
+
+    INPUT:
+
+    An object
+
+    OUTPUT:
+
+    A constructive description of the object from scratch, by a list of pairs
+    of a construction functor and an object to which the construction functor
+    is to be applied. The first pair is formed by ``None`` and the given object.
+
+    EXAMPLE::
+
+        sage: from sage.categories.pushout import construction_tower
+        sage: construction_tower(MatrixSpace(FractionField(QQ['t']),2))
+        [(None, Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in t over Rational Field), (MatrixFunctor, Fraction Field of Univariate Polynomial Ring in t over Rational Field), (FractionField, Univariate Polynomial Ring in t over Rational Field), (Poly[t], Rational Field), (FractionField, Integer Ring)]
+
     """
-    for i in range(100):
-        for j in range(100):
-            try:
-                R = lattice[i,j]
-                print i, j, R
-            except KeyError:
-                break
-
-def construction_tower(R):
     tower = [(None, R)]
     c = R.construction()
     while c is not None:
@@ -1423,6 +3270,31 @@
 
 
 def type_to_parent(P):
+    """
+    An auxiliary function that is used in :func:`pushout`.
+
+    INPUT:
+
+    A type
+
+    OUTPUT:
+
+    A Sage parent structure corresponding to the given type
+
+    TEST::
+    
+        sage: from sage.categories.pushout import type_to_parent
+        sage: type_to_parent(int)
+        Integer Ring
+        sage: type_to_parent(float)
+        Real Double Field
+        sage: type_to_parent(complex)
+        Complex Double Field
+        sage: type_to_parent(list)
+        Traceback (most recent call last):
+        ...
+        TypeError: Not a scalar type.
+    """
     import sage.rings.all
     if P in [int, long]:
         return sage.rings.all.ZZ
diff -r b4e473888eb9 -r 1a7c8feb901d sage/groups/perm_gps/permgroup.py
--- a/sage/groups/perm_gps/permgroup.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/groups/perm_gps/permgroup.py	Wed Jul 21 14:25:41 2010 +0100
@@ -341,7 +341,7 @@
         if gens is None:
             self._gap_string = gap_group if isinstance(gap_group, str) else str(gap_group)
             self._gens = self._gens_from_gap()
-            return
+            return None
 
         gens = [self._element_class()(x, check=False).list() for x in gens]
         self._deg = max([0]+[max(g) for g in gens])
@@ -1111,8 +1111,13 @@
         EXAMPLES::
         
             sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]])
-            sage: G.random_element()
-            (1,2)(4,5)
+            sage: a = G.random_element()
+            sage: a in G
+            True
+            sage: a.parent() is G
+            True
+            sage: a^6
+            ()
         """
         current_randstate().set_seed_gap()
 
diff -r b4e473888eb9 -r 1a7c8feb901d sage/matrix/matrix0.pyx
--- a/sage/matrix/matrix0.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/matrix/matrix0.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -3769,13 +3769,13 @@
             [ 6 11]
             sage: parent(d)
             Full MatrixSpace of 2 by 2 dense matrices over Rational Field
-            sage: d = b*c; d
+            sage: d = b+c
             Traceback (most recent call last):
             ...
-            TypeError: unsupported operand parent(s) for '*': 'Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7' and 'Full MatrixSpace of 2 by 2 dense matrices over Rational Field'
-            sage: d = b*c.change_ring(GF(7)); d
-            [2 3]
-            [6 4]
+            TypeError: unsupported operand parent(s) for '+': 'Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7' and 'Full MatrixSpace of 2 by 2 dense matrices over Rational Field'
+            sage: d = b+c.change_ring(GF(7)); d
+            [0 2]
+            [4 6]
         
         EXAMPLE of matrix times matrix where one matrix is sparse and the
         other is dense (in such mixed cases, the result is always dense)::
diff -r b4e473888eb9 -r 1a7c8feb901d sage/modules/free_module.py
--- a/sage/modules/free_module.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/modules/free_module.py	Wed Jul 21 14:25:41 2010 +0100
@@ -136,6 +136,8 @@
 
 - Niles Johnson (2010-08): Trac #3893: ``random_element()`` should pass on ``*args`` and ``**kwds``.
 
+- Simon King (2010-12): Trac #8800: Fixing a bug in ``denominator()``.
+
 """
 
 ###########################################################################
@@ -349,7 +351,7 @@
         if not isinstance(sparse,bool):
             raise TypeError, "Argument sparse (= %s) must be True or False" % sparse
 
-        if not base_ring.is_commutative():
+        if not (hasattr(base_ring,'is_commutative') and base_ring.is_commutative()):
             raise TypeError, "The base_ring must be a commutative ring."
 
         if not sparse and isinstance(base_ring,sage.rings.real_double.RealDoubleField_class):
@@ -596,6 +598,8 @@
             (VectorFunctor, Multivariate Polynomial Ring in x0, x1, x2 over Rational Field)
         """
         from sage.categories.pushout import VectorFunctor
+        if hasattr(self,'_inner_product_matrix'):
+            return VectorFunctor(self.rank(), self.is_sparse(),self.inner_product_matrix()), self.base_ring()
         return VectorFunctor(self.rank(), self.is_sparse()), self.base_ring()
 
     # FIXME: what's the level of generality of FreeModuleHomspace?
@@ -4891,21 +4895,22 @@
         
         EXAMPLES::
         
-            sage: V = QQ^3                                                                        
-            sage: L = V.span([[1,1/2,1/3], [-1/5,2/3,3]],ZZ)                                      
-            sage: L                                                                               
-            Free module of degree 3 and rank 2 over Integer Ring                                  
-            Echelon basis matrix:                                                                 
-            [ 1/5 19/6 37/3]                                                                      
-            [   0 23/6 46/3]                                                                      
+            sage: V = QQ^3 
+            sage: L = V.span([[1,1/2,1/3], [-1/5,2/3,3]],ZZ) 
+            sage: L
+            Free module of degree 3 and rank 2 over Integer Ring
+            Echelon basis matrix:
+            [ 1/5 19/6 37/3]
+            [   0 23/6 46/3]
             sage: L._denominator(L.echelonized_basis_matrix().list())
             30
+
         """
         if len(B) == 0:
             return 1
-        d = sage.rings.integer.Integer(B[0].denominator())
+        d = sage.rings.integer.Integer((hasattr(B[0],'denominator') and B[0].denominator()) or 1)
         for x in B[1:]:
-            d = d.lcm(x.denominator())
+            d = d.lcm((hasattr(x,'denominator') and x.denominator()) or 1)
         return d
     
     def _repr_(self):
diff -r b4e473888eb9 -r 1a7c8feb901d sage/modules/free_module_element.pyx
--- a/sage/modules/free_module_element.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/modules/free_module_element.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -1498,13 +1498,24 @@
             70
             sage: 2*5*7
             70
+
+        TESTS:
+
+        The following was fixed in trac ticket #8800::
+
+            sage: M = GF(5)^3
+            sage: v = M((4,0,2))
+            sage: v.denominator()
+            1
+
         """
         R = self.base_ring()
         if self.degree() == 0: return 1
         x = self.list()
-        d = x[0].denominator()
+        # it may be that the marks do not have a denominator!
+        d = x[0].denominator() if hasattr(x[0],'denominator') else 1
         for y in x:
-            d = d.lcm(y.denominator())
+            d = d.lcm(y.denominator()) if hasattr(y,'denominator') else d
         return d
         
     def dict(self, copy=True):
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/integer_ring.pyx
--- a/sage/rings/integer_ring.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/integer_ring.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -713,7 +713,8 @@
             Relative Order in Number Field in a with defining polynomial x^2 + 1 over its base field
         """
         if embedding is not None:
-            raise NotImplementedError
+            if embedding!=[None]*len(embedding):
+                raise NotImplementedError
         from sage.rings.number_field.order import EquationOrder
         return EquationOrder(poly, names)
 
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/number_field/number_field.py
--- a/sage/rings/number_field/number_field.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/number_field/number_field.py	Wed Jul 21 14:25:41 2010 +0100
@@ -369,9 +369,8 @@
           To:   Number Field in b with defining polynomial x^6 - x^2 + 1/10
           Defn: a -> b^2
     
-    The ``QuadraticField`` and
-    ``CyclotomicField`` constructors create an embedding by
-    default unless otherwise specified.
+    The ``QuadraticField`` and ``CyclotomicField`` constructors
+    create an embedding by default unless otherwise specified.
     
     ::
     
@@ -419,6 +418,15 @@
         sage: W.<a> = NumberField(x^2 + 1); W
         Number Field in a with defining polynomial x^2 + 1 over its base field
 
+    The following has been fixed in trac ticket #8800::
+
+        sage: P.<x> = QQ[]
+        sage: K.<a> = NumberField(x^3-5,embedding=0)
+        sage: L.<b> = K.extension(x^2+a)
+        sage: F, R = L.construction()
+        sage: F(R) == L    # indirect doctest
+        True
+
     """
     if name is None and names is None:
         raise TypeError, "You must specify the name of the generator."
@@ -426,7 +434,7 @@
         name = names
 
     if isinstance(polynomial, (list, tuple)):
-        return NumberFieldTower(polynomial, name)
+        return NumberFieldTower(polynomial, name, embeddings=embedding)
         
     name = sage.structure.parent_gens.normalize_names(1, name)
 
@@ -1024,6 +1032,76 @@
         embedding = number_field_morphisms.create_embedding_from_approx(self, embedding)
         self._populate_coercion_lists_(embedding=embedding)
 
+    def construction(self):
+        r"""
+        Construction of self
+
+        EXAMPLE::
+
+            sage: K.<a>=NumberField(x^3+x^2+1,embedding=CC.gen())
+            sage: F,R = K.construction()
+            sage: F
+            AlgebraicExtensionFunctor
+            sage: R
+            Rational Field
+            sage: F(R) == K
+            True
+
+        Note that, if a number field is provided with an embedding,
+        the construction functor applied to the rationals is not
+        necessarily identic with the number field. The reason is
+        that the construction functor uses a value for the embedding
+        that is equivalent, but not necessarily equal, to the one
+        provided in the definition of the number field::
+
+            sage: F(R) is K
+            False
+            sage: F.embeddings
+            [0.2327856159383841? + 0.7925519925154479?*I]
+
+        TEST::
+
+            sage: K.<a> = NumberField(x^3+x+1)
+            sage: R.<t> = ZZ[]
+            sage: a+t     # indirect doctest
+            t + a
+            sage: (a+t).parent()
+            Univariate Polynomial Ring in t over Number Field in a with defining polynomial x^3 + x + 1
+
+        The construction works for non-absolute number fields as well::
+
+            sage: K.<a,b,c>=NumberField([x^3+x^2+1,x^2+1,x^7+x+1])
+            sage: F,R = K.construction()
+            sage: F(R) == K
+            True
+
+        ::
+
+            sage: P.<x> = QQ[]
+            sage: K.<a> = NumberField(x^3-5,embedding=0)
+            sage: L.<b> = K.extension(x^2+a)
+            sage: a*b
+            a*b
+
+        """
+        from sage.categories.pushout import AlgebraicExtensionFunctor
+        from sage.all import QQ
+        if self.is_absolute():
+            return (AlgebraicExtensionFunctor([self.polynomial()], [self.variable_name()], [None if self.coerce_embedding() is None else self.coerce_embedding()(self.gen())]), QQ)
+        names = self.variable_names()
+        polys = []
+        embeddings = []
+        K = self
+        while (1):
+            if K.is_absolute():
+                break
+            polys.append(K.relative_polynomial())
+            embeddings.append(None if K.coerce_embedding() is None else K.coerce_embedding()(self.gen()))
+            K = K.base_field()
+        polys.append(K.relative_polynomial())
+        embeddings.append(None if K.coerce_embedding() is None else K.coerce_embedding()(K.gen()))
+        return (AlgebraicExtensionFunctor(polys, names, embeddings), QQ) 
+
     def _element_constructor_(self, x):
         r"""
         Make x into an element of this number field, possibly not canonically.
@@ -4422,13 +4500,15 @@
             ...
             ValueError: Fractional ideal (5) is not a prime ideal
         """
+        from sage.rings.number_field.number_field_ideal import is_NumberFieldIdeal
+        if is_NumberFieldIdeal(prime) and prime.number_field() is not self:
+            raise ValueError, "%s is not an ideal of %s"%(prime,self)
         # This allows principal ideals to be specified using a generator:
         try:
             prime = self.ideal(prime)
         except TypeError:
             pass
 
-        from sage.rings.number_field.number_field_ideal import is_NumberFieldIdeal
         if not is_NumberFieldIdeal(prime) or prime.number_field() is not self:
             raise ValueError, "%s is not an ideal of %s"%(prime,self)
         if check and not prime.is_prime():
@@ -4880,23 +4960,50 @@
         """
         Coerce a number field element x into this number field.
 
-        In most cases this currently doesn't work (since it is
-        barely implemented) -- it only works for constants.
+        REMARK:
+
+        The name of this method was chosen for historical reasons.
+        In fact, what it does is not a coercion but a conversion.
 
         INPUT:
-            x -- an element of some number field
-
-        EXAMPLES:
+
+        ``x`` -- an element of some number field
+
+        ASSUMPTION:
+
+        ``x`` should be an element of a number field whose underlying
+        polynomial ring allows conversion into the polynomial ring of
+        ``self``.
+
+        Note that it is only tested that there is a method
+        ``x.polynomial()`` yielding an output that can be converted
+        into ``self.polynomial_ring()``.
+
+        OUTPUT:
+
+        An element of ``self`` corresponding to ``x``.
+
+        EXAMPLES::
+
             sage: K.<a> = NumberField(x^3 + 2)
             sage: L.<b> = NumberField(x^2 + 1)
             sage: K._coerce_from_other_number_field(L(2/3))
-            2/3        
-        """
-        f = x.polynomial()
-        if f.degree() <= 0:
-            return self._element_class(self, f[0])
-        # todo: more general coercion if embedding have been asserted
-        raise TypeError, "Cannot coerce element into this number field"
+            2/3
+
+        TESTS:
+
+        The following was fixed in trac ticket #8800::
+
+            sage: P.<x> = QQ[]
+            sage: K.<a> = NumberField(x^3-5,embedding=0)
+            sage: L.<b> = K.extension(x^2+a)
+            sage: F,R = L.construction()
+            sage: F(R) == L   #indirect doctest
+            True
+
+        """
+        f = self.polynomial_ring()(x.polynomial())
+        return self._element_class(self, f)
     
     def _coerce_non_number_field_element_in(self, x):
         """
@@ -4985,10 +5092,15 @@
 
     def _coerce_map_from_(self, R):
         """
-        Canonical coercion of x into self.
-
-        Currently integers, rationals, and this field itself coerce
-        canonically into this field. 
+        Canonical coercion of a ring R into self.
+
+        Currently any ring coercing into the base ring canonically coerces
+        into this field, as well as orders in any number field coercing into
+        this field, and of course the field itself as well.
+
+        Two embedded number fields may mutually coerce into each other, if
+        the pushout of the two ambient fields exists and if it is possible
+        to construct an :class:`~sage.rings.number_field.number_field_morphisms.EmbeddedNumberFieldMorphism`.
 
         EXAMPLES::
 
@@ -5004,7 +5116,8 @@
             sage: S.coerce(y) is y
             True
 
-        Fields with embeddings into an ambient field coerce naturally.
+        Fields with embeddings into an ambient field coerce naturally by the given embedding::
+
             sage: CyclotomicField(15).coerce(CyclotomicField(5).0 - 17/3)
             zeta15^3 - 17/3
             sage: K.<a> = CyclotomicField(16)
@@ -5016,29 +5129,58 @@
               To:   Number Field in a with defining polynomial x^2 + 3
               Defn: zeta3 -> 1/2*a - 1/2
 
-        There are situations for which one might imagine canonical
-        coercion could make sense (at least after fixing choices), but
-        which aren't yet implemented:
+        Two embedded number fields with mutual coercions (testing against a
+        bug that was fixed in trac ticket #8800)::
+
+            sage: K.<r4> = NumberField(x^4-2)
+            sage: L1.<r2_1> = NumberField(x^2-2, embedding = r4**2)
+            sage: L2.<r2_2> = NumberField(x^2-2, embedding = -r4**2)
+            sage: r2_1+r2_2    # indirect doctest
+            0
+            sage: (r2_1+r2_2).parent() is L1
+            True
+            sage: (r2_2+r2_1).parent() is L2
+            True
+
+        Coercion of an order (testing against a bug that was fixed in
+        trac ticket #8800)::
+
+            sage: K.has_coerce_map_from(L1)
+            True
+            sage: L1.has_coerce_map_from(K)
+            False
+            sage: K.has_coerce_map_from(L1.maximal_order())
+            True
+            sage: L1.has_coerce_map_from(K.maximal_order())
+            False
+
+        There are situations for which one might imagine conversion
+        could make sense (at least after fixing choices), but of course
+        there will be no coercion from the Symbolic Ring to a Number Field::
+
             sage: K.<a> = QuadraticField(2)
             sage: K.coerce(sqrt(2))
             Traceback (most recent call last):
             ...
             TypeError: no canonical coercion from Symbolic Ring to Number Field in a with defining polynomial x^2 - 2
 
-        TESTS:
+        TESTS::
+
             sage: K.<a> = NumberField(polygen(QQ)^3-2)
             sage: type(K.coerce_map_from(QQ))
             <type 'sage.structure.coerce_maps.DefaultConvertMap_unique'>
             
-        Make sure we still get our optimized morphisms for special fields:
+        Make sure we still get our optimized morphisms for special fields::
+
             sage: K.<a> = NumberField(polygen(QQ)^2-2)
             sage: type(K.coerce_map_from(QQ))
             <type 'sage.rings.number_field.number_field_element_quadratic.Q_to_quadratic_field_element'>
+
         """
         if R in [int, long, ZZ, QQ, self.base()]:
             return self._generic_convert_map(R)
         from sage.rings.number_field.order import is_NumberFieldOrder
-        if is_NumberFieldOrder(R) and R.number_field().has_coerce_map_from(self):
+        if is_NumberFieldOrder(R) and self.has_coerce_map_from(R.number_field()):
             return self._generic_convert_map(R)
         if is_NumberField(R) and R != QQ:
             if R.coerce_embedding() is not None:
@@ -5047,9 +5189,23 @@
                         from sage.categories.pushout import pushout
                         ambient_field = pushout(R.coerce_embedding().codomain(), self.coerce_embedding().codomain())
                         if ambient_field is not None:
+                            try:
+                                # the original ambient field
+                                return number_field_morphisms.EmbeddedNumberFieldMorphism(R, self, ambient_field)
+                            except ValueError: # no embedding found
+                                # there might be one in the alg. completion
+                                return number_field_morphisms.EmbeddedNumberFieldMorphism(R, self, ambient_field.algebraic_closure() if hasattr(ambient_field,'algebraic_closure') else ambient_field)
+                    except (ValueError, TypeError, sage.structure.coerce_exceptions.CoercionException),msg:
+                        # no success with the pushout
+                        try:
                             return number_field_morphisms.EmbeddedNumberFieldMorphism(R, self)
-                    except (TypeError, ValueError):
-                        pass
+                        except (TypeError, ValueError):
+                            pass
+                else:
+                    # R is embedded, self isn't. So, we could only have
+                    # the forgetful coercion. But this yields to non-commuting
+                    # coercions, as was pointed out at ticket #8800
+                    return None
 
     def _magma_init_(self, magma):
         """
@@ -6540,6 +6696,11 @@
         """
         return NumberField_cyclotomic_v1, (self.__n, self.variable_name(), self.gen_embedding())
 
+    def construction(self):
+        F,R = NumberField_generic.construction(self)
+        F.cyclotomic = self.__n
+        return F,R
+
     def _magma_init_(self, magma):
         """
         Function returning a string to create this cyclotomic field in
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/number_field/number_field_element.pyx
--- a/sage/rings/number_field/number_field_element.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/number_field/number_field_element.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -4315,6 +4315,9 @@
             ...
             TypeError: Cannot coerce element into this number field
         """
+        from sage.all import parent
+        if not self.__K.has_coerce_map_from(parent(x)):
+            raise TypeError, "Cannot coerce element into this number field"
         return self.__W.coordinates(self.__to_V(self.__K(x)))
     
     def __cmp__(self, other):
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/number_field/number_field_ideal.py
--- a/sage/rings/number_field/number_field_ideal.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/number_field/number_field_ideal.py	Wed Jul 21 14:25:41 2010 +0100
@@ -241,11 +241,24 @@
             '\\left(17\\right)'
         """
         return '\\left(%s\\right)'%(", ".join(map(latex.latex, self._gens_repr())))
-       
+
     def __cmp__(self, other):
         """
         Compare an ideal of a number field to something else.
 
+        REMARK:
+
+        By default, comparing ideals is the same as comparing
+        their generator list. But of course, different generators
+        can give rise to the same ideal. And this can easily
+        be detected using Hermite normal form.
+
+        Unfortunately, there is a difference between "cmp" and
+        "==": In the first case, this method is directly called.
+        In the second case, it is only called *after coercion*.
+        However, we ensure that "cmp(I,J)==0" and "I==J" will
+        always give the same answer for number field ideals.
+
         EXAMPLES::
 
             sage: K.<a> = NumberField(x^2 + 3); K
@@ -262,9 +275,29 @@
             True
             sage: f[1][0] == GF(7)(5)
             False
+
+        TESTS::
+
+            sage: L.<b> = NumberField(x^8-x^4+1)
+            sage: F_2 = L.fractional_ideal(b^2-1)
+            sage: F_4 = L.fractional_ideal(b^4-1)
+            sage: F_2 == F_4
+            True
+
         """
         if not isinstance(other, NumberFieldIdeal):
+            # this can only occur with cmp(,)
             return cmp(type(self), type(other))
+        if self.parent()!=other.parent():
+            # again, this can only occur if cmp(,)
+            # is called
+            if self==other:
+                return 0
+            c = cmp(self.pari_hnf(), other.pari_hnf())
+            if c: return c
+            return cmp(self.parent(),other.parent())
+        # We can now assume that both have the same parent,
+        # even if originally cmp(,) was called.
         return cmp(self.pari_hnf(), other.pari_hnf())
 
     def coordinates(self, x):
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/number_field/number_field_morphisms.pyx
--- a/sage/rings/number_field/number_field_morphisms.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/number_field/number_field_morphisms.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -109,6 +109,23 @@
     This allows one to go from one number field in another consistently, 
     assuming they both have specified embeddings into an ambient field
     (by default it looks for an embedding into `\CC`). 
+
+    EXAMPLES::
+
+        sage: K.<i> = NumberField(x^2+1,embedding=QQbar(I))
+        sage: L.<i> = NumberField(x^2+1,embedding=-QQbar(I))
+        sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism
+        sage: EmbeddedNumberFieldMorphism(K,L,CDF)
+        Generic morphism:
+          From: Number Field in i with defining polynomial x^2 + 1
+          To:   Number Field in i with defining polynomial x^2 + 1
+          Defn: i -> -i
+        sage: EmbeddedNumberFieldMorphism(K,L,QQbar)
+        Generic morphism:
+          From: Number Field in i with defining polynomial x^2 + 1
+          To:   Number Field in i with defining polynomial x^2 + 1
+          Defn: i -> -i
+
     """
     cdef readonly ambient_field
 
@@ -191,11 +208,11 @@
             sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldConversion
             sage: K.<a> = NumberField(x^2-17, embedding=4.1)
             sage: L.<b> = NumberField(x^4-17, embedding=2.0)
-            sage: f = EmbeddedNumberFieldConversion(L, K)
-            sage: f(b^2)
-            a
-            sage: f(L(a/2-11))
-            1/2*a - 11
+            sage: f = EmbeddedNumberFieldConversion(K, L)
+            sage: f(a)
+            b^2
+            sage: f(K(b^2/2-11))
+            1/2*b^2 - 11
         """
         if ambient_field is None:
             from sage.rings.complex_double import CDF
@@ -269,6 +286,10 @@
                 return r
     else:
         # since things are inexact, try and pick the closest one
+        # -- unless the ambient field is inexact and has no prec(),
+        # which holds, e.g., for the symbolic ring
+        if not hasattr(ambient_field,'prec'):
+            return None
         if max_prec is None:
             max_prec = ambient_field.prec() * 32
         while ambient_field.prec() < max_prec:
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/polynomial/polynomial_quotient_ring.py
--- a/sage/rings/polynomial/polynomial_quotient_ring.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/polynomial/polynomial_quotient_ring.py	Wed Jul 21 14:25:41 2010 +0100
@@ -234,18 +234,18 @@
     def __reduce__(self):
         return PolynomialQuotientRing_generic, (self.__ring, self.__polynomial, self.variable_names())
 
-    def __call__(self, x):
+    def _element_constructor_(self, x):
         """
-        Coerce x into this quotient ring. Anything that can be coerced into
-        the polynomial ring can be coerced into the quotient.
+        Convert x into this quotient ring. Anything that can be converted into
+        the polynomial ring can be converted into the quotient.
         
         INPUT:
         
         
-        -  ``x`` - object to be coerced
+        -  ``x`` - object to be converted
         
         
-        OUTPUT: an element obtained by coercing x into this ring.
+        OUTPUT: an element obtained by converting x into this ring.
         
         EXAMPLES::
         
@@ -263,16 +263,60 @@
             alpha + 1
             sage: S(S.gen()^10+1)
             90*alpha^2 - 109*alpha + 28
+
+        TESTS:
+
+        Conversion should work even if there is no coercion.
+        This was fixed in trac ticket #8800::
+
+            sage: P.<x> = QQ[]
+            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
+            sage: Q = P.quo([(x^2+1)^2])
+            sage: Q1.has_coerce_map_from(Q)
+            False
+            sage: Q1(Q.gen())
+            xbar
+
         """
         if isinstance(x, PolynomialQuotientRingElement):
             P = x.parent()
             if P is self:
                 return x
-            elif P == self:
-                return PolynomialQuotientRingElement(self, self.__ring(x.lift()), check=False)
+            return PolynomialQuotientRingElement(self, self.__ring(x.lift()), check=False)
         return PolynomialQuotientRingElement(
                         self, self.__ring(x) , check=True)
 
+    def _coerce_map_from_(self, R):
+        """
+        Anything coercing into ``self``'s polynomial ring coerces into ``self``.
+        Any quotient polynomial ring whose polynomial ring coerces into
+        ``self``'s polynomial ring and whose modulus is divided by the modulus
+        of ``self`` coerces into ``self``.
+
+        AUTHOR:
+
+        - Simon King (2010-12): Trac ticket #8800
+
+        TESTS::
+
+            sage: P5.<x> = GF(5)[]
+            sage: Q = P5.quo([(x^2+1)^2])
+            sage: P.<x> = ZZ[]
+            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
+            sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)])
+            sage: Q.has_coerce_map_from(Q1)  #indirect doctest
+            True
+            sage: Q1.has_coerce_map_from(Q)
+            False
+            sage: Q1.has_coerce_map_from(Q2)
+            False
+
+        """
+        if self.__ring.has_coerce_map_from(R):
+            return True
+        if isinstance(R, PolynomialQuotientRing_generic):
+            return self.__ring.has_coerce_map_from(R.polynomial_ring()) and self.__polynomial.divides(R.modulus())
+
     def _is_valid_homomorphism_(self, codomain, im_gens):
         try:
             # We need that elements of the base ring of the polynomial
@@ -367,6 +411,29 @@
         return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s"%(
             self.variable_name(), self.base_ring(), self.modulus())
 
+    def construction(self):
+        """
+        Functorial construction of ``self``
+
+        EXAMPLES::
+
+            sage: P.<t>=ZZ[]
+            sage: Q = P.quo(5+t^2)
+            sage: F, R = Q.construction()
+            sage: F(R) == Q
+            True
+            sage: P.<t> = GF(3)[]
+            sage: Q = P.quo([2+t^2])
+            sage: F, R = Q.construction()
+            sage: F(R) == Q
+            True
+
+        AUTHOR:
+
+        -- Simon King (2010-05)
+        """
+        from sage.categories.pushout import QuotientFunctor
+        return QuotientFunctor([self.modulus()]*self.base(),self.variable_names(),self.is_field()), self.base()
 
     def base_ring(self):
         r"""
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/qqbar.py
--- a/sage/rings/qqbar.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/qqbar.py	Wed Jul 21 14:25:41 2010 +0100
@@ -848,6 +848,17 @@
         """
         return self
     
+    def construction(self):
+        """
+        EXAMPLE::
+
+            sage: QQbar.construction()
+            (AlgebraicClosureFunctor, Rational Field)
+        """
+        from sage.categories.pushout import AlgebraicClosureFunctor
+        from sage.all import QQ
+        return (AlgebraicClosureFunctor(), QQ)
+
     def gens(self):
         return(QQbar_I, )
 
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/quotient_ring.py
--- a/sage/rings/quotient_ring.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/quotient_ring.py	Wed Jul 21 14:25:41 2010 +0100
@@ -249,7 +249,14 @@
         from sage.categories.pushout import QuotientFunctor
         # Is there a better generic way to distinguish between things like Z/pZ as a field and Z/pZ as a ring?
         from sage.rings.field import Field
-        return QuotientFunctor(self.__I, as_field=isinstance(self, Field)), self.__R
+        try:
+            names = self.variable_names()
+        except ValueError:
+            try:
+                names = self.cover_ring().variable_names()
+            except ValueError:
+                names = None
+        return QuotientFunctor(self.__I, names=names, as_field=isinstance(self, Field)), self.__R
 
     def _repr_(self):
         """
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/residue_field.pyx
--- a/sage/rings/residue_field.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/residue_field.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -160,7 +160,8 @@
 class ResidueFieldFactory(UniqueFactory):
     """
     A factory that returns the residue class field of a prime ideal p
-    of the ring of integers of a number field, or of a polynomial ring over a finite field.
+    of the ring of integers of a number field, or of a polynomial ring
+    over a finite field.
 
     INPUT:
     
@@ -296,12 +297,13 @@
         
     def create_object(self, version, key, **kwds):
         p, names, impl = key
+        pring = p.ring()
 
-        if p.ring() is ZZ:
+        if pring is ZZ:
             return ResidueFiniteField_prime_modn(p, names, p.gen(), None, None, None)
-        if is_PolynomialRing(p.ring()):
-            K = p.ring().fraction_field()
-            Kbase = p.ring().base_ring()
+        if is_PolynomialRing(pring):
+            K = pring.fraction_field()
+            Kbase = pring.base_ring()
             f = p.gen()
             if f.degree() == 1 and Kbase.is_prime_field() and (impl is None or impl == 'modn'):
                 return ResidueFiniteField_prime_modn(p, None, Kbase.order(), None, None, None)
@@ -320,9 +322,9 @@
         if is_NumberFieldIdeal(p):
             characteristic = p.smallest_integer()
         else: # ideal of a function field
-            characteristic = p.ring().base_ring().characteristic()
+            characteristic = pring.base_ring().characteristic()
         # Once we have function fields, we should probably have an if statement here.
-        K = p.ring().fraction_field()
+        K = pring.fraction_field()
         #OK = K.maximal_order() # Need to change to p.order inside the __init__s for the residue fields.
 
         U, to_vs, to_order = p._p_quotient(characteristic)
@@ -454,9 +456,19 @@
 
     def _element_constructor_(self, x):
         """
-        This is called after x fails to coerce into the finite field (without the convert map from the number field).
+        This is called after x fails to convert into ``self`` as
+        abstract finite field (without considering the underlying
+        number field).
 
-        So the strategy is to try to coerce into the number field, and then use the convert map.
+        So the strategy is to try to convert into the number field,
+        and then proceed to the residue field.
+
+        NOTE:
+
+        The behaviour of this method was changed in trac ticket #8800.
+        Before, an error was raised if there was no coercion. Now,
+        a conversion is possible even when there is no coercion.
+        This is like for different finite fields.
 
         EXAMPLES::
 
@@ -467,17 +479,49 @@
             sage: F = OK.residue_field(P)
             sage: ResidueField_generic._element_constructor_(F, i)
             8
+
+        With ticket #8800, we also have::
+
             sage: ResidueField_generic._element_constructor_(F, GF(13)(8))
-            Traceback (most recent call last):
-            ...
-            TypeError: cannot coerce <type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
+            8
 
-            #sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7)
-            #sage: k.<a> = P.residue_field()
-            #sage: ResidueField_generic._element_constructor_(k, t)
-            #a
-            #sage: ResidueField_generic._element_constructor_(k, GF(17)(4))
-            #4
+        Here is a test that was temporarily removed, but newly introduced
+        in ticket #8800::
+
+            sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + t^2 + 7)
+            sage: k.<a> = P.residue_field()
+            sage: k(t)
+            a
+            sage: k(GF(17)(4))
+            4
+
+        In the remaining tests, we elaborate a bit more on the difference of
+        coercion and conversion::
+
+            sage: K.<r4> = NumberField(x^4-2)
+            sage: L.<r4> = NumberField(x^4-2, embedding=CDF.0)
+            sage: FK = K.fractional_ideal(K.0)
+            sage: FL = L.fractional_ideal(L.0)
+
+        There is no coercion from the embedded to the unembedded
+        number field. Hence, the two fractional ideals are different.
+        By consequence, the resulting residue fields are different::
+
+            sage: RL = ResidueField(FL)
+            sage: RK = ResidueField(FK)
+            sage: RK == RL
+            False
+
+        Since ``RL`` is defined with the embedded number field ``L``, there
+        is no coercion from the maximal order of ``K`` to ``RL``. However,
+        conversion is possible::
+
+            sage: OK = K.maximal_order()
+            sage: RL.has_coerce_map_from(OK)
+            False
+            sage: RL(OK.1)
+            0
+
         """
         K = OK = self.p.ring()
         if OK.is_field():
@@ -495,7 +539,10 @@
         elif K.has_coerce_map_from(R):
             x = K(x)
         else:
-            raise TypeError, "cannot coerce %s"%type(x)                
+            try:
+                x = K(x)
+            except (TypeError, ValueError):
+                raise TypeError, "cannot coerce %s"%type(x)                
         return self(x)
 
     def _coerce_map_from_(self, R):
diff -r b4e473888eb9 -r 1a7c8feb901d sage/rings/ring.pyx
--- a/sage/rings/ring.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/rings/ring.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -1245,6 +1245,12 @@
         - ``poly`` -- A polynomial whose coefficients are coercible into self
         - ``name`` -- (optional) name for the root of f
             
+        NOTE:
+
+        Using this method on an algebraically complete field does *not*
+        return this field; the construction self[x] / (f(x)) is done
+        anyway.
+
         EXAMPLES::
         
             sage: R = QQ['x']
@@ -1272,7 +1278,7 @@
         if name is None:
             name = str(poly.parent().gen(0))
         if embedding is not None:
-            raise NotImplementedError
+            raise NotImplementedError, "ring extension with prescripted embedding is not implemented"
         R = self[name]
         I = R.ideal(R(poly.list()))
         return R.quotient(I, name)
diff -r b4e473888eb9 -r 1a7c8feb901d sage/schemes/elliptic_curves/ell_local_data.py
--- a/sage/schemes/elliptic_curves/ell_local_data.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/schemes/elliptic_curves/ell_local_data.py	Wed Jul 21 14:25:41 2010 +0100
@@ -634,7 +634,7 @@
         - ``cp`` (int) is the Tamagawa number
 
 
-        EXAMPLES (this raised an type error in sage prior to 4.4.4, see ticket #7930) ::
+        EXAMPLES (this raised a type error in sage prior to 4.4.4, see ticket #7930) ::
 
             sage: E = EllipticCurve('99d1')
                           
@@ -651,15 +651,13 @@
 
         EXAMPLES:
 
-        The following example shows that the bug at #9324 is fixed:
+        The following example shows that the bug at #9324 is fixed::
 
             sage: K.<a> = NumberField(x^2-x+6)
             sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006])
             sage: E.conductor() # indirect doctest
             Fractional ideal (18, 6*a)
 
-        
-
         """
         E = self._curve
         P = self._prime
@@ -692,9 +690,26 @@
 
         pval = lambda x: x.valuation(prime)
         pdiv = lambda x: x.is_zero() or pval(x) > 0
-        pinv = lambda x: F.lift(~F(x))
-        proot = lambda x,e: F.lift(F(x).nth_root(e, extend = False, all = True)[0])
-        preduce = lambda x: F.lift(F(x))
+        # Since ResidueField is cached in a way that
+        # does not care much about embeddings of number
+        # fields, it can happen that F.p.ring() is different
+        # from K. This is a problem: If F.p.ring() has no
+        # embedding but K has, then there is no coercion
+        # from F.p.ring().maximal_order() to K. But it is
+        # no problem to do an explicit conversion in that
+        # case (Simon King, trac ticket #8800).
+        
+        from sage.categories.pushout import pushout, CoercionException
+        try:
+            if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ
+                _tmp_ = pushout(F.p.ring().maximal_order(),K)
+            pinv = lambda x: F.lift(~F(x))
+            proot = lambda x,e: F.lift(F(x).nth_root(e, extend = False, all = True)[0])
+            preduce = lambda x: F.lift(F(x))
+        except CoercionException: # the pushout does not exist, we need conversion
+            pinv = lambda x: K(F.lift(~F(x)))
+            proot = lambda x,e: K(F.lift(F(x).nth_root(e, extend = False, all = True)[0]))
+            preduce = lambda x: K(F.lift(F(x)))
 
         def _pquadroots(a, b, c):
             r"""
diff -r b4e473888eb9 -r 1a7c8feb901d sage/schemes/elliptic_curves/ell_number_field.py
--- a/sage/schemes/elliptic_curves/ell_number_field.py	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/schemes/elliptic_curves/ell_number_field.py	Wed Jul 21 14:25:41 2010 +0100
@@ -1908,10 +1908,10 @@
 
             sage: K.<i> = QuadraticField(-1)
             sage: E1 = EllipticCurve([i + 1, 0, 1, -240*i - 400, -2869*i - 2627])
-            sage: E1.conductor()                                                 
+            sage: E1.conductor()
             Fractional ideal (-7*i + 4)
-            sage: E2 = EllipticCurve([1+i,0,1,0,0])                              
-            sage: E2.conductor()                                                 
+            sage: E2 = EllipticCurve([1+i,0,1,0,0])
+            sage: E2.conductor()
             Fractional ideal (-7*i + 4)
             sage: E1.is_isogenous(E2)
             Traceback (most recent call last):
diff -r b4e473888eb9 -r 1a7c8feb901d sage/structure/coerce.pyx
--- a/sage/structure/coerce.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/structure/coerce.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -355,7 +355,7 @@
         
             sage: import traceback
             sage: cm.exception_stack()
-            [(<class 'sage.structure.coerce_exceptions.CoercionException'>, CoercionException(AttributeError("'IdealMonoid_c_with_category' object has no attribute 'base_extend'",),), <traceback object at ...>), (<type 'exceptions.TypeError'>, TypeError("no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 3'",), <traceback object at ...>)]
+            [(<type 'exceptions.TypeError'>, TypeError('No coercion from Rational Field to pushout Ring of integers modulo 1',), <traceback object at ...>), (<type 'exceptions.TypeError'>, TypeError("no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 3'",), <traceback object at ...>)]
             sage: print ''.join(sum([traceback.format_exception(*info) for info in cm.exception_stack()], []))
             Traceback (most recent call last):
             ...
diff -r b4e473888eb9 -r 1a7c8feb901d sage/structure/parent.pyx
--- a/sage/structure/parent.pyx	Tue Mar 08 15:10:11 2011 +0100
+++ b/sage/structure/parent.pyx	Wed Jul 21 14:25:41 2010 +0100
@@ -909,7 +909,7 @@
             mor = <map.Map>mor_ptr
         else:
             mor = <map.Map>self.convert_map_from(R)
-            
+
         if mor is not None:
             if no_extra_args:
                 return mor._call_(x)
@@ -1649,7 +1649,20 @@
         usually denotes a special relationship (e.g. sub-objects, choice of
         completion, etc.)
 
-        EXAMPLES: 
+        EXAMPLES::
+
+            sage: K.<a>=NumberField(x^3+x^2+1,embedding=1)
+            sage: K.coerce_embedding()
+            Generic morphism:
+              From: Number Field in a with defining polynomial x^3 + x^2 + 1
+              To:   Real Lazy Field
+              Defn: a -> -1.465571231876768?
+            sage: K.<a>=NumberField(x^3+x^2+1,embedding=CC.gen())
+            sage: K.coerce_embedding()
+            Generic morphism:
+              From: Number Field in a with defining polynomial x^3 + x^2 + 1
+              To:   Complex Lazy Field
+              Defn: a -> 0.2327856159383841? + 0.7925519925154479?*I
         """
         return self._embedding
             
@@ -1808,7 +1821,7 @@
             return self.coerce_map_from(S._type)
         if self._coerce_from_hash is None: # this is because parent.__init__() does not always get called
             self.init_coerce(False)
-        cdef object ret
+        #cdef object ret
         try:
             return self._coerce_from_hash[S]
         except KeyError:
