1 /* Copyright (C) 2017 LinBox
2  *
3  * Written by Gavin Harrison, August 2017
4  *
5  * ========LICENCE========
6  * This file is part of the library LinBox.
7  *
8   * LinBox is free software: you can redistribute it and/or modify
9  * it under the terms of the  GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  * ========LICENCE========
22  */
23 
24 #ifndef __LINBOX_polynomial_local_x_H
25 #define __LINBOX_polynomial_local_x_H
26 
27 #include "linbox/linbox-config.h"
28 #include "linbox/util/debug.h"
29 
30 #include <stdlib.h>
31 #include <algorithm>
32 
33 // Namespace in which all LinBox code resides
34 namespace LinBox
35 {
36 	template<class Field>
37 	class PolynomialLocalX {
38 	public:
39 		typedef typename Field::Element Polynomial;
40 		typedef typename Field::CoeffField CoeffField;
41 		typedef typename Field::Coeff Coeff;
42 
43 		// f(x) * x^e ; x does not divide f(x)
44 		typedef struct {
45 			size_t e;
46 			Polynomial f;
47 		} Element;
48 
49 		// typedef UnparametricRandIter<Element> RandIter;
50 
51 		// typedef NTL_zz_p CoeffField;
52 		// typedef NTL::zz_p Coeff;
53 
54 		const Field _F;
55 		const Element zero, one, mOne, X;
56 		size_t exp;
57 
PolynomialLocalX(const Field & F,size_t exponent)58 		PolynomialLocalX(const Field &F, size_t exponent) : _F(F),
59 			zero({0, _F.zero}), one({0, _F.one}), mOne({0, _F.mOne}),
60 			X({1, _F.one}), exp(exponent)
61 			{}
62 
PolynomialLocalX(const PolynomialLocalX & P)63 		PolynomialLocalX(const PolynomialLocalX &P) : _F(P._F), zero(P.zero),
64 			one(P.one), mOne(P.mOne), X(P.X), exp(P.exp) {}
65 
PolynomialLocalX(const PolynomialLocalX & P,size_t exponent)66 		PolynomialLocalX(const PolynomialLocalX &P, size_t exponent) : _F(P.F),
67 			zero(P.zero), one(P.one), mOne(P.mOne), X(P.X), exp(exponent) {}
68 
setExponent(size_t exponent)69 		void setExponent(size_t exponent) {
70 			exp = exponent;
71 		}
72 
getExponent()73 		size_t getExponent() const {
74 			return exp;
75 		}
76 
getCoeffField()77 		const CoeffField &getCoeffField() const {
78 			return _F.getCoeffField();
79 		}
80 
firstNonZeroCoeff(const Element & a)81 		size_t firstNonZeroCoeff(const Element &a) const {
82 			return a.e;
83 		}
84 
normalize(Element & a,const Polynomial & b)85 		Element &normalize(Element &a, const Polynomial &b) const {
86 			if (_F.isZero(b)) {
87 				return a = zero;
88 			}
89 
90 			size_t i = 0;
91 			for (; i <= _F.deg(b); i++) {
92 				Coeff coeff;
93 				if (!getCoeffField().isZero(_F.getCoeff(coeff, b, i))) {
94 					break;
95 				}
96 			}
97 
98 			Polynomial tmp, x, xe;
99 			std::vector<integer> v;
100 			_F.init(x, v = {0, 1});
101 			_F.pow(xe, x, i);
102 			_F.div(tmp, b, xe);
103 
104 			return a = {
105 				i,
106 				tmp
107 			};
108 		}
109 
normalize(Element & a,const Element & b)110 		Element &normalize(Element &a, const Element &b) const {
111 			Element tmp;
112 			normalize(tmp, b.f);
113 			return a = {b.e + tmp.e, tmp.f};
114 		}
115 
denormalize(Polynomial & a,const Element & b)116 		Polynomial &denormalize(Polynomial &a, const Element &b) const {
117 			Polynomial tmp, x, xe;
118 			std::vector<integer> v;
119 			_F.init(x, v = {0, 1});
120 			_F.pow(xe, x, b.e);
121 			_F.mul(a, b.f, xe);
122 
123 			return a;
124 		}
125 
assign(Element & a,const Element & b)126 		Element &assign(Element &a, const Element &b) const {
127 			Polynomial tmp;
128 			_F.assign(tmp, b.f);
129 			return a = {b.e, tmp};
130 		}
131 
init(Element & p)132 		Element &init(Element &p) const {
133 			return assign(p, zero);
134 		}
135 
init(Element & p,const std::vector<integer> & v)136 		Element &init(Element &p, const std::vector<integer> &v) const {
137 			Polynomial tmp;
138 			_F.init(tmp, v);
139 			return normalize(p, tmp);
140 		}
141 
init(Element & a,const Polynomial & b)142 		Element &init(Element &a, const Polynomial &b) const {
143 			return normalize(a, b);
144 		}
145 
convert(integer & a,const Element & b)146 		integer &convert(integer &a, const Element &b) const {
147 			Polynomial tmp;
148 			return _F.convert(a, denormalize(tmp, b));
149 		}
150 
write(std::ostream & os)151 		std::ostream& write(std::ostream& os) const {
152 			os << "Polynomial local ring at X^" << exp << " using ";
153 			_F.write(os);
154 			return os;
155 		}
156 
write(std::ostream & os,const Element & p)157 		std::ostream& write(std::ostream& os, const Element &p) const {
158 			Polynomial tmp;
159 			_F.write(os, denormalize(tmp, p));
160 			return os;
161 		}
162 
writeNormalized(std::ostream & os,const Element & p)163 		std::ostream& writeNormalized(std::ostream& os, const Element &p) const {
164 			if (p.e == 0) {
165 				_F.write(os, p.f);
166 				return os;
167 			}
168 
169 			os << "x";
170 			if (p.e > 1) {
171 				os << "^" << p.e;
172 			}
173 
174 			if (_F.isOne(p.f)) {
175 				return os;
176 			}
177 
178 			_F.write(os << "*(", p.f) << ")";
179 			return os;
180 		}
181 
isZero(const Element & a)182 		bool isZero(const Element &a) const {
183 			return _F.isZero(a.f);
184 		}
185 
isOne(const Element & a)186 		bool isOne(const Element &a) const {
187 			return a.e == 0 && _F.isOne(a.f);
188 		}
189 
isMOne(const Element & a)190 		bool isMOne(const Element &a) const {
191 			return a.e == 0 && _F.isMOne(a.f);
192 		}
193 
areEqual(const Element & a,const Element & b)194 		bool areEqual(const Element &a, const Element &b) const {
195 			return a.e == b.e && _F.areEqual(a.f, b.f);
196 		}
197 
isUnit(const Element & a)198 		bool isUnit(const Element &a) const {
199 			return a.e == 0 && !isZero(a);
200 		}
201 
deg(const Element & p)202 		size_t deg(const Element &p) const {
203 			return _F.deg(p.f) + p.e;
204 		}
205 
getCoeff(Coeff & c,const Element & a,size_t e)206 		Coeff &getCoeff(Coeff &c, const Element &a, size_t e) const {
207 			if (e < a.e) {
208 				return getCoeffField().assign(c, getCoeffField().zero);
209 			}
210 
211 			return _F.getCoeff(c, a.f, a.e - e);
212 		}
213 
leadCoeff(Coeff & c,const Element & a)214 		Coeff &leadCoeff(Coeff &c, const Element &a) const {
215 			return _F.leadCoeff(c, a.f);
216 		}
217 
monic(Element & m,const Element & a)218 		Element &monic(Element &m, const Element &a) const {
219 			Polynomial mf;
220 			_F.monic(mf, a.f);
221 
222 			return m = {
223 				a.e,
224 				mf
225 			};
226 		}
227 
228 		/// returns true if b divides a evenly
isDivisor(const Element & a,const Element & b)229 		bool isDivisor(const Element &a, const Element &b) const {
230 			return b.e <= a.e && !isZero(b);
231 		}
232 
233 		// b = a * x^e
leftShift(Element & b,const Element & a,size_t e)234 		Element &leftShift(Element &b, const Element &a, size_t e) const {
235 			if (a.e + e > exp) {
236 				return b = zero;
237 			}
238 
239 			return b = {a.e + e, a.f};
240 		}
241 
242 		// b = a / x^e
rightShift(Element & b,const Element & a,size_t e)243 		Element &rightShift(Element &b, const Element &a, size_t e) const {
244 			return b = {a.e - e, a.f};
245 		}
246 
rightShiftIn(Element & b,size_t e)247 		Element &rightShiftIn(Element &b, size_t e) const {
248 			b.e -= e;
249 			return b;
250 		}
251 
div(Element & q,const Element & a,const Element & b)252 		Element &div(Element &q, const Element &a, const Element &b) const {
253 			if (isZero(a)) {
254 				return q = zero;
255 			}
256 
257 			if (_F.isOne(b.f)) {
258 				return q = {a.e - b.e, a.f};
259 			}
260 
261 			Polynomial tmp, x, xe, xer;
262 			std::vector<integer> v = {0, 1};
263 			_F.init(x, v);
264 			_F.pow(xe, x, exp - a.e + b.e);
265 			_F.pow(xer, x, exp - a.e + b.e);
266 
267 			_F.invMod(tmp, b.f, xe);
268 			_F.mulin(tmp, a.f);
269 			_F.modin(tmp, xer);
270 
271 			return q = {a.e - b.e, tmp};
272 		}
273 
divin(Element & a,const Element & b)274 		Element &divin(Element &a, const Element &b) const {
275 			Element tmp;
276 			assign(tmp, a);
277 			return div(a, tmp, b);
278 		}
279 
mul(Element & c,const Element & a,const Element & b)280 		Element &mul(Element &c, const Element &a, const Element &b) const {
281 			if (isZero(a) || isZero(b)) {
282 				return c = zero;
283 			}
284 
285 			if (_F.isOne(a.f)) {
286 				return c = {a.e + b.e, b.f};
287 			}
288 			if (_F.isOne(b.f)) {
289 				return c = {a.e + b.e, a.f};
290 			}
291 
292 			Polynomial tmp, x, xe;
293 			std::vector<integer> v = {0, 1};
294 			_F.init(x, v);
295 			_F.pow(xe, x, exp - a.e - b.e);
296 			_F.mul(tmp, a.f, b.f);
297 			_F.modin(tmp, xe);
298 
299 			return c = {a.e + b.e, tmp};
300 		}
301 
mulin(Element & a,const Element & b)302 		Element &mulin(Element &a, const Element &b) const {
303 			Element tmp;
304 			assign(tmp, a);
305 			return mul(a, b, tmp);
306 		}
307 
pow(Element & r,const Element & a,size_t e)308 		Element &pow(Element &r, const Element &a, size_t e) {
309 			if (a.e * e >= exp) {
310 				return r = zero;
311 			}
312 
313 			Polynomial tmp;
314 			_F.pow(tmp, a.f, e);
315 			return r = {
316 				a.e * e,
317 				tmp
318 			};
319 		}
320 
add(Element & c,const Element & a,const Element & b)321 		Element &add(Element &c, const Element &a, const Element &b) const {
322 			if (a.e > b.e) {
323 				return add(c, b, a);
324 			}
325 
326 			if (a.e == b.e) {
327 				Polynomial tmp;
328 				_F.add(tmp, a.f, b.f);
329 				return normalize(c, {a.e, tmp});
330 			}
331 
332 			Polynomial tmp, x, xe;
333 			std::vector<integer> v = {0, 1};
334 			_F.init(x, v);
335 			_F.pow(xe, x, b.e - a.e);
336 			_F.mul(tmp, xe, b.f);
337 			_F.addin(tmp, a.f);
338 			return normalize(c, {a.e, tmp});
339 		}
340 
addin(Element & a,const Element & b)341 		Element &addin(Element &a, const Element &b) const {
342 			Element tmp;
343 			assign(tmp, a);
344 			return add(a, b, tmp);
345 		}
346 
neg(Element & a,const Element & b)347 		Element &neg(Element &a, const Element &b) const {
348 			Polynomial tmp;
349 			_F.neg(tmp, b.f);
350 			return a = {b.e, tmp};
351 		}
352 
negin(Element & a)353 		Element &negin(Element &a) const {
354 			Element tmp;
355 			assign(tmp, a);
356 			return neg(a, tmp);
357 		}
358 
359 		// r = a*x + y
axpy(Element & r,const Element & a,const Element & x,const Element & y)360 		Element &axpy(Element &r, const Element &a, const Element &x, const Element &y) const {
361 			mul(r, a, x);
362 			return addin(r, y);
363 		}
364 
365 		// r += a * x
axpyin(Element & r,const Element & a,const Element & x)366 		Element &axpyin(Element &r, const Element &a, const Element &x) const {
367 			Element tmp;
368 			assign(tmp, r);
369 
370 			return axpy(r, a, x, tmp);
371 		}
372 
inv(Element & r,const Element & a)373 		Element &inv(Element &r, const Element &a) {
374 			assert(isUnit(a));
375 
376 			Polynomial x, xe;
377 			std::vector<integer> v = {0, 1};
378 			_F.init(x, v);
379 			_F.pow(xe, x, exp);
380 
381 			Polynomial tmp;
382 			_F.invMod(tmp, a.f, xe);
383 
384 			return normalize(r, tmp);
385 		}
386 	}; // end of class PolynomialLocalX
387 
388 	template<>
389 	class PolynomialLocalX<NTL_zz_pX> {
390 	public:
391 		typedef NTL_zz_pX Field;
392 
393 		typedef typename Field::Element Polynomial;
394 		typedef typename Field::CoeffField CoeffField;
395 		typedef typename Field::Coeff Coeff;
396 
397 		// f(x) * x^e ; x does not divide f(x)
398 		typedef typename Field::Element Element;
399 
400 		// typedef UnparametricRandIter<Element> RandIter;
401 
402 		const Field _F;
403 		const Element zero, one, mOne;
404 		size_t exp;
405 
PolynomialLocalX(const Field & F,size_t exponent)406 		PolynomialLocalX(const Field &F, size_t exponent) : _F(F),
407 			zero(_F.zero), one(_F.one), mOne(_F.mOne), exp(exponent)
408 			{}
409 
PolynomialLocalX(const PolynomialLocalX & P)410 		PolynomialLocalX(const PolynomialLocalX &P) : _F(P._F), zero(P.zero),
411 			one(P.one), mOne(P.mOne), exp(P.exp) {}
412 
setExponent(size_t exponent)413 		void setExponent(size_t exponent) {
414 			exp = exponent;
415 		}
416 
getExponent()417 		size_t getExponent() const {
418 			return exp;
419 		}
420 
getCoeffField()421 		const CoeffField &getCoeffField() const {
422 			return _F.getCoeffField();
423 		}
424 
firstNonZeroCoeff(const Element & a)425 		size_t firstNonZeroCoeff(const Element &a) const {
426 			size_t i = 0;
427 			for (; i <= _F.deg(a) && NTL::coeff(a, i) == 0; i++);
428 			return i;
429 		}
430 
assign(Element & a,const Element & b)431 		Element &assign(Element &a, const Element &b) const {
432 			return _F.assign(a, b);
433 		}
434 
normalize(Element & a,const Polynomial & b)435 		Element &normalize(Element &a, const Polynomial &b) const {
436 			return assign(a, b);
437 		}
438 
denormalize(Polynomial & a,const Element & b)439 		Polynomial &denormalize(Polynomial &a, const Element &b) const {
440 			return assign(a, b);
441 		}
442 
init(Element & p)443 		Element &init(Element &p) const {
444 			return assign(p, zero);
445 		}
446 
init(Element & p,const std::vector<integer> & v)447 		Element &init(Element &p, const std::vector<integer> &v) const {
448 			return _F.init(p, v);
449 		}
450 
init(Element & a,const Polynomial & b)451 		Element &init(Element &a, const Polynomial &b) const {
452 			return assign(a, b);
453 		}
454 
convert(integer & a,const Element & b)455 		integer &convert(integer &a, const Element &b) const {
456 			return _F.convert(a, b);
457 		}
458 
write(std::ostream & os)459 		std::ostream& write(std::ostream& os) const {
460 			os << "Polynomial local ring at X^" << exp << " using ";
461 			_F.write(os);
462 			return os;
463 		}
464 
write(std::ostream & os,const Element & p)465 		std::ostream& write(std::ostream& os, const Element &p) const {
466 			Polynomial tmp;
467 			_F.write(os, denormalize(tmp, p));
468 			return os;
469 		}
470 
writeNormalized(std::ostream & os,const Element & p)471 		std::ostream& writeNormalized(std::ostream& os, const Element &p) const {
472 			return write(os, p);
473 		}
474 
isZero(const Element & a)475 		bool isZero(const Element &a) const {
476 			return _F.isZero(a);
477 		}
478 
isOne(const Element & a)479 		bool isOne(const Element &a) const {
480 			return _F.isOne(a);
481 		}
482 
isMOne(const Element & a)483 		bool isMOne(const Element &a) const {
484 			return _F.isMOne(a);
485 		}
486 
areEqual(const Element & a,const Element & b)487 		bool areEqual(const Element &a, const Element &b) const {
488 			return _F.areEqual(a, b);
489 		}
490 
isUnit(const Element & a)491 		bool isUnit(const Element &a) const {
492 			Coeff coeff;
493 			return _F.getCoeff(coeff, a, 0) != 0;
494 		}
495 
deg(const Element & p)496 		size_t deg(const Element &p) const {
497 			return _F.deg(p);
498 		}
499 
getCoeff(Coeff & c,const Element & a,size_t e)500 		Coeff &getCoeff(Coeff &c, const Element &a, size_t e) const {
501 			return _F.getCoeff(c, a, e);
502 		}
503 
leadCoeff(Coeff & c,const Element & a)504 		Coeff &leadCoeff(Coeff &c, const Element &a) const {
505 			return _F.leadCoeff(c, a);
506 		}
507 
monic(Element & m,const Element & a)508 		Element &monic(Element &m, const Element &a) const {
509 			return _F.monic(m, a);
510 		}
511 
512 		/// returns true if b divides a evenly
isDivisor(const Element & a,const Element & b)513 		bool isDivisor(const Element &a, const Element &b) const {
514 			if (isZero(b)) {
515 				return false;
516 			}
517 
518 			if (isZero(a)) {
519 				return true;
520 			}
521 
522 			return firstNonZeroCoeff(a) >= firstNonZeroCoeff(b);
523 		}
524 
525 		// b = a * x^e
leftShift(Element & b,const Element & a,size_t e)526 		Element &leftShift(Element &b, const Element &a, size_t e) const {
527 			if (firstNonZeroCoeff(a) + e >= exp) {
528 				return b = zero;
529 			}
530 
531 			return b = NTL::trunc(a << e, exp);
532 		}
533 
leftShiftIn(Element & b,size_t e)534 		Element &leftShiftIn(Element &b, size_t e) const {
535 			if (firstNonZeroCoeff(b) + e >= exp) {
536 				return b = zero;
537 			}
538 
539 			return b = NTL::trunc(b << e, exp);
540 		}
541 
542 		// b = a / x^e
rightShift(Element & b,const Element & a,size_t e)543 		Element &rightShift(Element &b, const Element &a, size_t e) const {
544 			return b = a >> e;
545 		}
546 
rightShiftIn(Element & b,size_t e)547 		Element &rightShiftIn(Element &b, size_t e) const {
548 			return b = b >> e;
549 		}
550 
mul(Element & c,const Element & a,const Element & b)551 		Element &mul(Element &c, const Element &a, const Element &b) const {
552 			return c = NTL::MulTrunc(a, b, exp);
553 		}
554 
mulin(Element & a,const Element & b)555 		Element &mulin(Element &a, const Element &b) const {
556 			Element tmp;
557 			assign(tmp, a);
558 			return mul(a, b, tmp);
559 		}
560 
add(Element & c,const Element & a,const Element & b)561 		Element &add(Element &c, const Element &a, const Element &b) const {
562 			return _F.add(c, a, b);
563 		}
564 
addin(Element & a,const Element & b)565 		Element &addin(Element &a, const Element &b) const {
566 			return _F.addin(a, b);
567 		}
568 
neg(Element & a,const Element & b)569 		Element &neg(Element &a, const Element &b) const {
570 			return _F.neg(a, b);
571 		}
572 
negin(Element & a)573 		Element &negin(Element &a) const {
574 			return _F.negin(a);
575 		}
576 
577 		// r = a*x + y
axpy(Element & r,const Element & a,const Element & x,const Element & y)578 		Element &axpy(Element &r, const Element &a, const Element &x, const Element &y) const {
579 			mul(r, a, x);
580 			return addin(r, y);
581 		}
582 
583 		// r += a * x
axpyin(Element & r,const Element & a,const Element & x)584 		Element &axpyin(Element &r, const Element &a, const Element &x) const {
585 			Element tmp;
586 			assign(tmp, r);
587 
588 			return axpy(r, a, x, tmp);
589 		}
590 
inv(Element & r,const Element & a)591 		Element &inv(Element &r, const Element &a) const {
592 			return r = NTL::InvTrunc(a, exp);
593 		}
594 	}; // end of class PolynomialLocalX<NTL_zz_px>
595 
596 	template<>
597 	class PolynomialLocalX<NTL_zz_pEX> {
598 	public:
599 		typedef NTL_zz_pEX Field;
600 
601 		typedef typename Field::Element Polynomial;
602 		typedef typename Field::CoeffField CoeffField;
603 		typedef typename Field::Coeff Coeff;
604 
605 		// f(x) * x^e ; x does not divide f(x)
606 		typedef typename Field::Element Element;
607 
608 		// typedef UnparametricRandIter<Element> RandIter;
609 
610 		const Field _F;
611 		const Element zero, one, mOne;
612 		size_t exp;
613 
PolynomialLocalX(const Field & F,size_t exponent)614 		PolynomialLocalX(const Field &F, size_t exponent) : _F(F),
615 			zero(_F.zero), one(_F.one), mOne(_F.mOne), exp(exponent)
616 			{}
617 
PolynomialLocalX(const PolynomialLocalX & P)618 		PolynomialLocalX(const PolynomialLocalX &P) : _F(P._F), zero(P.zero),
619 			one(P.one), mOne(P.mOne), exp(P.exp) {}
620 
setExponent(size_t exponent)621 		void setExponent(size_t exponent) {
622 			exp = exponent;
623 		}
624 
getExponent()625 		size_t getExponent() const {
626 			return exp;
627 		}
628 
getCoeffField()629 		const CoeffField &getCoeffField() const {
630 			return _F.getCoeffField();
631 		}
632 
firstNonZeroCoeff(const Element & a)633 		size_t firstNonZeroCoeff(const Element &a) const {
634 			size_t i = 0;
635 			for (; i <= _F.deg(a) && NTL::coeff(a, i) == 0; i++);
636 			return i;
637 		}
638 
assign(Element & a,const Element & b)639 		Element &assign(Element &a, const Element &b) const {
640 			return _F.assign(a, b);
641 		}
642 
normalize(Element & a,const Polynomial & b)643 		Element &normalize(Element &a, const Polynomial &b) const {
644 			return assign(a, b);
645 		}
646 
denormalize(Polynomial & a,const Element & b)647 		Polynomial &denormalize(Polynomial &a, const Element &b) const {
648 			return assign(a, b);
649 		}
650 
init(Element & p)651 		Element &init(Element &p) const {
652 			return assign(p, zero);
653 		}
654 
init(Element & p,const std::vector<integer> & v)655 		Element &init(Element &p, const std::vector<integer> &v) const {
656 			return _F.init(p, v);
657 		}
658 
init(Element & a,const Polynomial & b)659 		Element &init(Element &a, const Polynomial &b) const {
660 			return assign(a, b);
661 		}
662 
convert(integer & a,const Element & b)663 		integer &convert(integer &a, const Element &b) const {
664 			return _F.convert(a, b);
665 		}
666 
write(std::ostream & os)667 		std::ostream& write(std::ostream& os) const {
668 			os << "Polynomial local ring at X^" << exp << " using ";
669 			_F.write(os);
670 			return os;
671 		}
672 
write(std::ostream & os,const Element & p)673 		std::ostream& write(std::ostream& os, const Element &p) const {
674 			Polynomial tmp;
675 			_F.write(os, denormalize(tmp, p));
676 			return os;
677 		}
678 
writeNormalized(std::ostream & os,const Element & p)679 		std::ostream& writeNormalized(std::ostream& os, const Element &p) const {
680 			return write(os, p);
681 		}
682 
isZero(const Element & a)683 		bool isZero(const Element &a) const {
684 			return _F.isZero(a);
685 		}
686 
isOne(const Element & a)687 		bool isOne(const Element &a) const {
688 			return _F.isOne(a);
689 		}
690 
isMOne(const Element & a)691 		bool isMOne(const Element &a) const {
692 			return _F.isMOne(a);
693 		}
694 
areEqual(const Element & a,const Element & b)695 		bool areEqual(const Element &a, const Element &b) const {
696 			return _F.areEqual(a, b);
697 		}
698 
isUnit(const Element & a)699 		bool isUnit(const Element &a) const {
700 			Coeff coeff;
701 			return _F.getCoeff(coeff, a, 0) != 0;
702 		}
703 
deg(const Element & p)704 		size_t deg(const Element &p) const {
705 			return _F.deg(p);
706 		}
707 
getCoeff(Coeff & c,const Element & a,size_t e)708 		Coeff &getCoeff(Coeff &c, const Element &a, size_t e) const {
709 			return _F.getCoeff(c, a, e);
710 		}
711 
leadCoeff(Coeff & c,const Element & a)712 		Coeff &leadCoeff(Coeff &c, const Element &a) const {
713 			return _F.leadCoeff(c, a);
714 		}
715 
monic(Element & m,const Element & a)716 		Element &monic(Element &m, const Element &a) const {
717 			return _F.monic(m, a);
718 		}
719 
720 		/// returns true if b divides a evenly
isDivisor(const Element & a,const Element & b)721 		bool isDivisor(const Element &a, const Element &b) const {
722 			if (isZero(b)) {
723 				return false;
724 			}
725 
726 			if (isZero(a)) {
727 				return true;
728 			}
729 
730 			return firstNonZeroCoeff(a) >= firstNonZeroCoeff(b);
731 		}
732 
733 		// b = a * x^e
leftShift(Element & b,const Element & a,size_t e)734 		Element &leftShift(Element &b, const Element &a, size_t e) const {
735 			if (firstNonZeroCoeff(a) + e >= exp) {
736 				return b = zero;
737 			}
738 
739 			return b = NTL::trunc(a << e, exp);
740 		}
741 
leftShiftIn(Element & b,size_t e)742 		Element &leftShiftIn(Element &b, size_t e) const {
743 			if (firstNonZeroCoeff(b) + e >= exp) {
744 				return b = zero;
745 			}
746 
747 			return b = NTL::trunc(b << e, exp);
748 		}
749 
750 		// b = a / x^e
rightShift(Element & b,const Element & a,size_t e)751 		Element &rightShift(Element &b, const Element &a, size_t e) const {
752 			return b = a >> e;
753 		}
754 
rightShiftIn(Element & b,size_t e)755 		Element &rightShiftIn(Element &b, size_t e) const {
756 			return b = b >> e;
757 		}
758 
mul(Element & c,const Element & a,const Element & b)759 		Element &mul(Element &c, const Element &a, const Element &b) const {
760 			return c = NTL::MulTrunc(a, b, exp);
761 		}
762 
mulin(Element & a,const Element & b)763 		Element &mulin(Element &a, const Element &b) const {
764 			Element tmp;
765 			assign(tmp, a);
766 			return mul(a, b, tmp);
767 		}
768 
add(Element & c,const Element & a,const Element & b)769 		Element &add(Element &c, const Element &a, const Element &b) const {
770 			return _F.add(c, a, b);
771 		}
772 
addin(Element & a,const Element & b)773 		Element &addin(Element &a, const Element &b) const {
774 			return _F.addin(a, b);
775 		}
776 
neg(Element & a,const Element & b)777 		Element &neg(Element &a, const Element &b) const {
778 			return _F.neg(a, b);
779 		}
780 
negin(Element & a)781 		Element &negin(Element &a) const {
782 			return _F.negin(a);
783 		}
784 
785 		// r = a*x + y
axpy(Element & r,const Element & a,const Element & x,const Element & y)786 		Element &axpy(Element &r, const Element &a, const Element &x, const Element &y) const {
787 			mul(r, a, x);
788 			return addin(r, y);
789 		}
790 
791 		// r += a * x
axpyin(Element & r,const Element & a,const Element & x)792 		Element &axpyin(Element &r, const Element &a, const Element &x) const {
793 			Element tmp;
794 			assign(tmp, r);
795 
796 			return axpy(r, a, x, tmp);
797 		}
798 
inv(Element & r,const Element & a)799 		Element &inv(Element &r, const Element &a) const {
800 			return r = NTL::InvTrunc(a, exp);
801 		}
802 	}; // end of class PolynomialLocalX<NTL_zz_px>
803 
804 	template<class PolynomialRing>
805 	class Hom<PolynomialRing, PolynomialLocalX<PolynomialRing>> {
806 	public:
807 		typedef PolynomialRing Source;
808 		typedef PolynomialLocalX<PolynomialRing> Target;
809 		typedef typename Source::Element SrcElt;
810 		typedef typename Target::Element Elt;
811 
812 	public:
Hom(const Source & S,const Target & T)813 		Hom(const Source& S, const Target& T) : _source(S), _target(T) {}
814 
image(Elt & t,const SrcElt & s)815 		Elt& image(Elt& t, const SrcElt& s) {
816 			return _target.init(t, s);
817 		}
818 
preimage(SrcElt & s,const Elt & t)819 		SrcElt& preimage(SrcElt& s, const Elt& t) {
820 			return _target.convert(s, t);
821 		}
822 
source()823 		const Source& source() { return _source;}
target()824 		const Target& target() { return _target;}
825 
826 	private:
827 		const Source& _source;
828 		const Target& _target;
829 	}; // end Hom<PolynomialRing, PolynomialLocalX>
830 } // end of namespace LinBox
831 
832 #endif // __LINBOX_polynomial_local_x_H
833 
834 
835 // vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,:0,t0,+0,=s
836 // Local Variables:
837 // mode: C++
838 // tab-width: 8
839 // indent-tabs-mode: nil
840 // c-basic-offset: 8
841 // End:
842 
843