LCOV - code coverage report
Current view: top level - ecm - sets_long.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 216 228 94.7 %
Date: 2022-03-21 11:19:20 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /* Functions for sets of long ints, to factor (Z/NZ)* into a set of sums
       2             :    as described in section 5 of "Improved Stage 2 to $P\pm{}1$ Factoring 
       3             :    Algorithms" by Peter L. Montgomery and Alexander Kruppa, ANTS 2008
       4             :    (8th Algorithmic Number Theory Symposium).
       5             :   
       6             : Copyright 2007, 2008, 2009, 2012 Alexander Kruppa, Paul Zimmermann.
       7             : 
       8             : This file is part of the ECM Library.
       9             : 
      10             : The ECM Library is free software; you can redistribute it and/or modify
      11             : it under the terms of the GNU Lesser General Public License as published by
      12             : the Free Software Foundation; either version 3 of the License, or (at your
      13             : option) any later version.
      14             : 
      15             : The ECM Library is distributed in the hope that it will be useful, but
      16             : WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      17             : or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
      18             : License for more details.
      19             : 
      20             : You should have received a copy of the GNU Lesser General Public License
      21             : along with the ECM Library; see the file COPYING.LIB.  If not, see
      22             : http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
      23             : 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
      24             : 
      25             : #include "config.h"
      26             : #include "ecm-impl.h"
      27             : #include <stdlib.h>
      28             : #ifdef HAVE_ALLOCA_H
      29             : #include <alloca.h>
      30             : #endif
      31             : #ifdef TESTDRIVE
      32             : #include <stdio.h>
      33             : FILE *ECM_STDOUT, *ECM_STDERR;
      34             : #endif
      35             : 
      36             : /*****************************************************************
      37             : 
      38             :           Functions for processing sets
      39             : 
      40             :   A set is a cardinality of unsigned long type and an array of 
      41             :   long ints. 
      42             :   A set of sets is an unsigned long telling the number of sets,
      43             :   an array that has several sets stored back-to-back.
      44             : 
      45             : *****************************************************************/
      46             : 
      47             : 
      48             : /* Copy a set from "*S" to "*T". Assumes that the sets do not overlap,
      49             :    or that T < S. */
      50             : 
      51             : static void
      52        7572 : set_copy (set_long_t *T, set_long_t *S)
      53             : {
      54             :   unsigned long i;
      55        7572 :   const unsigned long c = S->card; /* We might overwrite S->card */
      56             :   
      57        7572 :   T->card = c;
      58       33397 :   for (i = 0UL; i < c; i++)
      59       25825 :     T->elem[i] = S->elem[i];
      60        7572 : }
      61             : 
      62             : 
      63             : /* Exchange two adjacent sets in memory. Since all "elem" arrays are stored
      64             :    in the same chunk of allocated memory, and not in different chunks, we
      65             :    cannot simply swap the "elem" pointers.
      66             :    If the set T has size c and the next has size d, after the swap the set T
      67             :    will have size d and the next will have size c.
      68             : */
      69             : static void 
      70        1840 : set_swap (set_long_t *T)
      71             : {
      72             :   set_long_t *next, *tmp;
      73             :   
      74        1840 :   next = sets_nextset (T);
      75        1840 :   tmp = alloca (set_sizeof (T->card));
      76             :   ASSERT(tmp != NULL);
      77        1840 :   set_copy (tmp, T);
      78        1840 :   set_copy (T, next);
      79             :   /* warning: sets_nextset(T) might differ from next, if T and next had
      80             :      different sizes */
      81        1840 :   set_copy (sets_nextset(T), tmp);  
      82        1840 : }
      83             : 
      84             : 
      85             : /* Functions for sorting an array of longs */
      86             : 
      87             : static inline void
      88           1 : swap_long (long *a, long *b)
      89             : {
      90             :   long t;
      91           1 :   t = *a;
      92           1 :   *a = *b;
      93           1 :   *b = t;
      94           1 : }
      95             : 
      96             : static inline void 
      97         596 : swapsort_long (long *a, long *b)
      98             : {
      99         596 :   if (*a > *b)
     100           1 :     swap_long (a, b);
     101         596 : }
     102             : 
     103             : void 
     104         554 : quicksort_long (long *a, unsigned long l)
     105             : {
     106             :   unsigned long i, j;
     107             :   long pivot;
     108             : 
     109         554 :   if (l < 2)
     110         182 :     return;
     111             : 
     112         372 :   j = l - 1;
     113         372 :   swapsort_long (a, a+j);
     114         372 :   if (l == 2)
     115         260 :     return;
     116             : 
     117         112 :   i = j / 2;
     118         112 :   swapsort_long (a, a+i);
     119         112 :   swapsort_long (a+i, a+j);
     120         112 :   if (l == 3)
     121          75 :     return;
     122             : 
     123          37 :   pivot = a[i]; /* Median of three */
     124             : 
     125             :   /* Stuff <= pivot goes in first list */
     126             : 
     127             :   /* Invariant: a[0 ... i-1] <= pivot, a[j+1 ... l-1] > pivot */
     128         126 :   for (i = 1; i < j;)
     129          89 :     if (a[i] > pivot)
     130             :       {
     131         113 :         for (; a[j] > pivot; j--);
     132          36 :         if (i < j)
     133           0 :           swap_long (a+(i++), a+j);
     134             :       }
     135             :     else
     136          53 :       i++;
     137             : 
     138             : #ifdef WANT_ASSERT
     139             :   for (j = 0; j < i; j++)
     140             :     ASSERT (a[j] <= pivot);
     141             :   for (j = i; j < l; j++)
     142             :     ASSERT(a[j] > pivot);
     143             : #endif
     144             : 
     145          37 :   quicksort_long (a, i);
     146          37 :   quicksort_long (a + i, l - i);
     147             : 
     148             : #ifdef WANT_ASSERT
     149             :   for (j = 0; i < l - 1; i++)
     150             :     ASSERT (a[j] <= a[j + 1]);
     151             : #endif
     152             : }
     153             : 
     154             : 
     155             : /* Returns max(S), where S == (Z/\beta Z)* as chosen by
     156             :    sets_get_factored_sorted() */
     157             : /* Assumes that S == 0 at recursion entry */
     158             : static void
     159     4546523 : sets_max_recurse (mpz_t S, const unsigned long beta)
     160             : {
     161     4546523 :   unsigned long P = beta, p, pk;
     162             :   unsigned int k;
     163             :   
     164     4546523 :   if (beta == 1UL)
     165     1051016 :     return;
     166             :   
     167     3495507 :   p = find_factor (P);
     168     3495507 :   k = 1; pk = p; P /= p;
     169     4360850 :   while (P % p == 0)
     170             :     {
     171      865343 :       k++;
     172      865343 :       pk *= p;
     173      865343 :       P /= p; /* P*pk=beta is invariant */
     174             :     }
     175     3495507 :   sets_max_recurse (S, P);
     176     3495507 :   mpz_mul_ui (S, S, pk);
     177     3495507 :   if (p == 2UL && k == 1)
     178           0 :     mpz_add_ui (S, S, P);
     179     3495507 :   else if (p == 2UL)
     180           0 :     mpz_add_ui (S, S, P * (pk / 2UL - 1UL));
     181     3495507 :   else if (p % 4UL == 1UL)
     182     1352828 :     mpz_add_ui (S, S, P * ((pk + p) / 2UL - 2UL));
     183     2142679 :   else if (p % 4UL == 3UL)
     184     2142679 :     mpz_add_ui (S, S, P * ((pk - 1UL) / 2UL));
     185             :   else
     186           0 :     abort();
     187             : }
     188             : 
     189             : void
     190     1051016 : sets_max (mpz_t S, const unsigned long beta)
     191             : {
     192     1051016 :   mpz_set_ui (S, 0UL);
     193     1051016 :   sets_max_recurse (S, beta);
     194     1051016 : }
     195             : 
     196             : 
     197             : /* Compute the set of sums over the "nr_sets" different sets in "*sets".
     198             :    The value of "add" is added to each element of the set of sums. 
     199             :    "*sum" will have {\prod_{S \in "*sets"} #S} entries and must have
     200             :    enough memory allocated. This number of elements in the set of sums 
     201             :    is the return value. In case of nr_sets == 0, "add" is written to *sets 
     202             :    and 1 is returned. The sets in "*sets" are assumed to be non-empty.
     203             :    If "*sum" is NULL, nothing is written, but the return value is computed
     204             :    correctly. */
     205             : 
     206             : static unsigned long 
     207        1461 : sets_sumset_recurse (long *sum, const set_long_t *sets, 
     208             :                     const unsigned long nr_sets, const long add)
     209             : {
     210        1461 :   unsigned long i, j = 0UL;
     211             : 
     212        1461 :   if (nr_sets == 0UL)
     213             :     {
     214         927 :       if (sum != NULL)
     215         927 :         sum[0] = add;
     216         927 :       return 1UL;
     217             :     }
     218             : 
     219             :   ASSERT (sets->card > 0UL);
     220        1515 :   for (i = 0UL; i < sets->card; i++)
     221             :     {
     222             :       /* Test for overflow */
     223         981 :       ASSERT_ALWAYS (add <= 0 || add + sets->elem[i] > sets->elem[i]);
     224         981 :       ASSERT_ALWAYS (add >= 0 || add + sets->elem[i] < sets->elem[i]);
     225         981 :       j += sets_sumset_recurse (sum + j, sets_nextset(sets), nr_sets - 1UL, 
     226         981 :                                 add + sets->elem[i]);
     227             :     }
     228             : 
     229         534 :   return j;
     230             : }
     231             : 
     232             : 
     233             : void 
     234         480 : sets_sumset (set_long_t *sum, const sets_long_t *sets)
     235             : {
     236         480 :   sum->card = sets_sumset_recurse (sum->elem, sets->sets, sets->nr, 0L);
     237         480 : }
     238             : 
     239             : 
     240             : /* Returns the minimal (if minmax == -1) or maximal (minmax == 1) value
     241             :    in the set of sums over the sets in "*sets". */
     242             : 
     243             : void
     244         480 : sets_sumset_minmax (mpz_t sum, const sets_long_t *sets, const int minmax)
     245             : {
     246             :   unsigned long i, nr;
     247         480 :   const set_long_t *set = sets->sets;
     248             :   long extremum;
     249             : 
     250             :   ASSERT (minmax == 1 || minmax == -1);
     251         480 :   mpz_set_ui (sum, 0UL);
     252             : 
     253        3615 :   for (nr = 0; nr < sets->nr; nr++)
     254             :     {
     255             :       ASSERT (set->card > 0UL);
     256        3135 :       extremum = set->elem[0];
     257             : 
     258        8301 :       for (i = 1UL; i < set->card; i++)
     259        5166 :         if ((minmax == -1 && set->elem[i] < extremum) ||
     260        5166 :             (minmax == 1 && set->elem[i] > extremum))
     261        5166 :           extremum = set->elem[i];
     262             :       
     263        3135 :       if (extremum >= 0)
     264        3135 :         mpz_add_ui (sum, sum, extremum);
     265             :       else
     266           0 :         mpz_sub_ui (sum, sum, -extremum);
     267        3135 :       set = sets_nextset (set);
     268             :     }
     269             : 
     270         480 :   return;
     271             : }
     272             : 
     273             : 
     274             : /* Store in (**L) arithmetic progressions of prime length whose sumset is 
     275             :    k/2*R_n, an arithmetic progression centered at 0 of common difference k 
     276             :    and cardinality n. If n is even, k must be as well to ensure integer
     277             :    results.
     278             :    I.e. n = 1: k/2*R_n = {0}, 
     279             :         n = 2: k/2*R_n = k/2 * {1, -1}, 
     280             :         n = 3: k/2*R_n = k * {-1, 0, 1}, 
     281             :         n = 4: k/2*R_n = k/2 * {-3, -1, 1, 3}, 
     282             :         n = 5: k/2*R_n = k * {-2, -1, 0, 1, 2} etc. 
     283             :   _ADDS_ the size in bytes of the set to "*sets_size"
     284             : */
     285             : 
     286             : static unsigned long
     287        5748 : sets_factored_Rn2 (set_long_t **L, size_t *sets_size, const long n, 
     288             :                    const long k)
     289             : {
     290        5748 :   unsigned long nr = 0UL;
     291             :   long i, m, q, r;
     292        5748 :   size_t size = 0;
     293             : 
     294             :   /* n must be odd, or n and k both even */
     295        5748 :   ASSERT_ALWAYS(n % 2L == 1L || k % 2L == 0L);
     296             :   ASSERT(L != NULL);
     297        5748 :   m = k; /* The multiplier accumulated so far, init to k */
     298        5748 :   r = n; /* The remaining cofactor of n */
     299       13512 :   for (q = 2L; r > 1L; q = (q + 1L) | 1L) /* Find prime factors of n */
     300             :     {
     301             :       ASSERT (q <= r);
     302       14034 :       while (r % q == 0L)
     303             :         {
     304        6270 :           if (*L != NULL)
     305             :             {
     306             :               /* Add m*R_q/2 to list */
     307        3135 :               (*L)->card = q;
     308       11436 :               for (i = 0L; i < q; i++)
     309             :                 {
     310        8301 :                   const long t = m * (2L * i - q + 1L);
     311             :                   ASSERT(t % 2L == 0L);
     312        8301 :                   (*L)->elem[i] = t / 2L;
     313             :                 }
     314        3135 :               *L = sets_nextset (*L);
     315        3135 :               nr++;
     316             :             }
     317        6270 :           size += set_sizeof ((unsigned long) q);
     318             :           /* Multiply this t to multiplier and treat remaining
     319             :              factors of the set */
     320        6270 :           m *= q;
     321        6270 :           r /= q;
     322             :         }
     323             :     }
     324        5748 :   if (sets_size != NULL)
     325        5748 :     *sets_size += size;
     326        5748 :   return nr;
     327             : }
     328             : 
     329             : 
     330             : /* Return a set L of sets M_i so that M_1 + ... + M_k is congruent to 
     331             :    (Z/nZ)*, which is the set of residue classes coprime to n. The M_i all
     332             :    have prime cardinality.
     333             :    The size of the set of sets "*L" in bytes is computed and stored in  
     334             :    "*sets_size" unless "*sets_size" is NULL.
     335             :    Return the number of sets in L. 
     336             :    If L is the NULL pointer, nothing will be stored in L. The correct
     337             :    return value (number of set in L) and "*sets_size" value will still 
     338             :    be computed, for example so that the correct amount of space can be 
     339             :    allocated and factor_coprimeset() be called again.
     340             : */
     341             : 
     342             : static unsigned long 
     343         960 : sets_factor_coprime (sets_long_t *sets, size_t *sets_size, 
     344             :                      const unsigned long n)
     345             : {
     346         960 :   unsigned long r, k, nr = 0UL;
     347             :   long p, np;
     348         960 :   size_t size = sizeof (unsigned long);
     349         960 :   set_long_t *set = NULL;
     350             :   
     351             :   ASSERT (n > 0UL);
     352         960 :   if (sets != NULL)
     353         480 :     set = sets->sets;
     354             : 
     355         960 :   r = n;
     356        4040 :   while (r > 1UL)
     357             :     {
     358       18856 :       for (p = 2L; r % p > 0L; p++); /* Find smallest prime p that divides r */
     359        6740 :       for (k = 0UL; r % p == 0UL; k++, r /= p); /* Find p^k || r */
     360        3080 :       np = n/p;
     361             : 
     362        3080 :       if (p == 2L && k == 1UL) /* Case 2^1. Deal with it before the */
     363             :         {                      /* while loop below decreases k. */
     364           0 :           if (set != NULL)
     365             :             {
     366           0 :               set->card = 1UL;
     367           0 :               set->elem[0] = np;
     368           0 :               set = sets_nextset (set);
     369             :             }
     370           0 :           size += set_sizeof (1UL);
     371           0 :           nr++;
     372             :         }
     373             : 
     374             :       /* If k > 1, do the \sum_{i=1}^{k-1} p^i (Z/pZ) part here.
     375             :          (Z/pZ) is represented by an arithmetic progression of
     376             :          common difference 1 and length p. */
     377             :                 
     378        3660 :       while (k-- > 1UL)
     379             :         {
     380         580 :           nr += sets_factored_Rn2 (&set, &size, p, np);
     381         580 :           np /= p;
     382             :         }
     383             : 
     384        3080 :       if (p % 4L == 3L)
     385             :         {
     386             :           /* We can use \hat{S}_p. Factor as 
     387             :              {-(p+1)/4, (p+1)/4} + C_{(p-1)/2} */
     388             :           
     389             :           /* Add the {-(p+1)/4, (p+1)/4} set to L */
     390        2088 :           nr += sets_factored_Rn2 (&set, &size, 2L, (p + 1L) / 2L * np);
     391             : 
     392             :           /* Add the np / 2 * R_{(p-1)/2} set to L */
     393        2088 :           nr += sets_factored_Rn2 (&set, &size, (p - 1L) / 2L, np);
     394             :         }
     395         992 :       else if (p % 4L == 1L)
     396             :         {
     397             :           /* Factor into arithmetic progressions of prime length.
     398             :              R_{p} = {-p+1, -p+3, ..., p-3, p+1}, i.e.
     399             :              R_2 = {-1, 1}, R_3 = {-2, 0, 2}, R_4 = {-3, -1, 1, 3}
     400             :              We have R_{sq} = R_q + q*R_s */
     401             :           
     402         992 :           nr += sets_factored_Rn2 (&set, &size, p - 1L, 2L * np);
     403             :         }
     404             :     }
     405             :   
     406         960 :   if (sets_size != NULL)
     407         480 :     *sets_size = size;
     408             : 
     409         960 :   if (sets != NULL)
     410         480 :     sets->nr = nr;
     411             : 
     412         960 :   return nr;
     413             : }
     414             : 
     415             : 
     416             : /* Sort the sets in F into order of ascending cardinality. Uses a simple
     417             :    Bubble sort. */
     418             : 
     419             : static void 
     420         480 : sets_sort (sets_long_t *sets)
     421             : {
     422             :   unsigned long i, nr_unsorted, highest_swap;
     423             :   set_long_t *set;
     424             : 
     425             :   /* The last sets->nr - nr_unsorted sets in "*sets" are known to be
     426             :      sorted and each one larger than any of the first nr_unsorted sets 
     427             :      in "*sets". */
     428         480 :   nr_unsorted = sets->nr;
     429        1517 :   while (nr_unsorted > 1UL)
     430             :     {
     431        1037 :       outputf (OUTPUT_TRACE, "nr_unsorted = %lu. ", nr_unsorted);
     432        1037 :       sets_print (OUTPUT_TRACE, sets);
     433        1037 :       set = sets->sets;
     434        1037 :       highest_swap = 1UL;
     435        6783 :       for (i = 1UL; i < nr_unsorted; i++)
     436             :         {
     437        5746 :           if (set->card > sets_nextset(set)->card)
     438             :             {
     439        1840 :               outputf (OUTPUT_TRACE, "sets_sort: swapping %lu and %lu\n", 
     440             :                        i - 1, i);
     441        1840 :               set_swap (set);
     442        1840 :               highest_swap = i;
     443             :             }
     444        5746 :           set = sets_nextset (set);
     445             :         }
     446        1037 :       nr_unsorted = highest_swap;
     447             :     }
     448             : 
     449             : #ifdef WANT_ASSERT
     450             :   set = sets->sets;
     451             :   for (i = 0UL; i + 1UL < sets->nr; i++)
     452             :     {
     453             :       ASSERT(set->card <= sets_nextset (set)->card);
     454             :       set = sets_nextset (set);
     455             :     }
     456             : #endif
     457         480 : }
     458             : 
     459             : /* Print all the sets in "*sets", formatted as a sum of sets */
     460             : 
     461             : void
     462        1092 : sets_print (const int verbosity, sets_long_t *sets)
     463             : {
     464             :   unsigned long i, j;
     465        1092 :   set_long_t *set = sets->sets;
     466             : 
     467        9470 :   for (i = 0UL; i < sets->nr; i++)
     468             :   {
     469        8378 :       if (i == 0UL)
     470        1092 :         outputf (verbosity, "{");
     471             :       else
     472        7286 :         outputf (verbosity, " + {");
     473             : 
     474             :       ASSERT(set->card > 0UL);
     475        8378 :       outputf (verbosity, "%ld", set->elem[0]);
     476       22442 :       for (j = 1UL; j < set->card; j++)
     477       14064 :         outputf (verbosity, ", %ld", set->elem[j]);
     478        8378 :       outputf (verbosity, "}");
     479        8378 :       set = sets_nextset (set);
     480             :   }
     481        1092 :   outputf (verbosity, "\n");
     482        1092 : }
     483             : 
     484             : 
     485             : /* Extract sets whose set of sums has cardinality "d". We expect that
     486             :    "d" divides the cardinality of the set of sums of "sets" and that
     487             :    the cardinalities of the sets in "sets" are all prime. 
     488             :    The amount of memory in bytes needed to store the extracted sets in 
     489             :    "*extracted" is stored at "*extr_size". The number of sets extracted
     490             :    is returned. (If d = p_1 * ... * p_k, the return value is k and 
     491             :    "*extr_size" is set_sizeof(p_1) + ... + set_sizeof(p_k).)
     492             :    If "*extracted" is NULL, nothing is written and no sets are removed
     493             :    from "*sets", but "*extr_size" is computed as if they were.  */
     494             : 
     495             : void
     496         960 : sets_extract (sets_long_t *extracted, size_t *extr_size, sets_long_t *sets, 
     497             :               const unsigned long d)
     498             : {
     499         960 :   unsigned long i, c, remaining_d = d;
     500         960 :   set_long_t *readfrom, *readnext, *moveto, *extractto = NULL;
     501         960 :   size_t extracted_size = sizeof (unsigned long);
     502             : 
     503         960 :   ASSERT_ALWAYS (d > 0UL);
     504             : 
     505         960 :   if (d == 1UL)
     506             :     {
     507             :       /* d == 1 means we need to extract a set of cardinality 1, which we
     508             :          most likely don't have in "*sets". (FIXME: check for set of 
     509             :          cardinality 1?) We return the set containing only zero, which
     510             :          can be added to any set of sets without changing the set of sums */
     511         362 :       if (extracted != NULL)
     512             :         {
     513         181 :           extracted->nr = 1;
     514         181 :           extractto = extracted->sets;
     515         181 :           extractto->card = 1UL;
     516         181 :           extractto->elem[0] = 0L;
     517             :         }
     518         362 :       if (extr_size != NULL)
     519         181 :         *extr_size = sizeof (unsigned long) + set_sizeof (1UL);
     520         362 :       return;
     521             :     }
     522             : 
     523         598 :   if (extracted != NULL)
     524             :     {
     525         299 :       extracted->nr = 0UL;
     526         299 :       extractto = extracted->sets;
     527             :     }
     528             :   /* All sets from *sets are read via *readfrom, and (assuming we actually
     529             :      extract them) are either copied to *extractto to *moveto */
     530         598 :   readfrom = moveto = sets->sets;
     531        4702 :   for (i = 0UL; i < sets->nr; i++)
     532             :     {
     533        4104 :       c = readfrom->card; /* readfrom->card may get garbled */
     534        4104 :       readnext = sets_nextset (readfrom);
     535        4104 :       if (remaining_d % c == 0UL)
     536             :         {
     537         652 :           if (extracted != NULL)
     538             :             {
     539             :               /* Copy this set to extractto */
     540         326 :               set_copy (extractto, readfrom);
     541         326 :               extractto = sets_nextset (extractto);
     542         326 :               extracted->nr++;
     543             :             }
     544         652 :           remaining_d /= c;
     545         652 :           extracted_size += set_sizeof (c);
     546             :         } else {
     547        3452 :           if (extracted != NULL)
     548             :             {
     549             :               /* Move this set within "*sets", filling the gaps left by 
     550             :                  extracted sets */
     551        1726 :               set_copy (moveto, readfrom);
     552        1726 :               moveto = sets_nextset (moveto);
     553             :             }
     554             :         }
     555        4104 :       readfrom = readnext;
     556             :     }
     557             : 
     558         598 :   ASSERT_ALWAYS (remaining_d == 1UL);
     559         598 :   if (extr_size != NULL)
     560         299 :     *extr_size = extracted_size;
     561         598 :   if (extracted != NULL)
     562         299 :     sets->nr -= extracted->nr;
     563             : }
     564             : 
     565             : sets_long_t *
     566         480 : sets_get_factored_sorted (const unsigned long beta)
     567             : {
     568             :   sets_long_t *sets;
     569             :   size_t size;
     570             : 
     571         480 :   sets_factor_coprime (NULL, &size, beta);
     572         480 :   sets = malloc (size);
     573         480 :   if (sets == NULL)
     574           0 :     return NULL;
     575         480 :   sets_factor_coprime (sets, NULL, beta);
     576             :   
     577         480 :   if (test_verbose (OUTPUT_TRACE))
     578             :     {
     579          10 :       outputf (OUTPUT_TRACE, 
     580             :               "sets_get_factored_sorted: Factored sets before sorting are ");
     581          10 :       sets_print (OUTPUT_TRACE, sets);
     582             :     }
     583             :   
     584         480 :   sets_sort (sets);
     585             :   
     586         480 :   if (test_verbose (OUTPUT_TRACE))
     587             :     {
     588          10 :       outputf (OUTPUT_TRACE, "Factored sets after sorting are ");
     589          10 :       sets_print (OUTPUT_TRACE, sets);
     590             :     }
     591             :   
     592         480 :   return sets;
     593             : }
     594             : 
     595             : #ifdef TESTDRIVE
     596             : static void
     597             : selftest (const unsigned long beta)
     598             : {
     599             :   sets_long_t *sets;
     600             :   set_long_t *sumset;
     601             :   unsigned long i, j, phibeta;
     602             :   mpz_t max;
     603             : 
     604             :   ASSERT_ALWAYS (beta > 0);
     605             :   sets = sets_get_factored_sorted (beta);
     606             :   
     607             :   /* Test that the sumset % beta is equal to (Z/betaZ)* % beta */
     608             :   phibeta = eulerphi (beta);
     609             :   sumset = malloc (set_sizeof (phibeta));
     610             :   if (sumset == NULL)
     611             :     {
     612             :       fprintf (stderr, "Cannot allocate memory in selftest\n");
     613             :       exit (1);
     614             :     }
     615             :   sets_sumset (sumset, sets);
     616             :   ASSERT_ALWAYS (sumset->card = phibeta);
     617             :   /* Also test that max (sumset) == sets_max (beta) */
     618             :   mpz_init (max);
     619             :   sets_max (max, beta);
     620             :   if (phibeta > 0)
     621             :     {
     622             :       long maxelem;
     623             :       maxelem = sumset->elem[0];
     624             :       for (i = 1; i < phibeta; i++)
     625             :         if (maxelem < sumset->elem[i])
     626             :           maxelem = sumset->elem[i];
     627             :       ASSERT_ALWAYS (mpz_cmp_si (max, maxelem) == 0);
     628             :     }
     629             :   else
     630             :     {
     631             :       ASSERT_ALWAYS (mpz_cmp_ui (max, 0UL) == 0);
     632             :     }
     633             :   mpz_clear (max);
     634             : 
     635             :  /*  printf ("sumset, before reduction: ");
     636             :   for (i = 0; i < phibeta; i++)
     637             :     printf ("%ld%s", sumset->elem[i], i < phibeta-1 ? ", " : "\n"); */
     638             :   for (i = 0; i < phibeta; i++)
     639             :     {
     640             :       sumset->elem[i] = (sumset->elem[i] < 0L) ? 
     641             :           beta - (long) ((unsigned long) (-sumset->elem[i]) % beta)
     642             :         : (unsigned long) sumset->elem[i] % beta;
     643             :       ASSERT_ALWAYS (sumset->elem[i] >= 0L);
     644             :       ASSERT_ALWAYS (sumset->elem[i] < (long) beta);
     645             :     }
     646             :   /* printf ("sumset, after reduction: ");
     647             :   for (i = 0; i < phibeta; i++)
     648             :     printf ("%ld%s", sumset->elem[i], i < phibeta-1 ? ", " : "\n"); */
     649             : 
     650             :   quicksort_long (sumset->elem, sumset->card);
     651             :   /* printf ("sumset, after sorting: ");
     652             :   for (i = 0; i < phibeta; i++)
     653             :     printf ("%ld%s", sumset->elem[i], i < phibeta-1 ? ", " : "\n"); */
     654             : 
     655             :   j = 0;
     656             :   for (i = 1; i < beta; i++)
     657             :     {
     658             :       if (gcd (i, beta) == 1)
     659             :         {
     660             :           if (sumset->elem[j] != (long) i)
     661             :             {
     662             :               printf ("sumset->elem[%ld] = %ld != %ld\n", 
     663             :                       j, sumset->elem[j], i);
     664             :               abort();
     665             :             }
     666             :           j++;
     667             :         }
     668             :     }
     669             :   free (sumset);
     670             :   free (sets);
     671             : }
     672             : 
     673             : int
     674             : main (int argc, char **argv)
     675             : {
     676             :   unsigned long beta;
     677             :   const unsigned long selftest_max = 1000;
     678             :   int loop = 1;
     679             : 
     680             :   ECM_STDOUT = stdout;
     681             :   ECM_STDERR = stderr;
     682             :   
     683             :   if (argc > 1)
     684             :     {
     685             :       beta = atol (argv[1]);
     686             :       loop = 0;
     687             :     }
     688             :   
     689             :   if (!loop)
     690             :     set_verbose (OUTPUT_TRACE);
     691             : 
     692             :   if (!loop)
     693             :     selftest (beta);
     694             :   else
     695             :     {
     696             :       printf ("Testing beta = 1, ..., %lu\n", selftest_max);
     697             :       for (beta = 1; beta < selftest_max; beta++)
     698             :         selftest (beta);
     699             :     }
     700             : 
     701             :   return 0;
     702             : }
     703             : #endif

Generated by: LCOV version 1.14