1 // Univariate Polynomials over some subring of the numbers.
3 #include "cl_SV_number.h"
5 #include "cl_integer.h"
8 // Assume a ring is a number ring.
9 inline cl_heap_number_ring* TheNumberRing (const cl_ring& R)
10 { return (cl_heap_number_ring*) R.heappointer; }
12 // Normalize a vector: remove leading zero coefficients.
13 // The result vector is known to have length len > 0.
14 static inline void num_normalize (cl_number_ring_ops<cl_number>& ops, cl_SV_number& result, uintL len)
16 if (ops.zerop(result[len-1])) {
19 if (!ops.zerop(result[len-1]))
23 var cl_SV_number newresult = cl_SV_number(cl_make_heap_SV_number_uninit(len));
24 for (var sintL i = len-1; i >= 0; i--)
25 init1(cl_number, newresult[i]) (result[i]);
30 static void num_fprint (cl_heap_univpoly_ring* UPR, cl_ostream stream, const _cl_UP& x)
32 DeclarePoly(cl_SV_number,x);
33 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
34 var sintL xlen = x.length();
38 var const cl_ring& R = UPR->basering();
39 var cl_string varname = get_varname(UPR);
40 for (var sintL i = xlen-1; i >= 0; i--)
41 if (!ops.zerop(x[i])) {
43 fprint(stream, " + ");
44 fprint(stream, cl_ring_element(R,x[i]));
47 fprint(stream, varname);
50 fprintdecimal(stream, i);
57 static cl_boolean num_equal (cl_heap_univpoly_ring* UPR, const _cl_UP& x, const _cl_UP& y)
59 DeclarePoly(cl_SV_number,x);
60 DeclarePoly(cl_SV_number,y);
61 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
62 var sintL xlen = x.length();
63 var sintL ylen = y.length();
66 for (var sintL i = xlen-1; i >= 0; i--)
67 if (!ops.equal(x[i],y[i]))
72 static const _cl_UP num_zero (cl_heap_univpoly_ring* UPR)
74 return _cl_UP(UPR, cl_null_SV_number);
77 static cl_boolean num_zerop (cl_heap_univpoly_ring* UPR, const _cl_UP& x)
80 { DeclarePoly(cl_SV_number,x);
81 var sintL xlen = x.length();
88 static const _cl_UP num_plus (cl_heap_univpoly_ring* UPR, const _cl_UP& x, const _cl_UP& y)
90 DeclarePoly(cl_SV_number,x);
91 DeclarePoly(cl_SV_number,y);
92 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
93 var sintL xlen = x.length();
94 var sintL ylen = y.length();
96 return _cl_UP(UPR, y);
98 return _cl_UP(UPR, x);
99 // Now xlen > 0, ylen > 0.
101 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(xlen));
103 for (i = xlen-1; i >= ylen; i--)
104 init1(cl_number, result[i]) (x[i]);
105 for (i = ylen-1; i >= 0; i--)
106 init1(cl_number, result[i]) (ops.plus(x[i],y[i]));
107 return _cl_UP(UPR, result);
110 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(ylen));
112 for (i = ylen-1; i >= xlen; i--)
113 init1(cl_number, result[i]) (y[i]);
114 for (i = xlen-1; i >= 0; i--)
115 init1(cl_number, result[i]) (ops.plus(x[i],y[i]));
116 return _cl_UP(UPR, result);
118 // Now xlen = ylen > 0. Add and normalize simultaneously.
119 for (var sintL i = xlen-1; i >= 0; i--) {
120 var cl_number hicoeff = ops.plus(x[i],y[i]);
121 if (!ops.zerop(hicoeff)) {
122 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(i+1));
123 init1(cl_number, result[i]) (hicoeff);
124 for (i-- ; i >= 0; i--)
125 init1(cl_number, result[i]) (ops.plus(x[i],y[i]));
126 return _cl_UP(UPR, result);
129 return _cl_UP(UPR, cl_null_SV_number);
132 static const _cl_UP num_minus (cl_heap_univpoly_ring* UPR, const _cl_UP& x, const _cl_UP& y)
134 DeclarePoly(cl_SV_number,x);
135 DeclarePoly(cl_SV_number,y);
136 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
137 var sintL xlen = x.length();
138 var sintL ylen = y.length();
140 return _cl_UP(UPR, y);
142 return _cl_UP(UPR, x);
143 // Now xlen > 0, ylen > 0.
145 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(xlen));
147 for (i = xlen-1; i >= ylen; i--)
148 init1(cl_number, result[i]) (x[i]);
149 for (i = ylen-1; i >= 0; i--)
150 init1(cl_number, result[i]) (ops.minus(x[i],y[i]));
151 return _cl_UP(UPR, result);
154 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(ylen));
156 for (i = ylen-1; i >= xlen; i--)
157 init1(cl_number, result[i]) (ops.uminus(y[i]));
158 for (i = xlen-1; i >= 0; i--)
159 init1(cl_number, result[i]) (ops.minus(x[i],y[i]));
160 return _cl_UP(UPR, result);
162 // Now xlen = ylen > 0. Add and normalize simultaneously.
163 for (var sintL i = xlen-1; i >= 0; i--) {
164 var cl_number hicoeff = ops.minus(x[i],y[i]);
165 if (!ops.zerop(hicoeff)) {
166 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(i+1));
167 init1(cl_number, result[i]) (hicoeff);
168 for (i-- ; i >= 0; i--)
169 init1(cl_number, result[i]) (ops.minus(x[i],y[i]));
170 return _cl_UP(UPR, result);
173 return _cl_UP(UPR, cl_null_SV_number);
176 static const _cl_UP num_uminus (cl_heap_univpoly_ring* UPR, const _cl_UP& x)
178 DeclarePoly(cl_SV_number,x);
179 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
180 var sintL xlen = x.length();
182 return _cl_UP(UPR, x);
184 // Negate. No normalization necessary, since the degree doesn't change.
185 var sintL i = xlen-1;
186 var cl_number hicoeff = ops.uminus(x[i]);
187 if (ops.zerop(hicoeff)) cl_abort();
188 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(xlen));
189 init1(cl_number, result[i]) (hicoeff);
190 for (i-- ; i >= 0; i--)
191 init1(cl_number, result[i]) (ops.uminus(x[i]));
192 return _cl_UP(UPR, result);
195 static const _cl_UP num_one (cl_heap_univpoly_ring* UPR)
197 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(1));
198 init1(cl_number, result[0]) (1);
199 return _cl_UP(UPR, result);
202 static const _cl_UP num_canonhom (cl_heap_univpoly_ring* UPR, const cl_I& x)
204 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(1));
205 init1(cl_number, result[0]) (x);
206 return _cl_UP(UPR, result);
209 static const _cl_UP num_mul (cl_heap_univpoly_ring* UPR, const _cl_UP& x, const _cl_UP& y)
211 DeclarePoly(cl_SV_number,x);
212 DeclarePoly(cl_SV_number,y);
213 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
214 var sintL xlen = x.length();
215 var sintL ylen = y.length();
217 return _cl_UP(UPR, x);
219 return _cl_UP(UPR, y);
221 var sintL len = xlen + ylen - 1;
222 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(len));
225 var sintL i = xlen-1;
226 var cl_number xi = x[i];
227 for (sintL j = ylen-1; j >= 0; j--)
228 init1(cl_number, result[i+j]) (ops.mul(xi,y[j]));
230 for (sintL i = xlen-2; i >= 0; i--) {
231 var cl_number xi = x[i];
232 for (sintL j = ylen-1; j > 0; j--)
233 result[i+j] = ops.plus(result[i+j],ops.mul(xi,y[j]));
234 /* j=0 */ init1(cl_number, result[i]) (ops.mul(xi,y[0]));
238 var sintL j = ylen-1;
239 var cl_number yj = y[j];
240 for (sintL i = xlen-1; i >= 0; i--)
241 init1(cl_number, result[i+j]) (ops.mul(x[i],yj));
243 for (sintL j = ylen-2; j >= 0; j--) {
244 var cl_number yj = y[j];
245 for (sintL i = xlen-1; i > 0; i--)
246 result[i+j] = ops.plus(result[i+j],ops.mul(x[i],yj));
247 /* i=0 */ init1(cl_number, result[j]) (ops.mul(x[0],yj));
250 // Normalize (not necessary in integral domains).
251 //num_normalize(ops,result,len);
252 if (ops.zerop(result[len-1])) cl_abort();
253 return _cl_UP(UPR, result);
256 static const _cl_UP num_square (cl_heap_univpoly_ring* UPR, const _cl_UP& x)
258 DeclarePoly(cl_SV_number,x);
259 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
260 var sintL xlen = x.length();
262 return cl_UP(UPR, x);
263 var sintL len = 2*xlen-1;
264 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(len));
266 // Loop through all 0 <= j < i <= xlen-1.
268 var sintL i = xlen-1;
269 var cl_number xi = x[i];
270 for (sintL j = i-1; j >= 0; j--)
271 init1(cl_number, result[i+j]) (ops.mul(xi,x[j]));
273 {for (sintL i = xlen-2; i >= 1; i--) {
274 var cl_number xi = x[i];
275 for (sintL j = i-1; j >= 1; j--)
276 result[i+j] = ops.plus(result[i+j],ops.mul(xi,x[j]));
277 /* j=0 */ init1(cl_number, result[i]) (ops.mul(xi,x[0]));
280 {for (sintL i = len-2; i >= 1; i--)
281 result[i] = ops.plus(result[i],result[i]);
284 init1(cl_number, result[2*(xlen-1)]) (ops.square(x[xlen-1]));
285 for (sintL i = xlen-2; i >= 1; i--)
286 result[2*i] = ops.plus(result[2*i],ops.square(x[i]));
288 init1(cl_number, result[0]) (ops.square(x[0]));
289 // Normalize (not necessary in integral domains).
290 //num_normalize(ops,result,len);
291 if (ops.zerop(result[len-1])) cl_abort();
292 return _cl_UP(UPR, result);
295 static const _cl_UP num_exptpos (cl_heap_univpoly_ring* UPR, const _cl_UP& x, const cl_I& y)
299 while (!oddp(b)) { a = UPR->_square(a); b = b >> 1; }
304 if (oddp(b)) { c = UPR->_mul(a,c); }
309 static const _cl_UP num_scalmul (cl_heap_univpoly_ring* UPR, const cl_ring_element& x, const _cl_UP& y)
311 if (!(UPR->basering() == x.ring())) cl_abort();
313 DeclarePoly(cl_number,x);
314 DeclarePoly(cl_SV_number,y);
315 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
316 var sintL ylen = y.length();
318 return _cl_UP(UPR, y);
320 return _cl_UP(UPR, cl_null_SV_number);
322 // No normalization necessary, since the degree doesn't change.
323 var cl_SV_number result = cl_SV_number(cl_make_heap_SV_number_uninit(ylen));
324 for (sintL i = ylen-1; i >= 0; i--)
325 init1(cl_number, result[i]) (ops.mul(x,y[i]));
326 return _cl_UP(UPR, result);
329 static sintL num_degree (cl_heap_univpoly_ring* UPR, const _cl_UP& x)
332 { DeclarePoly(cl_SV_number,x);
333 return (sintL) x.length() - 1;
336 static const _cl_UP num_monomial (cl_heap_univpoly_ring* UPR, const cl_ring_element& x, uintL e)
338 if (!(UPR->basering() == x.ring())) cl_abort();
339 { DeclarePoly(cl_number,x);
340 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
342 return _cl_UP(UPR, cl_null_SV_number);
345 var cl_SV_number result = cl_SV_number(len);
347 return _cl_UP(UPR, result);
351 static const cl_ring_element num_coeff (cl_heap_univpoly_ring* UPR, const _cl_UP& x, uintL index)
353 DeclarePoly(cl_SV_number,x);
354 var cl_heap_number_ring* R = TheNumberRing(UPR->basering());
355 if (index < x.length())
356 return cl_ring_element(R, x[index]);
361 static const _cl_UP num_create (cl_heap_univpoly_ring* UPR, sintL deg)
364 return _cl_UP(UPR, cl_null_SV_number);
366 var sintL len = deg+1;
367 return _cl_UP(UPR, cl_SV_number(len));
371 static void num_set_coeff (cl_heap_univpoly_ring* UPR, _cl_UP& x, uintL index, const cl_ring_element& y)
373 DeclareMutablePoly(cl_SV_number,x);
374 if (!(UPR->basering() == y.ring())) cl_abort();
375 { DeclarePoly(cl_number,y);
376 if (!(index < x.length())) cl_abort();
380 static void num_finalize (cl_heap_univpoly_ring* UPR, _cl_UP& x)
382 DeclareMutablePoly(cl_SV_number,x); // NB: x is modified by reference!
383 var cl_number_ring_ops<cl_number>& ops = *TheNumberRing(UPR->basering())->ops;
384 var uintL len = x.length();
386 num_normalize(ops,x,len);
389 static const cl_ring_element num_eval (cl_heap_univpoly_ring* UPR, const _cl_UP& x, const cl_ring_element& y)
392 // If x = 0, return 0.
393 // If y = 0, return x[0].
394 // Else compute (...(x[len-1]*y+x[len-2])*y ...)*y + x[0].
395 DeclarePoly(cl_SV_number,x);
396 if (!(UPR->basering() == y.ring())) cl_abort();
397 { DeclarePoly(cl_number,y);
398 var cl_heap_number_ring* R = TheNumberRing(UPR->basering());
399 var cl_number_ring_ops<cl_number>& ops = *R->ops;
400 var uintL len = x.length();
404 return cl_ring_element(R, x[0]);
406 var cl_number z = x[i];
408 z = ops.plus(ops.mul(z,y),x[i]);
409 return cl_ring_element(R, z);
412 static cl_univpoly_setops num_setops = {
417 static cl_univpoly_addops num_addops = {
425 static cl_univpoly_mulops num_mulops = {
433 static cl_univpoly_modulops num_modulops = {
437 static cl_univpoly_polyops num_polyops = {
447 class cl_heap_num_univpoly_ring : public cl_heap_univpoly_ring {
448 SUBCLASS_cl_heap_univpoly_ring()
451 cl_heap_num_univpoly_ring (const cl_ring& r)
452 : cl_heap_univpoly_ring (r, &num_setops, &num_addops, &num_mulops, &num_modulops, &num_polyops) {}