Ticket #6013: trac_6013-relativize.patch

File trac_6013-relativize.patch, 9.0 KB (added by ncalexan, 14 years ago)
  • sage/rings/number_field/number_field.py

    # HG changeset patch
    # User Nick Alexander <ncalexander@gmail.com>
    # Date 1241943060 25200
    # Branch symbolics_switch
    # Node ID 86d2671485b7d2863c32e78e3c8fcf4f11dd0e09
    # Parent  885474e687e4464363d70334fca8da223aaeb3db
    #6013: rewrite number field relativize to be much faster
    
    diff -r 885474e687e4 -r 86d2671485b7 sage/rings/number_field/number_field.py
    a b  
    120120#import order
    121121
    122122from sage.structure.element import is_Element
    123 from sage.categories.map import is_Map
    124123from sage.structure.sequence import Sequence
    125124
    126125import sage.structure.parent_gens
     
    54015400        return a relative number field `K` isomorphic to self that is relative
    54025401        over the absolute field `\QQ(\alpha)` or the domain of `alpha`, along
    54035402        with isomorphisms from `K` to self and from self to `K`.
    5404        
    5405         INPUT:
    5406        
     5403
     5404        INPUT::
    54075405       
    54085406        -  ``alpha`` - an element of self  or an embedding of a subfield into self
    54095407       
     
    54115409           field K and the subfield QQ(alpha) names[0] generators K and
    54125410           names[1] QQ(alpha).
    54135411       
    5414        
    5415         OUTPUT:
    5416        
    5417        
    5418         -  ``K`` - relative number field
    5419        
    5420        
    5421         Also, ``K.structure()`` returns from_K and to_K,
    5422         where from_K is an isomorphism from K to self and to_K is an
    5423         isomorphism from self to K.
    5424        
    5425         EXAMPLES::
    5426        
     5412
     5413        OUTPUT::
     5414
     5415            K   -- relative number field
     5416
     5417        Also, \code{K.structure()} returns from_K and to_K, where
     5418        from_K is an isomorphism from K to self and to_K is an isomorphism
     5419        from self to K.
     5420
     5421        EXAMPLES:
    54275422            sage: K.<a> = NumberField(x^10 - 2)
    54285423            sage: L.<c,d> = K.relativize(a^4 + a^2 + 2); L
    54295424            Number Field in c with defining polynomial x^2 - 1/5*d^4 + 8/5*d^3 - 23/5*d^2 + 7*d - 18/5 over its base field
     
    55015496            Number Field in a1 with defining polynomial x - 1
    55025497            sage: L.base_field().base_field()
    55035498            Rational Field
    5504 
     5499 
    55055500            sage: L = K.relativize(K(2), 'a'); L
    55065501            Number Field in a0 with defining polynomial x^4 + 2*x^2 + 2 over its base field
    55075502            sage: L.base_field()
    55085503            Number Field in a1 with defining polynomial x - 2
    55095504            sage: L.base_field().base_field()
    55105505            Rational Field
     5506
     5507            We can relativize over a relative field:
     5508
     5509            sage: K.<z> = CyclotomicField(16)
     5510            sage: L, L_into_K, _ = K.subfields(4)[0]; L
     5511            Number Field in z0 with defining polynomial x^4 + 16
     5512            sage: F, F_into_L, _ = L.subfields(2)[0]; F
     5513            Number Field in z00 with defining polynomial x^2 + 64
     5514
     5515            sage: L_over_F = L.relativize(F_into_L, 'c'); L_over_F
     5516            Number Field in c0 with defining polynomial x^2 - 1/2*z00 over its base field
     5517            sage: L_over_F_into_L, _ = L_over_F.structure()
     5518
     5519            sage: K_over_rel = K.relativize(L_into_K * L_over_F_into_L, 'a'); K_over_rel
     5520            Number Field in a0 with defining polynomial x^2 - 1/2*c0 over its base field
     5521            sage: K_over_rel.base_field() is L_over_F
     5522            True
     5523            sage: K_over_rel.structure()
     5524            (Relative number field morphism:
     5525              From: Number Field in a0 with defining polynomial x^2 - 1/2*c0 over its base field
     5526              To:   Cyclotomic Field of order 16 and degree 8
     5527              Defn: a0 |--> z
     5528                    c0 |--> 2*z^2
     5529                    z00 |--> 8*z^4, Ring morphism:
     5530              From: Cyclotomic Field of order 16 and degree 8
     5531              To:   Number Field in a0 with defining polynomial x^2 - 1/2*c0 over its base field
     5532              Defn: z |--> a0)
     5533
     5534            We can relativize over a really large field.  This requires great
     5535            care to not factor or do any operation that would trigger a pari
     5536            nfinit() internally.
     5537
     5538            sage: K.<a> = CyclotomicField(3^3*2^3)
     5539            sage: R = K.relativize(a^(3^2), 't'); R
     5540            Number Field in t0 with defining polynomial x^9 - t1 over its base field
     5541            sage: R.structure()
     5542            (Relative number field morphism:
     5543              From: Number Field in t0 with defining polynomial x^9 - t1 over its base field
     5544              To:   Cyclotomic Field of order 216 and degree 72
     5545              Defn: t0 |--> a
     5546                    t1 |--> a^9,
     5547             Ring morphism:
     5548              From: Cyclotomic Field of order 216 and degree 72
     5549              To:   Number Field in t0 with defining polynomial x^9 - t1 over its base field
     5550              Defn: a |--> t0)
    55115551        """
    55125552        # step 1: construct the abstract field generated by alpha.w
    55135553        # step 2: make a relative extension of it.
    55145554        # step 3: construct isomorphisms
     5555        from sage.all import vector, matrix
    55155556
    55165557        names = sage.structure.parent_gens.normalize_names(2, names)
    55175558
     5559        from sage.categories.map import is_Map
    55185560        if is_Map(alpha):
    55195561            # alpha better be a morphism with codomain self
    55205562            if alpha.codomain() != self:
    55215563                raise ValueError, "Co-domain of morphism must be self"
    55225564            L = alpha.domain()
    55235565            alpha = alpha(L.gen()) # relativize over phi's domain
    5524             f = alpha.minpoly()
     5566            f = L.defining_polynomial() # = alpha.minpoly()
    55255567        else:
    55265568            # alpha must be an element coercible to self
    55275569            alpha = self(alpha)
    55285570            f = alpha.minpoly()
    55295571            L = NumberField(f, names[1])
    55305572
    5531         g = self.defining_polynomial()
    5532         h = L['x'](g)
    5533         F = h.factor()
    5534        
    5535         for f, e in F:
    5536             if L.absolute_degree() * f.degree() == self.absolute_degree():
    5537                 M = L.extension(f, names[0])
    5538                 beta = M(L.gen())
    5539                 try:
    5540                     to_M = self.hom([M.gen(0)], M, check=True)  # be paranoid
    5541                 except TypeError:
    5542                     continue
    5543                 if to_M(alpha) == beta:
    5544                     # Bingo.
    5545                     # We have now constructed a relative
    5546                     # number field M, and an isomorphism
    5547                     # self --> M that sends alpha to
    5548                     # the generator of the intermediate field.
    5549                     from_M = M.hom([self.gen()], self, check=True)
    5550                     M._set_structure(from_M, to_M)  # don't have to
    5551                                                     # worry about caching since relative number fields aren't cached.
    5552                     return M
    5553                
    5554         assert False, "bug in relativize"
     5573        # now we do some linear algebra to find the minpoly of self.gen() over L
     5574        L_into_self = L.hom([alpha])
     5575
     5576        extdeg = self.absolute_degree() // L.absolute_degree() # [ L : self ]
     5577        a = self.gen()
     5578
     5579        # we will find a linear relation between small powers of a over L
     5580        basis = [ a**i * b for i in range(extdeg) for b in map(L_into_self, L.power_basis()) ]
     5581        basis.append(a**extdeg) # this one makes the basis no longer a basis
     5582        mat = matrix([ b.vector() for b in basis ])
     5583        soln_space = mat.left_kernel(mat.row_space()(0))
     5584        # the solution space is one dimensional and the last entry is non-zero
     5585        # because a satisfies no smaller linear relation
     5586        assert soln_space.dimension() == 1
     5587        (reln, ) = soln_space.basis()
     5588        assert reln[-1] != 0
     5589        reln = reln * ~reln[-1]
     5590
     5591        # now we need to get those coeffs in L
     5592        coeff_mat = matrix(extdeg, f.degree(), list(reln)[:-1]) # easy way to divide into the correct lengths
     5593        coeffs_in_L = [ r*vector(L.power_basis()) for r in coeff_mat.rows() ]
     5594        # f is the minimal polynomial of a over L
     5595        f = L['x'](coeffs_in_L + [1])
     5596        # sanity check...
     5597        mp_in_self = self['x'](map(L_into_self, f.coeffs()))
     5598        assert mp_in_self(a) == 0
     5599
     5600        M = L.extension(f, names[0])
     5601        beta = M(L.gen())
     5602        to_M = self.hom([M.gen(0)], M, check=True)  # be paranoid
     5603        assert to_M(alpha) == beta
     5604        # Bingo.
     5605        # We have now constructed a relative
     5606        # number field M, and an isomorphism
     5607        # self --> M that sends alpha to
     5608        # the generator of the intermediate field.
     5609
     5610        # this strange step avoids computing an embedding of the base_field L
     5611        # into self, a computation which triggers a pari nfinit().  Without
     5612        # this, the relativize done over a huge field above is not feasible.
     5613        base_hom = L.hom([alpha], self)
     5614        from_M = M.Hom(self)([self.gen()], base_hom=base_hom, check=True)
     5615
     5616        # at some point in the future, we will worry about caching since relative
     5617        # number fields should be cached but aren't -- yet
     5618        M._set_structure(from_M, to_M)
     5619        return M
    55555620
    55565621    # Synonyms so that terminology appropriate to relative number fields
    55575622    # can be applied to an absolute number field: