Ticket #7643: trac_7643.patch

File trac_7643.patch, 23.4 KB (added by Francis Clarke, 13 years ago)

based on 4.3.rc0

  • sage/rings/number_field/number_field.py

    # HG changeset patch
    # User Francis Clarke <F.Clarke@Swansea.ac.uk>
    # Date 1260823202 0
    # Node ID e839322b0afc60fb94d29d3e617f9ee50ee07c2c
    # Parent  964c2f4ce74db0417a771de0b0cfc951b1fab73c
    Improved composita
    
    diff -r 964c2f4ce74d -r e839322b0afc sage/rings/number_field/number_field.py
    a b  
    166166    from sage.categories.fields import Fields
    167167    return codomain in Fields()
    168168
     169from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs
     170
    169171def proof_flag(t):
    170172    """
    171173    Used for easily determining the correct proof flag to use.
     
    25482550    def composite_fields(self, other, names=None, both_maps=False, preserve_embedding=True):
    25492551        """
    25502552        List of all possible composite number fields formed from self and
    2551         other, as well as possibly embeddings into the compositum.  See the
    2552         documentation for both_maps below.
    2553 
    2554         If preserve_embedding is ``True`` and if self and other *both* have
    2555         embeddings into the same ambient field, only compositums respecting
    2556         both embeddings are returned.  If one (or both) of self or other does
    2557         not have an embedding, or they do not have embeddings into the same
    2558         ambient field, or preserve_embedding is not ``True`` all possible
    2559         composite number fields are returned.
     2553        other, together with (optionally) embeddings into the compositum;
     2554        see the documentation for both_maps below.
     2555
     2556        If preserve_embedding is True and if self and other both have
     2557        embeddings into the same ambient field, or into fields which are
     2558        contained in a common field, only the compositum respecting
     2559        both embeddings is returned.  If one (or both) of self or other
     2560        does not have an embedding or preserve_embedding is False,
     2561        all possible composite number fields are returned.
    25602562
    25612563        INPUT:
    25622564           
     
    25642566
    25652567        - ``names`` - generator name for composite fields
    25662568
    2567         - ``both_maps`` - (default: False)  if True, return quadruples (F,
    2568           self_into_F, other_into_F, k) such that self_into_F maps self into
    2569           F, other_into_F maps other into F, and k is an integer such that
    2570           other_into_F(other.gen()) + k*self_into_F(self.gen()) == F.gen()
    2571 
    2572         - ``preserve_embedding`` - (default: True)  return only compositums with
    2573           compatible ambient embeddings.
     2569        - ``both_maps`` - (default: False)  if True, return quadruples
     2570          (F, self_into_F, other_into_F, k) such that self_into_F is an
     2571          embedding of self in F, other_into_F is an embedding of in F,
     2572          and k is an integer such that F.gen() equals
     2573          other_into_F(other.gen()) + k*self_into_F(self.gen())
     2574          If both self and other have embeddings into an ambient field, then
     2575          F will have an embedding with respect to which both self_into_F
     2576          and other_into_F will be compatible with the ambient embeddings.
     2577
     2578        - ``preserve_embedding`` - (default: True) if self and other have
     2579          ambient embeddings, then return only the compatible compositum.
    25742580       
    25752581        OUTPUT:
    25762582       
    2577        
    25782583        -  ``list`` - list of the composite fields, possibly with maps.
    25792584       
    25802585       
     
    25822587       
    25832588            sage: K.<a> = NumberField(x^4 - 2)
    25842589            sage: K.composite_fields(K)
     2590            [Number Field in a0 with defining polynomial x^4 - 162,
     2591             Number Field in a1 with defining polynomial x^8 + 28*x^4 + 2500]
     2592       
     2593        A particular compositum is selected, together with compatible maps
     2594        into the compositum, if the fields are endowed with a real or
     2595        complex embedding::
     2596
     2597            sage: K1 = NumberField(x^4 - 2, 'a', embedding=RR(2^(1/4)))
     2598            sage: K2 = NumberField(x^4 - 2, 'a', embedding=RR(-2^(1/4)))
     2599            sage: K1.composite_fields(K2)
     2600            [Number Field in a0 with defining polynomial x^4 - 162]
     2601            sage: [F, f, g, k], = K1.composite_fields(K2, both_maps=True); F
     2602            Number Field in a0 with defining polynomial x^4 - 162
     2603            sage: f(K1.0), g(K2.0)
     2604            (-1/3*a0, 1/3*a0)
     2605
     2606        With preserve_embedding set to False, the embeddings are ignored::
     2607
     2608            sage: K1.composite_fields(K2, preserve_embedding=False)
    25852609            [Number Field in a0 with defining polynomial x^4 - 162,
    2586              Number Field in a1 with defining polynomial x^4 - 2,
    2587              Number Field in a2 with defining polynomial x^8 + 28*x^4 + 2500]
    2588             sage: k.<a> = NumberField(x^3 + 2)
    2589             sage: m.<b> = NumberField(x^3 + 2)
    2590             sage: k.composite_fields(m, 'c')
    2591             [Number Field in c0 with defining polynomial x^3 - 2,
    2592              Number Field in c1 with defining polynomial x^6 - 40*x^3 + 1372]
    2593 
    2594         Let's get the maps as well::
    2595 
    2596             sage: Q1.<a> = NumberField(x^2 + 2, 'b').extension(x^2 + 3, 'c').absolute_field()
    2597             sage: Q2.<b> = NumberField(x^2 + 3, 'a').extension(x^2 + 5, 'c').absolute_field()
    2598             sage: Q1.composite_fields(Q2)
    2599             [Number Field in ab0 with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600,
    2600              Number Field in ab1 with defining polynomial x^8 + 160*x^6 + 6472*x^4 + 74880*x^2 + 1296]
    2601 
    2602             sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, both_maps=True)[0]
    2603             sage: F
    2604             Number Field in ab0 with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600
     2610             Number Field in a1 with defining polynomial x^8 + 28*x^4 + 2500]
     2611
     2612        Changing the embedding selects a different compositum::
     2613
     2614            sage: K3 = NumberField(x^4 - 2, 'a', embedding=CC(2^(1/4)*I))
     2615            sage: [F, f, g, k], = K1.composite_fields(K3, both_maps=True); F
     2616            Number Field in a0 with defining polynomial x^8 + 28*x^4 + 2500
     2617            sage: f(K1.0), g(K3.0)
     2618            (1/240*a0^5 - 41/120*a0, 1/120*a0^5 + 19/60*a0)
     2619
     2620        If no embeddings are specified, the maps into the composite are chosen arbitrarily::
     2621
     2622            sage: Q1.<a> = NumberField(x^4 + 10*x^2 + 1)
     2623            sage: Q2.<b> = NumberField(x^4 + 16*x^2 + 4)
     2624            sage: Q1.composite_fields(Q2, 'c')
     2625            [Number Field in c with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600]
     2626            sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, 'c', both_maps=True)[0]
    26052627            sage: Q1_into_F
    26062628            Ring morphism:
    26072629              From: Number Field in a with defining polynomial x^4 + 10*x^2 + 1
    2608               To:   Number Field in ab0 with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600
    2609               Defn: a |--> 19/14400*ab0^7 + 137/1800*ab0^5 + 2599/3600*ab0^3 + 8/15*ab0
    2610             sage: Q2_into_F
    2611             Ring morphism:
    2612               From: Number Field in b with defining polynomial x^4 + 16*x^2 + 4
    2613               To:   Number Field in ab0 with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600
    2614               Defn: b |--> 19/7200*ab0^7 + 137/900*ab0^5 + 2599/1800*ab0^3 + 31/15*ab0
    2615 
    2616             sage: Q1_into_F.domain() is Q1
    2617             True
    2618             sage: Q2_into_F(b) + k*Q1_into_F(a) == F.gen()
    2619             True
    2620 
    2621         Let's check something about the "other" composite field::
    2622 
    2623             sage: F, Q1_into_F, Q2_into_F, k = Q1.composite_fields(Q2, both_maps=True)[1]
    2624             sage: Q1_into_F.domain() is Q1
    2625             True
    2626             sage: Q2_into_F(b) + k*Q1_into_F(a) == F.gen()
    2627             True
     2630              To:   Number Field in c with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600
     2631              Defn: a |--> 19/14400*c^7 + 137/1800*c^5 + 2599/3600*c^3 + 8/15*c
     2632
     2633        This is just one of four embeddings of Q1 into F::
     2634            sage: Hom(Q1, F).order()
     2635            4
    26282636
    26292637        TESTS:
    26302638
     
    26342642            sage: K0.<b> = CyclotomicField(7, 'a').subfields(3)[0][0].change_names()
    26352643            sage: K1.<a1> = K0.extension(x^2 - 2*b^2, 'a1').absolute_field()
    26362644            sage: K2.<a2> = K0.extension(x^2 - 3*b^2, 'a2').absolute_field()
    2637             sage: K1
    2638             Number Field in a1 with defining polynomial x^6 - 10*x^4 + 24*x^2 - 8
    2639             sage: K2
    2640             Number Field in a2 with defining polynomial x^6 - 15*x^4 + 54*x^2 - 27
    2641             sage: K1.is_isomorphic(K2)
    2642             False
    26432645
    26442646        We need embeddings, so we redefine::
    26452647
    26462648            sage: L1.<a1> = NumberField(K1.polynomial(), 'a1', embedding=CC.0)
    2647             sage: CDF(a1)
    2648             -0.629384245426
    26492649            sage: L2.<a2> = NumberField(K2.polynomial(), 'a2', embedding=CC.0)
    2650             sage: CDF(a2)
    2651             -0.77083512672
     2650            sage: [CDF(a1), CDF(a2)]
     2651            [-0.629384245426, -0.77083512672]
     2652
     2653        and we get the same embeddings via the compositum::
    26522654
    26532655            sage: F, L1_into_F, L2_into_F, k = L1.composite_fields(L2, both_maps=True)[0]
    2654             sage: CDF(F.gen())
    2655             -0.141450881294
    2656 
    2657         Both subfield generators have correct embeddings::
    2658 
    2659             sage: CDF(L1_into_F(L1.gen())), CDF(L1.gen())
    2660             (-0.629384245426, -0.629384245426)
    2661             sage: CDF(L2_into_F(L2.gen())), CDF(L2.gen())
    2662             (-0.77083512672, -0.77083512672)
    2663 
    2664         On the other hand, without embeddings, there are more composite fields::
    2665 
    2666             sage: M1.<a1> = NumberField(L1.polynomial(), 'a1')
    2667             sage: M2.<a2> = NumberField(L2.polynomial(), 'a2')
    2668             sage: M1.composite_fields(M2)
    2669             [Number Field in a1a20 with defining polynomial x^12 - 50*x^10 + 613*x^8 - 1270*x^6 + 526*x^4 - 60*x^2 + 1,
    2670              Number Field in a1a21 with defining polynomial x^12 - 50*x^10 + 865*x^8 - 6730*x^6 + 24970*x^4 - 43152*x^2 + 27889,
    2671              Number Field in a1a22 with defining polynomial x^12 - 50*x^10 + 865*x^8 - 6310*x^6 + 18670*x^4 - 14928*x^2 + 1849]
    2672 
    2673         Here's another example::
    2674 
    2675             sage: Q1.<a> = NumberField(x^4 + 10*x^2 + 1, embedding=CC.0); Q1, CDF(a)
    2676             (Number Field in a with defining polynomial x^4 + 10*x^2 + 1, 0.317837245196*I)
    2677             sage: Q2.<b> = NumberField(x^4 + 16*x^2 + 4, embedding=CC.0); Q2, CDF(b)
    2678             (Number Field in b with defining polynomial x^4 + 16*x^2 + 4, 0.504017169931*I)
    2679 
    2680             sage: len(Q1.composite_fields(Q2))
    2681             1
    2682             sage: F, Q1_into_F, Q2_into_F, k2 = Q1.composite_fields(Q2, both_maps=True)[0]
    2683             sage: F, CDF(F.gen())
    2684             (Number Field in ab1 with defining polynomial x^8 + 160*x^6 + 6472*x^4 + 74880*x^2 + 1296,
    2685              -0.131657320461*I)
    2686 
    2687             sage: t = Q2_into_F(Q2.gen()) + k2*Q1_into_F(Q1.gen()); t, CDF(t)
    2688             (ab1, -0.131657320461*I)
    2689             sage: abs(t.minpoly()(CDF(t))) < 1e-8
    2690             True
    2691 
    2692         Let's check that the preserve_embedding flag is respected::
    2693        
    2694             sage: len(Q1.composite_fields(Q2))
    2695             1
    2696             sage: len(Q1.composite_fields(Q2, preserve_embedding=False))
    2697             2
     2656            sage: [CDF(L1_into_F(L1.gen())), CDF(L2_into_F(L2.gen()))]
     2657            [-0.629384245426, -0.77083512672]
    26982658
    26992659        Let's check that if only one field has an embedding, the resulting
    2700         fields do not have an embedding::
    2701        
    2702             sage: Q2.<b> = NumberField(x^4 + 16*x^2 + 4)
    2703             sage: Q2.coerce_embedding() is None
    2704             True
    2705 
    2706             sage: Q1.composite_fields(Q2)
    2707             [Number Field in ab0 with defining polynomial x^8 + 64*x^6 + 904*x^4 + 3840*x^2 + 3600,
    2708              Number Field in ab1 with defining polynomial x^8 + 160*x^6 + 6472*x^4 + 74880*x^2 + 1296]
    2709             sage: Q1.composite_fields(Q2)[0].coerce_embedding() is None
    2710             True
    2711         """
    2712         if names is None:
    2713             sv = self.variable_name(); ov = other.variable_name()
    2714             names = sv + (ov if ov != sv else "")
     2660        fields do not have embeddings::
     2661       
     2662            sage: L1.composite_fields(K2)[0].coerce_embedding() is None
     2663            True
     2664            sage: L2.composite_fields(K1)[0].coerce_embedding() is None
     2665            True
     2666
     2667        We check that other can be a relative number field::
     2668       
     2669            sage: L.<a, b> = NumberField([x^3 - 5, x^2 + 3])       
     2670            sage: CyclotomicField(3, 'w').composite_fields(L, both_maps=True)
     2671            [(Number Field in wa with defining polynomial x^6 - 3*x^5 + 6*x^4 - 17*x^3 + 21*x^2 + 12*x + 16, Ring morphism:
     2672              From: Cyclotomic Field of order 3 and degree 2
     2673              To:   Number Field in wa with defining polynomial x^6 - 3*x^5 + 6*x^4 - 17*x^3 + 21*x^2 + 12*x + 16
     2674              Defn: w |--> -1/36*wa^5 + 5/36*wa^4 - 5/18*wa^3 + 25/36*wa^2 - 35/36*wa - 5/9, Relative number field morphism:
     2675              From: Number Field in a with defining polynomial x^3 - 5 over its base field
     2676              To:   Number Field in wa with defining polynomial x^6 - 3*x^5 + 6*x^4 - 17*x^3 + 21*x^2 + 12*x + 16
     2677              Defn: a |--> 1/36*wa^5 - 5/36*wa^4 + 5/18*wa^3 - 25/36*wa^2 + 71/36*wa - 4/9
     2678                    b |--> 1/18*wa^5 - 5/18*wa^4 + 5/9*wa^3 - 25/18*wa^2 + 35/18*wa + 1/9, -1)]
     2679        """
    27152680        if not isinstance(other, NumberField_generic):
    27162681            raise TypeError, "other must be a number field."
    2717         f = self.pari_polynomial()
    2718         g = other.pari_polynomial()
    2719 
    2720         R = self.absolute_polynomial().parent()
     2682
     2683        sv = self.variable_name(); ov = other.variable_name()
     2684        if names is None:
     2685            names = sv + (ov if ov != sv else "")
    27212686        name = sage.structure.parent_gens.normalize_names(1, names)[0]
    27222687
    27232688        # should we try to preserve embeddings?
     
    27272692        if other.coerce_embedding() is None:
    27282693            subfields_have_embeddings = False
    27292694        if subfields_have_embeddings:
    2730             if self.coerce_embedding().codomain() is not other.coerce_embedding().codomain():
     2695            try:
     2696                from sage.categories.pushout import pushout
     2697                ambient_field = pushout(self.coerce_embedding().codomain(), other.coerce_embedding().codomain())
     2698            except CoercionException:
     2699                ambient_field = None
     2700            if ambient_field is None:
    27312701                subfields_have_embeddings = False
    27322702
     2703        f = self.pari_polynomial()
     2704        g = other.pari_polynomial()
     2705        R = self.absolute_polynomial().parent()
     2706
    27332707        if not both_maps and not subfields_have_embeddings:
    27342708            # short cut!
    2735             C = map(R, f.polcompositum(g))
    2736             return [ NumberField(C[i], name + str(i)) for i in range(len(C)) ]
    2737 
    2738         # If flag = 1, outputs a vector of 4-component vectors [R, a, b,
    2739         # k], where R ranges through the list of all possible compositums
     2709            # eliminate duplicates from the fields given by polcompositum
     2710            # and return the resulting number fields.  There is no need to
     2711            # check that the polynomials are irreducible.
     2712            C = []
     2713            for r in f.polcompositum(g):
     2714                if not any(r.nfisisom(s) for s in C):
     2715                    C.append(r)
     2716            C = map(R, C)
     2717
     2718            if len(C) == 1 and name != sv and name != ov:
     2719                names =[name]
     2720            else:
     2721                names = [name + str(i) for i in range(len(C))]
     2722
     2723            return [ NumberField(r, names[i], check=False) for i, r in enumerate(C) ]
     2724           
     2725        # If flag = 1, polcompositum outputs a vector of 4-component vectors
     2726        # [R, a, b, k], where R ranges through the list of all possible compositums
    27402727        # as above, and a (resp. b) expresses the root of P (resp. Q) as
    27412728        # an element of Q(X )/(R). Finally, k is a small integer such that
    2742         # b + ka = X modulo R.
    2743         C = f.polcompositum(g, 1)
    2744         rets = []
    2745 
    2746         embedding = None
     2729        # b + ka = X modulo R. 
     2730        # In this case duplicates must only be eliminated if embeddings are going
     2731        # to be preserved.
     2732        C = []
     2733        for v in f.polcompositum(g, 1):
     2734            if subfields_have_embeddings or not any(v[0].nfisisom(u[0]) for u in C):
     2735                C.append(v)
     2736       
    27472737        a = self.gen()
    27482738        b = other.gen()
    2749         for i in range(len(C)):
    2750             r, a_in_F, b_in_F, k = C[i]
     2739
     2740        # If both subfields are provided with embeddings, then we must select
     2741        # the compositum which corresponds to these embeddings.  We do this by
     2742        # evaluating the given polynomials at the corresponding embedded values.
     2743        # For the case we want the result will be zero, but rounding errors are
     2744        # difficult to predict, so we just take the field which yields the
     2745        # mimumum value.
     2746        if subfields_have_embeddings:
     2747            poly_vals = []
     2748            for r, _, _, k in C:
     2749                r = R(r)
     2750                k = ZZ(k) # essential
     2751                embedding = other.coerce_embedding()(b) + k*self.coerce_embedding()(a)
     2752                poly_vals.append(sage.rings.complex_double.CDF(r(embedding)).abs())
     2753            i = poly_vals.index(min(poly_vals))
     2754            C = [C[i]]
     2755
     2756        if len(C) == 1 and name != sv and name != ov:
     2757            names =[name]
     2758        else:
     2759            names = [name + str(i) for i in range(len(C))]
     2760
     2761        if both_maps and not other.is_absolute():
     2762            other_abs = other.absolute_field('z')
     2763            _, to_other_abs = other_abs.structure()
     2764
     2765        embedding = None
     2766        rets = []
     2767        for i, [r, a_in_F, b_in_F, k] in enumerate(C):
    27512768            r = R(r)
    2752             k = ZZ(k)
    2753 
     2769            k = ZZ(k) # essential
    27542770            if subfields_have_embeddings:
    27552771                embedding = other.coerce_embedding()(b) + k*self.coerce_embedding()(a)
    2756                 if r(embedding) > 1e-30: # XXX how to do this more generally?
    2757                     continue
    2758 
    2759             F = NumberField(r, name + str(i), embedding=embedding)
    2760             a_in_F = F(a_in_F)
    2761             b_in_F = F(b_in_F)
    2762             into_F1 = self.hom ([a_in_F], check=True)
    2763             into_F2 = other.hom([b_in_F], check=True)
    2764             assert into_F2(b) + k*into_F1(a) == F.gen()
    2765             rets.append( (F, into_F1, into_F2, k) )
    2766 
    2767         if not both_maps:
    2768             return [ F for F, _, _, _ in rets ]
    2769         else:
    2770             return rets
     2772            F = NumberField(r, names[i], check=False, embedding=embedding)
     2773            if both_maps:
     2774                self_to_F = self.hom ([F(a_in_F)])
     2775                if other.is_absolute():
     2776                    other_to_F = other.hom([F(b_in_F)])
     2777                else:
     2778                    other_abs_to_F = other_abs.hom([F(b_in_F)])
     2779                    other_to_F = RelativeNumberFieldHomomorphism_from_abs(other.Hom(F), other_abs_to_F*to_other_abs)
     2780                rets.append( (F, self_to_F, other_to_F, k) )
     2781            else:
     2782                rets.append(F)
     2783        return rets
    27712784
    27722785    def absolute_degree(self):
    27732786        """
  • sage/rings/number_field/number_field_rel.py

    diff -r 964c2f4ce74d -r e839322b0afc sage/rings/number_field/number_field_rel.py
    a b  
    511511            sage: K.<a,b> = NumberField([x^4 + 3, x^2 + 2]); K
    512512            Number Field in a with defining polynomial x^4 + 3 over its base field
    513513            sage: K.galois_closure('c')
    514             Number Field in c with defining polynomial x^16 + 144*x^14 + 8988*x^12 + 329616*x^10 + 7824006*x^8 + 113989680*x^6 + 1360354716*x^4 + 3470308272*x^2 + 9407642049
     514            Number Field in c with defining polynomial x^16 + 16*x^14 + 28*x^12 + 784*x^10 + 19846*x^8 - 595280*x^6 + 2744476*x^4 + 3212848*x^2 + 29953729
    515515        """
    516516        return self.absolute_field('a').galois_closure(names=names)
    517517
     518    def composite_fields(self, other, names=None, both_maps=False, preserve_embedding=True):
     519        """
     520        List of all possible composite number fields formed from self and
     521        other, together with (optionally) embeddings into the compositum;
     522        see the documentation for both_maps below.
     523
     524        Since relative fields do not have ambient embeddings,
     525        preserve_embedding has no effect.  In every case all possible
     526        composite number fields are returned.
     527
     528        INPUT:
     529           
     530        - ``other`` - a number field
     531
     532        - ``names`` - generator name for composite fields
     533
     534        - ``both_maps`` - (default: False)  if True, return quadruples
     535          (F, self_into_F, other_into_F, k) such that self_into_F maps self into
     536          F, other_into_F maps other into F, and k is an integer such that
     537          other_into_F(other.gen()) + k*self_into_F(self.gen()) == F.gen()
     538          If both self and other have embeddings into an ambient field, then
     539          F will have an embedding with respect to which both self_into_F
     540          and other_into_F will be compatible with the ambient embeddings.
     541
     542        - ``preserve_embedding`` - (default: True) has no effect, but is kept
     543          for compatibility with the absolute version of this function.  In every
     544          case the list of all possible compositums is returned.
     545       
     546        OUTPUT:
     547       
     548        -  ``list`` - list of the composite fields, possibly with maps.
     549       
     550       
     551        EXAMPLES::
     552       
     553            sage: K.<a, b> = NumberField([x^2 + 5, x^2 - 2])
     554            sage: L.<c, d> = NumberField([x^2 + 5, x^2 - 3])
     555            sage: K.composite_fields(L)
     556            [Number Field in ac with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600]
     557            sage: K.composite_fields(L, both_maps=True)
     558            [[Number Field in ac with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600,
     559              Relative number field morphism:
     560              From: Number Field in a with defining polynomial x^2 + 5 over its base field
     561             To:   Number Field in ac with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600
     562              Defn: a |--> -9/66560*ac^7 + 11/4160*ac^5 - 241/4160*ac^3 - 101/104*ac
     563                    b |--> -21/166400*ac^7 + 73/20800*ac^5 - 779/10400*ac^3 + 7/260*ac,
     564              Relative number field morphism:
     565              From: Number Field in c with defining polynomial x^2 + 5 over its base field
     566              To:   Number Field in ac with defining polynomial x^8 - 24*x^6 + 464*x^4 + 3840*x^2 + 25600
     567              Defn: c |--> -9/66560*ac^7 + 11/4160*ac^5 - 241/4160*ac^3 - 101/104*ac
     568                    d |--> -3/25600*ac^7 + 7/1600*ac^5 - 147/1600*ac^3 + 1/40*ac,
     569              -2]]
     570        """
     571        if not isinstance(other, NumberField_generic):
     572            raise TypeError, "other must be a number field."
     573        if names is None:
     574            sv = self.variable_name(); ov = other.variable_name()
     575            names = sv + (ov if ov != sv else "")
     576
     577        self_abs = self.absolute_field('w')
     578        abs_composites = self_abs.composite_fields(other, names=names, both_maps=both_maps)
     579
     580        if not both_maps:
     581            return abs_composites
     582
     583        _, to_self_abs = self_abs.structure()
     584
     585        rets = []
     586        for F, self_abs_to_F, other_to_F, k in abs_composites:
     587            self_to_F = RelativeNumberFieldHomomorphism_from_abs(self.Hom(F), self_abs_to_F*to_self_abs)
     588            rets.append([F, self_to_F, other_to_F, k])
     589        return rets
     590
    518591    def absolute_degree(self):
    519592        """
    520593        The degree of this relative number field over the rational field.