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 <stddef.h>
20 #include <stdio.h>
21 #include "DUPZfactor_liftq.h"
22 #include "jalloc.h"
23 #include "jaaerror.h"
24 #include "DUPZ_DUPFF.h"
25 #include "DUPZfactor_info.h"
26 
27 
28 /***************************************************************************/
29 
30 
DUPZfactor_lifter_ctor(DUPFF g,DUPFF h,DUPZfactor_lifter g_lifter,DUPZfactor_lifter h_lifter)31 DUPZfactor_lifter DUPZfactor_lifter_ctor(DUPFF g, DUPFF h, DUPZfactor_lifter g_lifter, DUPZfactor_lifter h_lifter)
32 {
33   DUPZfactor_lifter ans;
34   DUPFF corr_factor, junk, tmp;
35   int df;
36 
37   if (DUPFFdeg(g) > DUPFFdeg(h)) return DUPZfactor_lifter_ctor(h, g, h_lifter, g_lifter);
38   ans = (DUPZfactor_lifter)MALLOC(sizeof(struct DUPZfactor_lift_struct));
39   ans->g = DUPFF_to_DUPZ(g);
40   ans->h = DUPFF_to_DUPZ(h);
41   df = DUPFFdeg(g) + DUPFFdeg(h);
42   tmp = DUPFFexgcd(&junk, &corr_factor, g, h);
43   if (DUPFFdeg(tmp) != 0) { JERROR(JERROR_HENSEL); exit(1); }
44   /* since the gcd is not monic we have to do this... */
45   DUPFFdiv2ff(corr_factor, DUPFFlc(tmp));
46   ans->corr_factor = DUPZnew(df-1); /* need spare space for revise_lift_tree */
47   DUPFF_to_DUPZ2(ans->corr_factor, corr_factor);
48   ans->g_lifter = g_lifter;
49   ans->h_lifter = h_lifter;
50   DUPFFfree(tmp);
51   DUPFFfree(corr_factor);
52   DUPFFfree(junk);
53 
54   return ans;
55 }
56 
57 
DUPZfactor_lift_dtor(DUPZfactor_lifter THIS)58 void DUPZfactor_lift_dtor(DUPZfactor_lifter THIS)
59 {
60   if (THIS == NULL) return;
61   if (THIS->g_lifter) DUPZfactor_lift_dtor(THIS->g_lifter);
62   if (THIS->h_lifter) DUPZfactor_lift_dtor(THIS->h_lifter);
63   DUPZfree(THIS->g);
64   DUPZfree(THIS->h);
65   DUPZfree(THIS->corr_factor);
66   FREE(THIS);
67 }
68 
69 /***************************************************************************/
70 
DUPZfactor_lift_step(DUPZfactor_lifter THIS,DUPZ f,mpz_t Q)71 void DUPZfactor_lift_step(DUPZfactor_lifter THIS, DUPZ f, mpz_t Q)
72 {
73   /* local workspace -- maybe put these in lifter struct??? */
74   DUPZ Delta, delta_g, tmp;
75   /* just aliases to make the code easier to read (!?!) */
76   DUPZ       g     = THIS->g;
77   DUPZ       h     = THIS->h;
78   DUPZ       alpha = THIS->corr_factor;
79 
80   Delta = DUPZmul(g, h);
81   DUPZsub3(Delta, f, Delta);
82   DUPZdiv2z(Delta, Q);
83   DUPZmod2z(Delta, Q);
84 
85   tmp = DUPZnew(DUPZdeg(f));
86   DUPZmul3(tmp, alpha, h);
87   mpz_sub_ui(tmp->coeffs[0], tmp->coeffs[0], 2);
88   DUPZmod2(tmp, g, Q);
89   DUPZmul3(tmp, alpha, tmp);
90   DUPZneg1(tmp);
91   DUPZmod2(tmp, g, Q);
92   DUPZcopy2(alpha, tmp);
93 
94   delta_g = DUPZnew(DUPZdeg(f));
95   DUPZcopy2(delta_g, Delta);
96   DUPZmod2(delta_g, g, Q);
97   DUPZmul3(delta_g, alpha, delta_g);
98   DUPZmod2(delta_g, g, Q);
99   DUPZmul3(tmp, h, delta_g);
100   DUPZsub3(tmp, Delta, tmp);
101   DUPZmdiv2(tmp, g, Q);
102   DUPZmul2z(delta_g, Q);
103   DUPZmul2z(tmp, Q);
104   DUPZadd3(g, g, delta_g);
105   DUPZadd3(h, h, tmp);
106   DUPZfree(Delta);DUPZfree(delta_g);DUPZfree(tmp);
107 
108   if (THIS->g_lifter) DUPZfactor_lift_step(THIS->g_lifter, g, Q);
109   if (THIS->h_lifter) DUPZfactor_lift_step(THIS->h_lifter, h, Q);
110 }
111 
112 
113 /***************************************************************************/
114 
DUPZfactor_lift_init_stupid(const DUPFFlist pfactors)115 static DUPZfactor_lifter DUPZfactor_lift_init_stupid(const DUPFFlist pfactors)
116 {
117   DUPZfactor_lifter ans;
118   DUPFFlist iter;
119   DUPFF tmp;
120   int df;
121 
122   df = 0;
123   for (iter = pfactors; iter; iter = iter->next)
124     df += DUPFFdeg(iter->poly);
125   ans = NULL;
126   tmp = DUPFFnew(df);
127   DUPFFcopy2(tmp, pfactors->poly);
128   for (iter = pfactors->next; iter; iter = iter->next)
129   {
130     ans = DUPZfactor_lifter_ctor(iter->poly, tmp, NULL, ans);
131     DUPFFmul3(tmp, tmp, iter->poly);
132   }
133   DUPFFfree(tmp);
134 
135   return ans;
136 }
137 
138 
DUPZfactor_lift_init(DUPZfactor_info THIS)139 void DUPZfactor_lift_init(DUPZfactor_info THIS)
140 {
141   THIS->lifter = DUPZfactor_lift_init_stupid(THIS->pfactors);
142 }
143 
144 
145 #if 0
146 /****************************************************************************/
147 /* This function is called after a speculative early search which has found */
148 /* at least one factor but further lifting is still required.               */
149 /* It creates a new lifting tree for the remaining factors.                 */
150 
151 static DUPZfactor_lifter revise_lifter(DUPZfactor_lifter old_tree, mpz_t Q)
152 {
153 ?????????????????????????????????????????????????????????????????????????????
154   if (old_tree->g_lifter != NULL) g1 = revise_lifter(old_tree->g_lifter, Q);
155   if (old_tree->h_lifter != NULL) h1 = revise_lifter(old_tree->h_lifter, Q);
156   ans->g = DUPZmul(g1->g, h1->g);
157   ans->h = DUPZmul(g1->h, h1->h);
158   ans->g_lifter = NULL;
159 
160   if (DUPZdeg(g1->g) == 0 || DUPZdeg(h1->g) == 0) goto tidy_up;
161   if (DUPZdeg(g1->g) > DUPZdeg(h1->g))
162   {
163     new_tree->g = g1->g; g1->g = NULL;
164     new_tree->h = h1->g; h1->g = NULL;
165     new_tree->g_lifter = g1->g_lifter;
166     new_tree->h_lifter = h1->g_lifter;
167     new_tree->corr_factor = DUPZnew(DUPZdeg(ans->g));
168     DUPZmul3(new_tree->corr_factor, old_tree->corr_factor, h1->h);
169     DUPZmod3(new_tree->corr_factor, new_tree->g, Q);
170   }
171   else
172   {
173     new_tree->g = h1->g; h1->g = NULL;
174     new_tree->h = g1->g; g1->g = NULL;
175     new_tree->g_lifter = h1->g_lifter;
176     new_tree->h_lifter = g1->g_lifter;
177     new_tree->corr_factor = DUPZnew(df-1);
178     DUPZmul3(new_tree->corr_factor, old_tree->corr_factor, g1->h);
179     DUPZmod3(new_tree->corr_factor, new_tree->h, Q);
180     DUPZmul3(new_tree->corr_factor, new_tree->corr_factor, new_tree->g);
181     DUPZmod3(new_tree->corr_factor, new_tree->h, Q);
182     DUPZneg(new_tree->corr_factor);
183     DUPZadd3(new_tree->corr_factor, new_tree->corr_factor, 1);
184     DUPZdivmodQ(new_tree->corr_factor, new_tree->h);
185   }
186   tidy_up:
187   DUPZfactor_lift_dtor(g1);
188   DUPZfactor_lift_dtor(h1);
189   return ans;
190 }
191 #endif
192 
revise_lift_tree(DUPZfactor_lifter * tree,mpz_t Q)193 static DUPZ revise_lift_tree(DUPZfactor_lifter *tree, mpz_t Q)
194 {
195   DUPZ G, H, ans;
196   int g_prune, h_prune;
197   DUPZfactor_lifter THIS = *tree;     /* alias */
198   DUPZ g = THIS->g;                /* alias */
199   DUPZ h = THIS->h;                /* alias */
200   DUPZ alpha = THIS->corr_factor;  /* alias */
201 
202   if (THIS->g_lifter != NULL)
203     G = revise_lift_tree(&THIS->g_lifter, Q);
204   else
205   {
206     if (DUPZdeg(g) > 0) G = int_to_DUPZ(1);
207     else
208     {
209       g->deg = - g->deg;
210       G = DUPZcopy(g); /* wasteful */
211     }
212   }
213   g_prune = (DUPZdeg(G) == DUPZdeg(g));
214 
215   if (THIS->h_lifter != NULL)
216     H = revise_lift_tree(&THIS->h_lifter, Q);
217   else
218   {
219     if (DUPZdeg(h) > 0) H = int_to_DUPZ(1);
220     else
221     {
222       h->deg = - h->deg;
223       H = DUPZcopy(h); /* wasteful */
224     }
225   }
226   h_prune = (DUPZdeg(H) == DUPZdeg(h));
227 
228   if (g_prune && h_prune)
229   {
230     DUPZfactor_lift_dtor(THIS);
231     *tree = NULL;
232     goto end;
233   }
234   if (g_prune)
235   {
236     *tree = THIS->h_lifter;
237     THIS->h_lifter = NULL;
238     DUPZfactor_lift_dtor(THIS);
239     goto end;
240   }
241   if (h_prune)
242   {
243     *tree = THIS->g_lifter;
244     THIS->g_lifter = NULL;
245     DUPZfactor_lift_dtor(THIS);
246     goto end;
247   }
248   DUPZmdiv2(g, G, Q);
249   DUPZmdiv2(h, H, Q);
250   DUPZmod2(alpha, g, Q);
251   DUPZmul3(alpha, alpha, H);
252   DUPZmod2(alpha, g, Q);
253 
254  end:
255   ans = DUPZmul(G, H);
256   DUPZfree(G); DUPZfree(H);
257   return ans;
258 }
259 
260 
DUPZfactor_lift_revise(DUPZfactor_info info)261 void DUPZfactor_lift_revise(DUPZfactor_info info)
262 {
263   DUPZfree(revise_lift_tree(&info->lifter, info->Q));
264 }
265 
266 
267 /***************************************************************************/
268 /* Make the lifted factors available to outsiders.                         */
269 /* We actually return pointers to our own copies so that outsiders can     */
270 /* modify them: they should negate the degree if the factor was used to    */
271 /* form a true factor (see DUPZfactor_lift_revise above).                  */
272 
DUPZfactor_lift_output(DUPZ ** factors,const DUPZfactor_lifter THIS,int i)273 int DUPZfactor_lift_output(DUPZ **factors, const DUPZfactor_lifter THIS, int i)
274 {
275   if (THIS->g_lifter) i = DUPZfactor_lift_output(factors, THIS->g_lifter, i);
276   else factors[i++] = &THIS->g;
277   if (THIS->h_lifter) i = DUPZfactor_lift_output(factors, THIS->h_lifter, i);
278   else factors[i++] = &THIS->h;
279   return i;
280 }
281 
282 /***************************************************************************/
283