// References : Cohen H., A course in computational algebraic number theory // (1996), page 21. bool crt(const Ptr<RCP<const Integer>> &R, const std::vector<RCP<const Integer>> &rem, const std::vector<RCP<const Integer>> &mod) { if (mod.size() > rem.size()) throw SymEngineException("Too few remainders"); if (mod.size() == 0) throw SymEngineException("Moduli vector cannot be empty"); integer_class m, r, g, s, t; m = mod[0]->as_integer_class(); r = rem[0]->as_integer_class(); for (unsigned i = 1; i < mod.size(); ++i) { mp_gcdext(g, s, t, m, mod[i]->as_integer_class()); // g = s * m + t * mod[i] t = rem[i]->as_integer_class() - r; if (not mp_divisible_p(t, g)) return false; r += m * s * (t / g); // r += m * (m**-1 mod[i]/g)* (rem[i] - r) / g m *= mod[i]->as_integer_class() / g; mp_fdiv_r(r, r, m); } *R = integer(std::move(r)); return true; }
void GaloisFieldDict::gf_div(const GaloisFieldDict &o, const Ptr<GaloisFieldDict> &quo, const Ptr<GaloisFieldDict> &rem) const { if (modulo_ != o.modulo_) throw std::runtime_error("Error: field must be same."); if (o.dict_.empty()) throw std::runtime_error("ZeroDivisionError"); std::vector<integer_class> dict_out; if (dict_.empty()) { *quo = GaloisFieldDict::from_vec(dict_out, modulo_); *rem = GaloisFieldDict::from_vec(dict_, modulo_); return; } auto dict_divisor = o.dict_; unsigned int deg_dividend = this->degree(); unsigned int deg_divisor = o.degree(); if (deg_dividend < deg_divisor) { *quo = GaloisFieldDict::from_vec(dict_out, modulo_); *rem = GaloisFieldDict::from_vec(dict_, modulo_); } else { dict_out = dict_; integer_class inv; mp_invert(inv, *(dict_divisor.rbegin()), modulo_); integer_class coeff; for (auto it = deg_dividend + 1; it-- != 0;) { coeff = dict_out[it]; auto lb = deg_divisor + it > deg_dividend ? deg_divisor + it - deg_dividend : 0; auto ub = std::min(it + 1, deg_divisor); for (size_t j = lb; j < ub; ++j) { mp_addmul(coeff, dict_out[it - j + deg_divisor], -dict_divisor[j]); } if (it >= deg_divisor) coeff *= inv; mp_fdiv_r(coeff, coeff, modulo_); dict_out[it] = coeff; } std::vector<integer_class> dict_rem, dict_quo; dict_rem.resize(deg_divisor); dict_quo.resize(deg_dividend - deg_divisor + 1); for (unsigned it = 0; it < dict_out.size(); it++) { if (it < deg_divisor) dict_rem[it] = dict_out[it]; else dict_quo[it - deg_divisor] = dict_out[it]; } *quo = GaloisFieldDict::from_vec(dict_quo, modulo_); *rem = GaloisFieldDict::from_vec(dict_rem, modulo_); } }
GaloisFieldDict GaloisFieldDict::gf_diff() const { auto df = degree(); GaloisFieldDict out = GaloisFieldDict({}, modulo_); out.dict_.resize(df, integer_class(0)); for (unsigned i = 1; i <= df; i++) { if (dict_[i] != integer_class(0)) { out.dict_[i - 1] = i * dict_[i]; mp_fdiv_r(out.dict_[i - 1], out.dict_[i - 1], modulo_); } } out.gf_istrip(); return out; }
void GaloisFieldDict::gf_monic(integer_class &res, const Ptr<GaloisFieldDict> &monic) const { *monic = static_cast<GaloisFieldDict>(*this); if (dict_.empty()) { res = integer_class(0); } else { res = *dict_.rbegin(); if (res != integer_class(1)) { integer_class inv, temp; mp_invert(inv, res, modulo_); for (auto &iter : monic->dict_) { temp = inv; temp *= iter; mp_fdiv_r(iter, temp, modulo_); } } } }
RCP<const Integer> mod_f(const Integer &n, const Integer &d) { integer_class q; mp_fdiv_r(q, n.as_integer_class(), d.as_integer_class()); return integer(std::move(q)); }