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