Ticket #10443: trac_10443-nf_discrete_log.patch

File trac_10443-nf_discrete_log.patch, 6.0 KB (added by davidloeffler, 11 years ago)

patch against 4.6.1.alpha3

  • sage/rings/number_field/number_field_ideal.py

    # HG changeset patch
    # User David Loeffler <d.loeffler.01@cantab.net>
    # Date 1291812480 0
    # Node ID ce5ef85e8dea9b2b125b171d7e6f7c4e5ee366f9
    # Parent  34b392ff7c6e5ae8d40ad1a258cf5d6b27ad2b0d
    #10443: improvements to number field discrete log
    
    diff -r 34b392ff7c6e -r ce5ef85e8dea sage/rings/number_field/number_field_ideal.py
    a b  
    22292229            AG._gens = tuple(map(k, g))
    22302230        return AG
    22312231
    2232     def ideallog(self, x):
     2232    def ideallog(self, x, gens=None, check=True):
    22332233        r"""
    2234         Returns the discrete logarithm of x with respect to the
    2235         generators given in the ``bid`` structure of the ideal
    2236         self.
     2234        Returns the discrete logarithm of x with respect to the generators
     2235        given in the ``bid`` structure of the ideal self, or with respect to
     2236        the generators ``gens`` if these are given.
    22372237       
    22382238        INPUT:
    22392239
    22402240        - ``x`` - a non-zero element of the number field of self,
    22412241          which must have valuation equal to 0 at all prime ideals in
    22422242          the support of the ideal self.
     2243        - ``gens`` - a list of elements of the number field which generate `(R
     2244          / I)^*`, where `R` is the ring of integers of the field and `I` is
     2245          this ideal, or ``None``. If ``None``, use the generators calculated
     2246          by :meth:`~idealstar`.
     2247        - ``check`` - if True, do a consistency check on the results. Ignored
     2248          if ``gens`` is None.
    22432249
    22442250        OUTPUT:
    22452251
    2246         - ``l`` - a list of integers `(x_i)` such that `0 \leq x_i < d_i` and
    2247           `x = \prod_i g_i^{x_i}` in `(R/I)^*`, where `I` = self, `R` = ring of
    2248           integers of the field, and `g_i` are the generators of `(R/I)^*`, of
    2249           orders `d_i` respectively, as given in the ``bid`` structure of
    2250           the ideal self.
    2251 
     2252        - ``l`` - a list of non-negative integers `(x_i)` such that `x =
     2253          \prod_i g_i^{x_i}` in `(R/I)^*`, where `x_i` are the generators, and
     2254          the list `(x_i)` is lexicographically minimal with respect to this
     2255          requirement. If the `x_i` generate independent cyclic factors of
     2256          order `d_i`, as is the case for the default generators calculated by
     2257          :meth:`~idealstar`, this just means that `0 \le x_i < d_i`.
     2258
     2259        A ``ValueError`` will be raised if the elements specified in ``gens``
     2260        do not in fact generate the unit group (even if the element `x` is in
     2261        the subgroup they generate).
     2262       
    22522263        EXAMPLES::
    22532264
    22542265            sage: k.<a> = NumberField(x^3 - 11)
     
    22612272            sage: A.small_residue(r) # random
    22622273            a^2 - 2
    22632274           
    2264         ALGORITHM: Uses Pari function ``ideallog``
     2275        Examples with custom generators::
     2276
     2277            sage: K.<a> = NumberField(x^2 - 7)
     2278            sage: I = K.ideal(17)
     2279            sage: I.ideallog(a + 7, [1+a, 2])
     2280            [10, 3]
     2281            sage: I.ideallog(a + 7, [2, 1+a])
     2282            [0, 118]
     2283
     2284            sage: L.<b> = NumberField(x^4 - x^3 - 7*x^2 + 3*x + 2)
     2285            sage: J = L.ideal(-b^3 - b^2 - 2)
     2286            sage: u = -14*b^3 + 21*b^2 + b - 1
     2287            sage: v = 4*b^2 + 2*b - 1
     2288            sage: J.ideallog(5+2*b, [u, v], check=True)
     2289            [4, 13]
     2290
     2291        A non-example::
     2292
     2293            sage: I.ideallog(a + 7, [2])
     2294            Traceback (most recent call last):
     2295            ...
     2296            ValueError: Given elements do not generate unit group -- they generate a subgroup of index 36
     2297
     2298        ALGORITHM: Uses Pari function ``ideallog``, and (if ``gens`` is not
     2299        None) a Hermite normal form calculation to express the result in terms
     2300        of the generators ``gens``.
    22652301        """
     2302        # sanitise input
     2303
    22662304        k = self.number_field()
    22672305        if not all([k(x).valuation(p)==0 for p, e in self.factor()]):
    22682306            raise TypeError, "the element must be invertible mod the ideal"
    22692307
     2308        # calculate ideal log w.r.t. standard gens
     2309
    22702310        #Now it is important to call _pari_bid_() with flag=2 to make sure
    22712311        #we fix a basis, since the log would be different for a different
    22722312        #choice of basis.
    2273         return map(ZZ, k.pari_nf().ideallog(x._pari_(), self._pari_bid_(2)))
     2313        L = map(ZZ, k.pari_nf().ideallog(x._pari_(), self._pari_bid_(2)))
     2314
     2315        if gens is None:
     2316            return L
     2317
     2318        # otherwise translate answer in terms of given gens
     2319        G = self.idealstar(2)
     2320        invs = G.invariants()
     2321        g = G.gens()
     2322        n = G.ngens()
     2323   
     2324        from sage.matrix.all import matrix, identity_matrix, zero_matrix, diagonal_matrix, block_matrix
     2325
     2326        # We use Hermite normal form twice: once to express the standard
     2327        # generators in terms of the new ones (independently of x) and once to
     2328        # reduce the resulting logarithm of x so it is lexicographically
     2329        # minimal.
     2330
     2331        mat = matrix(ZZ, map(self.ideallog, gens)).augment(identity_matrix(ZZ, len(gens)))
     2332        mat = mat.stack( diagonal_matrix(ZZ, invs).augment(zero_matrix(ZZ, len(invs), len(gens))))
     2333        hmat = mat.hermite_form()
     2334        A = hmat[0:len(invs), 0:len(invs)]
     2335        if A != identity_matrix(len(invs)):
     2336            raise ValueError, "Given elements do not generate unit group -- they generate a subgroup of index %s" % A.det()
     2337        B = hmat[0:len(invs), len(invs):]
     2338        C = hmat[len(invs):, len(invs):]
     2339        #print "Matrix of relations:\n%s" % C
     2340        M = (matrix(ZZ, L) * B)
     2341        N = block_matrix([identity_matrix(1), M, zero_matrix(len(gens), 1), C], 2,2,subdivide=False)
     2342        ans = N.hermite_form()[0, 1:].list()
     2343
     2344        if check:
     2345            from sage.rings.all import Zmod
     2346            t = 1
     2347            for i in xrange(len(ans)):
     2348                t = self.reduce(t * gens[i]**ans[i])
     2349            assert t == self.reduce(x * x.denominator() * (~Zmod(self.norm())(x.denominator())).lift())
     2350
     2351        return ans
    22742352
    22752353    def element_1_mod(self, other):
    22762354        r"""