# HG changeset patch
# User Francis Clarke <francis.w.clarke@gmail.com>
# Date 1298627770 0
# Node ID 05a4991534ec0c8ac25930628a45d836f63b7795
# Parent  2fcb23bf655ccafad123a763050806d8e1360cb7
#10850 composition and comparison of number-field homomorphisms

diff -r 2fcb23bf655c -r 05a4991534ec sage/rings/morphism.pyx
--- a/sage/rings/morphism.pyx	Thu Feb 24 11:10:54 2011 +0000
+++ b/sage/rings/morphism.pyx	Fri Feb 25 09:56:10 2011 +0000
@@ -657,7 +657,10 @@
         """
         If ``homset`` is a homset of rings and ``right`` is a
         ring homomorphism given by the images of generators,
-        the composition with ``self`` will be of the same type.
+        (indirectly in the case of homomorphisms from relative
+        number fields), the composition with ``self`` will be 
+        of the appropriate type.
+
         Otherwise, a formal composite map is returned.
 
         EXAMPLES::
@@ -672,6 +675,27 @@
               To:   Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
               Defn: x |--> a + b
                     y |--> a - b
+
+        When ``right`` is defined by the images of generators, the
+        result has the type of a homomorphism between its domain and
+        codomain::
+
+            sage: C = CyclotomicField(24)
+            sage: f = End(C)[1]
+            sage: type(f*f) == type(f)
+            True
+       
+        An example where the domain of ``right`` is a relative number field::
+            sage: PQ.<X> = QQ[]
+            sage: K.<a, b> = NumberField([X^2 - 2, X^2 - 3])
+            sage: e, u, v, w = End(K)
+            sage: u*v
+            Relative number field endomorphism of Number Field in a with defining polynomial X^2 - 2 over its base field
+              Defn: a |--> -a
+                    b |--> b
+
+        An example where ``right`` is not a ring homomorphism::
+
             sage: from sage.categories.morphism import SetMorphism
             sage: h = SetMorphism(Hom(R,S,Rings()), lambda p: p[0])
             sage: g*h
@@ -686,17 +710,25 @@
                       From: Multivariate Polynomial Ring in a, b over Rational Field
                       To:   Fraction Field of Multivariate Polynomial Ring in a, b over Rational Field
 
-        AUTHOR:
+        AUTHORS:
 
         -- Simon King (2010-05)
+        -- Francis Clarke (2011-02)
 
         """
         from sage.all import Rings
-        if isinstance(right, RingHomomorphism_im_gens) and homset.homset_category().is_subcategory(Rings()):
-            try:
-                return RingHomomorphism_im_gens(homset, [self(g) for g in right.im_gens()])
-            except ValueError:
-                pass
+        if homset.homset_category().is_subcategory(Rings()):
+            if isinstance(right, RingHomomorphism_im_gens):
+                try:
+                    return homset([self(g) for g in right.im_gens()])
+                except ValueError:
+                    pass
+            from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs
+            if isinstance(right, RelativeNumberFieldHomomorphism_from_abs):
+                try:
+                    return homset(self*right.abs_hom())
+                except ValueError:
+                    pass
         return sage.categories.map.Map._composition_(self, right, homset)
 
     def is_injective(self):
diff -r 2fcb23bf655c -r 05a4991534ec sage/rings/number_field/morphism.py
--- a/sage/rings/number_field/morphism.py	Thu Feb 24 11:10:54 2011 +0000
+++ b/sage/rings/number_field/morphism.py	Fri Feb 25 09:56:10 2011 +0000
@@ -616,6 +616,19 @@
         self.__im_gens = v
         return v
 
+    def __cmp__(self, other):
+        """
+        Compare 
+        EXAMPLES:
+            sage: K.<a, b> = NumberField([x^2 - 2, x^2 - 3])
+            sage: e, u, v, w = End(K)
+            sage: all([u^2 == e, u*v == w, u != e])
+            True
+        """
+        if not isinstance(other, RelativeNumberFieldHomomorphism_from_abs):
+            return cmp(type(self), type(other))
+        return cmp(self.abs_hom(), other.abs_hom())
+
     def _repr_defn(self):
         r"""
         Return a string describing the images of the generators under this map.
