1 //   Copyright (c)  1997-2006  John Abbott
2 
3 //   This file is part of the source of CoCoALib, the CoCoA Library.
4 
5 //   CoCoALib is free software: you can redistribute it and/or modify
6 //   it under the terms of the GNU General Public License as published by
7 //   the Free Software Foundation, either version 3 of the License, or
8 //   (at your option) any later version.
9 
10 //   CoCoALib is distributed in the hope that it will be useful,
11 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //   GNU General Public License for more details.
14 
15 //   You should have received a copy of the GNU General Public License
16 //   along with CoCoALib.  If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 #include "DUPZfactor_combine.h"
20 #include "mpz_log.h"
21 /* We use a random number in DUPZfactor_combine_init, so include stdlib.h */
22 #include <stdlib.h>
23 #include <stddef.h>
24 /* Use float.h just to get DBL_EPSILON and DBL_MANT_DIG, used in DUPZfactor_combiner_set_n1coeffd_bounds */
25 #include <float.h>
26 
27 #include <math.h>
28 #include "jalloc.h"
29 #include "logi.h"
30 #include "WGD.h"
31 #include "DUPZevaluate.h"
32 #include "DUPZfactor_bound.h"
33 #include "DUPFF.h"
34 #include "DUPZ_DUPFF.h"
35 #include "DUPZfactor_refine_fds.h"
36 
37 /* This is defined in DUPZfactor.c. */
38 extern void DUPZfactor_finish(DUPZfactor_info THIS);
39 
40 /***************************************************************************/
41 /* These static variables are initialised by DUPZfactor_combine_init.      */
42 
43 static mpz_t num, den, tmp, lcm;
44 
45 /* for accounting/debugging */
46 static int divisions;
47 static int count1, count2, count3, count4, count5, count6;
48 
49 /***************************************************************************/
50 /* This function sets values for P and Q the numerator and denominator     */
51 /* bounds to be used during rational reconstruction.  During early         */
52 /* searching the value for Q is "guessed" (approx 1/(2*sqrt(lc(f)))).      */
53 
DUPZfactor_combiner_set_PQ(DUPZfactor_combiner THIS)54 static void DUPZfactor_combiner_set_PQ(DUPZfactor_combiner THIS)
55 {
56   /* numerator/denominator bounds for rational reconstruction */
57   /* Updated whenever non-monic factors are found             */
58   if (mpz_log(THIS->modulus) > logi(2) + 2*mpz_log(DUPZlc(THIS->info->f)))
59     mpz_abs(THIS->Q, DUPZlc(THIS->info->f));
60   else
61   {
62     mpz_set_ui(THIS->Q, 1);
63     mpz_mul_2exp(THIS->Q, THIS->Q, mpz_sizeinbase(THIS->modulus, 4)-1);
64   }
65 
66   mpz_fdiv_q(THIS->P, THIS->modulus, THIS->Q);
67   mpz_fdiv_q_ui(THIS->P, THIS->P, 2);
68 }
69 
70 #if 0
71 static void DUPZfactor_combiner_set_n1coeff_bounds(DUPZfactor_combiner THIS)
72 {
73   mpz_t tmp;
74   int i;
75   double log_bound;
76 
77   mpz_init(tmp);
78   for (i=0; i < nfactors; i++)
79   {
80     fi = *THIS->factors[i];
81     mpz_mul(tmp, fi->coeff[degfi - delta], DUPZlc(THIS->info->f));
82     mpz_fdiv_r(tmp, tmp, modulus);
83     mpz_mul_2exp(tmp, tmp, 32);    /* assumes unsigned is 32 bits */
84     mpz_fdiv_q(tmp, tmp, modulus);
85     n1coeff[i] = mpz_get_ui(tmp);
86   }
87 
88   log_bound = THIS->info->bounds->root_bound + THIS->info->bounds->leading_coeff - THIS->height * logi(THIS->p);
89   if (log_bound < -32*logi(2)) n1bound = 1;
90   else n1bound = 1 + exp(32*logi(2) + log_bound);
91   mpz_clear(tmp);
92 }
93 #endif
94 
DUPZfactor_combiner_set_n1coeffd_bounds(DUPZfactor_combiner THIS)95 static void DUPZfactor_combiner_set_n1coeffd_bounds(DUPZfactor_combiner THIS)
96 {
97 /*  const int nfactors = DUPFFlist_length(THIS->info->pfactors);*/
98   int log2_modulus, shift;
99   double tmpd, log_modulus;
100   const int float_bits = DBL_MANT_DIG;
101   const double eps = DBL_EPSILON;
102   DUPZ fi;
103   mpz_t n1coeff, half_modulus; /* workspace */
104   int i, delta;
105 
106   log_modulus = mpz_log(THIS->modulus);
107   mpz_init(n1coeff);
108   mpz_init_set(half_modulus, THIS->modulus);
109   mpz_fdiv_q_ui(half_modulus, half_modulus, 2);
110   log2_modulus = mpz_sizeinbase(THIS->modulus, 2);
111   shift = log2_modulus - float_bits - 10; /* 10 is rather arbitrary */
112   if (shift < 0) shift = 0;
113 delta=1;
114   for (i=0; i < THIS->nfactors_orig; i++)
115   {
116     if (THIS->used[i]) continue;
117     fi = *THIS->factors[i];
118     mpz_set(n1coeff, fi->coeffs[DUPZdeg(fi)-delta]);
119 /*printf("d-1 coeff of f[%d]=",i);mpz_out_str(stdout,10,n1coeff);printf("\n");*/
120     mpz_mul(n1coeff, n1coeff, DUPZlc(THIS->info->f));
121     mpz_fdiv_r(n1coeff, n1coeff, THIS->modulus);
122     if (mpz_cmp(n1coeff, half_modulus) > 0)
123       mpz_sub(n1coeff, n1coeff, THIS->modulus);
124     mpz_tdiv_q_2exp(n1coeff, n1coeff, shift);
125     THIS->n1coeffd[i] = mpz_get_d(n1coeff);
126     mpz_tdiv_q_2exp(n1coeff, THIS->modulus, shift);
127     THIS->n1coeffd[i] /= mpz_get_d(n1coeff);
128 /*DUPZprint(fi);*/
129 /*printf("THIS->n1coeffd[%d]=%g\n",i,THIS->n1coeffd[i]);*/
130   }
131   mpz_clear(n1coeff);
132   mpz_clear(half_modulus);
133   THIS->n1coeffd_bound = exp(THIS->info->bounds->leading_coeff + THIS->info->bounds->root_bound - mpz_log(THIS->modulus));
134   THIS->n1coeffd_bound += 2*eps;
135   THIS->n1coeffd_sum[0] = 0;
136 /*
137  *printf("mpz_log(THIS->modulus)=%g\n",mpz_log(THIS->modulus));
138  *printf("THIS->info->bounds->root_bound=%g\n",THIS->info->bounds->root_bound);
139  *printf("THIS->info->bounds->leading_coeff=%g\n",THIS->info->bounds->leading_coeff);
140  *printf("THIS->n1coeffd_bound=%g\n",THIS->n1coeffd_bound);
141  */
142   THIS->n1coeffd_flag = 0;
143   tmpd = THIS->info->bounds->leading_coeff + THIS->info->bounds->root_bound;
144   if (log_modulus < logi(10) + logi(DUPZdeg(THIS->info->f)) + tmpd) return;
145   THIS->n1coeffd_flag = 1;
146 }
147 
148 
149 
DUPZfactor_combiner_ctor(DUPZfactor_info info)150 DUPZfactor_combiner DUPZfactor_combiner_ctor(DUPZfactor_info info)
151 {
152   DUPZ f = info->f;  /* aliasing for convenience */
153   DUPZfactor_combiner THIS;
154   int i;
155   double rt_bd;
156   const int nfactors = DUPFFlist_length(info->pfactors);
157   const int range = 10; /* should be the same as range in DUPZfactor_sqfr */
158 
159   THIS = (DUPZfactor_combiner)MALLOC(sizeof(struct DUPZfactor_combine_struct));
160   THIS->info = info;
161   THIS->tuple_deg = 0;
162 
163   mpz_init_set(THIS->modulus, info->Q);
164   THIS->nfactors_orig = nfactors; /* this never changes */
165   THIS->nfactors = nfactors;      /* this counts down as factors are used */
166   THIS->factors = (DUPZ**)MALLOC(nfactors*sizeof(DUPZ*));
167   DUPZfactor_lift_output(THIS->factors, info->lifter, 0);
168 /*
169  *printf("There are %d modular factors:\n", nfactors);
170  *for(i=0;i<nfactors;i++)DUPZprint(*THIS->factors[i]);
171  */
172   THIS->combination = (int*)MALLOC(nfactors*sizeof(int));
173   THIS->used = (int*)MALLOC(nfactors*sizeof(int));
174   for (i=0; i < nfactors; i++) THIS->used[i] = 0;
175 
176   THIS->n1coeffd = (double*)MALLOC(nfactors*sizeof(double));
177   THIS->n1coeffd_sum = (double*)MALLOC(nfactors*sizeof(double));
178   DUPZfactor_combiner_set_n1coeffd_bounds(THIS);
179 
180   /* pick random value from [-range, range] avoiding 0 */
181   THIS->evaluation_point = rand()%(2*range) - range;
182   if (THIS->evaluation_point == 0) THIS->evaluation_point = range;
183 
184   /* the two lines below are odd to avoid risk of overflow */
185   rt_bd = info->bounds->root_bound;
186   THIS->log_ev_pt = rt_bd + log(1+exp(logi(abs(THIS->evaluation_point)) - rt_bd));
187   mpz_init(THIS->f_value);
188   DUPZevaluate(THIS->f_value, f, THIS->evaluation_point);
189   /* we have removed small linear factors from f, so f_value is non-zero */
190   THIS->factor_value = (mpz_t*)MALLOC(nfactors*sizeof(mpz_t));
191   for (i=0; i < nfactors; i++)
192   {
193     mpz_init(THIS->factor_value[i]);
194     DUPZevaluate(THIS->factor_value[i], *THIS->factors[i], THIS->evaluation_point);
195   }
196 
197   mpz_init(THIS->P);
198   mpz_init(THIS->Q);
199   DUPZfactor_combiner_set_PQ(THIS);
200   THIS->factor = DUPZnew(DUPZdeg(f)); /* Must be big enough to contain either the */
201   THIS->quot = DUPZnew(DUPZdeg(f));   /* putative factor or its complement.       */
202   THIS->rem = DUPZnew(DUPZdeg(f));
203   mpz_init(THIS->value_at_1);
204   DUPZevaluate(THIS->value_at_1, f, 1);
205   mpz_init(THIS->value_at_m1);
206   DUPZevaluate(THIS->value_at_m1, f, -1);
207 
208   THIS->tc_combination = (int*)MALLOC(nfactors*sizeof(int));
209   THIS->tc_combination[0] = -1;
210   THIS->tc_product = (mpz_t*)MALLOC(nfactors*sizeof(mpz_t));
211   for (i=0; i < nfactors; i++) mpz_init(THIS->tc_product[i]);
212 
213   return THIS;
214 }
215 
216 
DUPZfactor_combiner_dtor(DUPZfactor_combiner THIS)217 void DUPZfactor_combiner_dtor(DUPZfactor_combiner THIS)
218 {
219   int i;
220 
221   DUPZfree(THIS->factor);
222   DUPZfree(THIS->quot);
223   DUPZfree(THIS->rem);
224 /*****for (i=0; i < THIS->nfactors_orig; i++) DUPZfree(THIS->factors[i]);*****/
225   FREE(THIS->factors);
226   mpz_clear(THIS->modulus);
227   mpz_clear(THIS->f_value);
228   mpz_clear(THIS->value_at_1);
229   mpz_clear(THIS->value_at_m1);
230   mpz_clear(THIS->P);
231   mpz_clear(THIS->Q);
232   for(i=0; i < THIS->nfactors_orig; i++) mpz_clear(THIS->factor_value[i]);
233   FREE(THIS->factor_value);
234   FREE(THIS->used);
235   FREE(THIS->n1coeffd);
236   FREE(THIS->n1coeffd_sum);
237 
238   FREE(THIS->combination);
239   FREE(THIS->tc_combination);
240   for (i=0; i < THIS->nfactors_orig; i++) mpz_clear(THIS->tc_product[i]);
241   FREE(THIS->tc_product);
242 
243   FREE(THIS);
244 }
245 
246 
247 
248 /***************************************************************************/
249 /* These are not constructor/destructor; "_init" must be called before     */
250 /* searching combinations, and "_done" must be called after all searching  */
251 /* has been finished.  These functions deal with globals.                  */
252 
DUPZfactor_combine_init()253 void DUPZfactor_combine_init()
254 {
255   divisions=count1=count2=count3=count4=count5=count6=0;
256   mpz_init(num);
257   mpz_init(den);
258   mpz_init(tmp);
259   mpz_init(lcm);
260 }
261 
DUPZfactor_combine_done()262 void DUPZfactor_combine_done()
263 {
264   mpz_clear(num); mpz_clear(den);  mpz_clear(tmp); mpz_clear(lcm);
265 #ifdef FACTOR_DEBUG
266   printf("\nSearch complete.  count1=%d, count2=%d, count3=%d, count4=%d, count5=%d, count6=%d\n", count1, count2, count3, count4, count5, count6);
267   printf("Total number of divisions: %d\n", divisions);
268 #endif
269 }
270 
271 
272 /***************************************************************************/
273 
274 static int DUPZfactor_combine1(DUPZfactor_combiner THIS, int n, int r, int i);
275 
DUPZfactor_combine(DUPZfactor_combiner THIS)276 static void DUPZfactor_combine(DUPZfactor_combiner THIS)
277 {
278   int tuple_size, max_tuple_size;
279   double log_modulus, log_lc, factor_bound;
280 
281   THIS->single_factor = 0;
282   log_modulus = mpz_log(THIS->modulus);
283   if (THIS->early)
284   {
285     max_tuple_size = (int)(10/logi(THIS->nfactors));
286     if (max_tuple_size > THIS->nfactors/2) max_tuple_size = THIS->nfactors/2;
287   }
288   else
289   {
290     log_lc = THIS->info->bounds->leading_coeff;
291     factor_bound = THIS->info->bounds->all_factors;
292     /* Search through only half the combinations if modulus is big enough */
293     if (log_modulus > 2*log_lc + factor_bound + 0.7) max_tuple_size = THIS->nfactors/2;
294     else { THIS->single_factor = 1; max_tuple_size = THIS->nfactors - 1; }
295   }
296 #ifdef FACTOR_DEBUG
297   printf("max_tuple_size=%d\n", max_tuple_size);
298 #endif
299   for (tuple_size=1; tuple_size <= max_tuple_size; tuple_size++)
300   {
301     if (tuple_size >= THIS->nfactors) break; /* only relevant during early searching */
302 #ifdef FACTOR_DEBUG
303     printf("\nInterim.  count1=%d, count2=%d, count3=%d, count4=%d, count5=%d, count6=%d", count1, count2, count3, count4, count5, count6);
304     printf("\n%d-tuples: ", tuple_size);
305 #endif
306     THIS->tuple_size = tuple_size;
307     THIS->tc_combination[tuple_size-1] = -1; /* so first call to tctest works properly */
308     DUPZfactor_combine1(THIS, THIS->nfactors, 0, 0);
309     if (THIS->early) continue;
310     /* Check if we can reduce to a search through half the combinations. */
311     log_lc = THIS->info->bounds->leading_coeff;
312     factor_bound = THIS->info->bounds->all_factors;
313     THIS->single_factor = 0;
314 //   2020-04-25 See redmine 1449.  This clever trick seems to be "bogus"  :-(
315 //    if (log_modulus > 2*log_lc + factor_bound + 0.7)
316 //    { max_tuple_size = THIS->nfactors/2; }
317 //    else { THIS->single_factor = 1; max_tuple_size = THIS->nfactors - 1; }
318     THIS->single_factor = 1; max_tuple_size = THIS->nfactors - 1;
319   }
320   if (THIS-> early || DUPZdeg(THIS->info->f) <= 0) return;
321   DUPZfactors_add(THIS->info->irreds, THIS->info->f);
322   THIS->info->f->deg = 0;
323 }
324 
325 
DUPZfactor_combine_early(DUPZfactor_combiner THIS)326 void DUPZfactor_combine_early(DUPZfactor_combiner THIS)
327 {
328   THIS->early = 1; /* flag that we're doing early searching */
329   DUPZfactor_combine(THIS);
330 }
331 
332 
DUPZfactor_combine_final(DUPZfactor_combiner THIS)333 void DUPZfactor_combine_final(DUPZfactor_combiner THIS)
334 {
335   THIS->early = 0; /* flag that this is the final search */
336   DUPZfactor_combine(THIS);
337 }
338 
339 
340 
341 /***************************************************************************/
342 /***************************************************************************/
343 /* n-1 coeff test */
344 
DUPZfactor_combine_n1test(DUPZfactor_combiner THIS)345 static int DUPZfactor_combine_n1test(DUPZfactor_combiner THIS)
346 {
347   int i, deg, df, D;
348   const DUPZ f = THIS->info->f;
349   DUPZ fi; /* just a convenient alias */
350   double n1_coeff_bound;
351 
352   deg = THIS->tuple_deg;
353 
354   df = DUPZdeg(f);
355 
356   /* Compute in tmp the n-1 coeff of the current tuple (or its complement).    */
357   /* Cannot just subtract from n-1 coeff in f because that value isn't to hand. */
358   mpz_set_ui(tmp, 0);
359   if (THIS->single_factor || deg <= df/2) /* tuple has low degree, so compute n-1 coeff directly */
360   {
361     D = deg;
362     for (i=0; i < THIS->tuple_size; i++)
363     {
364       fi = *THIS->factors[THIS->combination[i]];
365       mpz_add(tmp, tmp, fi->coeffs[DUPZdeg(fi)-1]);
366     }
367   }
368   else /* tuple has high degree, so compute n-1 coeff of its complement */
369   {
370     D = df - deg;
371     for (i=0; i < THIS->nfactors_orig; i++)
372     {
373       if (THIS->used[i]) continue;
374       fi = *THIS->factors[i];
375       mpz_add(tmp, tmp, fi->coeffs[DUPZdeg(fi)-1]);
376     }
377   }
378   mpz_fdiv_r(tmp, tmp, THIS->modulus);
379   /* Now compute the rational corresponding to the modular value. */
380   modular_to_rational(num, den, THIS->Q, tmp, THIS->modulus);
381 
382   /* check magnitude of numerator */
383   if (mpz_sgn(num) == 0) return 1;
384   n1_coeff_bound = THIS->info->bounds->root_bound + logi(D) + 0.001;
385   if (mpz_log(num) - mpz_log(den) > n1_coeff_bound) return 0;
386 
387   /* check denominator divides leading coeff */
388   mpz_fdiv_r(num, DUPZlc(f), den);
389   if (mpz_sgn(num) != 0) return 0;
390   return 1;
391 }
392 
393 
394 /***************************************************************************/
395 /* Trailing coeff test                                                     */
396 /* SIDE EFFECT: sets THIS->log_tc (used in coefftest below)                */
397 
DUPZfactor_combine_tctest(DUPZfactor_combiner THIS)398 static int DUPZfactor_combine_tctest(DUPZfactor_combiner THIS)
399 {
400   DUPZ f = THIS->info->f;  /* convenient alias */
401   int i, deg, df;
402   DUPZ fi; /* just a convenient alias */
403 
404   deg = THIS->tuple_deg;
405   df = DUPZdeg(f);
406   /* compute in tmp the trailing coeff of the current combination */
407   mpz_set_ui(tmp, 1);
408   if (THIS->single_factor || deg <= df/2)
409   {
410     for (i=0; i < THIS->tuple_size; i++)
411     {
412       if (THIS->combination[i] == THIS->tc_combination[i]) continue;
413       THIS->tc_combination[i] = THIS->combination[i];
414       THIS->tc_combination[i+1] = -1;
415       fi = *THIS->factors[THIS->combination[i]];
416       if (i == 0) mpz_set(THIS->tc_product[i], fi->coeffs[0]);
417       else
418       {
419         mpz_mul(THIS->tc_product[i], THIS->tc_product[i-1], fi->coeffs[0]);
420         mpz_fdiv_r(THIS->tc_product[i], THIS->tc_product[i], THIS->modulus);
421       }
422     }
423     mpz_set(tmp, THIS->tc_product[i-1]);
424   }
425   else
426   {
427     for (i=0; i < THIS->nfactors_orig; i++)
428     {
429       if (THIS->used[i]) continue;
430       fi = *THIS->factors[i];
431       mpz_mul(tmp, tmp, fi->coeffs[0]);
432       mpz_fdiv_r(tmp, tmp, THIS->modulus);
433     }
434   }
435 
436   /* NB tmp != 0 because we excluded primes dividing the trailing coeff */
437   modular_to_rational(num, den, THIS->Q, tmp, THIS->modulus);
438 
439   /* check numerator divides trailing coeff of original polynomial */
440   mpz_fdiv_r(tmp, f->coeffs[0], num);
441   if (mpz_sgn(tmp) != 0) return 0;
442 
443   /* check denominator divides leading coeff */
444   mpz_fdiv_r(tmp, DUPZlc(f), den);
445   if (mpz_sgn(tmp) != 0) return 0;
446 
447   THIS->log_tc = mpz_log(num) - mpz_log(den); /* used in coefftest below */
448   return 1;
449 }
450 
451 
DUPZfactor_combine_evaltest(DUPZfactor_combiner THIS)452 static int DUPZfactor_combine_evaltest(DUPZfactor_combiner THIS)
453 {
454   int i, deg, df, D;
455   DUPZ f = THIS->info->f; /* convenient alias */
456 
457   df = DUPZdeg(f);
458   deg = THIS->tuple_deg;
459   if (THIS->single_factor || deg <= df/2) D = deg; else D = df - deg;
460   /* Do eval at r test only if P/Q > (r + root_bound)^D */
461   if (mpz_log(THIS->P) - mpz_log(THIS->Q) < D*THIS->log_ev_pt + 0.001) return 1;
462   /* compute in tmp the value at r of the current combination (or its complement) */
463   mpz_set_ui(tmp, 1);
464   if (THIS->single_factor || deg <= df/2) /* tuple has low degree, so compute its value directly */
465   {
466     for (i=0; i < THIS->tuple_size; i++)
467     {
468       mpz_mul(tmp, tmp, THIS->factor_value[THIS->combination[i]]);
469       mpz_fdiv_r(tmp, tmp, THIS->modulus);
470     }
471   }
472   else /* tuple has high degree, so compute value of its complement instead */
473   {
474     for (i=0; i < THIS->nfactors_orig; i++)
475     {
476       if (THIS->used[i]) continue;
477       mpz_mul(tmp, tmp, THIS->factor_value[i]);
478       mpz_fdiv_r(tmp, tmp, THIS->modulus);
479     }
480   }
481 
482   modular_to_rational(num, den, THIS->Q, tmp, THIS->modulus);
483 
484   if (mpz_sgn(num) == 0) return 0;
485 
486   /* check numerator divides the value of f */
487   mpz_fdiv_r(num, THIS->f_value, num);
488   if (mpz_sgn(num) != 0) return 0;
489 
490   /* check denominator divides lc(f) */
491   mpz_fdiv_r(den, DUPZlc(f), den);
492   if (mpz_sgn(den) != 0) return 0;
493 
494   return 1;
495 }
496 
497 
498 /***************************************************************************/
499 /* Coefficient test: the modular factors are multiplied, and the coeffs of */
500 /* the product converted to rationals checking numerator and denominator   */
501 /* have possible values.  This test is relatively expensive.               */
502 
DUPZfactor_combine_coefftest(DUPZfactor_combiner THIS)503 static int DUPZfactor_combine_coefftest(DUPZfactor_combiner THIS)
504 {
505   int i, j, deg, df, D;
506   DUPZ f = THIS->info->f;             /* alias */
507   DUPZ g = THIS->factor;              /* alias */
508   double log_coeff, forward, reverse; /* forward and reverse bounds */
509 
510   deg = THIS->tuple_deg;
511   df = DUPZdeg(f);
512   /* if deg <= df/2 then we multiply out the combination,     */
513   /* otherwise we multiply out the complementary combination. */
514   if (THIS->single_factor || deg <= df/2)
515   {
516     D = deg;
517     DUPZcopy2(g, *THIS->factors[THIS->combination[0]]);
518     for (i=1; i < THIS->tuple_size; i++)
519     {
520       DUPZmul3(g, g, *THIS->factors[THIS->combination[i]]);
521       for (j=DUPZdeg(g); j >= 0; j--)
522 	mpz_fdiv_r(g->coeffs[j], g->coeffs[j], THIS->modulus);
523     }
524   }
525   else
526   {
527     D = df - deg;
528     mpz_set_ui(g->coeffs[0], 1);
529     g->deg = 0;
530     for (i=0; i < THIS->nfactors_orig; i++)
531     {
532       if (THIS->used[i]) continue;
533       DUPZmul3(g, g, *THIS->factors[i]);
534       for (j=DUPZdeg(g); j >= 0; j--)
535 	mpz_fdiv_r(g->coeffs[j], g->coeffs[j], THIS->modulus);
536     }
537   }
538 
539 
540   forward = 0.001;          /* add 0.001 to allow for rounding error */
541   reverse = THIS->log_tc + D*THIS->info->bounds->reverse_root_bound + 0.001;
542   mpz_set_ui(lcm, 1);
543   for (i=D-1; i >= 0; i--)
544   {
545     forward += logi(i+1) - logi(D-i) + THIS->info->bounds->root_bound;
546     reverse += logi(i+1) - logi(D-i) - THIS->info->bounds->reverse_root_bound;
547     if (mpz_sgn(g->coeffs[i]) == 0) continue;
548     modular_to_rational(num, den, THIS->Q, g->coeffs[i], THIS->modulus);
549     mpz_fdiv_r(tmp, DUPZlc(f), den);          /* check denom divides lc(f) */
550     if (mpz_sgn(tmp) != 0) return 0;          /* if not, factor is false */
551 
552     /* check coeff is within permitted range */
553     log_coeff = mpz_log(num) - mpz_log(den);
554     if (log_coeff > forward || log_coeff > reverse) return 0;
555 
556     /* store rational in THIS->factor and THIS->quot */
557     mpz_set(g->coeffs[i], num);
558     mpz_set(THIS->quot->coeffs[i], den);
559 
560     /* update the common denominator */
561     mpz_gcd(tmp, lcm, den);
562     mpz_divexact(den, den, tmp);
563     mpz_mul(lcm, lcm, den);
564   }
565 
566   /* make THIS->factor have a common denominator */
567   for (i=D-1; i >= 0; i--)
568   {
569     if (mpz_sgn(g->coeffs[i]) == 0) continue;
570     if (mpz_cmp(lcm, THIS->quot->coeffs[i]) == 0) continue;
571     mpz_divexact(den, lcm, THIS->quot->coeffs[i]);
572     mpz_mul(g->coeffs[i], g->coeffs[i], den);
573   }
574   mpz_set(g->coeffs[D], lcm);
575 
576   return 1;
577 }
578 
579 
580 /***************************************************************************/
581 /* Division test: we divide the putative factor into the polynomial.       */
582 /* We initially check that the values at 1 and -1 divide those of f.       */
583 /* Then we just do long division.  This test is potentially very expensive */
584 /* if the putative factor is not a true one -- should hardly ever happen.  */
585 
DUPZfactor_combine_dividetest(DUPZfactor_combiner THIS)586 static int DUPZfactor_combine_dividetest(DUPZfactor_combiner THIS)
587 {
588   DUPZ f = THIS->info->f;  /* convenient alias */
589 
590   /* These two preliminary checks are most relevant during early detection */
591   /* check value of factor at 1 divides the value of f at 1 */
592   DUPZevaluate(tmp, THIS->factor, 1);
593   if (mpz_sgn(tmp) == 0) return 0;
594   mpz_fdiv_r(tmp, THIS->value_at_1, tmp);
595   if (mpz_sgn(tmp) != 0) return 0;
596 
597   /* check value of factor at -1 divides the value of f at -1 */
598   DUPZevaluate(tmp, THIS->factor, -1);
599   if (mpz_sgn(tmp) == 0) return 0;
600   mpz_fdiv_r(tmp, THIS->value_at_m1, tmp);
601   if (mpz_sgn(tmp) != 0) return 0;
602 
603   /* we expect this division almost always to be exact */
604   DUPZdiv4(THIS->quot, THIS->rem, f, THIS->factor);
605   divisions++;
606   if (DUPZdeg(THIS->rem) >= 0) return 0;
607 
608   /* Swap factor and quot if we have built the complement in factor. */
609   if (!THIS->single_factor && THIS->tuple_deg > DUPZdeg(THIS->info->f)/2)
610     DUPZswap(THIS->quot, THIS->factor);
611   return 1;
612 }
613 
614 
615 /***************************************************************************/
616 /* This function is called if we cannot immediately show that the factor   */
617 /* is irreducible.  A more stringent irreducibility test is conducted, and */
618 /* if necessary, a subsidiary factorization is performed.                  */
619 
DUPZfactor_combine_fork(DUPZfactor_combiner old,DUPZ factor)620 static void DUPZfactor_combine_fork(DUPZfactor_combiner old, DUPZ factor)
621 {
622   int i, irred, dmax;
623   DUPZfactor_info fork;
624   DUPFF fp, rem;
625   DUPFFlist iter;
626   bound_info bd;
627   double lift_height = mpz_log(old->modulus) - 0.001; /* allow for rounding */
628 
629   /* initial quick tests for "obvious" irreducibility */
630   if (old->tuple_size == 1 || !old->early)
631   {
632     DUPZfactors_add(old->info->irreds, factor);
633     return;
634   }
635   dmax = DUPZdeg(factor)/2;
636   while (!old->info->fds[dmax]) dmax--;
637   bd = DUPZcopy_refine_bound(old->info->bounds, factor, dmax);
638   if (bd->lift_bound < lift_height)
639   {
640     FREE(bd);
641     DUPZfactors_add(old->info->irreds, factor);
642     return;
643   }
644   fork = (DUPZfactor_info)MALLOC(sizeof(struct DUPZfactor_info_struct));
645   fork->f = DUPZcopy(factor);
646   fork->irreds = old->info->irreds;
647   fork->p = old->info->p;
648 
649   fork->nprimes = old->info->nprimes;
650   fork->FFq = (FF*)MALLOC(fork->nprimes*sizeof(FF));
651   fork->qfactors = (DUPFFlist*)MALLOC(fork->nprimes*sizeof(DUPFFlist));
652   fork->fds = (int*)MALLOC((1+DUPZdeg(fork->f))*sizeof(int));
653   for (i=0; i <= DUPZdeg(fork->f); i++) fork->fds[i] = old->info->fds[i];
654   fork->bounds = NULL;
655   mpz_init_set(fork->recip_lcf, old->info->recip_lcf);
656   mpz_mul(fork->recip_lcf, fork->recip_lcf, DUPZlc(old->info->f));
657   mpz_divexact(fork->recip_lcf, fork->recip_lcf, DUPZlc(factor));
658   mpz_init_set(fork->Q, old->info->Q);
659   fork->lifter = NULL;
660 
661   /* determine new factorizations modulo the various primes */
662   fp = DUPFFnew(DUPZdeg(fork->f));
663   rem = DUPFFnew(DUPZdeg(fork->f));
664   irred = 0;
665   for (i=0; i < old->info->nprimes; i++)
666   {
667     FFselect(old->info->FFq[i]);
668     fork->FFq[i] = FFctor(CurrentFF.prime); /* wasteful copy */
669     fork->qfactors[i] = NULL;
670     DUPZ_to_DUPFF2(fp, fork->f);
671     for (iter = old->info->qfactors[i]; iter; iter = iter->next)
672     {
673       DUPFFcopy2(rem, fp);
674       DUPFFrem2(rem, iter->poly);
675       if (DUPFFdeg(rem) >= 0) continue;
676       fork->qfactors[i] = DUPFFlist_append(DUPFFlist_ctor(DUPFFcopy(iter->poly), 1), fork->qfactors[i]);
677     }
678     irred = DUPZfactor_refine_fds(fork->fds, fork->qfactors[i]);
679 /*    if (irred) break;*/ /* including this line makes deallocation trickier */
680   }
681   /* select correct prime for rest of computation */
682   fork->p_index = old->info->p_index;
683   fork->pfactors = fork->qfactors[fork->p_index];
684   FFselect(fork->FFq[fork->p_index]);
685   DUPFFfree(fp);
686   DUPFFfree(rem);
687   if (irred)
688   {
689     FREE(bd);
690     DUPZfactors_add(fork->irreds, fork->f);
691     DUPZfactor_info_dtor(fork);
692     return;
693   }
694 
695   /* update bounds */
696   fork->dmax = old->info->dmax;
697   if (fork->dmax > DUPZdeg(fork->f)/2) fork->dmax = DUPZdeg(fork->f)/2;
698 
699   while (!fork->fds[dmax]) dmax--;
700   fork->dmax = dmax;
701 /*  fork->dmin = old->info->dmin;                */
702 /*  while (!fork->fds[fork->dmin]) fork->dmin++; */
703   DUPZrefine_bound(bd, fork->f, dmax);
704   fork->bounds = bd;
705   if (bd->lift_bound < lift_height)
706   {
707     DUPZfactors_add(fork->irreds, fork->f);
708     DUPZfactor_info_dtor(fork);
709     return;
710   }
711   DUPZfactor_info_set_target_height(fork);
712 
713 
714 /*************************************************************  DUPZfactor_lift_revise1(fork, old->info->lifter->r); **********************/
715 #ifdef FACTOR_DEBUG
716   printf("\nFactor may be reducible: starting subsidiary factorization\n");
717 #endif
718   DUPZfactor_finish(fork);
719 #ifdef FACTOR_DEBUG
720   printf("Subsidiary factorization complete; resuming previous factorization\n");
721 #endif
722   DUPZfactor_info_dtor(fork);
723 }
724 
725 /***************************************************************************/
726 /* Upon entry to this function THIS->factor contains the factor built from */
727 /* the current tuple, while THIS->quot contains its complement (i.e. the   */
728 /* quotient of f by the factor found.                                      */
729 
DUPZfactor_combine_found(DUPZfactor_combiner THIS)730 static void DUPZfactor_combine_found(DUPZfactor_combiner THIS)
731 {
732   const DUPZ f = THIS->info->f;  /* convenient alias */
733 DUPZ fi;
734   double rt_bd;
735   int i, irred, df;
736   DUPFF rem, fp;
737   DUPFFlist iter, next, *prev;
738 
739   DUPZfactor_combine_fork(THIS, THIS->factor); /* recurse on factor, needed only if using early detection */
740 for(i=0;i<THIS->tuple_size;i++){fi=*THIS->factors[THIS->combination[i]];fi->deg=-fi->deg;}
741   DUPZcopy2(f, THIS->quot);
742   mpz_mul(THIS->info->recip_lcf, THIS->info->recip_lcf, DUPZlc(THIS->factor));
743   df = DUPZdeg(f);
744   THIS->nfactors -= THIS->tuple_size;
745 
746   /* ---- we may be able to prove that what's left is irreducible ----- */
747   /* determine new factorizations modulo the various primes */
748 #ifdef FACTOR_DEBUG
749   printf("Checking if quotient is irred\n");
750 #endif
751   fp = DUPFFnew(df);
752   rem = DUPFFnew(df);
753   irred = 0;
754   for (i=0; i < THIS->info->nprimes; i++)
755   {
756     FFselect(THIS->info->FFq[i]);
757     prev = &THIS->info->qfactors[i];
758     DUPZ_to_DUPFF2(fp, f);
759     for (iter = THIS->info->qfactors[i]; iter; iter = next)
760     {
761       next = iter->next;
762       DUPFFcopy2(rem, fp);
763       DUPFFrem2(rem, iter->poly);
764       if (DUPFFdeg(rem) >= 0) DUPFFlist_elem_dtor(iter);
765       else { *prev = iter; prev = &iter->next; }
766     }
767     *prev = NULL;
768     irred = DUPZfactor_refine_fds(THIS->info->fds, THIS->info->qfactors[i]);
769 #ifdef FACTOR_DEBUG
770     printf("irred (via FDS) for remaining factor: %d\n",irred);
771 #endif
772     if (irred) break;
773   }
774 
775   THIS->info->pfactors = THIS->info->qfactors[THIS->info->p_index];
776   FFselect(THIS->info->FFq[THIS->info->p_index]);
777   DUPFFfree(fp);
778   DUPFFfree(rem);
779   if (irred)
780   {
781     DUPZfactors_add(THIS->info->irreds, f);
782     for (i=0; i < THIS->nfactors_orig; i++) THIS->used[i] = 1;
783 for (i=0; i < THIS->nfactors_orig; i++) {fi=*THIS->factors[i];if (DUPZdeg(fi)>0) fi->deg = -fi->deg; }
784     THIS->nfactors = 0;
785     f->deg = 0;
786     return;
787   }
788   if (THIS->info->dmax > df/2) THIS->info->dmax = df/2;
789   while (!THIS->info->fds[THIS->info->dmax]) THIS->info->dmax--;
790 /*  while (!THIS->info->fds[THIS->info->dmin]) THIS->info->dmin++; */
791 
792   /* update bounds */
793 #ifdef FACTOR_DEBUG
794   printf("Updating factor bounds...\n");
795 #endif
796   DUPZrefine_bound(THIS->info->bounds, f, THIS->info->dmax);
797   DUPZfactor_info_set_target_height(THIS->info);
798 /* #ifdef FACTOR_DEBUG */
799 /* printf("bound info\n----------\n"); */
800 /* printf("deg\t\t%d\n", THIS->info->bounds->df); */
801 /* printf("lc\t\t%f\n", THIS->info->bounds->leading_coeff); */
802 /* printf("tc\t\t%f\n", THIS->info->bounds->trailing_coeff); */
803 /* printf("dmax\t\t%d\n", THIS->info->bounds->dmax); */
804 /* printf("Bombieri2\t%f\n", THIS->info->bounds->Bombieri2); */
805 /* printf("root_bound\t%f\n", THIS->info->bounds->root_bound); */
806 /* printf("rev_root_bound\t%f\n", THIS->info->bounds->reverse_root_bound); */
807 /* printf("all_factors\t%f\n", THIS->info->bounds->all_factors); */
808 /* printf("lift_bound\t%f\n", THIS->info->bounds->lift_bound); */
809 /* #endif */
810 
811   if (THIS->early && THIS->info->target_height <= THIS->info->current_height)
812   {
813     THIS->early = 0;
814 #ifdef FACTOR_DEBUG
815     printf("[early search has now become final search]");
816 #endif
817   }
818 
819   /* update log_ev_pt */
820   rt_bd = THIS->info->bounds->root_bound;
821   THIS->log_ev_pt = rt_bd + log(1+exp(logi(abs(THIS->evaluation_point)) - rt_bd));
822 
823   /* update f_value */
824   DUPZevaluate(THIS->f_value, f, THIS->evaluation_point);
825 
826   /* update P, Q */
827   DUPZfactor_combiner_set_PQ(THIS);
828 
829   /* update n1coeff_bounds */
830   DUPZfactor_combiner_set_n1coeffd_bounds(THIS);
831 }
832 
833 
834 
DUPZfactor_combine1(DUPZfactor_combiner THIS,int n,int r,int i)835 static int DUPZfactor_combine1(DUPZfactor_combiner THIS, int n, int r, int i)
836 /* any true factors found will be added to ans.   */
837 /* n is number of factors still to be considered, */
838 /* r is number of factors already picked,         */
839 /* i is index of next factor to consider          */
840 {
841   int deg, found;
842 
843   if (n < THIS->tuple_size - r) return 0;
844   if (r < THIS->tuple_size)
845   {
846     /*    if (deg > dmax) return;*/
847     if (THIS->used[i]) return DUPZfactor_combine1(THIS, n, r, i+1);
848     THIS->combination[r] = i;
849     THIS->used[i] = 2;
850     deg = DUPZdeg(*THIS->factors[i]);
851     THIS->tuple_deg += deg;
852     THIS->n1coeffd_sum[r+1] = THIS->n1coeffd_sum[r] + THIS->n1coeffd[i];
853      /* first try with this factor */
854     found = DUPZfactor_combine1(THIS, n-1, r+1, i+1);
855     THIS->tuple_deg -= deg;
856     if (!found) THIS->used[i] = 0;
857     /* special case if n = nfactors/2 */
858     if (!found && !THIS->single_factor && (r == 0) && (THIS->nfactors == 2*THIS->tuple_size)) return 0;
859     if (!found) return DUPZfactor_combine1(THIS, n-1, r, i+1);
860     if (r > 0) return 1; /* unwind to "top level" */
861     /* now we must be at "top level" */
862     if (!THIS->single_factor && THIS->nfactors < 2*THIS->tuple_size) return 0;
863     if (THIS->nfactors <= THIS->tuple_size) return 0;
864 
865     /* now try without this factor */
866     return DUPZfactor_combine1(THIS, n - THIS->tuple_size, r, i+1);
867   }
868 
869 #ifdef FACTOR_DEBUG
870   printf("Trying tuple: \t"); for (i=0; i < THIS->tuple_size; i++) printf("%d ", THIS->combination[i]); printf("\n");
871 #endif
872 count1++;
873 
874   /* check degree is possible */
875   if (THIS->info->fds[THIS->tuple_deg] == 0) return 0;
876 count2++;
877 
878 
879   if (THIS->n1coeffd_flag)
880   {
881     /* Compute in deg the nearest integer to THIS->n1coeffd_sum */
882     if (THIS->n1coeffd_sum[THIS->tuple_size] >= 0)
883       deg = (int)(THIS->n1coeffd_sum[THIS->tuple_size] + 0.5);
884     else deg = (int)(THIS->n1coeffd_sum[THIS->tuple_size] - 0.5);
885 
886     if (fabs(THIS->n1coeffd_sum[THIS->tuple_size] - deg) >= THIS->tuple_deg * THIS->n1coeffd_bound) return 0;
887   }
888   else
889     if (!DUPZfactor_combine_n1test(THIS)) return 0;
890 
891 /*
892  *  if (!DUPZfactor_combine_1test(THIS)) {printf("!");fflush(stdout);return 0;}
893  */
894 count3++;
895 
896   if (!DUPZfactor_combine_tctest(THIS)) return 0;
897 count4++;
898 
899   if (!DUPZfactor_combine_evaltest(THIS)) return 0;
900 count5++;
901 
902   if (!DUPZfactor_combine_coefftest(THIS)) return 0;
903 count6++;
904 
905   if (!DUPZfactor_combine_dividetest(THIS)) return 0;
906 
907   DUPZfactor_combine_found(THIS);
908 
909   return 1;
910 }
911