1 /*
2     Copyright (C) 2013 Tom Bachmann
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <http://www.gnu.org/licenses/>.
10 */
11 
12 #ifndef FMPZ_POLYXX_H
13 #define FMPZ_POLYXX_H
14 
15 #include <cstdlib>
16 #include <string>
17 
18 #include "flint.h"
19 #include "fmpz_poly.h"
20 
21 #include "fmpzxx.h"
22 #include "fmpz_vecxx.h"
23 
24 #include "flintxx/expression.h"
25 #include "flintxx/flint_classes.h"
26 #include "flintxx/flint_exception.h"
27 #include "flintxx/frandxx.h"
28 #include "flintxx/ltuple.h"
29 #include "flintxx/traits.h"
30 #include "flintxx/traits_fwd.h"
31 
32 // TODO exhibit this as a specialisation of a generic poly<fmpzxx>
33 // TODO newton basis?
34 // TODO power series class?
35 // TODO input
36 // TODO addmul
37 // TODO more hensel lifting?
38 
39 namespace flint {
40 // function "declarations"
41 FLINT_DEFINE_UNOP(sqr_karatsuba)
FLINT_DEFINE_UNOP(sqrt_classical)42 FLINT_DEFINE_UNOP(sqrt_classical)
43 
44 FLINT_DEFINE_BINOP(evaluate_divconquer)
45 FLINT_DEFINE_BINOP(evaluate_horner)
46 FLINT_DEFINE_BINOP(gcd_heuristic)
47 FLINT_DEFINE_BINOP(gcd_modular)
48 FLINT_DEFINE_BINOP(gcd_subresultant)
49 FLINT_DEFINE_BINOP(mul_karatsuba)
50 FLINT_DEFINE_BINOP(mulmid_classical)
51 FLINT_DEFINE_BINOP(mul_SS)
52 FLINT_DEFINE_BINOP(divides)
53 FLINT_DEFINE_BINOP(pow_addchains)
54 FLINT_DEFINE_BINOP(pow_binomial)
55 FLINT_DEFINE_BINOP(pow_multinomial)
56 FLINT_DEFINE_BINOP(pseudo_div)
57 FLINT_DEFINE_BINOP(pseudo_divrem)
58 FLINT_DEFINE_BINOP(pseudo_divrem_basecase)
59 FLINT_DEFINE_BINOP(pseudo_divrem_cohen)
60 FLINT_DEFINE_BINOP(pseudo_divrem_divconquer)
61 FLINT_DEFINE_BINOP(pseudo_rem)
62 FLINT_DEFINE_BINOP(pseudo_rem_cohen)
63 FLINT_DEFINE_BINOP(sqrlow)
64 FLINT_DEFINE_BINOP(sqrlow_classical)
65 FLINT_DEFINE_BINOP(sqrlow_karatsuba_n)
66 FLINT_DEFINE_BINOP(sqrlow_KS)
67 FLINT_DEFINE_BINOP(taylor_shift_divconquer)
68 FLINT_DEFINE_BINOP(xgcd_modular)
69 
70 FLINT_DEFINE_THREEARY(mulhigh_karatsuba_n)
71 FLINT_DEFINE_THREEARY(mulhigh_n)
72 FLINT_DEFINE_THREEARY(mullow_karatsuba_n)
73 FLINT_DEFINE_THREEARY(mullow_SS)
74 
75 
76 FLINT_DEFINE_BINOP(fmpz_polyxx_interpolate)
77 FLINT_DEFINE_UNOP(fmpz_polyxx_product_roots)
78 FLINT_DEFINE_UNOP(fmpz_polyxx_lead)
79 FLINT_DEFINE_BINOP(fmpz_polyxx_get_coeff)
80 FLINT_DEFINE_BINOP(fmpz_polyxx_bit_unpack)
81 FLINT_DEFINE_BINOP(fmpz_polyxx_bit_unpack_unsigned)
82 
83 FLINT_DEFINE_SEVENARY(hensel_lift)
84 FLINT_DEFINE_SEVENARY(hensel_lift_without_inverse)
85 FLINT_DEFINE_SIXARY(hensel_lift_only_inverse)
86 
87 
88 namespace detail {
89 template<class Poly>
90 struct fmpz_poly_traits
91 {
92     typedef FLINT_UNOP_BUILD_RETTYPE(
93                 fmpz_polyxx_lead, fmpzxx, Poly) lead_ref_t;
94     typedef lead_ref_t lead_srcref_t;
95     static lead_ref_t lead(const Poly& p) {return fmpz_polyxx_lead(p);}
96 
97     template<class T>
98     struct coeff
99     {
100         typedef FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_get_coeff, Poly, T) ref_t;
101         typedef ref_t srcref_t;
102         static ref_t get(const Poly& p, const T& t)
103             {return fmpz_polyxx_get_coeff(p, t);}
104     };
105 };
106 }
107 
108 template<class Operation, class Data>
109 class fmpz_polyxx_expression
110     : public expression<derived_wrapper<fmpz_polyxx_expression>,
111                             Operation, Data>
112 {
113 public:
114     typedef expression<derived_wrapper< ::flint::fmpz_polyxx_expression>,
115               Operation, Data> base_t;
116     typedef detail::fmpz_poly_traits<fmpz_polyxx_expression> poly_traits_t;
117 
118     FLINTXX_DEFINE_BASICS(fmpz_polyxx_expression)
FLINTXX_DEFINE_CTORS(fmpz_polyxx_expression)119     FLINTXX_DEFINE_CTORS(fmpz_polyxx_expression)
120     FLINTXX_DEFINE_C_REF(fmpz_polyxx_expression, fmpz_poly_struct, _poly)
121 
122     // static methods which only make sense with fmpz_polyxx
123     static fmpz_polyxx_expression randtest(frandxx& state, slong len,
124             flint_bitcnt_t bits)
125     {
126         fmpz_polyxx_expression res;
127         fmpz_poly_randtest(res._poly(), state._data(), len, bits);
128         return res;
129     }
randtest_unsigned(frandxx & state,slong len,flint_bitcnt_t bits)130     static fmpz_polyxx_expression randtest_unsigned(frandxx& state, slong len,
131             flint_bitcnt_t bits)
132     {
133         fmpz_polyxx_expression res;
134         fmpz_poly_randtest_unsigned(res._poly(), state._data(), len, bits);
135         return res;
136     }
randtest_not_zero(frandxx & state,slong len,flint_bitcnt_t bits)137     static fmpz_polyxx_expression randtest_not_zero(frandxx& state, slong len,
138             flint_bitcnt_t bits)
139     {
140         fmpz_polyxx_expression res;
141         fmpz_poly_randtest_not_zero(res._poly(), state._data(), len, bits);
142         return res;
143     }
144 
145     template<class Fmpz_vec1, class Fmpz_vec2>
FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_interpolate,Fmpz_vec1,Fmpz_vec2)146     static FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_interpolate,
147         Fmpz_vec1, Fmpz_vec2)
148     interpolate(const Fmpz_vec1& xs, const Fmpz_vec2& ys)
149     {
150         return fmpz_polyxx_interpolate(xs, ys);
151     }
152 
153     template<class Fmpz_vec>
FLINT_UNOP_ENABLE_RETTYPE(fmpz_polyxx_product_roots,Fmpz_vec)154     static FLINT_UNOP_ENABLE_RETTYPE(fmpz_polyxx_product_roots, Fmpz_vec)
155     product_roots(const Fmpz_vec& xs)
156     {
157         return fmpz_polyxx_product_roots(xs);
158     }
159 
160     template<class Arg1, class Arg2>
FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_bit_unpack,Arg1,Arg2)161     static FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_bit_unpack,
162         Arg1, Arg2)
163     bit_unpack(const Arg1& a1, const Arg2& a2)
164     {
165         return fmpz_polyxx_bit_unpack(a1, a2);
166     }
167     template<class Arg1, class Arg2>
FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_bit_unpack_unsigned,Arg1,Arg2)168     static FLINT_BINOP_ENABLE_RETTYPE(fmpz_polyxx_bit_unpack_unsigned,
169         Arg1, Arg2)
170     bit_unpack_unsigned(const Arg1& a1, const Arg2& a2)
171     {
172         return fmpz_polyxx_bit_unpack_unsigned(a1, a2);
173     }
174 
175     template<class T>
from_ground(const T & t)176     static fmpz_polyxx_expression from_ground(const T& t)
177     {
178         fmpz_polyxx_expression res;
179         fmpzxx u; u = t;
180         res.set_coeff(0, u);
181         return res;
182     }
183 
184     template<class Nmod_poly>
_lift(const Nmod_poly & poly)185     static fmpz_polyxx_expression _lift(const Nmod_poly& poly)
186     {
187         fmpz_polyxx_expression res(poly.length());
188         fmpz_poly_set_nmod_poly(res._poly(), poly._poly());
189         return res;
190     }
191     template<class Nmod_poly>
192     static fmpz_polyxx_expression lift(const Nmod_poly& poly,
193             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0)
194     {
195         return _lift(poly.evaluate());
196     }
197     template<class Nmod_poly>
_lift_unsigned(const Nmod_poly & poly)198     static fmpz_polyxx_expression _lift_unsigned(const Nmod_poly& poly)
199     {
200         fmpz_polyxx_expression res(poly.length());
201         fmpz_poly_set_nmod_poly_unsigned(res._poly(), poly.evaluate()._poly());
202         return res;
203     }
204     template<class Nmod_poly>
205     static fmpz_polyxx_expression lift_unsigned(const Nmod_poly& poly,
206             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0)
207     {
208         return _lift_unsigned(poly.evaluate());
209     }
210 
zero()211     static fmpz_polyxx_expression zero() {return fmpz_polyxx_expression();}
one()212     static fmpz_polyxx_expression one()
213     {
214         fmpz_polyxx_expression res;
215         res.set_one();
216         return res;
217     }
218 
219     // These only make sense with immediates
realloc(slong alloc)220     void realloc(slong alloc) {fmpz_poly_realloc(_poly(), alloc);}
fit_length(slong len)221     void fit_length(slong len) {fmpz_poly_fit_length(_poly(), len);}
_normalise()222     void _normalise() {_fmpz_poly_normalise(_poly());}
_set_length(slong len)223     void _set_length(slong len) {_fmpz_poly_set_length(_poly(), len);}
zero_coeffs(slong i,slong j)224     void zero_coeffs(slong i, slong j) {fmpz_poly_zero_coeffs(_poly(), i, j);}
set_zero()225     void set_zero() {fmpz_poly_zero(_poly());}
set_one()226     void set_one() {fmpz_poly_one(_poly());}
227 
228     // The result of these are undefined if n is >= length
229     // You also may have to call _normalise().
230     template<class T>
coeff(const T & n)231     typename poly_traits_t::template coeff<T>::ref_t coeff(const T& n)
232     {
233         return poly_traits_t::template coeff<T>::get(*this, n);
234     }
235     template<class T>
236     typename poly_traits_t::template coeff<T>::srcref_t
coeff(const T & n)237         coeff(const T& n) const
238     {
239         return poly_traits_t::template coeff<T>::get(*this, n);
240     }
lead()241     typename poly_traits_t::lead_ref_t lead()
242     {
243         return poly_traits_t::lead(*this);
244     }
lead()245     typename poly_traits_t::lead_srcref_t lead() const
246     {
247         return poly_traits_t::lead(*this);
248     }
249 
250     // These only make sense with target immediates
251     template<class Fmpz>
252     typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type
set_coeff(slong n,const Fmpz & x)253     set_coeff(slong n, const Fmpz& x)
254     {
255         fmpz_poly_set_coeff_fmpz(_poly(), n, x.evaluate()._fmpz());
256     }
257     template<class T>
258     typename mp::enable_if<traits::is_signed_integer<T> >::type
set_coeff(slong n,T x)259     set_coeff(slong n, T x)
260     {
261         fmpz_poly_set_coeff_si(_poly(), n, x);
262     }
263     template<class T>
264     typename mp::enable_if<traits::is_unsigned_integer<T> >::type
set_coeff(slong n,T x)265     set_coeff(slong n, T x)
266     {
267         fmpz_poly_set_coeff_ui(_poly(), n, x);
268     }
269 
truncate(slong n)270     void truncate(slong n) {fmpz_poly_truncate(_poly(), n);}
271 
272     // These cause evaluation
length()273     slong length() const {return fmpz_poly_length(this->evaluate()._poly());}
degree()274     slong degree() const {return fmpz_poly_degree(this->evaluate()._poly());}
is_one()275     bool is_one() const {return fmpz_poly_is_one(this->evaluate()._poly());}
is_zero()276     bool is_zero() const {return fmpz_poly_is_zero(this->evaluate()._poly());}
is_unit()277     bool is_unit() const {return fmpz_poly_is_unit(this->evaluate()._poly());}
max_limbs()278     ulong max_limbs() const {return fmpz_poly_max_limbs(this->evaluate()._poly());}
max_bits()279     slong max_bits() const {return fmpz_poly_max_bits(this->evaluate()._poly());}
280 
pretty(const char * x)281     std::string pretty(const char* x) const
282     {
283         char* str = fmpz_poly_get_str_pretty(this->evaluate()._poly(), x);
284         std::string res(str);
285         flint_free(str);
286         return res;
287     }
288 
signature(slong & r1,slong & r2)289     void signature(slong& r1, slong& r2) const
290     {
291         fmpz_poly_signature(&r1, &r2, this->evaluate()._poly());
292     }
293 
294     int read_pretty(char** x, FILE* f = stdin)
295     {
296         return fmpz_poly_fread_pretty(f, _poly(), x);
297     }
298 
299     // lazy member forwarding
300     FLINTXX_DEFINE_MEMBER_BINOP_(operator(), compeval)
301     FLINTXX_DEFINE_MEMBER_BINOP_(get_coeff, fmpz_polyxx_get_coeff)
302 
303     FLINTXX_DEFINE_MEMBER_BINOP(bit_pack)
304     FLINTXX_DEFINE_MEMBER_BINOP(compose_divconquer)
305     FLINTXX_DEFINE_MEMBER_BINOP(compose_horner)
306     FLINTXX_DEFINE_MEMBER_BINOP(div_basecase)
307     FLINTXX_DEFINE_MEMBER_BINOP(div_divconquer)
308     FLINTXX_DEFINE_MEMBER_BINOP(divexact)
309     FLINTXX_DEFINE_MEMBER_BINOP(divides)
310     FLINTXX_DEFINE_MEMBER_BINOP(divrem)
311     FLINTXX_DEFINE_MEMBER_BINOP(divrem_basecase)
312     FLINTXX_DEFINE_MEMBER_BINOP(divrem_divconquer)
313     FLINTXX_DEFINE_MEMBER_BINOP(div_root)
314     FLINTXX_DEFINE_MEMBER_BINOP(evaluate_divconquer)
315     FLINTXX_DEFINE_MEMBER_BINOP(evaluate_horner)
316     FLINTXX_DEFINE_MEMBER_BINOP(fdiv_2exp)
317     FLINTXX_DEFINE_MEMBER_BINOP(gcd)
318     FLINTXX_DEFINE_MEMBER_BINOP(gcd_heuristic)
319     FLINTXX_DEFINE_MEMBER_BINOP(gcd_modular)
320     FLINTXX_DEFINE_MEMBER_BINOP(gcd_subresultant)
321     FLINTXX_DEFINE_MEMBER_BINOP(inv_series)
322     FLINTXX_DEFINE_MEMBER_BINOP(inv_series_newton)
323     FLINTXX_DEFINE_MEMBER_BINOP(lcm)
324     FLINTXX_DEFINE_MEMBER_BINOP(mul_2exp)
325     FLINTXX_DEFINE_MEMBER_BINOP(mul_classical)
326     FLINTXX_DEFINE_MEMBER_BINOP(mul_karatsuba)
327     FLINTXX_DEFINE_MEMBER_BINOP(mul_KS)
328     FLINTXX_DEFINE_MEMBER_BINOP(mulmid_classical)
329     FLINTXX_DEFINE_MEMBER_BINOP(mul_SS)
330     FLINTXX_DEFINE_MEMBER_BINOP(shift_left)
331     FLINTXX_DEFINE_MEMBER_BINOP(shift_right)
332     FLINTXX_DEFINE_MEMBER_BINOP(pow)
333     FLINTXX_DEFINE_MEMBER_BINOP(pow_addchains)
334     FLINTXX_DEFINE_MEMBER_BINOP(pow_binexp)
335     FLINTXX_DEFINE_MEMBER_BINOP(pow_binomial)
336     FLINTXX_DEFINE_MEMBER_BINOP(pow_multinomial)
337     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_div)
338     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_divrem)
339     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_divrem_basecase)
340     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_divrem_cohen)
341     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_divrem_divconquer)
342     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_rem)
343     FLINTXX_DEFINE_MEMBER_BINOP(pseudo_rem_cohen)
344     FLINTXX_DEFINE_MEMBER_BINOP(resultant)
345     FLINTXX_DEFINE_MEMBER_BINOP(reverse)
346     FLINTXX_DEFINE_MEMBER_BINOP(revert_series)
347     FLINTXX_DEFINE_MEMBER_BINOP(revert_series_lagrange)
348     FLINTXX_DEFINE_MEMBER_BINOP(revert_series_lagrange_fast)
349     FLINTXX_DEFINE_MEMBER_BINOP(revert_series_newton)
350     FLINTXX_DEFINE_MEMBER_BINOP(smod)
351     FLINTXX_DEFINE_MEMBER_BINOP(sqrlow)
352     FLINTXX_DEFINE_MEMBER_BINOP(sqrlow_classical)
353     FLINTXX_DEFINE_MEMBER_BINOP(sqrlow_karatsuba_n)
354     FLINTXX_DEFINE_MEMBER_BINOP(sqrlow_KS)
355     FLINTXX_DEFINE_MEMBER_BINOP(taylor_shift)
356     FLINTXX_DEFINE_MEMBER_BINOP(taylor_shift_divconquer)
357     FLINTXX_DEFINE_MEMBER_BINOP(taylor_shift_horner)
358     FLINTXX_DEFINE_MEMBER_BINOP(tdiv)
359     FLINTXX_DEFINE_MEMBER_BINOP(tdiv_2exp)
360     FLINTXX_DEFINE_MEMBER_BINOP(xgcd)
361     FLINTXX_DEFINE_MEMBER_BINOP(xgcd_modular)
362 
363     FLINTXX_DEFINE_MEMBER_UNOP(derivative)
364     FLINTXX_DEFINE_MEMBER_UNOP(primitive_part)
365     FLINTXX_DEFINE_MEMBER_UNOP(sqr)
366     FLINTXX_DEFINE_MEMBER_UNOP(sqr_classical)
367     FLINTXX_DEFINE_MEMBER_UNOP(sqr_karatsuba)
368     FLINTXX_DEFINE_MEMBER_UNOP(sqr_KS)
369     FLINTXX_DEFINE_MEMBER_UNOP(sqrt)
370     FLINTXX_DEFINE_MEMBER_UNOP(sqrt_classical)
371 
372     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, bound_roots)
373     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, twonorm)
374 
375     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, content)
376     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(fmpzxx, height)
377 
378     FLINTXX_DEFINE_MEMBER_3OP(compose_series)
379     FLINTXX_DEFINE_MEMBER_3OP(compose_series_brent_kung)
380     FLINTXX_DEFINE_MEMBER_3OP(compose_series_horner)
381     FLINTXX_DEFINE_MEMBER_3OP(div_series)
382     FLINTXX_DEFINE_MEMBER_3OP(mulhigh_classical)
383     FLINTXX_DEFINE_MEMBER_3OP(mulhigh_karatsuba_n)
384     FLINTXX_DEFINE_MEMBER_3OP(mulhigh_n)
385     FLINTXX_DEFINE_MEMBER_3OP(mullow)
386     FLINTXX_DEFINE_MEMBER_3OP(mullow_classical)
387     FLINTXX_DEFINE_MEMBER_3OP(mullow_karatsuba_n)
388     FLINTXX_DEFINE_MEMBER_3OP(mullow_KS)
389     FLINTXX_DEFINE_MEMBER_3OP(mullow_SS)
390     FLINTXX_DEFINE_MEMBER_3OP(pow_trunc)
391 
392     FLINTXX_DEFINE_MEMBER_4OP(CRT)
393 };
394 
395 namespace detail {
396 struct fmpz_poly_data;
397 }
398 
399 typedef fmpz_polyxx_expression<operations::immediate, detail::fmpz_poly_data>
400            fmpz_polyxx;
401 typedef fmpz_polyxx_expression<operations::immediate,
402             flint_classes::ref_data<fmpz_polyxx, fmpz_poly_struct> >
403            fmpz_polyxx_ref;
404 typedef fmpz_polyxx_expression<operations::immediate,
405             flint_classes::srcref_data<
406                 fmpz_polyxx, fmpz_polyxx_ref, fmpz_poly_struct> >
407            fmpz_polyxx_srcref;
408 
409 namespace detail {
410 template<>
411 struct fmpz_poly_traits<fmpz_polyxx_srcref>
412 {
413     typedef fmpzxx_srcref lead_srcref_t;
414     typedef fmpzxx_srcref lead_ref_t;
415 
416     template<class P>
417     static lead_srcref_t lead(const P& p)
418         {return lead_srcref_t::make(fmpz_poly_lead(p._poly()));}
419 
420     template<class T>
421     struct coeff
422     {
423         typedef typename mp::enable_if<
424             traits::is_integer<T>, fmpzxx_srcref>::type ref_t;
425         typedef ref_t srcref_t;
426 
427         template<class P>
428         static srcref_t get(const P& p, const T& n)
429             {return srcref_t::make(fmpz_poly_coeff_ptr(p._poly(), n));}
430     };
431 };
432 template<>
433 struct fmpz_poly_traits<fmpz_polyxx_ref>
434 {
435     typedef fmpzxx_ref lead_ref_t;
436     typedef fmpzxx_ref lead_srcref_t;
437 
438     template<class P>
439     static lead_ref_t lead(P p)
440         {return lead_ref_t::make(fmpz_poly_lead(p._poly()));}
441 
442     template<class T>
443     struct coeff
444     {
445         typedef fmpzxx_ref ref_t;
446         typedef fmpzxx_ref srcref_t;
447 
448         template<class P>
449         static ref_t get(P p, const T& n)
450             {return ref_t::make(fmpz_poly_get_coeff_ptr(p._poly(), n));}
451     };
452 };
453 template<>
454 struct fmpz_poly_traits<fmpz_polyxx>
455 {
456     typedef fmpzxx_ref lead_ref_t;
457     typedef fmpzxx_srcref lead_srcref_t;
458 
459     template<class P>
460     static lead_ref_t lead(P& p)
461         {return lead_ref_t::make(fmpz_poly_lead(p._poly()));}
462     template<class P>
463     static lead_srcref_t lead(const P& p)
464         {return lead_srcref_t::make(fmpz_poly_lead(p._poly()));}
465 
466     template<class T>
467     struct coeff
468     {
469         typedef fmpzxx_ref ref_t;
470         typedef fmpzxx_srcref srcref_t;
471 
472         template<class P>
473         static ref_t get(P& p, const T& n)
474             {return ref_t::make(fmpz_poly_get_coeff_ptr(p._poly(), n));}
475         template<class P>
476         static srcref_t get(const P& p, const T& n)
477             {return srcref_t::make(fmpz_poly_get_coeff_ptr(p._poly(), n));}
478     };
479 };
480 
481 struct fmpz_poly_data
482 {
483     fmpz_poly_t inner;
484     typedef fmpz_poly_t& data_ref_t;
485     typedef const fmpz_poly_t& data_srcref_t;
486 
487     fmpz_poly_data() {fmpz_poly_init(inner);}
488     ~fmpz_poly_data() {fmpz_poly_clear(inner);}
489 
490     fmpz_poly_data(const fmpz_poly_data& o)
491     {
492         fmpz_poly_init(inner);
493         fmpz_poly_set(inner, o.inner);
494     }
495 
496     fmpz_poly_data(fmpz_polyxx_srcref r)
497     {
498         fmpz_poly_init(inner);
499         fmpz_poly_set(inner, r._poly());
500     }
501 
502     fmpz_poly_data(slong alloc)
503     {
504         fmpz_poly_init2(inner, alloc);
505     }
506 
507     fmpz_poly_data(const char* str)
508     {
509         fmpz_poly_init(inner);
510         execution_check(!fmpz_poly_set_str(inner, str),
511                 "construct from string", "fmpz_polyxx");
512     }
513 };
514 } // detail
515 
516 namespace traits {
517 template<class T> struct is_fmpz_polyxx : mp::or_<
518      traits::is_T_expr<T, fmpz_polyxx>,
519      flint_classes::is_source<fmpz_polyxx, T> > { };
520 } // traits
521 namespace mp {
522 template<class T1, class T2 = void, class T3 = void, class T4 = void>
523 struct all_fmpz_polyxx : mp::and_<all_fmpz_polyxx<T1>, all_fmpz_polyxx<T2, T3, T4> > { };
524 template<class T>
525 struct all_fmpz_polyxx<T, void, void, void> : traits::is_fmpz_polyxx<T> { };
526 
527 template<class Out, class T1, class T2 = void, class T3 = void, class T4 = void>
528 struct enable_all_fmpz_polyxx
529     : mp::enable_if<all_fmpz_polyxx<T1, T2, T3, T4>, Out> { };
530 } // mp
531 
532 namespace rules {
533 #define FMPZ_POLYXX_COND_S FLINTXX_COND_S(fmpz_polyxx)
534 #define FMPZ_POLYXX_COND_T FLINTXX_COND_T(fmpz_polyxx)
535 
536 FLINTXX_DEFINE_EQUALS(fmpz_polyxx, fmpz_poly_equal(e1._poly(), e2._poly()))
537 
538 FLINT_DEFINE_DOIT_COND2(assignment, FMPZ_POLYXX_COND_T, FMPZ_POLYXX_COND_S,
539         fmpz_poly_set(to._poly(), from._poly()))
540 FLINT_DEFINE_DOIT_COND2(assignment, FMPZ_POLYXX_COND_T,
541         traits::is_signed_integer,
542         fmpz_poly_set_si(to._poly(), from))
543 FLINT_DEFINE_DOIT_COND2(assignment, FMPZ_POLYXX_COND_T,
544         traits::is_unsigned_integer,
545         fmpz_poly_set_ui(to._poly(), from))
546 FLINT_DEFINE_DOIT_COND2(assignment, FMPZ_POLYXX_COND_T, FMPZXX_COND_S,
547         fmpz_poly_set_fmpz(to._poly(), from._fmpz()))
548 FLINTXX_DEFINE_ASSIGN_STR(fmpz_polyxx, execution_check(
549             !fmpz_poly_set_str(to._poly(), from), "assign string", "fmpz_polyxx"))
550 
551 FLINT_DEFINE_PRINT_COND(FMPZ_POLYXX_COND_S, fmpz_poly_fprint(to, from._poly()))
552 FLINT_DEFINE_PRINT_PRETTY_COND_2(FMPZ_POLYXX_COND_S, const char*,
553         fmpz_poly_fprint_pretty(to, from._poly(), extra))
554 FLINT_DEFINE_READ_COND(FMPZ_POLYXX_COND_T, fmpz_poly_fread(from, to._poly()))
555 
556 FLINTXX_DEFINE_TO_STR(fmpz_polyxx, fmpz_poly_get_str(from._poly()))
557 FLINTXX_DEFINE_SWAP(fmpz_polyxx, fmpz_poly_swap(e1._poly(), e2._poly()))
558 
559 FLINT_DEFINE_BINARY_EXPR_COND2(reverse_op, fmpz_polyxx,
560         FMPZ_POLYXX_COND_S, traits::fits_into_slong,
561         fmpz_poly_reverse(to._poly(), e1._poly(), e2))
562 
563 FLINT_DEFINE_BINARY_EXPR_COND2(plus, fmpz_polyxx,
564         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
565         fmpz_poly_add(to._poly(), e1._poly(), e2._poly()))
566 FLINT_DEFINE_BINARY_EXPR_COND2(minus, fmpz_polyxx,
567         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
568         fmpz_poly_sub(to._poly(), e1._poly(), e2._poly()))
569 
570 FLINT_DEFINE_UNARY_EXPR_COND(negate, fmpz_polyxx, FMPZ_POLYXX_COND_S,
571         fmpz_poly_neg(to._poly(), from._poly()))
572 
573 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_polyxx,
574         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
575         fmpz_poly_scalar_mul_fmpz(to._poly(), e1._poly(), e2._fmpz()))
576 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_polyxx,
577         FMPZ_POLYXX_COND_S, traits::is_signed_integer,
578         fmpz_poly_scalar_mul_si(to._poly(), e1._poly(), e2))
579 FLINT_DEFINE_CBINARY_EXPR_COND2(times, fmpz_polyxx,
580         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer,
581         fmpz_poly_scalar_mul_ui(to._poly(), e1._poly(), e2))
582 
583 FLINT_DEFINE_CBINARY_EXPR_COND2(mul_2exp_op, fmpz_polyxx,
584         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer,
585         fmpz_poly_scalar_mul_2exp(to._poly(), e1._poly(), e2))
586 
587 FLINT_DEFINE_CBINARY_EXPR_COND2(divided_by, fmpz_polyxx,
588         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
589         fmpz_poly_scalar_fdiv_fmpz(to._poly(), e1._poly(), e2._fmpz()))
590 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpz_polyxx,
591         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer,
592         fmpz_poly_scalar_fdiv_ui(to._poly(), e1._poly(), e2))
593 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpz_polyxx,
594         FMPZ_POLYXX_COND_S, traits::is_signed_integer,
595         fmpz_poly_scalar_fdiv_si(to._poly(), e1._poly(), e2))
596 
597 FLINT_DEFINE_CBINARY_EXPR_COND2(fdiv_2exp_op, fmpz_polyxx,
598         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer,
599         fmpz_poly_scalar_fdiv_2exp(to._poly(), e1._poly(), e2))
600 
601 #define FMPZ_POLYXX_DEFINE_SCALAR_DIVFUNCS(name) \
602 FLINT_DEFINE_CBINARY_EXPR_COND2(name##_op, fmpz_polyxx, \
603         FMPZ_POLYXX_COND_S, FMPZXX_COND_S, \
604         fmpz_poly_scalar_##name##_fmpz(to._poly(), e1._poly(), e2._fmpz())) \
605 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpz_polyxx, \
606         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer, \
607         fmpz_poly_scalar_##name##_ui(to._poly(), e1._poly(), e2)) \
608 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpz_polyxx, \
609         FMPZ_POLYXX_COND_S, traits::is_signed_integer, \
610         fmpz_poly_scalar_##name##_si(to._poly(), e1._poly(), e2))
611 FMPZ_POLYXX_DEFINE_SCALAR_DIVFUNCS(tdiv)
612 FMPZ_POLYXX_DEFINE_SCALAR_DIVFUNCS(divexact)
613 
614 FLINT_DEFINE_CBINARY_EXPR_COND2(tdiv_2exp_op, fmpz_polyxx,
615         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer,
616         fmpz_poly_scalar_tdiv_2exp(to._poly(), e1._poly(), e2))
617 
618 FLINT_DEFINE_BINARY_EXPR_COND2(modulo, fmpz_polyxx,
619         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
620         fmpz_poly_scalar_mod_fmpz(to._poly(), e1._poly(), e2._fmpz()))
621 
622 FLINT_DEFINE_BINARY_EXPR_COND2(smod_op, fmpz_polyxx,
623         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
624         fmpz_poly_scalar_smod_fmpz(to._poly(), e1._poly(), e2._fmpz()))
625 
626 FLINT_DEFINE_BINARY_EXPR_COND2(bit_pack_op, fmpzxx,
627         FMPZ_POLYXX_COND_S, traits::fits_into_flint_bitcnt_t,
628         fmpz_poly_bit_pack(to._fmpz(), e1._poly(), e2))
629 
630 FLINT_DEFINE_BINARY_EXPR_COND2(fmpz_polyxx_bit_unpack_op, fmpz_polyxx,
631         FMPZXX_COND_S, traits::fits_into_flint_bitcnt_t,
632         fmpz_poly_bit_unpack(to._poly(), e1._fmpz(), e2))
633 
634 FLINT_DEFINE_BINARY_EXPR_COND2(fmpz_polyxx_bit_unpack_unsigned_op, fmpz_polyxx,
635         FMPZXX_COND_S, traits::fits_into_flint_bitcnt_t,
636         fmpz_poly_bit_unpack_unsigned(to._poly(), e1._fmpz(), e2))
637 
638 FLINT_DEFINE_BINARY_EXPR_COND2(times, fmpz_polyxx,
639         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
640         fmpz_poly_mul(to._poly(), e1._poly(), e2._poly()))
641 
642 #define FMPZ_POLYXX_DEFINE_MUL(name) \
643 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpz_polyxx, \
644         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, \
645         fmpz_poly_##name(to._poly(), e1._poly(), e2._poly()))
646 FMPZ_POLYXX_DEFINE_MUL(mul_classical)
647 FMPZ_POLYXX_DEFINE_MUL(mulmid_classical)
648 FMPZ_POLYXX_DEFINE_MUL(mul_karatsuba)
649 FMPZ_POLYXX_DEFINE_MUL(mul_SS)
650 FMPZ_POLYXX_DEFINE_MUL(mul_KS)
651 
652 FLINT_DEFINE_UNARY_EXPR_COND(sqr_KS_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
653         fmpz_poly_sqr_KS(to._poly(), from._poly()))
654 FLINT_DEFINE_UNARY_EXPR_COND(sqr_karatsuba_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
655         fmpz_poly_sqr_karatsuba(to._poly(), from._poly()))
656 FLINT_DEFINE_UNARY_EXPR_COND(sqr_classical_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
657         fmpz_poly_sqr_classical(to._poly(), from._poly()))
658 FLINT_DEFINE_UNARY_EXPR_COND(sqr_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
659         fmpz_poly_sqr(to._poly(), from._poly()))
660 
661 #define FMPZ_POLYXX_DEFINE_SQRLOW(name) \
662 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpz_polyxx, \
663         FMPZ_POLYXX_COND_S, traits::fits_into_slong, \
664         fmpz_poly_##name(to._poly(), e1._poly(), e2))
665 FMPZ_POLYXX_DEFINE_SQRLOW(sqrlow_KS)
666 FMPZ_POLYXX_DEFINE_SQRLOW(sqrlow_karatsuba_n)
667 FMPZ_POLYXX_DEFINE_SQRLOW(sqrlow_classical)
668 FMPZ_POLYXX_DEFINE_SQRLOW(sqrlow)
669 
670 #define FMPZ_POLYXX_DEFINE_POW(name) \
671 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, fmpz_polyxx, \
672         FMPZ_POLYXX_COND_S, traits::is_unsigned_integer, \
673         fmpz_poly_##name(to._poly(), e1._poly(), e2))
674 FMPZ_POLYXX_DEFINE_POW(pow_multinomial)
675 FMPZ_POLYXX_DEFINE_POW(pow_binomial)
676 FMPZ_POLYXX_DEFINE_POW(pow_addchains)
677 FMPZ_POLYXX_DEFINE_POW(pow_binexp)
678 FMPZ_POLYXX_DEFINE_POW(pow)
679 
680 FLINT_DEFINE_BINARY_EXPR_COND2(shift_left_op, fmpz_polyxx,
681         FMPZ_POLYXX_COND_S, traits::fits_into_slong,
682         fmpz_poly_shift_left(to._poly(), e1._poly(), e2))
683 FLINT_DEFINE_BINARY_EXPR_COND2(shift_right_op, fmpz_polyxx,
684         FMPZ_POLYXX_COND_S, traits::fits_into_slong,
685         fmpz_poly_shift_right(to._poly(), e1._poly(), e2))
686 
687 FLINT_DEFINE_UNARY_EXPR_COND(height_op, fmpzxx, FMPZ_POLYXX_COND_S,
688         fmpz_poly_height(to._fmpz(), from._poly()))
689 FLINT_DEFINE_UNARY_EXPR_COND(twonorm_op, fmpzxx, FMPZ_POLYXX_COND_S,
690         fmpz_poly_2norm(to._fmpz(), from._poly()))
691 
692 FMPZ_POLYXX_DEFINE_MUL(gcd)
693 FMPZ_POLYXX_DEFINE_MUL(gcd_subresultant)
694 FMPZ_POLYXX_DEFINE_MUL(gcd_heuristic)
695 FMPZ_POLYXX_DEFINE_MUL(gcd_modular)
696 FMPZ_POLYXX_DEFINE_MUL(lcm)
697 
698 FLINT_DEFINE_BINARY_EXPR_COND2(resultant_op, fmpzxx,
699         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
700         fmpz_poly_resultant(to._fmpz(), e1._poly(), e2._poly()))
701 
702 FLINT_DEFINE_UNARY_EXPR_COND(content_op, fmpzxx, FMPZ_POLYXX_COND_S,
703         fmpz_poly_content(to._fmpz(), from._poly()))
704 FLINT_DEFINE_UNARY_EXPR_COND(primitive_part_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
705         fmpz_poly_primitive_part(to._poly(), from._poly()))
706 
707 FLINT_DEFINE_BINARY_EXPR_COND2(div_basecase_op, fmpz_polyxx,
708         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
709         fmpz_poly_div_basecase(to._poly(), e1._poly(), e2._poly()))
710 FLINT_DEFINE_BINARY_EXPR_COND2(div_divconquer_op, fmpz_polyxx,
711         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
712         fmpz_poly_div_divconquer(to._poly(), e1._poly(), e2._poly()))
713 
714 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpz_polyxx,
715         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
716         fmpz_poly_div(to._poly(), e1._poly(), e2._poly()))
717 
718 FLINT_DEFINE_BINARY_EXPR_COND2(rem_basecase_op, fmpz_polyxx,
719         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
720         fmpz_poly_rem_basecase(to._poly(), e1._poly(), e2._poly()))
721 FLINT_DEFINE_BINARY_EXPR_COND2(modulo, fmpz_polyxx,
722         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
723         fmpz_poly_rem(to._poly(), e1._poly(), e2._poly()))
724 
725 FLINT_DEFINE_BINARY_EXPR_COND2(div_root_op, fmpz_polyxx,
726         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
727         fmpz_poly_div_root(to._poly(), e1._poly(), e2._fmpz()))
728 
729 FLINT_DEFINE_BINARY_EXPR_COND2(inv_series_newton_op, fmpz_polyxx,
730         FMPZ_POLYXX_COND_S, traits::fits_into_slong,
731         fmpz_poly_inv_series_newton(to._poly(), e1._poly(), e2))
732 FLINT_DEFINE_BINARY_EXPR_COND2(inv_series_op, fmpz_polyxx,
733         FMPZ_POLYXX_COND_S, traits::fits_into_slong,
734         fmpz_poly_inv_series(to._poly(), e1._poly(), e2))
735 
736 FLINT_DEFINE_BINARY_EXPR_COND2(pseudo_rem_cohen_op, fmpz_polyxx,
737         FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
738         fmpz_poly_pseudo_rem_cohen(to._poly(), e1._poly(), e2._poly()))
739 
740 FLINT_DEFINE_UNARY_EXPR_COND(derivative_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
741         fmpz_poly_derivative(to._poly(), from._poly()))
742 
743 FMPZ_POLYXX_DEFINE_MUL(compose)
744 FMPZ_POLYXX_DEFINE_MUL(compose_horner)
745 FMPZ_POLYXX_DEFINE_MUL(compose_divconquer)
746 
747 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_op, fmpzxx,
748         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
749         fmpz_poly_evaluate_fmpz(to._fmpz(), e1._poly(), e2._fmpz()))
750 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_divconquer_op, fmpzxx,
751         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
752         fmpz_poly_evaluate_divconquer_fmpz(to._fmpz(), e1._poly(), e2._fmpz()))
753 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_horner_op, fmpzxx,
754         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
755         fmpz_poly_evaluate_horner_fmpz(to._fmpz(), e1._poly(), e2._fmpz()))
756 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_op, fmpz_vecxx,
757         FMPZ_POLYXX_COND_S, FMPZ_VECXX_COND_S,
758         fmpz_poly_evaluate_fmpz_vec(to._data().array, e1._poly(),
759             e2._data().array, e2.size()))
760 
761 FLINT_DEFINE_BINARY_EXPR_COND2(fmpz_polyxx_interpolate_op, fmpz_polyxx,
762         FMPZ_VECXX_COND_S, FMPZ_VECXX_COND_S,
763         fmpz_poly_interpolate_fmpz_vec(to._poly(), e1._data().array,
764             e2._data().array, e2.size()))
765 
766 FLINT_DEFINE_BINARY_EXPR_COND2(taylor_shift_horner_op, fmpz_polyxx,
767         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
768         fmpz_poly_taylor_shift_horner(to._poly(), e1._poly(), e2._fmpz()))
769 FLINT_DEFINE_BINARY_EXPR_COND2(taylor_shift_divconquer_op, fmpz_polyxx,
770         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
771         fmpz_poly_taylor_shift_divconquer(to._poly(), e1._poly(), e2._fmpz()))
772 FLINT_DEFINE_BINARY_EXPR_COND2(taylor_shift_op, fmpz_polyxx,
773         FMPZ_POLYXX_COND_S, FMPZXX_COND_S,
774         fmpz_poly_taylor_shift(to._poly(), e1._poly(), e2._fmpz()))
775 
776 FMPZ_POLYXX_DEFINE_SQRLOW(revert_series)
777 FMPZ_POLYXX_DEFINE_SQRLOW(revert_series_newton)
778 FMPZ_POLYXX_DEFINE_SQRLOW(revert_series_lagrange_fast)
779 FMPZ_POLYXX_DEFINE_SQRLOW(revert_series_lagrange)
780 
781 FLINT_DEFINE_UNARY_EXPR_COND(sqrt_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
782         execution_check(fmpz_poly_sqrt(to._poly(), from._poly()),
783             "sqrt", "fmpz_polyxx"))
784 FLINT_DEFINE_UNARY_EXPR_COND(sqrt_classical_op, fmpz_polyxx, FMPZ_POLYXX_COND_S,
785         execution_check(fmpz_poly_sqrt_classical(to._poly(), from._poly()),
786             "sqrt_classical", "fmpz_polyxx"))
787 
788 FLINT_DEFINE_UNARY_EXPR_COND(fmpz_polyxx_product_roots_op, fmpz_polyxx,
789         FMPZ_VECXX_COND_S,
790         fmpz_poly_product_roots_fmpz_vec(to._poly(),
791             from._data().array, from.size()))
792 
793 FLINT_DEFINE_BINARY_EXPR_COND2(fmpz_polyxx_get_coeff_op, fmpzxx,
794         FMPZ_POLYXX_COND_S, traits::is_integer,
795         fmpz_poly_get_coeff_fmpz(to._fmpz(), e1._poly(), e2))
796 FLINT_DEFINE_UNARY_EXPR_COND(fmpz_polyxx_lead_op, fmpzxx,
797         FMPZ_POLYXX_COND_S,
798         fmpz_set(to._fmpz(), fmpz_poly_lead(from._poly())))
799 
800 FLINT_DEFINE_UNARY_EXPR_COND(bound_roots_op, fmpzxx, FMPZ_POLYXX_COND_S,
801         fmpz_poly_bound_roots(to._fmpz(), from._poly()))
802 
803 namespace rdetail {
804 typedef make_ltuple<mp::make_tuple<fmpz_polyxx, fmpz_polyxx>::type>::type
805     fmpz_polyxx_pair;
806 typedef make_ltuple<mp::make_tuple<fmpzxx, fmpz_polyxx, fmpz_polyxx>::type>::type
807     fmpzxx_fmpz_polyxx_pair;
808 } // rdetail
809 #define FMPZ_POLYXX_DEFINE_DIVREM(name) \
810 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, rdetail::fmpz_polyxx_pair, \
811     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, \
812     fmpz_poly_##name(to.template get<0>()._poly(), to.template get<1>()._poly(), \
813         e1._poly(), e2._poly()))
814 FMPZ_POLYXX_DEFINE_DIVREM(divrem_basecase)
815 FMPZ_POLYXX_DEFINE_DIVREM(divrem_divconquer)
816 FMPZ_POLYXX_DEFINE_DIVREM(divrem)
817 FMPZ_POLYXX_DEFINE_DIVREM(pseudo_divrem_cohen)
818 
819 #define FMPZ_POLYXX_DEFINE_MULFUNC(name) \
820 FLINT_DEFINE_THREEARY_EXPR_COND3(name##_op, fmpz_polyxx, \
821     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, traits::fits_into_slong, \
822     fmpz_poly_##name(to._poly(), e1._poly(), e2._poly(), e3))
823 
824 FMPZ_POLYXX_DEFINE_MULFUNC(mullow_classical)
825 FMPZ_POLYXX_DEFINE_MULFUNC(mulhigh_classical)
826 FMPZ_POLYXX_DEFINE_MULFUNC(mullow_karatsuba_n)
827 FMPZ_POLYXX_DEFINE_MULFUNC(mulhigh_karatsuba_n)
828 FMPZ_POLYXX_DEFINE_MULFUNC(mullow_KS)
829 FMPZ_POLYXX_DEFINE_MULFUNC(mullow_SS)
830 FMPZ_POLYXX_DEFINE_MULFUNC(mullow)
831 FMPZ_POLYXX_DEFINE_MULFUNC(mulhigh_n)
832 
833 FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_op, rdetail::fmpzxx_fmpz_polyxx_pair,
834     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
835     fmpz_poly_xgcd(to.template get<0>()._fmpz(), to.template get<1>()._poly(),
836         to.template get<2>()._poly(), e1._poly(), e2._poly()))
837 FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_modular_op, rdetail::fmpzxx_fmpz_polyxx_pair,
838     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
839     fmpz_poly_xgcd_modular(to.template get<0>()._fmpz(),
840         to.template get<1>()._poly(),
841         to.template get<2>()._poly(), e1._poly(), e2._poly()))
842 
843 FLINT_DEFINE_THREEARY_EXPR_COND3(pow_trunc_op, fmpz_polyxx,
844     FMPZ_POLYXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
845     fmpz_poly_pow_trunc(to._poly(), e1._poly(), e2, e3))
846 
847 #define FMPZ_POLYXX_DEFINE_SERIES(name) \
848 FLINT_DEFINE_THREEARY_EXPR_COND3(name##_op, fmpz_polyxx, \
849     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, traits::fits_into_slong, \
850     fmpz_poly_##name(to._poly(), e1._poly(), e2._poly(), e3))
851 FMPZ_POLYXX_DEFINE_SERIES(div_series)
852 FMPZ_POLYXX_DEFINE_SERIES(compose_series_brent_kung)
853 FMPZ_POLYXX_DEFINE_SERIES(compose_series_horner)
854 FMPZ_POLYXX_DEFINE_SERIES(compose_series)
855 
856 namespace rdetail {
857 typedef make_ltuple<mp::make_tuple<fmpz_polyxx, fmpz_polyxx, ulong>::type>::type
858     fmpz_polyxx_pair_ulong;
859 typedef make_ltuple<mp::make_tuple<fmpz_polyxx, ulong>::type>::type
860     fmpz_polyxx_ulong;
861 typedef make_ltuple<mp::make_tuple<bool, fmpz_polyxx>::type>::type
862     bool_fmpz_polyxx;
863 }
864 #define FMPZ_POLYXX_DEFINE_PSEUDO_DIVREM(name) \
865 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, rdetail::fmpz_polyxx_pair_ulong, \
866     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, \
867     fmpz_poly_##name(to.template get<0>()._poly(), to.template get<1>()._poly(), \
868         &to.template get<2>(), e1._poly(), e2._poly()))
869 FMPZ_POLYXX_DEFINE_PSEUDO_DIVREM(pseudo_divrem_basecase)
870 FMPZ_POLYXX_DEFINE_PSEUDO_DIVREM(pseudo_divrem_divconquer)
871 FMPZ_POLYXX_DEFINE_PSEUDO_DIVREM(pseudo_divrem)
872 
873 FLINT_DEFINE_BINARY_EXPR_COND2(pseudo_div_op, rdetail::fmpz_polyxx_ulong,
874     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
875     fmpz_poly_pseudo_div(to.template get<0>()._poly(), &to.template get<1>(),
876         e1._poly(), e2._poly()))
877 FLINT_DEFINE_BINARY_EXPR_COND2(pseudo_rem_op, rdetail::fmpz_polyxx_ulong,
878     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
879     fmpz_poly_pseudo_rem(to.template get<0>()._poly(), &to.template get<1>(),
880         e1._poly(), e2._poly()))
881 
882 FLINT_DEFINE_BINARY_EXPR_COND2(divides_op, rdetail::bool_fmpz_polyxx,
883     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
884     to.template get<0> () =
885         fmpz_poly_divides(to.template get<1>()._poly(), e1._poly(), e2._poly()))
886 
887 namespace rdetail {
888 typedef make_ltuple<mp::make_tuple<
889         fmpz_polyxx, fmpz_polyxx, fmpz_polyxx, fmpz_polyxx>::type>::type
890     fmpz_polyxx_quadruple;
891 }
892 FLINT_DEFINE_SEVENARY_EXPR_COND7(hensel_lift_op, rdetail::fmpz_polyxx_quadruple,
893     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
894     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
895     FMPZXX_COND_S, FMPZXX_COND_S,
896     fmpz_poly_hensel_lift(to.template get<0>()._poly(),
897         to.template get<1>()._poly(), to.template get<2>()._poly(),
898         to.template get<3>()._poly(),
899         e1._poly(), e2._poly(), e3._poly(), e4._poly(), e5._poly(),
900         e6._fmpz(), e7._fmpz()))
901 FLINT_DEFINE_SEVENARY_EXPR_COND7(hensel_lift_without_inverse_op,
902     rdetail::fmpz_polyxx_pair,
903     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
904     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
905     FMPZXX_COND_S, FMPZXX_COND_S,
906     fmpz_poly_hensel_lift_without_inverse(to.template get<0>()._poly(),
907         to.template get<1>()._poly(),
908         e1._poly(), e2._poly(), e3._poly(), e4._poly(), e5._poly(),
909         e6._fmpz(), e7._fmpz()))
910 FLINT_DEFINE_SIXARY_EXPR_COND6(hensel_lift_only_inverse_op,
911     rdetail::fmpz_polyxx_pair,
912     FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S, FMPZ_POLYXX_COND_S,
913     FMPZ_POLYXX_COND_S,
914     FMPZXX_COND_S, FMPZXX_COND_S,
915     fmpz_poly_hensel_lift_only_inverse(to.template get<0>()._poly(),
916         to.template get<1>()._poly(),
917         e1._poly(), e2._poly(), e3._poly(), e4._poly(),
918         e5._fmpz(), e6._fmpz()))
919 } // rules
920 
921 // immediate functions
922 // TODO make lazy when we have nmod class
923 template<class Poly>
924 inline typename mp::enable_all_fmpz_polyxx<mp_limb_t, Poly>::type
925 evaluate_mod(const Poly& p, mp_limb_t x, mp_limb_t n)
926 {
927     return fmpz_poly_evaluate_mod(p.evaluate()._poly(), x, n);
928 }
929 
930 template<class Fmpz_poly>
931 int read_pretty(Fmpz_poly& f, char** x,
932         typename mp::enable_if<FMPZ_POLYXX_COND_T<Fmpz_poly> >::type* = 0)
933 {
934     return f.read_pretty(x);
935 }
936 template<class Fmpz_poly>
937 int read_pretty(FILE* fi, Fmpz_poly& f, char** x,
938         typename mp::enable_if<FMPZ_POLYXX_COND_T<Fmpz_poly> >::type* = 0)
939 {
940     return f.read_pretty(x, fi);
941 }
942 } // flint
943 
944 #include "nmod_polyxx.h" // modular reconstruction code
945 
946 #include "fmpz_poly_factorxx.h"
947 
948 #endif
949