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 NMOD_POLYXX_H
13 #define NMOD_POLYXX_H
14 
15 #include <cstdlib>
16 #include <vector>
17 
18 #include "nmod_poly.h"
19 
20 #include "fmpzxx.h"
21 #include "nmod_vecxx.h"
22 #include "fmpz_polyxx.h"
23 #include "fmpq_polyxx.h"
24 
25 #include "flintxx/expression.h"
26 #include "flintxx/ltuple.h"
27 #include "flintxx/flint_classes.h"
28 #include "flintxx/flint_exception.h"
29 #include "flintxx/frandxx.h"
30 #include "flintxx/stdmath.h"
31 #include "flintxx/traits.h"
32 
33 // TODO exhibit this as a specialisation of a generic poly<nmodxx>
34 // TODO input
35 // TODO automatic mulmod, powmod etc?
36 // TODO use underscore function versions?
37 // TODO nmod_series class?
38 // TODO subproduct trees?
39 
40 namespace flint {
41 FLINT_DEFINE_BINOP(div_newton)
FLINT_DEFINE_BINOP(divrem_newton)42 FLINT_DEFINE_BINOP(divrem_newton)
43 FLINT_DEFINE_BINOP(evaluate_fast)
44 FLINT_DEFINE_BINOP(evaluate_iter)
45 FLINT_DEFINE_BINOP(exp_series_basecase)
46 FLINT_DEFINE_BINOP(gcd_euclidean)
47 FLINT_DEFINE_BINOP(gcd_hgcd)
48 FLINT_DEFINE_BINOP(inv_series_basecase)
49 FLINT_DEFINE_BINOP(nmod_polyxx_get_coeff)
50 FLINT_DEFINE_BINOP(deflate)
51 FLINT_DEFINE_BINOP(inflate)
52 FLINT_DEFINE_BINOP(resultant_euclidean)
53 FLINT_DEFINE_BINOP(taylor_shift_convolution)
54 FLINT_DEFINE_BINOP(xgcd_euclidean)
55 FLINT_DEFINE_BINOP(xgcd_hgcd)
56 
57 FLINT_DEFINE_THREEARY(compose_mod)
58 FLINT_DEFINE_THREEARY(compose_mod_brent_kung)
59 FLINT_DEFINE_THREEARY(compose_mod_horner)
60 FLINT_DEFINE_THREEARY(div_newton_n_preinv)
61 FLINT_DEFINE_THREEARY(divrem_newton_n_preinv)
62 FLINT_DEFINE_THREEARY(exp_series_monomial)
63 FLINT_DEFINE_THREEARY(log_series_monomial)
64 FLINT_DEFINE_THREEARY(mulmod)
65 FLINT_DEFINE_THREEARY(powmod_binexp)
66 
67 FLINT_DEFINE_BINOP(nmod_polyxx_interpolate)
68 FLINT_DEFINE_BINOP(nmod_polyxx_interpolate_barycentric)
69 FLINT_DEFINE_BINOP(nmod_polyxx_interpolate_fast)
70 FLINT_DEFINE_BINOP(nmod_polyxx_interpolate_newton)
71 FLINT_DEFINE_UNOP(nmod_polyxx_product_roots)
72 
73 FLINT_DEFINE_FOURARY(compose_mod_brent_kung_preinv)
74 FLINT_DEFINE_FOURARY(mulmod_preinv)
75 FLINT_DEFINE_FOURARY(powmod_binexp_preinv)
76 
77 template<class Operation, class Data>
78 class nmod_polyxx_expression
79     : public expression<derived_wrapper<nmod_polyxx_expression>,
80                             Operation, Data>
81 {
82 public:
83     typedef expression<derived_wrapper< ::flint::nmod_polyxx_expression>,
84               Operation, Data> base_t;
85 
86     FLINTXX_DEFINE_BASICS(nmod_polyxx_expression)
87     FLINTXX_DEFINE_CTORS(nmod_polyxx_expression)
88     FLINTXX_DEFINE_C_REF(nmod_polyxx_expression, nmod_poly_struct, _poly)
89 
90     // static functions for nmod_polyxx
91     template<class Nmod_vec1, class Nmod_vec2>
92     static FLINT_BINOP_ENABLE_RETTYPE(nmod_polyxx_interpolate,
93         Nmod_vec1, Nmod_vec2)
94     interpolate(const Nmod_vec1& xs, const Nmod_vec2& ys)
95     {
96         return nmod_polyxx_interpolate(xs, ys);
97     }
98     template<class Nmod_vec1, class Nmod_vec2>
99     static FLINT_BINOP_ENABLE_RETTYPE(nmod_polyxx_interpolate_fast,
100         Nmod_vec1, Nmod_vec2)
101     interpolate_fast(const Nmod_vec1& xs, const Nmod_vec2& ys)
102     {
103         return nmod_polyxx_interpolate_fast(xs, ys);
104     }
105     template<class Nmod_vec1, class Nmod_vec2>
106     static FLINT_BINOP_ENABLE_RETTYPE(nmod_polyxx_interpolate_newton,
107         Nmod_vec1, Nmod_vec2)
108     interpolate_newton(const Nmod_vec1& xs, const Nmod_vec2& ys)
109     {
110         return nmod_polyxx_interpolate_newton(xs, ys);
111     }
112     template<class Nmod_vec1, class Nmod_vec2>
113     static FLINT_BINOP_ENABLE_RETTYPE(nmod_polyxx_interpolate_barycentric,
114         Nmod_vec1, Nmod_vec2)
115     interpolate_barycentric(const Nmod_vec1& xs, const Nmod_vec2& ys)
116     {
117         return nmod_polyxx_interpolate_barycentric(xs, ys);
118     }
119 
120     template<class Nmod_vec>
121     static FLINT_UNOP_ENABLE_RETTYPE(nmod_polyxx_product_roots, Nmod_vec)
122     product_roots(const Nmod_vec& xs)
123     {
124         return nmod_polyxx_product_roots(xs);
125     }
126 
127     // XXX this is difficult to make lazy
128     template<class Fmpz>
129     static typename mp::enable_if<traits::is_fmpzxx<Fmpz>,
130         nmod_polyxx_expression>::type
131     bit_unpack(const Fmpz& a, flint_bitcnt_t bits, nmodxx_ctx_srcref modulus)
132     {
133         nmod_polyxx_expression res(modulus);
134         nmod_poly_bit_unpack(res._poly(), a.evaluate()._fmpz(), bits);
135         return res;
136     }
137 
138     FLINTXX_DEFINE_FORWARD_STATIC(from_ground)
139     FLINTXX_DEFINE_FORWARD_STATIC(reduce)
140 
141     static nmod_polyxx_expression zero(mp_limb_t n)
142         {return nmod_polyxx_expression(n);}
143     static nmod_polyxx_expression one(mp_limb_t n)
144     {
145         nmod_polyxx_expression res(n);
146         res.set_one();
147         return res;
148     }
149 
150     static nmod_polyxx_expression randtest(mp_limb_t n,
151             frandxx& state, slong len)
152     {
153         nmod_polyxx_expression res(n);
154         res.set_randtest(state, len);
155         return res;
156     }
157 
158     static nmod_polyxx_expression randtest_irreducible(mp_limb_t n,
159             frandxx& state, slong len)
160     {
161         nmod_polyxx_expression res(n);
162         res.set_randtest_irreducible(state, len);
163         return res;
164     }
165 
166     // these only make sense with immediates
167     void realloc(slong alloc) {nmod_poly_realloc(_poly(), alloc);}
168     void fit_length(slong len) {nmod_poly_fit_length(_poly(), len);}
169     void _normalise() {_nmod_poly_normalise(_poly());}
170     nmodxx_ctx_srcref _ctx() const
171         {return nmodxx_ctx_srcref::make(_poly()->mod);}
172     void set_zero() {nmod_poly_zero(_poly());}
173     void set_one() {nmod_poly_one(_poly());}
174 
175     // These only make sense with target immediates
176     void set_coeff(slong n, ulong c) {nmod_poly_set_coeff_ui(_poly(), n, c);}
177     template<class Nmod>
178     typename mp::enable_if<traits::is_nmodxx<Nmod> >::type
179     set_coeff(slong j, const Nmod& c)
180     {
181         // TODO this does not need reduction
182         nmod_poly_set_coeff_ui(_poly(), j, c.template to<mp_limb_t>());
183     }
184     void truncate(slong n) {nmod_poly_truncate(_poly(), n);}
185 
186     void set_randtest(frandxx& state, slong len)
187         {nmod_poly_randtest(_poly(), state._data(), len);}
188     void set_randtest_irreducible(frandxx& state, slong len)
189         {nmod_poly_randtest_irreducible(_poly(), state._data(), len);}
190 
191     template<class Poly>
192     slong remove(const Poly& p)
193     {
194         return nmod_poly_remove(_poly(), p.evaluate()._poly());
195     }
196 
197     // These work on any expression without evaluation
198     nmodxx_ctx_srcref estimate_ctx() const;
199     mp_limb_t modulus() const {return estimate_ctx().n();}
200 
201     evaluated_t create_temporary() const
202     {
203         return evaluated_t(estimate_ctx());
204     }
205 
206     // These cause evaluation
207     slong length() const {return nmod_poly_length(this->evaluate()._poly());}
208     slong degree() const {return nmod_poly_degree(this->evaluate()._poly());}
209     bool is_one() const {return nmod_poly_is_one(this->evaluate()._poly());}
210     bool is_zero() const {return nmod_poly_is_zero(this->evaluate()._poly());}
211     bool is_squarefree() const
212         {return nmod_poly_is_squarefree(this->evaluate()._poly());}
213     bool is_irreducible() const
214         {return nmod_poly_is_irreducible(this->evaluate()._poly());}
215     slong max_bits() const {return nmod_poly_max_bits(this->evaluate()._poly());}
216     ulong deflation() const
217         {return nmod_poly_deflation(this->evaluate()._poly());}
218 
219     // Lazy members
220     FLINTXX_DEFINE_MEMBER_BINOP_(get_coeff, nmod_polyxx_get_coeff)
221     FLINTXX_DEFINE_MEMBER_BINOP_(operator(), compeval)
222     FLINTXX_DEFINE_MEMBER_BINOP(inflate)
223     FLINTXX_DEFINE_MEMBER_BINOP(deflate)
224 
225     FLINTXX_DEFINE_MEMBER_BINOP(compose_divconquer)
226     FLINTXX_DEFINE_MEMBER_BINOP(compose_horner)
227     FLINTXX_DEFINE_MEMBER_BINOP(div_basecase)
228     FLINTXX_DEFINE_MEMBER_BINOP(div_divconquer)
229     FLINTXX_DEFINE_MEMBER_BINOP(div_newton)
230     FLINTXX_DEFINE_MEMBER_BINOP(divrem)
231     FLINTXX_DEFINE_MEMBER_BINOP(divrem_basecase)
232     FLINTXX_DEFINE_MEMBER_BINOP(divrem_divconquer)
233     FLINTXX_DEFINE_MEMBER_BINOP(divrem_newton)
234     FLINTXX_DEFINE_MEMBER_BINOP(div_root)
235     FLINTXX_DEFINE_MEMBER_BINOP(evaluate_fast)
236     FLINTXX_DEFINE_MEMBER_BINOP(evaluate_iter)
237     FLINTXX_DEFINE_MEMBER_BINOP(gcd)
238     FLINTXX_DEFINE_MEMBER_BINOP(gcd_euclidean)
239     FLINTXX_DEFINE_MEMBER_BINOP(gcd_hgcd)
240     FLINTXX_DEFINE_MEMBER_BINOP(inv_series)
241     FLINTXX_DEFINE_MEMBER_BINOP(inv_series_basecase)
242     FLINTXX_DEFINE_MEMBER_BINOP(inv_series_newton)
243     FLINTXX_DEFINE_MEMBER_BINOP(invsqrt_series)
244     FLINTXX_DEFINE_MEMBER_BINOP(mul_classical)
245     FLINTXX_DEFINE_MEMBER_BINOP(mul_KS)
246     FLINTXX_DEFINE_MEMBER_BINOP(shift_left)
247     FLINTXX_DEFINE_MEMBER_BINOP(shift_right)
248     FLINTXX_DEFINE_MEMBER_BINOP(pow)
249     FLINTXX_DEFINE_MEMBER_BINOP(pow_binexp)
250     FLINTXX_DEFINE_MEMBER_BINOP(rem_basecase)
251     FLINTXX_DEFINE_MEMBER_BINOP(resultant)
252     FLINTXX_DEFINE_MEMBER_BINOP(resultant_euclidean)
253     FLINTXX_DEFINE_MEMBER_BINOP(reverse)
254     FLINTXX_DEFINE_MEMBER_BINOP(revert_series)
255     FLINTXX_DEFINE_MEMBER_BINOP(revert_series_lagrange)
256     FLINTXX_DEFINE_MEMBER_BINOP(revert_series_lagrange_fast)
257     FLINTXX_DEFINE_MEMBER_BINOP(revert_series_newton)
258     FLINTXX_DEFINE_MEMBER_BINOP(sqrt_series)
259     FLINTXX_DEFINE_MEMBER_BINOP(taylor_shift)
260     FLINTXX_DEFINE_MEMBER_BINOP(taylor_shift_convolution)
261     FLINTXX_DEFINE_MEMBER_BINOP(taylor_shift_horner)
262     FLINTXX_DEFINE_MEMBER_BINOP(xgcd)
263     FLINTXX_DEFINE_MEMBER_BINOP(xgcd_euclidean)
264     FLINTXX_DEFINE_MEMBER_BINOP(xgcd_hgcd)
265     FLINTXX_DEFINE_MEMBER_BINOP(log_series)
266     FLINTXX_DEFINE_MEMBER_BINOP(exp_series)
267     FLINTXX_DEFINE_MEMBER_BINOP(exp_series_basecase)
268     FLINTXX_DEFINE_MEMBER_BINOP(atan_series)
269     FLINTXX_DEFINE_MEMBER_BINOP(atanh_series)
270     FLINTXX_DEFINE_MEMBER_BINOP(asin_series)
271     FLINTXX_DEFINE_MEMBER_BINOP(asinh_series)
272     FLINTXX_DEFINE_MEMBER_BINOP(sin_series)
273     FLINTXX_DEFINE_MEMBER_BINOP(cos_series)
274     FLINTXX_DEFINE_MEMBER_BINOP(tan_series)
275     FLINTXX_DEFINE_MEMBER_BINOP(sinh_series)
276     FLINTXX_DEFINE_MEMBER_BINOP(cosh_series)
277     FLINTXX_DEFINE_MEMBER_BINOP(tanh_series)
278 
279     FLINTXX_DEFINE_MEMBER_BINOP(bit_pack)
280 
281     FLINTXX_DEFINE_MEMBER_UNOP(derivative)
282     FLINTXX_DEFINE_MEMBER_UNOP(integral)
283     FLINTXX_DEFINE_MEMBER_UNOP(make_monic)
284     FLINTXX_DEFINE_MEMBER_UNOP(sqrt)
285 
286     FLINTXX_DEFINE_MEMBER_3OP(compose_mod)
287     FLINTXX_DEFINE_MEMBER_3OP(compose_mod_horner)
288     FLINTXX_DEFINE_MEMBER_3OP(compose_mod_brent_kung)
289     FLINTXX_DEFINE_MEMBER_3OP(compose_series)
290     FLINTXX_DEFINE_MEMBER_3OP(compose_series_brent_kung)
291     FLINTXX_DEFINE_MEMBER_3OP(compose_series_divconquer)
292     FLINTXX_DEFINE_MEMBER_3OP(compose_series_horner)
293     FLINTXX_DEFINE_MEMBER_3OP(div_newton_n_preinv)
294     FLINTXX_DEFINE_MEMBER_3OP(divrem_newton_n_preinv)
295     FLINTXX_DEFINE_MEMBER_3OP(div_series)
296     FLINTXX_DEFINE_MEMBER_3OP(mulhigh)
297     FLINTXX_DEFINE_MEMBER_3OP(mulhigh_classical)
298     FLINTXX_DEFINE_MEMBER_3OP(mullow)
299     FLINTXX_DEFINE_MEMBER_3OP(mullow_classical)
300     FLINTXX_DEFINE_MEMBER_3OP(mullow_KS)
301     FLINTXX_DEFINE_MEMBER_3OP(mulmod)
302     FLINTXX_DEFINE_MEMBER_3OP(powmod_binexp)
303     FLINTXX_DEFINE_MEMBER_3OP(pow_trunc)
304     FLINTXX_DEFINE_MEMBER_3OP(pow_trunc_binexp)
305 
306     FLINTXX_DEFINE_MEMBER_4OP(compose_mod_brent_kung_preinv)
307     FLINTXX_DEFINE_MEMBER_4OP(mulmod_preinv)
308     FLINTXX_DEFINE_MEMBER_4OP(powmod_binexp_preinv)
309 };
310 
311 namespace detail {
312 struct nmod_poly_data;
313 }
314 
315 typedef nmod_polyxx_expression<operations::immediate, detail::nmod_poly_data>
316            nmod_polyxx;
317 typedef nmod_polyxx_expression<operations::immediate,
318             flint_classes::ref_data<nmod_polyxx, nmod_poly_struct> >
319            nmod_polyxx_ref;
320 typedef nmod_polyxx_expression<operations::immediate,
321             flint_classes::srcref_data<
322                 nmod_polyxx, nmod_polyxx_ref, nmod_poly_struct> >
323            nmod_polyxx_srcref;
324 
325 namespace detail {
326 struct nmod_poly_data
327 {
328     nmod_poly_t inner;
329     typedef nmod_poly_t& data_ref_t;
330     typedef const nmod_poly_t& data_srcref_t;
331 
nmod_poly_datanmod_poly_data332     nmod_poly_data(mp_limb_t n) {nmod_poly_init(inner, n);}
nmod_poly_datanmod_poly_data333     nmod_poly_data(nmodxx_ctx_srcref c)
334     {
335         nmod_poly_init_preinv(inner, c.n(), c._nmod().ninv);
336     }
nmod_poly_datanmod_poly_data337     nmod_poly_data(mp_limb_t n, slong alloc) {nmod_poly_init2(inner, n, alloc);}
nmod_poly_datanmod_poly_data338     nmod_poly_data(nmodxx_ctx_srcref c, slong alloc)
339     {
340         nmod_poly_init2_preinv(inner, c.n(), c._nmod().ninv, alloc);
341     }
~nmod_poly_datanmod_poly_data342     ~nmod_poly_data() {nmod_poly_clear(inner);}
343 
nmod_poly_datanmod_poly_data344     nmod_poly_data(const nmod_poly_data& o)
345     {
346         nmod_poly_init2_preinv(inner, o.inner->mod.n,
347                 o.inner->mod.ninv, o.inner->length);
348         nmod_poly_set(inner, o.inner);
349     }
350 
nmod_poly_datanmod_poly_data351     nmod_poly_data(nmod_polyxx_srcref r)
352     {
353         nmod_poly_init2_preinv(inner, r.modulus(),
354                 r._poly()->mod.ninv, r.length());
355         nmod_poly_set(inner, r._poly());
356     }
357 
nmod_poly_datanmod_poly_data358     nmod_poly_data(const char* str)
359     {
360         mp_limb_t n;slong length;
361         execution_check(flint_sscanf(str, "%wd %wu", &length, &n) == 2
362             && (nmod_poly_init2(inner, n, length), nmod_poly_set_str(inner, str)),
363                 "construct from string", "nmod_polyxx");
364     }
365 
366     template<class Nmod>
367     static nmod_poly_data from_ground(const Nmod& x,
368             typename mp::enable_if<traits::is_nmodxx<Nmod> >::type* = 0)
369     {
370         nmod_poly_data res(x.estimate_ctx());
371         nmod_poly_set_coeff_ui(res.inner, 0, x.template to<mp_limb_t>());
372         return res;
373     }
from_groundnmod_poly_data374     static nmod_poly_data from_ground(mp_limb_t x, nmodxx_ctx_srcref c)
375     {
376         nmod_poly_data res(c);
377         nmod_poly_set_coeff_ui(res.inner, 0, x);
378         return res;
379     }
380 
381     // TODO maybe make these lazy
382     template<class Fmpz_poly>
383     static nmod_poly_data reduce(const Fmpz_poly& p, nmodxx_ctx_srcref c,
384             typename mp::enable_if<traits::is_fmpz_polyxx<Fmpz_poly> >::type* = 0)
385     {
386         nmod_poly_data res(c);
387         fmpz_poly_get_nmod_poly(res.inner, p.evaluate()._poly());
388         return res;
389     }
390     template<class Fmpz_poly>
391     static nmod_poly_data reduce(const Fmpz_poly& p, mp_limb_t m,
392             typename mp::enable_if<traits::is_fmpz_polyxx<Fmpz_poly> >::type* = 0)
393     {
394         nmod_poly_data res(m);
395         fmpz_poly_get_nmod_poly(res.inner, p.evaluate()._poly());
396         return res;
397     }
398 
399     template<class Fmpq_poly>
400     static nmod_poly_data reduce_(const Fmpq_poly& p, nmodxx_ctx_srcref c,
401             typename mp::enable_if<traits::is_fmpq_polyxx<Fmpq_poly> >::type* = 0)
402     {
403         nmod_poly_data res(c, p.length());
404         for(slong i = 0;i < p.length();++i)
405             nmod_poly_set_coeff_ui(res. inner, i,
406                     nmodxx::red(p.get_coeff(i), c).template to<mp_limb_t>());
407         return res;
408     }
409     template<class Fmpq_poly>
410     static nmod_poly_data reduce(const Fmpq_poly& p, nmodxx_ctx_srcref c,
411             typename mp::enable_if<traits::is_fmpq_polyxx<Fmpq_poly> >::type* = 0)
412     {
413         return reduce_(p.evaluate(), c);
414     }
415     template<class Fmpq_poly>
416     static nmod_poly_data reduce(const Fmpq_poly& p, mp_limb_t m,
417             typename mp::enable_if<traits::is_fmpq_polyxx<Fmpq_poly> >::type* = 0)
418     {
419         return reduce_(p.evaluate(), nmodxx_ctx(m));
420     }
421 };
422 } // detail
423 namespace traits {
424 template<> struct has_nmodxx_ctx<nmod_polyxx> : mp::true_ { };
425 template<> struct has_nmodxx_ctx<nmod_polyxx_ref> : mp::true_ { };
426 template<> struct has_nmodxx_ctx<nmod_polyxx_srcref> : mp::true_ { };
427 
428 template<class T> struct is_nmod_polyxx : mp::or_<
429      traits::is_T_expr<T, nmod_polyxx>,
430      flint_classes::is_source<nmod_polyxx, T> > { };
431 } // traits
432 template<class Operation, class Data>
433 inline nmodxx_ctx_srcref
434 nmod_polyxx_expression<Operation, Data>::estimate_ctx() const
435 {
436     return tools::find_nmodxx_ctx(*this);
437 }
438 
439 namespace rules {
440 #define NMOD_POLYXX_COND_S FLINTXX_COND_S(nmod_polyxx)
441 #define NMOD_POLYXX_COND_T FLINTXX_COND_T(nmod_polyxx)
442 
443 NMODXX_DEFINE_INSTANTIATE_TEMPORARIES(nmod_polyxx)
444 
445 FLINT_DEFINE_DOIT_COND2(assignment, NMOD_POLYXX_COND_T, NMOD_POLYXX_COND_S,
446         nmod_poly_set(to._poly(), from._poly()))
447 
448 FLINTXX_DEFINE_ASSIGN_STR(nmod_polyxx, execution_check(
449             nmod_poly_set_str(to._poly(), from), "assign string", "nmod_polyxx"))
450 
451 FLINT_DEFINE_PRINT_COND(NMOD_POLYXX_COND_S, nmod_poly_fprint(to, from._poly()))
452 FLINT_DEFINE_READ_COND(NMOD_POLYXX_COND_T, nmod_poly_fread(from, to._poly()))
453 
454 FLINTXX_DEFINE_EQUALS(nmod_polyxx, nmod_poly_equal(e1._poly(), e2._poly()))
455 FLINTXX_DEFINE_TO_STR(nmod_polyxx, nmod_poly_get_str(from._poly()))
456 FLINTXX_DEFINE_SWAP(nmod_polyxx, nmod_poly_swap(e1._poly(), e2._poly()))
457 
458 FLINT_DEFINE_BINARY_EXPR_COND2(nmod_polyxx_get_coeff_op, nmodxx,
459         NMOD_POLYXX_COND_S, traits::fits_into_slong,
460         to.set_nored(nmod_poly_get_coeff_ui(e1._poly(), e2)))
461 
462 FLINT_DEFINE_BINARY_EXPR_COND2(plus, nmod_polyxx,
463         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
464         nmod_poly_add(to._poly(), e1._poly(), e2._poly()))
465 FLINT_DEFINE_BINARY_EXPR_COND2(minus, nmod_polyxx,
466         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
467         nmod_poly_sub(to._poly(), e1._poly(), e2._poly()))
468 
469 FLINT_DEFINE_UNARY_EXPR_COND(negate, nmod_polyxx, NMOD_POLYXX_COND_S,
470         nmod_poly_neg(to._poly(), from._poly()))
471 
472 FLINT_DEFINE_BINARY_EXPR_COND2(reverse_op, nmod_polyxx,
473         NMOD_POLYXX_COND_S, traits::fits_into_slong,
474         nmod_poly_reverse(to._poly(), e1._poly(), e2))
475 
476 FLINT_DEFINE_BINARY_EXPR_COND2(shift_left_op, nmod_polyxx,
477         NMOD_POLYXX_COND_S, traits::fits_into_slong,
478         nmod_poly_shift_left(to._poly(), e1._poly(), e2))
479 FLINT_DEFINE_BINARY_EXPR_COND2(shift_right_op, nmod_polyxx,
480         NMOD_POLYXX_COND_S, traits::fits_into_slong,
481         nmod_poly_shift_right(to._poly(), e1._poly(), e2))
482 
483 FLINT_DEFINE_CBINARY_EXPR_COND2(times, nmod_polyxx,
484         NMOD_POLYXX_COND_S, NMODXX_COND_S,
485         nmod_poly_scalar_mul_nmod(to._poly(), e1._poly(), e2._limb()))
486 FLINT_DEFINE_UNARY_EXPR_COND(make_monic_op, nmod_polyxx, NMOD_POLYXX_COND_S,
487         nmod_poly_make_monic(to._poly(), from._poly()))
488 
489 FLINT_DEFINE_BINARY_EXPR_COND2(bit_pack_op, fmpzxx,
490         NMOD_POLYXX_COND_S, traits::fits_into_flint_bitcnt_t,
491         nmod_poly_bit_pack(to._fmpz(), e1._poly(), e2))
492 
493 FLINT_DEFINE_BINARY_EXPR_COND2(times, nmod_polyxx,
494         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
495         nmod_poly_mul(to._poly(), e1._poly(), e2._poly()))
496 FLINT_DEFINE_BINARY_EXPR_COND2(mul_classical_op, nmod_polyxx,
497         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
498         nmod_poly_mul_classical(to._poly(), e1._poly(), e2._poly()))
499 FLINT_DEFINE_BINARY_EXPR_COND2(mul_KS_op, nmod_polyxx,
500         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
501         nmod_poly_mul_KS(to._poly(), e1._poly(), e2._poly(), 0 /* TODO */))
502 
503 #define NMOD_POLYXX_DEFINE_MULFUNC(name) \
504 FLINT_DEFINE_THREEARY_EXPR_COND3(name##_op, nmod_polyxx, \
505     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, traits::fits_into_slong, \
506     nmod_poly_##name(to._poly(), e1._poly(), e2._poly(), e3))
507 NMOD_POLYXX_DEFINE_MULFUNC(mullow_classical)
508 NMOD_POLYXX_DEFINE_MULFUNC(mullow)
509 NMOD_POLYXX_DEFINE_MULFUNC(mulhigh_classical)
510 NMOD_POLYXX_DEFINE_MULFUNC(mulhigh)
511 
512 FLINT_DEFINE_THREEARY_EXPR_COND3(mullow_KS_op, nmod_polyxx,
513     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, traits::fits_into_slong,
514     nmod_poly_mullow_KS(to._poly(), e1._poly(), e2._poly(), 0 /* TODO */, e3))
515 
516 FLINT_DEFINE_THREEARY_EXPR_COND3(mulmod_op, nmod_polyxx,
517     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
518     nmod_poly_mulmod(to._poly(), e1._poly(), e2._poly(), e3._poly()))
519 
520 FLINT_DEFINE_FOURARY_EXPR_COND4(mulmod_preinv_op, nmod_polyxx,
521     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
522     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
523     nmod_poly_mulmod_preinv(to._poly(), e1._poly(), e2._poly(),
524         e3._poly(), e4._poly()))
525 
526 FLINT_DEFINE_BINARY_EXPR_COND2(pow_binexp_op, nmod_polyxx,
527         NMOD_POLYXX_COND_S, traits::is_unsigned_integer,
528         nmod_poly_pow_binexp(to._poly(), e1._poly(), e2))
529 FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, nmod_polyxx,
530         NMOD_POLYXX_COND_S, traits::is_unsigned_integer,
531         nmod_poly_pow(to._poly(), e1._poly(), e2))
532 
533 FLINT_DEFINE_THREEARY_EXPR_COND3(powmod_binexp_op, nmod_polyxx,
534     NMOD_POLYXX_COND_S, traits::is_unsigned_integer, NMOD_POLYXX_COND_S,
535     nmod_poly_powmod_ui_binexp(to._poly(), e1._poly(), e2, e3._poly()))
536 
537 FLINT_DEFINE_FOURARY_EXPR_COND4(powmod_binexp_preinv_op, nmod_polyxx,
538     NMOD_POLYXX_COND_S, traits::is_unsigned_integer,
539     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
540     nmod_poly_powmod_ui_binexp_preinv(to._poly(), e1._poly(), e2,
541         e3._poly(), e4._poly()))
542 
543 FLINT_DEFINE_THREEARY_EXPR_COND3(pow_trunc_op, nmod_polyxx,
544     NMOD_POLYXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
545     nmod_poly_pow_trunc(to._poly(), e1._poly(), e2, e3))
546 FLINT_DEFINE_THREEARY_EXPR_COND3(pow_trunc_binexp_op, nmod_polyxx,
547     NMOD_POLYXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
548     nmod_poly_pow_trunc_binexp(to._poly(), e1._poly(), e2, e3))
549 
550 FLINT_DEFINE_UNARY_EXPR_COND(derivative_op, nmod_polyxx, NMOD_POLYXX_COND_S,
551         nmod_poly_derivative(to._poly(), from._poly()))
552 FLINT_DEFINE_UNARY_EXPR_COND(integral_op, nmod_polyxx, NMOD_POLYXX_COND_S,
553         nmod_poly_integral(to._poly(), from._poly()))
554 
555 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_op, nmodxx,
556         NMOD_POLYXX_COND_S, NMODXX_COND_S,
557         to.set_nored(nmod_poly_evaluate_nmod(e1._poly(), e2._limb())))
558 
559 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_op, nmod_vecxx,
560         NMOD_POLYXX_COND_S, NMOD_VECXX_COND_S,
561         nmod_poly_evaluate_nmod_vec(to._array(), e1._poly(), e2._array(),
562             to.size()))
563 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_fast_op, nmod_vecxx,
564         NMOD_POLYXX_COND_S, NMOD_VECXX_COND_S,
565         nmod_poly_evaluate_nmod_vec_fast(to._array(), e1._poly(), e2._array(),
566             to.size()))
567 FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_iter_op, nmod_vecxx,
568         NMOD_POLYXX_COND_S, NMOD_VECXX_COND_S,
569         nmod_poly_evaluate_nmod_vec_iter(to._array(), e1._poly(), e2._array(),
570             to.size()))
571 
572 namespace rdetail {
573 typedef make_ltuple<mp::make_tuple<nmod_polyxx, nmod_polyxx>::type>::type
574     nmod_polyxx_pair;
575 } // rdetail
576 #define NMOD_POLYXX_DEFINE_DIVREM(name) \
577 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, rdetail::nmod_polyxx_pair, \
578     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, \
579     nmod_poly_##name(to.template get<0>()._poly(), to.template get<1>()._poly(), \
580         e1._poly(), e2._poly()))
581 NMOD_POLYXX_DEFINE_DIVREM(divrem_basecase)
582 NMOD_POLYXX_DEFINE_DIVREM(divrem_divconquer)
583 NMOD_POLYXX_DEFINE_DIVREM(divrem_newton)
584 NMOD_POLYXX_DEFINE_DIVREM(divrem)
585 
586 FLINT_DEFINE_BINARY_EXPR_COND2(div_basecase_op, nmod_polyxx,
587         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
588         nmod_poly_div_basecase(to._poly(), e1._poly(), e2._poly()))
589 FLINT_DEFINE_BINARY_EXPR_COND2(div_divconquer_op, nmod_polyxx,
590         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
591         nmod_poly_div_divconquer(to._poly(), e1._poly(), e2._poly()))
592 FLINT_DEFINE_BINARY_EXPR_COND2(div_newton_op, nmod_polyxx,
593         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
594         nmod_poly_div_newton(to._poly(), e1._poly(), e2._poly()))
595 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, nmod_polyxx,
596         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
597         nmod_poly_div_divconquer(to._poly(), e1._poly(), e2._poly()))
598 
599 FLINT_DEFINE_THREEARY_EXPR_COND3(div_newton_n_preinv_op, nmod_polyxx,
600         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
601         nmod_poly_div_newton_n_preinv(to._poly(),
602             e1._poly(), e2._poly(), e3._poly()))
603 FLINT_DEFINE_THREEARY_EXPR_COND3(divrem_newton_n_preinv_op,
604         rdetail::nmod_polyxx_pair,
605         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
606         nmod_poly_divrem_newton_n_preinv(to.template get<0>()._poly(),
607             to.template get<1>()._poly(), e1._poly(), e2._poly(), e3._poly()))
608 
609 FLINT_DEFINE_BINARY_EXPR_COND2(rem_basecase_op, nmod_polyxx,
610         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
611         nmod_poly_rem_basecase(to._poly(), e1._poly(), e2._poly()))
612 FLINT_DEFINE_BINARY_EXPR_COND2(modulo, nmod_polyxx,
613         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
614         nmod_poly_rem(to._poly(), e1._poly(), e2._poly()))
615 
616 FLINT_DEFINE_BINARY_EXPR_COND2(inv_series_newton_op, nmod_polyxx,
617         NMOD_POLYXX_COND_S, traits::fits_into_slong,
618         nmod_poly_inv_series_newton(to._poly(), e1._poly(), e2))
619 FLINT_DEFINE_BINARY_EXPR_COND2(inv_series_op, nmod_polyxx,
620         NMOD_POLYXX_COND_S, traits::fits_into_slong,
621         nmod_poly_inv_series(to._poly(), e1._poly(), e2))
622 FLINT_DEFINE_BINARY_EXPR_COND2(inv_series_basecase_op, nmod_polyxx,
623         NMOD_POLYXX_COND_S, traits::fits_into_slong,
624         nmod_poly_inv_series_basecase(to._poly(), e1._poly(), e2))
625 
626 #define NMOD_POLYXX_DEFINE_SERIES(name) \
627 FLINT_DEFINE_THREEARY_EXPR_COND3(name##_op, nmod_polyxx, \
628     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, traits::fits_into_slong, \
629     nmod_poly_##name(to._poly(), e1._poly(), e2._poly(), e3))
630 NMOD_POLYXX_DEFINE_SERIES(div_series)
631 
632 FLINT_DEFINE_BINARY_EXPR_COND2(compose_op, nmod_polyxx,
633         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
634         nmod_poly_compose(to._poly(), e1._poly(), e2._poly()))
635 FLINT_DEFINE_BINARY_EXPR_COND2(compose_divconquer_op, nmod_polyxx,
636         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
637         nmod_poly_compose_divconquer(to._poly(), e1._poly(), e2._poly()))
638 FLINT_DEFINE_BINARY_EXPR_COND2(compose_horner_op, nmod_polyxx,
639         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
640         nmod_poly_compose_horner(to._poly(), e1._poly(), e2._poly()))
641 
642 FLINT_DEFINE_BINARY_EXPR_COND2(div_root_op, nmod_polyxx,
643         NMOD_POLYXX_COND_S, NMODXX_COND_S,
644         nmod_poly_div_root(to._poly(), e1._poly(), e2._limb()))
645 
646 FLINT_DEFINE_BINARY_EXPR_COND2(nmod_polyxx_interpolate_op, nmod_polyxx,
647         NMOD_VECXX_COND_S, NMOD_VECXX_COND_S,
648         nmod_poly_interpolate_nmod_vec(to._poly(), e1._data().array,
649             e2._data().array, e2.size()))
650 FLINT_DEFINE_BINARY_EXPR_COND2(nmod_polyxx_interpolate_fast_op, nmod_polyxx,
651         NMOD_VECXX_COND_S, NMOD_VECXX_COND_S,
652         nmod_poly_interpolate_nmod_vec_fast(to._poly(), e1._data().array,
653             e2._data().array, e2.size()))
654 FLINT_DEFINE_BINARY_EXPR_COND2(nmod_polyxx_interpolate_newton_op, nmod_polyxx,
655         NMOD_VECXX_COND_S, NMOD_VECXX_COND_S,
656         nmod_poly_interpolate_nmod_vec_newton(to._poly(), e1._data().array,
657             e2._data().array, e2.size()))
658 FLINT_DEFINE_BINARY_EXPR_COND2(nmod_polyxx_interpolate_barycentric_op, nmod_polyxx,
659         NMOD_VECXX_COND_S, NMOD_VECXX_COND_S,
660         nmod_poly_interpolate_nmod_vec_barycentric(to._poly(), e1._data().array,
661             e2._data().array, e2.size()))
662 
663 FLINT_DEFINE_BINARY_EXPR_COND2(taylor_shift_horner_op, nmod_polyxx,
664         NMOD_POLYXX_COND_S, NMODXX_COND_S,
665         nmod_poly_taylor_shift_horner(to._poly(), e1._poly(), e2._limb()))
666 FLINT_DEFINE_BINARY_EXPR_COND2(taylor_shift_convolution_op, nmod_polyxx,
667         NMOD_POLYXX_COND_S, NMODXX_COND_S,
668         nmod_poly_taylor_shift_convolution(to._poly(), e1._poly(), e2._limb()))
669 FLINT_DEFINE_BINARY_EXPR_COND2(taylor_shift_op, nmod_polyxx,
670         NMOD_POLYXX_COND_S, NMODXX_COND_S,
671         nmod_poly_taylor_shift(to._poly(), e1._poly(), e2._limb()))
672 
673 FLINT_DEFINE_THREEARY_EXPR_COND3(compose_mod_op, nmod_polyxx,
674         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
675         nmod_poly_compose_mod(to._poly(), e1._poly(), e2._poly(), e3._poly()))
676 FLINT_DEFINE_THREEARY_EXPR_COND3(compose_mod_horner_op, nmod_polyxx,
677         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
678         nmod_poly_compose_mod_horner(
679             to._poly(), e1._poly(), e2._poly(), e3._poly()))
680 FLINT_DEFINE_THREEARY_EXPR_COND3(compose_mod_brent_kung_op, nmod_polyxx,
681         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
682         nmod_poly_compose_mod_brent_kung(
683             to._poly(), e1._poly(), e2._poly(), e3._poly()))
684 FLINT_DEFINE_FOURARY_EXPR_COND4(compose_mod_brent_kung_preinv_op, nmod_polyxx,
685         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
686         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
687         nmod_poly_compose_mod_brent_kung_preinv(
688             to._poly(), e1._poly(), e2._poly(), e3._poly(), e4._poly()))
689 
690 FLINT_DEFINE_BINARY_EXPR_COND2(gcd_op, nmod_polyxx,
691         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
692         nmod_poly_gcd(to._poly(), e1._poly(), e2._poly()))
693 FLINT_DEFINE_BINARY_EXPR_COND2(gcd_hgcd_op, nmod_polyxx,
694         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
695         nmod_poly_gcd_hgcd(to._poly(), e1._poly(), e2._poly()))
696 FLINT_DEFINE_BINARY_EXPR_COND2(gcd_euclidean_op, nmod_polyxx,
697         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
698         nmod_poly_gcd_euclidean(to._poly(), e1._poly(), e2._poly()))
699 
700 namespace rdetail {
701 typedef make_ltuple<mp::make_tuple<nmod_polyxx, nmod_polyxx, nmod_polyxx>::type>::type
702     nmod_polyxx_triple;
703 } // rdetail
704 FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_op, rdetail::nmod_polyxx_triple,
705     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
706     nmod_poly_xgcd(to.template get<0>()._poly(), to.template get<1>()._poly(),
707         to.template get<2>()._poly(), e1._poly(), e2._poly()))
708 FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_hgcd_op, rdetail::nmod_polyxx_triple,
709     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
710     nmod_poly_xgcd_hgcd(to.template get<0>()._poly(),
711         to.template get<1>()._poly(),
712         to.template get<2>()._poly(), e1._poly(), e2._poly()))
713 FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_euclidean_op, rdetail::nmod_polyxx_triple,
714     NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
715     nmod_poly_xgcd_euclidean(to.template get<0>()._poly(),
716         to.template get<1>()._poly(),
717         to.template get<2>()._poly(), e1._poly(), e2._poly()))
718 
719 FLINT_DEFINE_BINARY_EXPR_COND2(resultant_op, nmodxx,
720         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
721         to.set_nored(nmod_poly_resultant(e1._poly(), e2._poly())))
722 FLINT_DEFINE_BINARY_EXPR_COND2(resultant_euclidean_op, nmodxx,
723         NMOD_POLYXX_COND_S, NMOD_POLYXX_COND_S,
724         to.set_nored(nmod_poly_resultant_euclidean(e1._poly(), e2._poly())))
725 
726 NMOD_POLYXX_DEFINE_SERIES(compose_series)
727 NMOD_POLYXX_DEFINE_SERIES(compose_series_horner)
728 NMOD_POLYXX_DEFINE_SERIES(compose_series_brent_kung)
729 NMOD_POLYXX_DEFINE_SERIES(compose_series_divconquer)
730 
731 #define NMOD_POLYXX_DEFINE_SERIESUN(name) \
732 FLINT_DEFINE_BINARY_EXPR_COND2(name##_op, nmod_polyxx, \
733         NMOD_POLYXX_COND_S, traits::fits_into_slong, \
734         nmod_poly_##name(to._poly(), e1._poly(), e2))
735 NMOD_POLYXX_DEFINE_SERIESUN(revert_series)
736 NMOD_POLYXX_DEFINE_SERIESUN(revert_series_newton)
737 NMOD_POLYXX_DEFINE_SERIESUN(revert_series_lagrange_fast)
738 NMOD_POLYXX_DEFINE_SERIESUN(revert_series_lagrange)
739 
740 #define NMOD_POLYXX_DEFINE_SERIES_F(name) \
741 FLINT_DEFINE_BINARY_EXPR_COND2(name##_series_op, nmod_polyxx, \
742         NMOD_POLYXX_COND_S, traits::fits_into_slong, \
743         nmod_poly_##name##_series(to._poly(), e1._poly(), e2))
744 NMOD_POLYXX_DEFINE_SERIES_F(sqrt)
745 NMOD_POLYXX_DEFINE_SERIES_F(invsqrt)
746 NMOD_POLYXX_DEFINE_SERIES_F(log)
747 NMOD_POLYXX_DEFINE_SERIES_F(exp)
748 NMOD_POLYXX_DEFINE_SERIES_F(atan)
749 NMOD_POLYXX_DEFINE_SERIES_F(atanh)
750 NMOD_POLYXX_DEFINE_SERIES_F(asin)
751 NMOD_POLYXX_DEFINE_SERIES_F(asinh)
752 NMOD_POLYXX_DEFINE_SERIES_F(sin)
753 NMOD_POLYXX_DEFINE_SERIES_F(cos)
754 NMOD_POLYXX_DEFINE_SERIES_F(tan)
755 NMOD_POLYXX_DEFINE_SERIES_F(sinh)
756 NMOD_POLYXX_DEFINE_SERIES_F(cosh)
757 NMOD_POLYXX_DEFINE_SERIES_F(tanh)
758 
759 FLINT_DEFINE_BINARY_EXPR_COND2(exp_series_basecase_op, nmod_polyxx,
760         NMOD_POLYXX_COND_S, traits::fits_into_slong,
761         nmod_poly_exp_series_basecase(to._poly(), e1._poly(), e2))
762 
763 FLINT_DEFINE_THREEARY_EXPR_COND3(log_series_monomial_op, nmod_polyxx,
764         NMODXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
765         nmod_poly_log_series_monomial_ui(to._poly(), e1._limb(), e2, e3))
766 FLINT_DEFINE_THREEARY_EXPR_COND3(exp_series_monomial_op, nmod_polyxx,
767         NMODXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
768         nmod_poly_exp_series_monomial_ui(to._poly(), e1._limb(), e2, e3))
769 
770 FLINT_DEFINE_UNARY_EXPR_COND(sqrt_op, nmod_polyxx, NMOD_POLYXX_COND_S,
771         execution_check(nmod_poly_sqrt(to._poly(), from._poly()),
772             "sqrt", "nmod_polyxx"))
773 
774 FLINT_DEFINE_UNARY_EXPR_COND(nmod_polyxx_product_roots_op, nmod_polyxx,
775         NMOD_VECXX_COND_S,
776         nmod_poly_product_roots_nmod_vec(to._poly(),
777             from._data().array, from.size()))
778 
779 FLINT_DEFINE_BINARY_EXPR_COND2(deflate_op, nmod_polyxx,
780         NMOD_POLYXX_COND_S, traits::is_unsigned_integer,
781         nmod_poly_deflate(to._poly(), e1._poly(), e2))
782 FLINT_DEFINE_BINARY_EXPR_COND2(inflate_op, nmod_polyxx,
783         NMOD_POLYXX_COND_S, traits::is_unsigned_integer,
784         nmod_poly_inflate(to._poly(), e1._poly(), e2))
785 } // rules
786 
787 
788 //////////////////////////////////////////////////////////////////////////////
789 // FACTORISATION
790 //////////////////////////////////////////////////////////////////////////////
791 
792 class nmod_poly_factorxx
793 {
794 private:
795     nmod_poly_factor_t inner;
796 
797 public:
798     nmod_poly_factorxx() {nmod_poly_factor_init(inner);}
799     ~nmod_poly_factorxx() {nmod_poly_factor_clear(inner);}
800 
801     nmod_poly_factorxx(const nmod_poly_factorxx& o)
802     {
803         nmod_poly_factor_init(inner);
804         nmod_poly_factor_set(inner, o.inner);
805     }
806 
807     bool operator==(const nmod_poly_factorxx& o)
808     {
809         if(o.size() != size())
810             return false;
811         for(slong i = 0;i < size();++i)
812             if(p(i) != o.p(i) || exp(i) != o.exp(i))
813             return false;
814         return true;
815     }
816 
817     nmod_poly_factorxx& operator=(const nmod_poly_factorxx& o)
818     {
819         nmod_poly_factor_set(inner, o.inner);
820         return *this;
821     }
822 
823     slong size() const {return inner->num;}
824     slong exp(slong i) const {return inner->exp[i];}
825     slong& exp(slong i) {return inner->exp[i];}
826     nmod_polyxx_srcref p(slong i) const
827         {return nmod_polyxx_srcref::make(inner->p + i);}
828     nmod_polyxx_ref p(slong i) {return nmod_polyxx_ref::make(inner->p + i);}
829 
830     nmod_poly_factor_t& _data() {return inner;}
831     const nmod_poly_factor_t& _data() const {return inner;}
832 
833     void realloc(slong a) {nmod_poly_factor_realloc(inner, a);}
834     void fit_length(slong a) {nmod_poly_factor_fit_length(inner, a);}
835 
836     void print() const {nmod_poly_factor_print(inner);}
837 
838     template<class Nmod_poly>
839     void insert(const Nmod_poly& p, slong e,
840             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0)
841         {nmod_poly_factor_insert(_data(), p.evaluate()._poly(), e);}
842 
843     void concat(const nmod_poly_factorxx& o)
844         {nmod_poly_factor_concat(_data(), o._data());}
845 
846     void pow(slong exp) {nmod_poly_factor_pow(_data(), exp);}
847 
848 #define NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(name) \
849     template<class Nmod_poly> \
850     void set_##name(const Nmod_poly& p, \
851             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0) \
852         {nmod_poly_##name(_data(), p.evaluate()._poly());}
853 
854     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor)
855     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_squarefree)
856     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_cantor_zassenhaus)
857     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_berlekamp)
858     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_kaltofen_shoup)
859     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_with_cantor_zassenhaus)
860     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_with_berlekamp)
861     NMOD_POLY_FACTORXX_DEFINE_SET_FACTOR(factor_with_kaltofen_shoup)
862 
863     template<class Nmod_poly>
864     bool set_factor_equal_deg_probab(frandxx& state, const Nmod_poly& p, slong d,
865             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0)
866     {
867         return nmod_poly_factor_equal_deg_prob(_data(), state._data(),
868                 p.evaluate()._poly(), d);
869     }
870     template<class Nmod_poly>
871     void set_factor_equal_deg(const Nmod_poly& p, slong d,
872             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0)
873     {
874         nmod_poly_factor_equal_deg(_data(), p.evaluate()._poly(), d);
875     }
876 
877     template<class Nmod_poly>
878     void set_factor_distinct_deg(const Nmod_poly& p, std::vector<slong>& degs,
879             typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0)
880     {
881         slong* dgs = &degs.front();
882         nmod_poly_factor_distinct_deg(_data(), p.evaluate()._poly(), &dgs);
883     }
884 };
885 
886 #define NMOD_POLY_FACTORXX_DEFINE_FACTOR(name) \
887 template<class Nmod_poly> \
888 nmod_poly_factorxx name(const Nmod_poly& p, \
889         typename mp::enable_if<traits::is_nmod_polyxx<Nmod_poly> >::type* = 0) \
890 { \
891     nmod_poly_factorxx res; \
892     res.set_##name(p); \
893     return res; \
894 }
895 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor)
896 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_squarefree)
897 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_cantor_zassenhaus)
898 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_berlekamp)
899 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_kaltofen_shoup)
900 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_with_cantor_zassenhaus)
901 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_with_berlekamp)
902 NMOD_POLY_FACTORXX_DEFINE_FACTOR(factor_with_kaltofen_shoup)
903 
904 // TODO do we want global versions of factor_distinct_deg etc?
905 
906 inline void print(const nmod_poly_factorxx& f)
907 {
908     f.print();
909 }
910 
911 
912 // CRT stuff
913 // Here for circular dependency reasons
914 namespace rules {
915 FLINT_DEFINE_FOURARY_EXPR_COND4(CRT_op, fmpz_polyxx,
916         FMPZ_POLYXX_COND_T, FMPZXX_COND_S, NMOD_POLYXX_COND_S, tools::is_bool,
917         fmpz_poly_CRT_ui(to._poly(), e1._poly(), e2._fmpz(), e3._poly(), e4))
918 } // rules
919 } // flint
920 
921 #endif
922