Home | History | Annotate | Line # | Download | only in generic
hgcd_reduce.c revision 1.1.1.1.8.2
      1  1.1.1.1.8.2  tls /* hgcd_reduce.c.
      2  1.1.1.1.8.2  tls 
      3  1.1.1.1.8.2  tls    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
      4  1.1.1.1.8.2  tls    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
      5  1.1.1.1.8.2  tls    GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
      6  1.1.1.1.8.2  tls 
      7  1.1.1.1.8.2  tls Copyright 2011, 2012 Free Software Foundation, Inc.
      8  1.1.1.1.8.2  tls 
      9  1.1.1.1.8.2  tls This file is part of the GNU MP Library.
     10  1.1.1.1.8.2  tls 
     11  1.1.1.1.8.2  tls The GNU MP Library is free software; you can redistribute it and/or modify
     12  1.1.1.1.8.2  tls it under the terms of the GNU Lesser General Public License as published by
     13  1.1.1.1.8.2  tls the Free Software Foundation; either version 3 of the License, or (at your
     14  1.1.1.1.8.2  tls option) any later version.
     15  1.1.1.1.8.2  tls 
     16  1.1.1.1.8.2  tls The GNU MP Library is distributed in the hope that it will be useful, but
     17  1.1.1.1.8.2  tls WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     18  1.1.1.1.8.2  tls or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     19  1.1.1.1.8.2  tls License for more details.
     20  1.1.1.1.8.2  tls 
     21  1.1.1.1.8.2  tls You should have received a copy of the GNU Lesser General Public License
     22  1.1.1.1.8.2  tls along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
     23  1.1.1.1.8.2  tls 
     24  1.1.1.1.8.2  tls #include "gmp.h"
     25  1.1.1.1.8.2  tls #include "gmp-impl.h"
     26  1.1.1.1.8.2  tls #include "longlong.h"
     27  1.1.1.1.8.2  tls 
     28  1.1.1.1.8.2  tls /* Computes R -= A * B. Result must be non-negative. Normalized down
     29  1.1.1.1.8.2  tls    to size an, and resulting size is returned. */
     30  1.1.1.1.8.2  tls static mp_size_t
     31  1.1.1.1.8.2  tls submul (mp_ptr rp, mp_size_t rn,
     32  1.1.1.1.8.2  tls 	mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
     33  1.1.1.1.8.2  tls {
     34  1.1.1.1.8.2  tls   mp_ptr tp;
     35  1.1.1.1.8.2  tls   TMP_DECL;
     36  1.1.1.1.8.2  tls 
     37  1.1.1.1.8.2  tls   ASSERT (bn > 0);
     38  1.1.1.1.8.2  tls   ASSERT (an >= bn);
     39  1.1.1.1.8.2  tls   ASSERT (rn >= an);
     40  1.1.1.1.8.2  tls   ASSERT (an + bn <= rn + 1);
     41  1.1.1.1.8.2  tls 
     42  1.1.1.1.8.2  tls   TMP_MARK;
     43  1.1.1.1.8.2  tls   tp = TMP_ALLOC_LIMBS (an + bn);
     44  1.1.1.1.8.2  tls 
     45  1.1.1.1.8.2  tls   mpn_mul (tp, ap, an, bp, bn);
     46  1.1.1.1.8.2  tls   if (an + bn > rn)
     47  1.1.1.1.8.2  tls     {
     48  1.1.1.1.8.2  tls       ASSERT (tp[rn] == 0);
     49  1.1.1.1.8.2  tls       bn--;
     50  1.1.1.1.8.2  tls     }
     51  1.1.1.1.8.2  tls   ASSERT_NOCARRY (mpn_sub (rp, rp, rn, tp, an + bn));
     52  1.1.1.1.8.2  tls   TMP_FREE;
     53  1.1.1.1.8.2  tls 
     54  1.1.1.1.8.2  tls   while (rn > an && (rp[rn-1] == 0))
     55  1.1.1.1.8.2  tls     rn--;
     56  1.1.1.1.8.2  tls 
     57  1.1.1.1.8.2  tls   return rn;
     58  1.1.1.1.8.2  tls }
     59  1.1.1.1.8.2  tls 
     60  1.1.1.1.8.2  tls /* Computes (a, b)  <--  M^{-1} (a; b) */
     61  1.1.1.1.8.2  tls /* FIXME:
     62  1.1.1.1.8.2  tls     x Take scratch parameter, and figure out scratch need.
     63  1.1.1.1.8.2  tls 
     64  1.1.1.1.8.2  tls     x Use some fallback for small M->n?
     65  1.1.1.1.8.2  tls */
     66  1.1.1.1.8.2  tls static mp_size_t
     67  1.1.1.1.8.2  tls hgcd_matrix_apply (const struct hgcd_matrix *M,
     68  1.1.1.1.8.2  tls 		   mp_ptr ap, mp_ptr bp,
     69  1.1.1.1.8.2  tls 		   mp_size_t n)
     70  1.1.1.1.8.2  tls {
     71  1.1.1.1.8.2  tls   mp_size_t an, bn, un, vn, nn;
     72  1.1.1.1.8.2  tls   mp_size_t mn[2][2];
     73  1.1.1.1.8.2  tls   mp_size_t modn;
     74  1.1.1.1.8.2  tls   mp_ptr tp, sp, scratch;
     75  1.1.1.1.8.2  tls   mp_limb_t cy;
     76  1.1.1.1.8.2  tls   unsigned i, j;
     77  1.1.1.1.8.2  tls 
     78  1.1.1.1.8.2  tls   TMP_DECL;
     79  1.1.1.1.8.2  tls 
     80  1.1.1.1.8.2  tls   ASSERT ( (ap[n-1] | bp[n-1]) > 0);
     81  1.1.1.1.8.2  tls 
     82  1.1.1.1.8.2  tls   an = n;
     83  1.1.1.1.8.2  tls   MPN_NORMALIZE (ap, an);
     84  1.1.1.1.8.2  tls   bn = n;
     85  1.1.1.1.8.2  tls   MPN_NORMALIZE (bp, bn);
     86  1.1.1.1.8.2  tls 
     87  1.1.1.1.8.2  tls   for (i = 0; i < 2; i++)
     88  1.1.1.1.8.2  tls     for (j = 0; j < 2; j++)
     89  1.1.1.1.8.2  tls       {
     90  1.1.1.1.8.2  tls 	mp_size_t k;
     91  1.1.1.1.8.2  tls 	k = M->n;
     92  1.1.1.1.8.2  tls 	MPN_NORMALIZE (M->p[i][j], k);
     93  1.1.1.1.8.2  tls 	mn[i][j] = k;
     94  1.1.1.1.8.2  tls       }
     95  1.1.1.1.8.2  tls 
     96  1.1.1.1.8.2  tls   ASSERT (mn[0][0] > 0);
     97  1.1.1.1.8.2  tls   ASSERT (mn[1][1] > 0);
     98  1.1.1.1.8.2  tls   ASSERT ( (mn[0][1] | mn[1][0]) > 0);
     99  1.1.1.1.8.2  tls 
    100  1.1.1.1.8.2  tls   TMP_MARK;
    101  1.1.1.1.8.2  tls 
    102  1.1.1.1.8.2  tls   if (mn[0][1] == 0)
    103  1.1.1.1.8.2  tls     {
    104  1.1.1.1.8.2  tls       /* A unchanged, M = (1, 0; q, 1) */
    105  1.1.1.1.8.2  tls       ASSERT (mn[0][0] == 1);
    106  1.1.1.1.8.2  tls       ASSERT (M->p[0][0][0] == 1);
    107  1.1.1.1.8.2  tls       ASSERT (mn[1][1] == 1);
    108  1.1.1.1.8.2  tls       ASSERT (M->p[1][1][0] == 1);
    109  1.1.1.1.8.2  tls 
    110  1.1.1.1.8.2  tls       /* Put B <-- B - q A */
    111  1.1.1.1.8.2  tls       nn = submul (bp, bn, ap, an, M->p[1][0], mn[1][0]);
    112  1.1.1.1.8.2  tls     }
    113  1.1.1.1.8.2  tls   else if (mn[1][0] == 0)
    114  1.1.1.1.8.2  tls     {
    115  1.1.1.1.8.2  tls       /* B unchanged, M = (1, q; 0, 1) */
    116  1.1.1.1.8.2  tls       ASSERT (mn[0][0] == 1);
    117  1.1.1.1.8.2  tls       ASSERT (M->p[0][0][0] == 1);
    118  1.1.1.1.8.2  tls       ASSERT (mn[1][1] == 1);
    119  1.1.1.1.8.2  tls       ASSERT (M->p[1][1][0] == 1);
    120  1.1.1.1.8.2  tls 
    121  1.1.1.1.8.2  tls       /* Put A  <-- A - q * B */
    122  1.1.1.1.8.2  tls       nn = submul (ap, an, bp, bn, M->p[0][1], mn[0][1]);
    123  1.1.1.1.8.2  tls     }
    124  1.1.1.1.8.2  tls   else
    125  1.1.1.1.8.2  tls     {
    126  1.1.1.1.8.2  tls       /* A = m00 a + m01 b  ==> a <= A / m00, b <= A / m01.
    127  1.1.1.1.8.2  tls 	 B = m10 a + m11 b  ==> a <= B / m10, b <= B / m11. */
    128  1.1.1.1.8.2  tls       un = MIN (an - mn[0][0], bn - mn[1][0]) + 1;
    129  1.1.1.1.8.2  tls       vn = MIN (an - mn[0][1], bn - mn[1][1]) + 1;
    130  1.1.1.1.8.2  tls 
    131  1.1.1.1.8.2  tls       nn = MAX (un, vn);
    132  1.1.1.1.8.2  tls       /* In the range of interest, mulmod_bnm1 should always beat mullo. */
    133  1.1.1.1.8.2  tls       modn = mpn_mulmod_bnm1_next_size (nn + 1);
    134  1.1.1.1.8.2  tls 
    135  1.1.1.1.8.2  tls       scratch = TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (modn, modn, M->n));
    136  1.1.1.1.8.2  tls       tp = TMP_ALLOC_LIMBS (modn);
    137  1.1.1.1.8.2  tls       sp = TMP_ALLOC_LIMBS (modn);
    138  1.1.1.1.8.2  tls 
    139  1.1.1.1.8.2  tls       ASSERT (n <= 2*modn);
    140  1.1.1.1.8.2  tls 
    141  1.1.1.1.8.2  tls       if (n > modn)
    142  1.1.1.1.8.2  tls 	{
    143  1.1.1.1.8.2  tls 	  cy = mpn_add (ap, ap, modn, ap + modn, n - modn);
    144  1.1.1.1.8.2  tls 	  MPN_INCR_U (ap, modn, cy);
    145  1.1.1.1.8.2  tls 
    146  1.1.1.1.8.2  tls 	  cy = mpn_add (bp, bp, modn, bp + modn, n - modn);
    147  1.1.1.1.8.2  tls 	  MPN_INCR_U (bp, modn, cy);
    148  1.1.1.1.8.2  tls 
    149  1.1.1.1.8.2  tls 	  n = modn;
    150  1.1.1.1.8.2  tls 	}
    151  1.1.1.1.8.2  tls 
    152  1.1.1.1.8.2  tls       mpn_mulmod_bnm1 (tp, modn, ap, n, M->p[1][1], mn[1][1], scratch);
    153  1.1.1.1.8.2  tls       mpn_mulmod_bnm1 (sp, modn, bp, n, M->p[0][1], mn[0][1], scratch);
    154  1.1.1.1.8.2  tls 
    155  1.1.1.1.8.2  tls       /* FIXME: Handle the small n case in some better way. */
    156  1.1.1.1.8.2  tls       if (n + mn[1][1] < modn)
    157  1.1.1.1.8.2  tls 	MPN_ZERO (tp + n + mn[1][1], modn - n - mn[1][1]);
    158  1.1.1.1.8.2  tls       if (n + mn[0][1] < modn)
    159  1.1.1.1.8.2  tls 	MPN_ZERO (sp + n + mn[0][1], modn - n - mn[0][1]);
    160  1.1.1.1.8.2  tls 
    161  1.1.1.1.8.2  tls       cy = mpn_sub_n (tp, tp, sp, modn);
    162  1.1.1.1.8.2  tls       MPN_DECR_U (tp, modn, cy);
    163  1.1.1.1.8.2  tls 
    164  1.1.1.1.8.2  tls       ASSERT (mpn_zero_p (tp + nn, modn - nn));
    165  1.1.1.1.8.2  tls 
    166  1.1.1.1.8.2  tls       mpn_mulmod_bnm1 (sp, modn, ap, n, M->p[1][0], mn[1][0], scratch);
    167  1.1.1.1.8.2  tls       MPN_COPY (ap, tp, nn);
    168  1.1.1.1.8.2  tls       mpn_mulmod_bnm1 (tp, modn, bp, n, M->p[0][0], mn[0][0], scratch);
    169  1.1.1.1.8.2  tls 
    170  1.1.1.1.8.2  tls       if (n + mn[1][0] < modn)
    171  1.1.1.1.8.2  tls 	MPN_ZERO (sp + n + mn[1][0], modn - n - mn[1][0]);
    172  1.1.1.1.8.2  tls       if (n + mn[0][0] < modn)
    173  1.1.1.1.8.2  tls 	MPN_ZERO (tp + n + mn[0][0], modn - n - mn[0][0]);
    174  1.1.1.1.8.2  tls 
    175  1.1.1.1.8.2  tls       cy = mpn_sub_n (tp, tp, sp, modn);
    176  1.1.1.1.8.2  tls       MPN_DECR_U (tp, modn, cy);
    177  1.1.1.1.8.2  tls 
    178  1.1.1.1.8.2  tls       ASSERT (mpn_zero_p (tp + nn, modn - nn));
    179  1.1.1.1.8.2  tls       MPN_COPY (bp, tp, nn);
    180  1.1.1.1.8.2  tls 
    181  1.1.1.1.8.2  tls       while ( (ap[nn-1] | bp[nn-1]) == 0)
    182  1.1.1.1.8.2  tls 	{
    183  1.1.1.1.8.2  tls 	  nn--;
    184  1.1.1.1.8.2  tls 	  ASSERT (nn > 0);
    185  1.1.1.1.8.2  tls 	}
    186  1.1.1.1.8.2  tls     }
    187  1.1.1.1.8.2  tls   TMP_FREE;
    188  1.1.1.1.8.2  tls 
    189  1.1.1.1.8.2  tls   return nn;
    190  1.1.1.1.8.2  tls }
    191  1.1.1.1.8.2  tls 
    192  1.1.1.1.8.2  tls mp_size_t
    193  1.1.1.1.8.2  tls mpn_hgcd_reduce_itch (mp_size_t n, mp_size_t p)
    194  1.1.1.1.8.2  tls {
    195  1.1.1.1.8.2  tls   mp_size_t itch;
    196  1.1.1.1.8.2  tls   if (BELOW_THRESHOLD (n, HGCD_REDUCE_THRESHOLD))
    197  1.1.1.1.8.2  tls     {
    198  1.1.1.1.8.2  tls       itch = mpn_hgcd_itch (n-p);
    199  1.1.1.1.8.2  tls 
    200  1.1.1.1.8.2  tls       /* For arbitrary p, the storage for _adjust is 2*(p + M->n) = 2 *
    201  1.1.1.1.8.2  tls 	 (p + ceil((n-p)/2) - 1 <= n + p - 1 */
    202  1.1.1.1.8.2  tls       if (itch < n + p - 1)
    203  1.1.1.1.8.2  tls 	itch = n + p - 1;
    204  1.1.1.1.8.2  tls     }
    205  1.1.1.1.8.2  tls   else
    206  1.1.1.1.8.2  tls     {
    207  1.1.1.1.8.2  tls       itch = 2*(n-p) + mpn_hgcd_itch (n-p);
    208  1.1.1.1.8.2  tls       /* Currently, hgcd_matrix_apply allocates its own storage. */
    209  1.1.1.1.8.2  tls     }
    210  1.1.1.1.8.2  tls   return itch;
    211  1.1.1.1.8.2  tls }
    212  1.1.1.1.8.2  tls 
    213  1.1.1.1.8.2  tls /* FIXME: Document storage need. */
    214  1.1.1.1.8.2  tls mp_size_t
    215  1.1.1.1.8.2  tls mpn_hgcd_reduce (struct hgcd_matrix *M,
    216  1.1.1.1.8.2  tls 		 mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t p,
    217  1.1.1.1.8.2  tls 		 mp_ptr tp)
    218  1.1.1.1.8.2  tls {
    219  1.1.1.1.8.2  tls   mp_size_t nn;
    220  1.1.1.1.8.2  tls   if (BELOW_THRESHOLD (n, HGCD_REDUCE_THRESHOLD))
    221  1.1.1.1.8.2  tls     {
    222  1.1.1.1.8.2  tls       nn = mpn_hgcd (ap + p, bp + p, n - p, M, tp);
    223  1.1.1.1.8.2  tls       if (nn > 0)
    224  1.1.1.1.8.2  tls 	/* Needs 2*(p + M->n) <= 2*(floor(n/2) + ceil(n/2) - 1)
    225  1.1.1.1.8.2  tls 	   = 2 (n - 1) */
    226  1.1.1.1.8.2  tls 	return mpn_hgcd_matrix_adjust (M, p + nn, ap, bp, p, tp);
    227  1.1.1.1.8.2  tls     }
    228  1.1.1.1.8.2  tls   else
    229  1.1.1.1.8.2  tls     {
    230  1.1.1.1.8.2  tls       MPN_COPY (tp, ap + p, n - p);
    231  1.1.1.1.8.2  tls       MPN_COPY (tp + n - p, bp + p, n - p);
    232  1.1.1.1.8.2  tls       if (mpn_hgcd_appr (tp, tp + n - p, n - p, M, tp + 2*(n-p)))
    233  1.1.1.1.8.2  tls 	return hgcd_matrix_apply (M, ap, bp, n);
    234  1.1.1.1.8.2  tls     }
    235  1.1.1.1.8.2  tls   return 0;
    236  1.1.1.1.8.2  tls }
    237