/*
Copyright (C) 2013 Tom Bachmann
Copyright (C) 2020 Daniel Schultz
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#ifndef FMPZ_MOD_POLYXX_H
#define FMPZ_MOD_POLYXX_H
#include "fmpz_mod_poly.h"
#include "fmpzxx.h"
#include "fmpz_polyxx.h"
#include "nmod_polyxx.h"
#include "flintxx/expression.h"
#include "flintxx/flint_classes.h"
#include "flintxx/flint_exception.h"
#include "flintxx/frandxx.h"
#include "flintxx/ltuple.h"
#include "flintxx/stdmath.h"
#include "flintxx/vector.h"
namespace flint {
///////////////////////////////////////////////////////////////////////////////
// fmpz_mod_ctx_struct wrappers
///////////////////////////////////////////////////////////////////////////////
class fmpz_modxx_ctx
{
private:
mutable fmpz_mod_ctx_t ctx;
public:
fmpz_mod_ctx_t& _ctx() const {return ctx;}
fmpzxx_ref modulus() {return fmpzxx_ref::make(ctx->n);}
fmpzxx_srcref modulus() const {return fmpzxx_srcref::make(ctx->n);}
fmpz_modxx_ctx(fmpzxx_srcref p)
{
fmpz_mod_ctx_init(ctx, p._fmpz());
}
fmpz_modxx_ctx(ulong p)
{
fmpz_mod_ctx_init_ui(ctx, p);
}
~fmpz_modxx_ctx() {fmpz_mod_ctx_clear(ctx);}
void set_modulus(fmpzxx_srcref p)
{
fmpz_mod_ctx_set_modulus(ctx, p._fmpz());
}
void set_modulus(ulong p)
{
fmpz_mod_ctx_set_modulus_ui(ctx, p);
}
};
class fmpz_modxx_ctx_srcref
{
private:
mutable fmpz_mod_ctx_struct* ctx;
fmpz_modxx_ctx_srcref(fmpz_mod_ctx_struct* c) : ctx(c) {}
public:
fmpz_mod_ctx_struct* _ctx() const {return ctx;}
fmpzxx_ref modulus() {return fmpzxx_ref::make(ctx->n);}
fmpzxx_srcref modulus() const {return fmpzxx_srcref::make(ctx->n);}
fmpz_modxx_ctx_srcref(fmpz_modxx_ctx& c)
: ctx(c._ctx()) {}
fmpz_modxx_ctx_srcref(const fmpz_modxx_ctx& c)
: ctx(c._ctx()) {}
static fmpz_modxx_ctx_srcref make(fmpz_mod_ctx_struct* c)
{return fmpz_modxx_ctx_srcref(c);}
};
namespace traits {
template struct has_fmpz_modxx_ctx : mp::false_ { };
template struct is_fmpz_mod_expr
: has_fmpz_modxx_ctx::type> { };
} // traits
namespace detail {
struct has_fmpz_modxx_ctx_predicate
{
template struct type : traits::has_fmpz_modxx_ctx { };
};
} // detail
namespace tools {
template
fmpz_modxx_ctx_srcref find_fmpz_modxx_ctx(const Expr& e)
{
return tools::find_subexpr(e).get_ctx();
}
} // tools
namespace detail {
template
struct fakemodtemplate : mp::enable_if > { };
} // detail
///////////////////////////////////////////////////////////////////////////////
// fmpz_mod_poly_struct wrappers
///////////////////////////////////////////////////////////////////////////////
FLINT_DEFINE_BINOP(divrem_f)
FLINT_DEFINE_BINOP(gcd_euclidean_f)
FLINT_DEFINE_BINOP(gcd_f)
FLINT_DEFINE_BINOP(radix)
FLINT_DEFINE_UNOP(fmpz_mod_polyxx_lead) // TODO standardise?
FLINT_DEFINE_BINOP(fmpz_mod_polyxx_get_coeff) // TODO standardise?
namespace detail {
template
struct fmpz_mod_poly_traits
{
typedef FLINT_UNOP_BUILD_RETTYPE(
fmpz_mod_polyxx_lead, fmpzxx, Poly) lead_ref_t;
typedef lead_ref_t lead_srcref_t;
static lead_ref_t lead(const Poly& p) {return fmpz_mod_polyxx_lead(p);}
};
} //detail
template
class fmpz_mod_polyxx_expression
: public expression,
Operation, Data>
{
public:
typedef expression,
Operation, Data> base_t;
typedef detail::fmpz_mod_poly_traits
poly_traits_t;
FLINTXX_DEFINE_BASICS(fmpz_mod_polyxx_expression)
FLINTXX_DEFINE_CTORS(fmpz_mod_polyxx_expression)
FLINTXX_DEFINE_C_REF(fmpz_mod_polyxx_expression, fmpz_mod_poly_struct, _poly)
public:
fmpz_modxx_ctx_srcref get_ctx() const {return this->_data().ctx;}
fmpz_mod_ctx_struct* _ctx() const {return get_ctx()._ctx();}
fmpz_modxx_ctx_srcref estimate_ctx() const {
return tools::find_fmpz_modxx_ctx(*this);}
static fmpz_mod_polyxx_expression zero(fmpz_modxx_ctx_srcref ctx)
{
return fmpz_mod_polyxx_expression(ctx);
}
static fmpz_mod_polyxx_expression one(fmpz_modxx_ctx_srcref ctx)
{
fmpz_mod_polyxx_expression res(ctx);
res.set_one();
return res;
}
// Create a temporary. The context will be estimated.
evaluated_t create_temporary() const
{
return evaluated_t(estimate_ctx());
}
static fmpz_mod_polyxx_expression randtest(
fmpz_modxx_ctx_srcref ctx, frandxx& state, slong len)
{
fmpz_mod_polyxx_expression res(ctx);
fmpz_mod_poly_randtest(res._poly(), state._data(), len, ctx._ctx());
return res;
}
static fmpz_mod_polyxx_expression randtest_irreducible(
fmpz_modxx_ctx_srcref ctx, frandxx& state, slong len)
{
fmpz_mod_polyxx_expression res(ctx);
fmpz_mod_poly_randtest_irreducible(res._poly(), state._data(), len, ctx._ctx());
return res;
}
static fmpz_mod_polyxx_expression randtest_not_zero(
fmpz_modxx_ctx_srcref ctx, frandxx& state, slong len)
{
fmpz_mod_polyxx_expression res(ctx);
fmpz_mod_poly_randtest_not_zero(res._poly(), state._data(), len, ctx._ctx());
return res;
}
// These only make sense with immediates
fmpzxx_srcref modulus() const {return get_ctx().modulus();}
// These only make sense with target immediates
void realloc(slong alloc) {fmpz_mod_poly_realloc(_poly(), alloc, _ctx());}
void fit_length(slong len) {fmpz_mod_poly_fit_length(_poly(), len, _ctx());}
void _normalise() {_fmpz_mod_poly_normalise(_poly());}
void set_coeff(slong n, ulong c) {fmpz_mod_poly_set_coeff_ui(_poly(), n, c, _ctx());}
template
typename mp::enable_if >::type
set_coeff(slong j, const Fmpz& c)
{
fmpz_mod_poly_set_coeff_fmpz(_poly(), j, c.evaluate()._fmpz(), _ctx());
}
void truncate(slong n) {fmpz_mod_poly_truncate(_poly(), n, _ctx());}
void zero_coeffs(slong i, slong j) {fmpz_mod_poly_zero_coeffs(_poly(), i, j, _ctx());}
void set_randtest(frandxx& state, slong len)
{fmpz_mod_poly_randtest(_poly(), state._data(), len, _ctx());}
void set_randtest_irreducible(frandxx& state, slong len)
{fmpz_mod_poly_randtest_irreducible(_poly(), state._data(), len, _ctx());}
void set_randtest_not_zero(frandxx& state, slong len)
{fmpz_mod_poly_randtest_not_zero(_poly(), state._data(), len, _ctx());}
template
slong remove(const Poly& p)
{
return fmpz_mod_poly_remove(_poly(), p.evaluate()._poly(), _ctx());
}
void set_zero() {fmpz_mod_poly_zero(_poly(), _ctx());}
// unified coefficient access
typename poly_traits_t::lead_ref_t lead()
{
return poly_traits_t::lead(*this);
}
typename poly_traits_t::lead_srcref_t lead() const
{
return poly_traits_t::lead(*this);
}
// these cause evaluation
slong length() const
{
auto e = this->evaluate();
return fmpz_mod_poly_length(e._poly(), e._ctx());
}
slong degree() const
{
auto e = this->evaluate();
return fmpz_mod_poly_degree(e._poly(), e._ctx());
}
bool is_zero() const
{
auto e = this->evaluate();
return fmpz_mod_poly_is_zero(e._poly(), e._ctx());
}
bool is_one() const
{
auto e = this->evaluate();
return fmpz_mod_poly_is_one(e._poly(), e._ctx());
}
bool is_squarefree() const
{
auto e = this->evaluate();
return fmpz_mod_poly_is_squarefree(e._poly(), e._ctx());
}
bool is_irreducible() const
{
auto e = this->evaluate();
return fmpz_mod_poly_is_irreducible(e._poly(), e._ctx());
}
bool is_irreducible_ddf() const
{
auto e = this->evaluate();
return fmpz_mod_poly_is_irreducible_ddf(e._poly(), e._ctx());
}
bool is_irreducible_rabin() const
{
auto e = this->evaluate();
return fmpz_mod_poly_is_irreducible_rabin(e._poly(), e._ctx());
}
// Lazy members
FLINTXX_DEFINE_MEMBER_BINOP_(get_coeff, fmpz_mod_polyxx_get_coeff)
FLINTXX_DEFINE_MEMBER_BINOP_(operator(), compeval)
FLINTXX_DEFINE_MEMBER_UNOP(derivative)
FLINTXX_DEFINE_MEMBER_UNOP(invmod)
FLINTXX_DEFINE_MEMBER_UNOP(make_monic)
FLINTXX_DEFINE_MEMBER_UNOP(sqr)
FLINTXX_DEFINE_MEMBER_BINOP(compose_divconquer)
FLINTXX_DEFINE_MEMBER_BINOP(compose_horner)
FLINTXX_DEFINE_MEMBER_BINOP(div_basecase)
FLINTXX_DEFINE_MEMBER_BINOP(divrem)
FLINTXX_DEFINE_MEMBER_BINOP(divrem_basecase)
FLINTXX_DEFINE_MEMBER_BINOP(divrem_divconquer)
FLINTXX_DEFINE_MEMBER_BINOP(divrem_f)
FLINTXX_DEFINE_MEMBER_BINOP(gcd)
FLINTXX_DEFINE_MEMBER_BINOP(gcd_euclidean)
FLINTXX_DEFINE_MEMBER_BINOP(gcd_euclidean_f)
FLINTXX_DEFINE_MEMBER_BINOP(gcd_f)
FLINTXX_DEFINE_MEMBER_BINOP(gcdinv)
FLINTXX_DEFINE_MEMBER_BINOP(invmod)
FLINTXX_DEFINE_MEMBER_BINOP(inv_series_newton)
FLINTXX_DEFINE_MEMBER_BINOP(shift_left)
FLINTXX_DEFINE_MEMBER_BINOP(shift_right)
FLINTXX_DEFINE_MEMBER_BINOP(pow)
FLINTXX_DEFINE_MEMBER_BINOP(radix)
FLINTXX_DEFINE_MEMBER_BINOP(rem_basecase)
FLINTXX_DEFINE_MEMBER_BINOP(xgcd)
FLINTXX_DEFINE_MEMBER_BINOP(xgcd_euclidean)
FLINTXX_DEFINE_MEMBER_3OP(compose_mod)
FLINTXX_DEFINE_MEMBER_3OP(compose_mod_brent_kung)
FLINTXX_DEFINE_MEMBER_3OP(compose_mod_horner)
FLINTXX_DEFINE_MEMBER_3OP(mullow)
FLINTXX_DEFINE_MEMBER_3OP(mulmod)
FLINTXX_DEFINE_MEMBER_3OP(powmod_binexp)
FLINTXX_DEFINE_MEMBER_3OP(pow_trunc)
FLINTXX_DEFINE_MEMBER_3OP(pow_trunc_binexp)
};
namespace detail {
struct fmpz_mod_poly_data;
}
typedef fmpz_mod_polyxx_expression fmpz_mod_polyxx;
typedef fmpz_mod_polyxx_expression >
fmpz_mod_polyxx_ref;
typedef fmpz_mod_polyxx_expression > fmpz_mod_polyxx_srcref;
namespace traits {
template<> struct has_fmpz_modxx_ctx : mp::true_ { };
template<> struct has_fmpz_modxx_ctx : mp::true_ { };
template<> struct has_fmpz_modxx_ctx : mp::true_ { };
} // traits
namespace flint_classes {
template<>
struct ref_data
{
typedef void IS_REF_OR_CREF;
typedef fmpz_mod_polyxx wrapped_t;
typedef fmpz_mod_poly_struct* data_ref_t;
typedef const fmpz_mod_poly_struct* data_srcref_t;
fmpz_mod_poly_struct* inner;
fmpz_modxx_ctx_srcref ctx;
template
ref_data(T& o, typename detail::fakemodtemplate::type* = 0)
: inner(o._data().inner), ctx(o._data().ctx) {}
static ref_data make(fmpz_mod_poly_struct* f, fmpz_modxx_ctx_srcref ctx)
{
return ref_data(f, ctx);
}
private:
ref_data(fmpz_mod_poly_struct* fp, fmpz_modxx_ctx_srcref c) : inner(fp), ctx(c) {}
};
template
struct srcref_data
{
typedef void IS_REF_OR_CREF;
typedef fmpz_mod_polyxx wrapped_t;
typedef const fmpz_mod_poly_struct* data_ref_t;
typedef const fmpz_mod_poly_struct* data_srcref_t;
const fmpz_mod_poly_struct* inner;
fmpz_modxx_ctx_srcref ctx;
template
srcref_data(const T& o,
typename detail::fakemodtemplate::type* = 0)
: inner(o._data().inner), ctx(o._data().ctx) {}
template
srcref_data(T o, typename detail::fakemodtemplate::type* = 0)
: inner(o._data().inner), ctx(o._data().ctx) {}
static srcref_data make(const fmpz_mod_poly_struct* f, fmpz_modxx_ctx_srcref ctx)
{
return srcref_data(f, ctx);
}
private:
srcref_data(const fmpz_mod_poly_struct* fp, fmpz_modxx_ctx_srcref c)
: inner(fp), ctx(c) {}
};
} // flint_classes
#define FMPZ_MOD_POLYXX_COND_S FLINTXX_COND_S(fmpz_mod_polyxx)
#define FMPZ_MOD_POLYXX_COND_T FLINTXX_COND_T(fmpz_mod_polyxx)
namespace detail {
template<>
struct fmpz_mod_poly_traits
{
typedef fmpzxx_srcref lead_srcref_t;
typedef fmpzxx_srcref lead_ref_t;
template
static lead_srcref_t lead(P p)
{return lead_srcref_t::make(fmpz_mod_poly_lead(p._poly(), p._ctx()));}
};
template<>
struct fmpz_mod_poly_traits
{
typedef fmpzxx_ref lead_ref_t;
typedef fmpzxx_ref lead_srcref_t;
template
static lead_ref_t lead(P p)
{return lead_ref_t::make(fmpz_mod_poly_lead(p._poly(), p._ctx()));}
};
template<>
struct fmpz_mod_poly_traits
{
typedef fmpzxx_ref lead_ref_t;
typedef fmpzxx_srcref lead_srcref_t;
template
static lead_ref_t lead(P& p)
{return lead_ref_t::make(fmpz_mod_poly_lead(p._poly(), p._ctx()));}
template
static lead_srcref_t lead(const P& p)
{return lead_srcref_t::make(fmpz_mod_poly_lead(p._poly(), p._ctx()));}
};
struct fmpz_mod_poly_data
{
typedef fmpz_mod_poly_t& data_ref_t;
typedef const fmpz_mod_poly_t& data_srcref_t;
fmpz_modxx_ctx_srcref ctx;
fmpz_mod_poly_t inner;
fmpz_mod_poly_data(fmpz_modxx_ctx_srcref c)
: ctx(c)
{
fmpz_mod_poly_init(inner, ctx._ctx());
}
fmpz_mod_poly_data(fmpz_modxx_ctx_srcref c, slong alloc)
: ctx(c)
{
fmpz_mod_poly_init2(inner, alloc, ctx._ctx());
}
fmpz_mod_poly_data(const fmpz_mod_poly_data& o)
: ctx(o.ctx)
{
fmpz_mod_poly_init2(inner, o.inner->length, ctx._ctx());
fmpz_mod_poly_set(inner, o.inner, ctx._ctx());
}
fmpz_mod_poly_data(fmpz_mod_polyxx_srcref c)
: ctx(c.get_ctx())
{
fmpz_mod_poly_init2(inner, c.length(), ctx._ctx());
fmpz_mod_poly_set(inner, c._poly(), ctx._ctx());
}
~fmpz_mod_poly_data() {fmpz_mod_poly_clear(inner, ctx._ctx());}
};
struct is_fmpz_mod_polyxx_predicate
{
template struct type : FMPZ_MOD_POLYXX_COND_S { };
};
} // detail
namespace traits {
template struct is_fmpz_mod_polyxx : mp::or_<
traits::is_T_expr,
flint_classes::is_source > { };
}
namespace rules {
FLINT_DEFINE_DOIT_COND2(assignment,
FMPZ_MOD_POLYXX_COND_T, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_set(to._poly(), from._poly(), to._ctx()))
FLINT_DEFINE_DOIT_COND2(assignment,
FMPZ_MOD_POLYXX_COND_T, traits::is_unsigned_integer,
fmpz_mod_poly_set_ui(to._poly(), from, to._ctx()))
FLINT_DEFINE_DOIT_COND2(assignment,
FMPZ_MOD_POLYXX_COND_T, FMPZXX_COND_S,
fmpz_mod_poly_set_fmpz(to._poly(), from._fmpz(), to._ctx()))
FLINT_DEFINE_DOIT_COND2(assignment,
FMPZ_MOD_POLYXX_COND_T, FMPZ_POLYXX_COND_S,
fmpz_mod_poly_set_fmpz_poly(to._poly(), from._poly(), to._ctx()))
FLINTXX_DEFINE_CONVERSION_TMP(fmpz_polyxx, fmpz_mod_polyxx,
fmpz_mod_poly_get_fmpz_poly(to._poly(), from._poly(), from._ctx()))
FLINTXX_DEFINE_SWAP(fmpz_mod_polyxx,
fmpz_mod_poly_swap(e1._poly(), e2._poly()))
FLINTXX_DEFINE_EQUALS(fmpz_mod_polyxx,
fmpz_mod_poly_equal(e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(fmpz_mod_polyxx_get_coeff_op,
fmpzxx, FMPZ_MOD_POLYXX_COND_S, traits::fits_into_slong,
fmpz_mod_poly_get_coeff_fmpz(to._fmpz(), e1._poly(), e2, e1._ctx()))
FLINT_DEFINE_PRINT_COND(FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_fprint(to, from._poly(), from._ctx()))
FLINT_DEFINE_PRINT_PRETTY_COND_2(FMPZ_MOD_POLYXX_COND_S, const char*,
fmpz_mod_poly_fprint_pretty(to, from._poly(), extra, from._ctx()))
// be careful with fread as it writes to the possibly shared ctx
FLINT_DEFINE_READ_COND(FMPZ_MOD_POLYXX_COND_T,
fmpz_mod_poly_fread(from, to._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(plus,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_add(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(minus,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_sub(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_CBINARY_EXPR_COND2(times,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S, FMPZXX_COND_S,
fmpz_mod_poly_scalar_mul_fmpz(to._poly(), e1._poly(), e2._fmpz(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(times, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_mul(to._poly(), e1._poly(), e2._poly(), to._ctx()))
// TODO expose the temporary
FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_polyxx tmp(to.get_ctx());
fmpz_mod_poly_divrem(to._poly(), tmp._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_UNARY_EXPR_COND(negate,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_neg(to._poly(), from._poly(), to._ctx()))
FLINT_DEFINE_UNARY_EXPR_COND(fmpz_mod_polyxx_lead_op,
fmpzxx, FMPZ_MOD_POLYXX_COND_S,
fmpz_set(to._fmpz(), fmpz_mod_poly_lead(from._poly(), from._ctx())))
FLINT_DEFINE_BINARY_EXPR_COND2(shift_left_op,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S, traits::fits_into_slong,
fmpz_mod_poly_shift_left(to._poly(), e1._poly(), e2, to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(shift_right_op,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S, traits::fits_into_slong,
fmpz_mod_poly_shift_right(to._poly(), e1._poly(), e2, to._ctx()))
FLINT_DEFINE_UNARY_EXPR_COND(make_monic_op,
fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_make_monic(to._poly(), from._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(mullow_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S, traits::fits_into_slong,
fmpz_mod_poly_mullow(to._poly(), e1._poly(), e2._poly(), e3, to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(mulmod_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_mulmod(to._poly(), e1._poly(), e2._poly(), e3._poly(), to._ctx()))
FLINT_DEFINE_UNARY_EXPR_COND(sqr_op, fmpz_mod_polyxx, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_sqr(to._poly(), from._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(modulo, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_rem(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(powmod_binexp_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, traits::is_unsigned_integer, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_powmod_ui_binexp(to._poly(), e1._poly(), e2, e3._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(powmod_binexp_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_powmod_fmpz_binexp(to._poly(), e1._poly(), e2._fmpz(), e3._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(pow_trunc_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
fmpz_mod_poly_pow_trunc(to._poly(), e1._poly(), e2, e3, to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(pow_trunc_binexp_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, traits::is_unsigned_integer, traits::fits_into_slong,
fmpz_mod_poly_pow_trunc_binexp(to._poly(), e1._poly(), e2, e3, to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, traits::is_unsigned_integer,
fmpz_mod_poly_pow(to._poly(), e1._poly(), e2, to._ctx()))
namespace rdetail {
typedef make_ltuple::type>::type
fmpz_mod_polyxx_pair;
typedef make_ltuple::type>::type
fmpz_mod_poly_divrem_f_rt;
} // rdetail
FLINT_DEFINE_BINARY_EXPR_COND2(divrem_basecase_op, rdetail::fmpz_mod_polyxx_pair,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_divrem_basecase(
to.template get<0>()._poly(), to.template get<1>()._poly(),
e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(divrem_divconquer_op, rdetail::fmpz_mod_polyxx_pair,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_divrem_divconquer(
to.template get<0>()._poly(), to.template get<1>()._poly(),
e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(divrem_op, rdetail::fmpz_mod_polyxx_pair,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_divrem_divconquer(
to.template get<0>()._poly(), to.template get<1>()._poly(),
e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(divrem_f_op, rdetail::fmpz_mod_poly_divrem_f_rt,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_divrem_f(
to.template get<0>()._fmpz(), to.template get<1>()._poly(),
to.template get<2>()._poly(), e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(div_basecase_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_div_basecase(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(rem_basecase_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_rem_basecase(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(inv_series_newton_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, traits::fits_into_slong,
fmpz_mod_poly_inv_series_newton(to._poly(), e1._poly(), e2, to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(gcd_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_gcd(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(gcd_euclidean_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_gcd_euclidean(to._poly(), e1._poly(), e2._poly(), to._ctx()))
namespace rdetail {
typedef make_ltuple::type>::type
fmpz_mod_polyxx_triple;
} // rdetail
FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_op, rdetail::fmpz_mod_polyxx_triple,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_xgcd(to.template get<0>()._poly(), to.template get<1>()._poly(),
to.template get<2>()._poly(), e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(xgcd_euclidean_op, rdetail::fmpz_mod_polyxx_triple,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_xgcd_euclidean(to.template get<0>()._poly(),
to.template get<1>()._poly(),
to.template get<2>()._poly(), e1._poly(), e2._poly(), e1._ctx()))
namespace rdetail {
typedef make_ltuple::type>::type
fmpz_mod_gcd_f_rt;
} // rdetail
FLINT_DEFINE_BINARY_EXPR_COND2(gcd_f_op, rdetail::fmpz_mod_gcd_f_rt,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_gcd_f(to.template get<0>()._fmpz(),
to.template get<1>()._poly(), e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(gcd_euclidean_f_op, rdetail::fmpz_mod_gcd_f_rt,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_gcd_euclidean_f(to.template get<0>()._fmpz(),
to.template get<1>()._poly(), e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(gcdinv_op, rdetail::fmpz_mod_polyxx_pair,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_gcdinv(
to.template get<0>()._poly(), to.template get<1>()._poly(),
e1._poly(), e2._poly(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(invmod_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
execution_check(fmpz_mod_poly_invmod(to._poly(), e1._poly(), e2._poly(), to._ctx()),
"invmod", "fmpz_mod_polyxx"))
FLINT_DEFINE_UNARY_EXPR_COND(derivative_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_derivative(to._poly(), from._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(evaluate_op, fmpzxx,
FMPZ_MOD_POLYXX_COND_S, FMPZXX_COND_S,
fmpz_mod_poly_evaluate_fmpz(to._fmpz(), e1._poly(), e2._fmpz(), e1._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(compose_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_compose(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(compose_divconquer_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_compose_divconquer(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_BINARY_EXPR_COND2(compose_horner_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_compose_horner(to._poly(), e1._poly(), e2._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(compose_mod_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_compose_mod(to._poly(), e1._poly(), e2._poly(), e3._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(compose_mod_horner_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_compose_mod_horner(to._poly(), e1._poly(), e2._poly(), e3._poly(), to._ctx()))
FLINT_DEFINE_THREEARY_EXPR_COND3(compose_mod_brent_kung_op, fmpz_mod_polyxx,
FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S, FMPZ_MOD_POLYXX_COND_S,
fmpz_mod_poly_compose_mod_brent_kung(to._poly(), e1._poly(), e2._poly(), e3._poly(), to._ctx()))
} // rules
///////////////////////////////////////////////////////////////////////////////
// fmpz_mod_poly_vecxx (for radix conversion)
///////////////////////////////////////////////////////////////////////////////
namespace detail {
struct fmpz_mod_poly_vector_data
{
slong size;
fmpz_mod_poly_struct** array;
fmpz_modxx_ctx_srcref ctx;
fmpz_mod_poly_vector_data(slong n, fmpz_modxx_ctx_srcref c)
: size(n), ctx(c)
{
array = new fmpz_mod_poly_struct*[n];
for(slong i = 0;i < n;++i)
{
array[i] = new fmpz_mod_poly_struct();
fmpz_mod_poly_init(array[i], ctx._ctx());
}
}
~fmpz_mod_poly_vector_data()
{
for(slong i = 0;i < size;++i)
{
fmpz_mod_poly_clear(array[i], ctx._ctx());
delete array[i];
}
delete[] array;
}
fmpz_mod_poly_vector_data(const fmpz_mod_poly_vector_data& o)
: size(o.size), ctx(o.ctx)
{
array = new fmpz_mod_poly_struct*[size];
for(slong i = 0;i < size;++i)
{
array[i] = new fmpz_mod_poly_struct();
fmpz_mod_poly_init(array[i], ctx._ctx());
fmpz_mod_poly_set(array[i], o.array[i], ctx._ctx());
}
}
fmpz_mod_polyxx_ref at(slong i)
{return fmpz_mod_polyxx_ref::make(array[i], ctx);}
fmpz_mod_polyxx_srcref at(slong i) const
{return fmpz_mod_polyxx_srcref::make(array[i], ctx);}
bool equals(const fmpz_mod_poly_vector_data& o) const
{
if(size != o.size)
return false;
for(slong i = 0;i < size;++i)
if(!fmpz_mod_poly_equal(array[i], o.array[i], ctx._ctx()))
return false;
return true;
}
};
struct fmpz_mod_poly_vector_traits
: wrapped_vector_traits
{
template
static typename Expr::evaluated_t create_temporary(const Expr& e)
{
return typename Expr::evaluated_t(e.size(), tools::find_fmpz_modxx_ctx(e));
}
};
} // detail
// TODO would it make more sense to have this have its own class?
typedef vector_expression<
detail::fmpz_mod_poly_vector_traits, operations::immediate,
detail::fmpz_mod_poly_vector_data> fmpz_mod_poly_vecxx;
// TODO references
template<>
struct enable_vector_rules : mp::false_ { };
namespace rules {
// TODO hack to make code look like references are implemented
template struct FMPZ_MOD_POLY_VECXX_COND_S
: mp::equal_types { };
#define FMPZ_MOD_POLY_VECXX_COND_T FMPZ_MOD_POLY_VECXX_COND_S
// TODO references
FLINT_DEFINE_GET(equals, bool, fmpz_mod_poly_vecxx, e1._data().equals(e2._data()))
} // rules
///////////////////////////////////////////////////////////////////////////////
// radix conversion
///////////////////////////////////////////////////////////////////////////////
class fmpz_mod_poly_radixxx
{
private:
fmpz_mod_poly_radix_t inner;
// not copyable
fmpz_mod_poly_radixxx(const fmpz_mod_poly_radixxx&);
public:
template
fmpz_mod_poly_radixxx(const Fmpz_mod_poly& r, slong deg,
typename mp::enable_if<
traits::is_fmpz_mod_polyxx >::type* = 0)
{
auto e = r.evaluate();
fmpz_mod_poly_radix_init(inner, e._poly(), deg, e._ctx());
}
~fmpz_mod_poly_radixxx() {fmpz_mod_poly_radix_clear(inner);}
fmpz_mod_poly_radix_t& _data() {return inner;}
const fmpz_mod_poly_radix_t& _data() const {return inner;}
slong degR() const {return inner->degR;}
};
namespace traits {
template struct is_fmpz_mod_poly_radixxx
: mp::equal_types { };
} // traits
namespace vectors {
template<>
struct outsize
{
template
static unsigned get(const Expr& e)
{
return e._data().first().degree() / e._data().second().degR() + 1;
}
};
}
namespace rules {
FLINT_DEFINE_BINARY_EXPR_COND2(radix_op, fmpz_mod_poly_vecxx,
FMPZ_MOD_POLYXX_COND_S, traits::is_fmpz_mod_poly_radixxx,
fmpz_mod_poly_radix(to._array(), e1._poly(), e2._data(), e1._ctx()))
}
} // flint
#include "fmpz_mod_poly_factorxx.h"
#endif