5 #ifndef SYMENGINE_FIELDS_H
6 #define SYMENGINE_FIELDS_H
10 #include <symengine/polys/upolybase.h>
19 integer_class modulo_;
26 if (a.degree() == b.degree())
27 return a.dict_ < b.dict_;
29 return a.degree() < b.degree();
34 if (a.first.degree() == b.first.degree())
35 return a.first.dict_ < b.first.dict_;
37 return a.first.degree() < b.first.degree();
42 GaloisFieldDict(GaloisFieldDict &&other) SYMENGINE_NOEXCEPT
47 GaloisFieldDict(
const int &i,
const integer_class &
mod);
48 GaloisFieldDict(
const map_uint_mpz &p,
const integer_class &
mod);
49 GaloisFieldDict(
const integer_class &i,
const integer_class &
mod);
52 const integer_class &modulo);
54 GaloisFieldDict(
const GaloisFieldDict &) =
default;
55 GaloisFieldDict &operator=(
const GaloisFieldDict &) =
default;
56 void gf_div(
const GaloisFieldDict &o,
const Ptr<GaloisFieldDict> &quo,
57 const Ptr<GaloisFieldDict> &rem)
const;
59 GaloisFieldDict gf_lshift(
const integer_class n)
const;
60 void gf_rshift(
const integer_class n,
const Ptr<GaloisFieldDict> &quo,
61 const Ptr<GaloisFieldDict> &rem)
const;
62 GaloisFieldDict gf_sqr()
const;
63 GaloisFieldDict gf_pow(
const unsigned long n)
const;
64 void gf_monic(integer_class &res,
const Ptr<GaloisFieldDict> &monic)
const;
65 GaloisFieldDict gf_gcd(
const GaloisFieldDict &o)
const;
66 GaloisFieldDict gf_lcm(
const GaloisFieldDict &o)
const;
67 GaloisFieldDict gf_diff()
const;
68 integer_class gf_eval(
const integer_class &a)
const;
69 vec_integer_class gf_multi_eval(
const vec_integer_class &v)
const;
72 bool gf_is_sqf()
const;
80 GaloisFieldDict gf_sqf_part()
const;
82 GaloisFieldDict gf_compose_mod(
const GaloisFieldDict &g,
83 const GaloisFieldDict &h)
const;
88 GaloisFieldDict gf_pow_mod(
const GaloisFieldDict &f,
89 const unsigned long &n)
const;
93 gf_frobenius_map(
const GaloisFieldDict &g,
96 gf_trace_map(
const GaloisFieldDict &a,
const GaloisFieldDict &b,
97 const GaloisFieldDict &c,
const unsigned long &n)
const;
98 GaloisFieldDict _gf_trace_map(
const GaloisFieldDict &f,
99 const unsigned long &n,
106 GaloisFieldDict _gf_pow_pnm1d2(
const GaloisFieldDict &f,
const unsigned &n,
109 GaloisFieldDict gf_random(
const unsigned int &n_val,
110 mp_randstate &state)
const;
116 gf_edf_zassenhaus(
const unsigned &n)
const;
147 GaloisFieldDict &operator=(GaloisFieldDict &&other) SYMENGINE_NOEXCEPT
149 if (
this != &other) {
153 return down_cast<GaloisFieldDict &>(*
this);
156 template <
typename T>
157 friend GaloisFieldDict operator+(
const GaloisFieldDict &a,
const T &b)
159 GaloisFieldDict c = a;
164 GaloisFieldDict &operator+=(
const GaloisFieldDict &other)
166 if (modulo_ != other.modulo_)
167 throw SymEngineException(
"Error: field must be same.");
168 if (other.dict_.size() == 0)
169 return down_cast<GaloisFieldDict &>(*
this);
170 if (this->dict_.
size() == 0) {
172 return down_cast<GaloisFieldDict &>(*
this);
174 if (other.dict_.size() < this->dict_.size()) {
175 for (
unsigned int i = 0; i < other.dict_.size(); i++) {
178 temp += other.dict_[i];
179 if (temp != integer_class(0)) {
180 mp_fdiv_r(temp, temp, modulo_);
185 for (
unsigned int i = 0; i < dict_.
size(); i++) {
188 temp += other.dict_[i];
189 if (temp != integer_class(0)) {
190 mp_fdiv_r(temp, temp, modulo_);
194 if (other.dict_.size() == this->dict_.size())
197 dict_.
insert(dict_.
end(), other.dict_.begin() + dict_.
size(),
200 return down_cast<GaloisFieldDict &>(*
this);
203 GaloisFieldDict &operator+=(
const integer_class &other)
205 if (dict_.
empty() or other == integer_class(0))
206 return down_cast<GaloisFieldDict &>(*
this);
207 integer_class temp = dict_[0] + other;
208 mp_fdiv_r(temp, temp, modulo_);
210 if (dict_.
size() == 1)
212 return down_cast<GaloisFieldDict &>(*
this);
215 template <
typename T>
216 friend GaloisFieldDict operator-(
const GaloisFieldDict &a,
const T &b)
218 GaloisFieldDict c = a;
222 GaloisFieldDict operator-()
const
224 GaloisFieldDict o(*
this);
225 for (
auto &a : o.dict_) {
233 GaloisFieldDict &negate();
235 GaloisFieldDict &operator-=(
const integer_class &other)
237 return *
this += (-1 * other);
240 GaloisFieldDict &operator-=(
const GaloisFieldDict &other)
242 if (modulo_ != other.modulo_)
243 throw SymEngineException(
"Error: field must be same.");
244 if (other.dict_.size() == 0)
245 return down_cast<GaloisFieldDict &>(*
this);
246 if (this->dict_.
size() == 0) {
248 return down_cast<GaloisFieldDict &>(*
this);
250 if (other.dict_.size() < this->dict_.size()) {
251 for (
unsigned int i = 0; i < other.dict_.size(); i++) {
254 temp -= other.dict_[i];
255 if (temp != integer_class(0)) {
256 mp_fdiv_r(temp, temp, modulo_);
261 for (
unsigned int i = 0; i < dict_.
size(); i++) {
264 temp -= other.dict_[i];
265 if (temp != integer_class(0)) {
266 mp_fdiv_r(temp, temp, modulo_);
270 if (other.dict_.size() == this->dict_.size())
273 auto orig_size = dict_.
size();
274 dict_.
resize(other.dict_.size());
275 for (
auto i = orig_size; i < other.dict_.size(); i++) {
276 dict_[i] = -other.dict_[i];
282 return down_cast<GaloisFieldDict &>(*
this);
285 static GaloisFieldDict mul(
const GaloisFieldDict &a,
286 const GaloisFieldDict &b);
288 friend GaloisFieldDict operator*(
const GaloisFieldDict &a,
289 const GaloisFieldDict &b)
291 return GaloisFieldDict::mul(a, b);
294 GaloisFieldDict &operator*=(
const integer_class &other)
297 return down_cast<GaloisFieldDict &>(*
this);
299 if (other == integer_class(0)) {
301 return down_cast<GaloisFieldDict &>(*
this);
304 for (
auto &arg : dict_) {
305 if (arg != integer_class(0)) {
307 mp_fdiv_r(arg, arg, modulo_);
311 return down_cast<GaloisFieldDict &>(*
this);
314 GaloisFieldDict &operator*=(
const GaloisFieldDict &other)
316 if (modulo_ != other.modulo_)
317 throw SymEngineException(
"Error: field must be same.");
319 return down_cast<GaloisFieldDict &>(*
this);
321 auto o_dict = other.dict_;
322 if (o_dict.empty()) {
324 return down_cast<GaloisFieldDict &>(*
this);
328 if (o_dict.size() == 1) {
329 for (
auto &arg : dict_) {
330 if (arg != integer_class(0)) {
332 mp_fdiv_r(arg, arg, modulo_);
336 return down_cast<GaloisFieldDict &>(*
this);
340 = GaloisFieldDict::mul(down_cast<GaloisFieldDict &>(*
this), other);
341 res.dict_.swap(this->dict_);
342 return down_cast<GaloisFieldDict &>(*
this);
346 friend GaloisFieldDict operator/(
const GaloisFieldDict &a,
const T &b)
348 GaloisFieldDict c = a;
353 GaloisFieldDict &operator/=(
const integer_class &other)
355 if (other == integer_class(0)) {
356 throw DivisionByZeroError(
"ZeroDivisionError");
359 return down_cast<GaloisFieldDict &>(*
this);
361 mp_invert(inv, other, modulo_);
362 for (
auto &arg : dict_) {
363 if (arg != integer_class(0)) {
365 mp_fdiv_r(arg, arg, modulo_);
369 return down_cast<GaloisFieldDict &>(*
this);
372 GaloisFieldDict &operator/=(
const GaloisFieldDict &other)
374 if (modulo_ != other.modulo_)
375 throw SymEngineException(
"Error: field must be same.");
376 auto dict_divisor = other.dict_;
377 if (dict_divisor.empty()) {
378 throw DivisionByZeroError(
"ZeroDivisionError");
381 return down_cast<GaloisFieldDict &>(*
this);
383 mp_invert(inv, *(dict_divisor.rbegin()), modulo_);
386 if (dict_divisor.size() == 1) {
387 for (
auto &iter : dict_) {
390 mp_fdiv_r(iter, iter, modulo_);
393 return down_cast<GaloisFieldDict &>(*
this);
396 size_t deg_dividend = this->degree();
397 size_t deg_divisor = other.degree();
398 if (deg_dividend < deg_divisor) {
400 return down_cast<GaloisFieldDict &>(*
this);
402 dict_out.
swap(dict_);
403 dict_.resize(deg_dividend - deg_divisor + 1);
405 for (
auto riter = deg_dividend; riter >= deg_divisor; --riter) {
406 coeff = dict_out[riter];
407 auto lb = deg_divisor + riter > deg_dividend
408 ? deg_divisor + riter - deg_dividend
410 auto ub =
std::min(riter + 1, deg_divisor);
411 for (
auto j = lb; j < ub; ++j) {
412 mp_addmul(coeff, dict_out[riter - j + deg_divisor],
416 mp_fdiv_r(coeff, coeff, modulo_);
417 dict_out[riter] = dict_[riter - deg_divisor] = coeff;
420 return down_cast<GaloisFieldDict &>(*
this);
424 friend GaloisFieldDict operator%(
const GaloisFieldDict &a,
const T &b)
426 GaloisFieldDict c = a;
431 GaloisFieldDict &operator%=(
const integer_class &other)
433 if (other == integer_class(0)) {
434 throw DivisionByZeroError(
"ZeroDivisionError");
437 return down_cast<GaloisFieldDict &>(*
this);
439 return down_cast<GaloisFieldDict &>(*
this);
442 GaloisFieldDict &operator%=(
const GaloisFieldDict &other)
444 if (modulo_ != other.modulo_)
445 throw SymEngineException(
"Error: field must be same.");
446 auto dict_divisor = other.dict_;
447 if (dict_divisor.empty()) {
448 throw DivisionByZeroError(
"ZeroDivisionError");
451 return down_cast<GaloisFieldDict &>(*
this);
453 mp_invert(inv, *(dict_divisor.rbegin()), modulo_);
456 if (dict_divisor.size() == 1) {
458 return down_cast<GaloisFieldDict &>(*
this);
461 size_t deg_dividend = this->degree();
462 size_t deg_divisor = other.degree();
463 if (deg_dividend < deg_divisor) {
464 return down_cast<GaloisFieldDict &>(*
this);
466 dict_out.
swap(dict_);
467 dict_.resize(deg_divisor);
469 for (
auto it = deg_dividend + 1; it-- != 0;) {
470 coeff = dict_out[it];
471 auto lb = deg_divisor + it > deg_dividend
472 ? deg_divisor + it - deg_dividend
474 auto ub =
std::min(it + 1, deg_divisor);
475 for (
size_t j = lb; j < ub; ++j) {
476 mp_addmul(coeff, dict_out[it - j + deg_divisor],
479 if (it >= deg_divisor) {
481 mp_fdiv_r(coeff, coeff, modulo_);
482 dict_out[it] = coeff;
484 mp_fdiv_r(coeff, coeff, modulo_);
485 dict_out[it] = dict_[it] = coeff;
489 return down_cast<GaloisFieldDict &>(*
this);
492 static GaloisFieldDict pow(
const GaloisFieldDict &a,
unsigned int p)
497 bool operator==(
const GaloisFieldDict &other)
const
499 return dict_ == other.dict_ and modulo_ == other.modulo_;
502 bool operator!=(
const GaloisFieldDict &other)
const
504 return not(*
this == other);
514 return dict_.empty();
517 unsigned degree()
const
521 return numeric_cast<unsigned>(dict_.size()) - 1;
533 if (dict_.size() == 1)
534 if (dict_[0] == integer_class(1))
539 integer_class get_coeff(
unsigned int x)
const
563 static RCP<const GaloisField> from_dict(
const RCP<const Basic> &var,
565 static RCP<const GaloisField> from_vec(
const RCP<const Basic> &var,
567 const integer_class &modulo);
568 static RCP<const GaloisField> from_uintpoly(
const UIntPoly &a,
569 const integer_class &modulo);
571 integer_class eval(
const integer_class &x)
const override
573 return get_poly().gf_eval(x);
578 return get_poly().gf_multi_eval(v);
581 typedef vec_integer_class::const_iterator iterator;
582 typedef vec_integer_class::const_reverse_iterator reverse_iterator;
583 iterator begin()
const
585 return get_poly().dict_.begin();
589 return get_poly().dict_.end();
591 reverse_iterator obegin()
const
593 return get_poly().dict_.rbegin();
595 reverse_iterator oend()
const
597 return get_poly().dict_.rend();
600 inline integer_class get_coeff(
unsigned int x)
const override
602 return get_poly().get_coeff(x);
605 vec_basic
get_args()
const override;
608 return get_poly().dict_;
611 inline int size()
const override
613 if (get_poly().empty())
615 return get_degree() + 1;
619 inline RCP<const GaloisField> gf_poly(RCP<const Basic> i,
620 GaloisFieldDict &&dict)
622 return GaloisField::from_dict(i,
std::move(dict));
625 inline RCP<const GaloisField> gf_poly(RCP<const Basic> i, map_uint_mpz &&dict,
626 integer_class modulo_)
628 GaloisFieldDict wrapper(dict, modulo_);
629 return GaloisField::from_dict(i,
std::move(wrapper));
632 inline RCP<const GaloisField> pow_upoly(
const GaloisField &a,
unsigned int p)
634 auto dict = GaloisField::container_type::pow(a.get_poly(), p);
635 return GaloisField::from_container(a.get_var(),
std::move(dict));
The base class for SymEngine.
#define IMPLEMENT_TYPEID(SYMENGINE_ID)
Inline members and functions.
The lowest unit of symbolic representation.
GaloisField(const RCP< const Basic > &var, GaloisFieldDict &&dict)
Constructor of GaloisField class.
bool is_canonical(const GaloisFieldDict &dict) const
hash_t __hash__() const override
vec_basic get_args() const override
Returns the list of arguments.
int compare(const Basic &o) const override
Main namespace for SymEngine package.
RCP< const Integer > mod(const Integer &n, const Integer &d)
modulo round toward zero