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