16static MultiPoly
truncate_mod_var(
const MultiPoly& poly,
const std::string& var,
19 const std::vector<std::string>& variables) {
20 if (polynomial.variables() == variables) {
return polynomial; }
21 if (polynomial.is_constant()) {
23 polynomial.is_zero() ? Rational(0) : polynomial.terms().front().second,
26 std::vector<size_t> coordinates;
27 coordinates.reserve(polynomial.variables().size());
28 for (
const auto&
variable : polynomial.variables()) {
29 auto position = std::find(variables.begin(), variables.end(),
variable);
30 if (position == variables.end()) {
31 throw std::invalid_argument(
"Hensel embedding: variable is absent from target ring");
33 coordinates.push_back(
static_cast<size_t>(position - variables.begin()));
35 std::vector<MultiPoly::Term> terms;
36 terms.reserve(polynomial.terms().size());
37 for (
const auto& term : polynomial.terms()) {
38 Monomial monomial(variables.size(), 0);
39 for (
size_t i = 0; i < term.first.size(); ++i) {
40 monomial[coordinates[i]] = term.first[i];
42 terms.emplace_back(std::move(monomial), term.second);
44 return MultiPoly(std::move(terms), variables);
50 const std::vector<std::string>&
vars) {
51 std::vector<MultiPoly> result;
52 result.reserve(univariate_factors.size());
53 for (
const auto& uf : univariate_factors) {
55 MultiPoly::from_univariate(uf, uf.variable_name),
vars));
62 const std::vector<std::string>&
vars,
int lift_var_idx,
63 const Rational& eval_point,
int degree_bound) {
64 std::vector<MultiPoly> shift_powers;
65 shift_powers.reserve(degree_bound + 1);
66 shift_powers.push_back(MultiPoly(Rational(1),
vars));
67 if (lift_var_idx >= 0) {
69 var_mono[lift_var_idx] = 1;
70 std::vector<MultiPoly::Term> lin_terms;
71 lin_terms.emplace_back(var_mono, Rational(1));
72 if (!eval_point.is_zero()) {
74 lin_terms.emplace_back(const_mono, -eval_point);
76 MultiPoly shift_lin(std::move(lin_terms),
vars);
77 shift_powers.push_back(shift_lin);
78 for (
int k = 2; k <= degree_bound; ++k) {
79 shift_powers.push_back(shift_powers[k - 1] * shift_lin);
82 for (
int k = 1; k <= degree_bound; ++k) {
83 shift_powers.push_back(MultiPoly(Rational(1),
vars));
90 const std::string& lift_var,
int lift_var_idx,
const Rational& eval_point,
91 int k,
const std::vector<MultiPoly>& shift_powers,
92 const std::vector<std::string>&
vars) {
94 if (eval_point.is_zero()) {
95 std::vector<MultiPoly::Term> error_k_terms;
96 for (
const auto& term : error.terms()) {
98 int exp = (lift_var_idx >= 0 &&
static_cast<size_t>(lift_var_idx) < mono.size())
99 ? mono[lift_var_idx] : 0;
102 reduced[lift_var_idx] = 0;
103 error_k_terms.emplace_back(std::move(reduced), term.second);
106 if (error_k_terms.empty()) {
return MultiPoly(Rational(0),
vars); }
107 error_k = MultiPoly(std::move(error_k_terms),
vars);
114 MultiPoly remainder = error;
115 for (
int j = 0; j < k; ++j) {
116 MultiPoly eval_check = remainder.eval(lift_var, eval_point);
117 if (!eval_check.is_zero()) {
118 remainder = MultiPoly(Rational(0),
vars);
122 remainder = remainder.exact_div(shift_powers[1]);
123 }
catch (
const std::runtime_error&) {
124 remainder = MultiPoly(Rational(0),
vars);
129 if (error_k.is_zero()) {
return error_k; }
135 const std::vector<MultiPoly>& factors,
const std::string& lift_var,
136 const Rational& eval_point,
const std::vector<std::string>&
vars) {
137 const int r =
static_cast<int>(factors.size());
138 std::vector<MultiPoly> cofactors;
139 cofactors.reserve(
r);
140 for (
int i = 0; i <
r; ++i) {
141 MultiPoly cof(Rational(1),
vars);
142 for (
int j = 0; j <
r; ++j) {
143 if (j == i) {
continue; }
145 factors[j].eval(lift_var, eval_point),
vars);
148 cofactors.push_back(cof);
154 int lift_var_idx,
int k) {
155 if (verify_error.is_zero()) {
return true; }
156 bool residual_ok =
true;
157 for (
const auto& term : verify_error.terms()) {
159 int exp = (lift_var_idx >= 0 &&
160 static_cast<size_t>(lift_var_idx) < mono.size())
161 ? mono[lift_var_idx] : 0;
171 const std::string&
variable,
int degree_bound) {
172 MultiPoly product = factors[0];
173 for (
size_t i = 1; i < factors.size(); ++i) {
174 product = product * factors[i];
181 std::vector<MultiPoly>& factors,
const std::string& lift_var,
int lift_var_idx,
182 const Rational& eval_point,
int degree_bound,
int factor_count) {
183 const auto&
vars = poly.variables();
185 eval_point, degree_bound);
186 for (
int k = 1; k <= degree_bound; ++k) {
189 MultiPoly error = poly_trunc - product;
190 if (error.is_zero()) {
continue; }
192 eval_point, k, shift_powers,
vars);
193 if (error_k.is_zero()) {
continue; }
197 cofactors, error_k, lift_var, eval_point, k + 1);
198 if (corrections.size() !=
static_cast<size_t>(factor_count)) {
return false; }
199 for (
int i = 0; i < factor_count; ++i) {
200 if (corrections[i].is_zero()) {
continue; }
201 MultiPoly correction_poly = corrections[i] * shift_powers[k];
202 factors[i] = factors[i] + correction_poly;
205 MultiPoly verify_error = poly_trunc - verify_product;
238 const MultiPoly& poly,
240 const std::string& lift_var,
241 const Rational& eval_point,
244 int r =
static_cast<int>(univariate_factors.size());
245 if (
r == 0) {
return {}; }
249 if (degree_bound <= 0) {
253 const auto&
vars = poly.variables();
256 std::string
main_var = univariate_factors[0].variable_name;
257 int lift_var_idx = -1;
258 for (
size_t i = 0; i <
vars.size(); ++i) {
259 if (
vars[i] == lift_var) { lift_var_idx =
static_cast<int>(i); }
262 for (
const auto& factor : univariate_factors) {
263 if (factor.variable_name !=
main_var) {
264 throw std::invalid_argument(
"Hensel lifting: univariate factor ring mismatch");
270 if (lift_var_idx < 0) {
274 MultiPoly base_product(Rational(1),
vars);
275 for (
const auto& factor : factors) { base_product = base_product * factor; }
276 if (base_product.eval(lift_var, eval_point) != poly.eval(lift_var, eval_point)) {
281 poly, factors, lift_var, lift_var_idx, eval_point, degree_bound,
r)) {
306 std::string var =
a.variable_name;
315 while (!r1.is_zero()) {
330 if (lc != Rational(1)) {
331 Rational inv = Rational(1) / lc;
334 for (
auto&
c : t0.coeffs)
c =
c * inv;
357 if (poly.is_zero()) {
return poly; }
359 const auto&
vars = poly.variables();
361 for (
size_t i = 0; i <
vars.size(); ++i) {
362 if (
vars[i] == var) { var_idx =
static_cast<int>(i);
break; }
365 if (var_idx < 0) {
return poly; }
367 std::vector<MultiPoly::Term> result_terms;
368 for (
const auto& term : poly.terms()) {
370 int exp = (
static_cast<size_t>(var_idx) < mono.size()) ? mono[var_idx] : 0;
371 if (
exp < degree_bound) {
372 result_terms.push_back(term);
376 if (result_terms.empty()) {
return MultiPoly(Rational(0),
vars); }
377 return MultiPoly(std::move(result_terms),
vars);
381 const std::vector<MultiPoly>& factors,
const std::string& var,
384 bool converted =
false;
387 f1_uni = factors[0].to_univariate();
388 f2_uni = factors[1].to_univariate();
390 }
catch (
const std::invalid_argument&) {
392 MultiPoly f1_eval = factors[0].eval(var, eval_point);
393 MultiPoly f2_eval = factors[1].eval(var, eval_point);
394 f1_uni = f1_eval.to_univariate();
395 f2_uni = f2_eval.to_univariate();
397 }
catch (
const std::invalid_argument&) {
406 if (f1_uni.
degree() <= 0) {
408 }
else if (f2_uni.
degree() <= 0) {
418 const std::string& var,
const Rational& eval_point,
421 target_uni =
target.to_univariate();
426 if (target_uni.
degree() > 0 &&
428 throw std::logic_error(
"target uses the lift variable");
430 }
catch (
const std::logic_error&) {
432 MultiPoly target_eval =
target.eval(var, eval_point);
433 target_uni = target_eval.to_univariate();
434 }
catch (
const std::invalid_argument&) {
435 if (
target.is_constant()) {
436 Rational
c =
target.is_zero() ? Rational(0) :
target.terms()[0].second;
443 if (target_uni.
degree() <= 0) {
452 const std::vector<MultiPoly>& factors,
const MultiPoly&
target,
453 const std::string& var,
const Rational& eval_point,
int degree_bound) {
454 const auto&
vars = factors[0].variables();
458 return {MultiPoly(Rational(0),
vars), MultiPoly(Rational(0),
vars)};
466 return {MultiPoly(Rational(0),
vars), MultiPoly(Rational(0),
vars)};
476 return {MultiPoly(Rational(0),
vars), MultiPoly(Rational(0),
vars)};
479 auto [quotient, remainder] = target_uni.
div_mod(g);
480 if (!remainder.is_zero()) {
481 return {MultiPoly(Rational(0),
vars), MultiPoly(Rational(0),
vars)};
492 auto [q1, r1] = s1_uni.
div_mod(f2_uni);
494 s2_uni = s2_uni + q1 * f1_uni;
496 if (!(s1_uni * f1_uni + s2_uni * f2_uni == target_uni)) {
return {}; }
500 MultiPoly::from_univariate(s1_uni, uni_var),
vars);
502 MultiPoly::from_univariate(s2_uni, uni_var),
vars);
506 return {s1_mp, s2_mp};
530 const std::vector<MultiPoly>& factors,
532 const std::string& var,
533 const Rational& eval_point,
536 int r =
static_cast<int>(factors.size());
537 if (
r == 0) {
return {}; }
541 MultiPoly s1 =
target.exact_div(factors[0]);
544 }
catch (
const std::runtime_error&) {
549 const auto&
vars = factors[0].variables();
558 MultiPoly g = factors[1];
559 for (
int i = 2; i <
r; ++i) {
564 std::vector<MultiPoly> two_factors = {factors[0], g};
566 two_factors,
target, var, eval_point, degree_bound);
568 if (two_solution.size() != 2) {
570 std::vector<MultiPoly> result(
r, MultiPoly(Rational(0),
vars));
575 MultiPoly s1 = two_solution[0];
576 MultiPoly t_poly = two_solution[1];
581 MultiPoly remaining_target = t_poly * g;
584 std::vector<MultiPoly> remaining_factors(factors.begin() + 1, factors.end());
586 remaining_factors, remaining_target, var, eval_point, degree_bound);
589 std::vector<MultiPoly> result;
590 result.push_back(std::move(s1));
591 for (
auto& sol : remaining_solution) {
592 result.push_back(std::move(sol));
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
static std::vector< MultiPoly > solve_diophantine_pair(const std::vector< MultiPoly > &factors, const MultiPoly &target, const std::string &var, const Rational &eval_point, int degree_bound)
const std::string & variable
ExprResult exp(const ExprPtr &expression, ComputationContext &context)
std::vector< int > Monomial
单项式类型,以整数向量表示各变量的指数
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
static bool diophantine_univariate_factors(const std::vector< MultiPoly > &factors, const std::string &var, const Rational &eval_point, Polynomial< Rational > &f1_uni, Polynomial< Rational > &f2_uni)
__attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorField gradient(const std const std::vector< std::string > & vars
static MultiPoly truncate_mod_var(const MultiPoly &poly, const std::string &var, int degree_bound)
将 MultiPoly 截断为关于指定变量次数 < degree_bound 的部分
static Polynomial< Rational > extended_gcd_poly(const Polynomial< Rational > &a, const Polynomial< Rational > &b, Polynomial< Rational > &s, Polynomial< Rational > &t)
一元多项式扩展 GCD(有理数域上)
const VectorField const VectorField & c
static std::vector< MultiPoly > lifting_shift_powers(const std::vector< std::string > &vars, int lift_var_idx, const Rational &eval_point, int degree_bound)
static MultiPoly truncated_factor_product(const std::vector< MultiPoly > &factors, const std::string &variable, int degree_bound)
static bool lifting_residual_is_zero(const MultiPoly &verify_error, int lift_var_idx, int k)
std::vector< MultiPoly > multivariate_hensel_lift(const MultiPoly &poly, const std::vector< Polynomial< Rational > > &univariate_factors, const std::string &lift_var, const Rational &eval_point, int degree_bound)
多元 Hensel 提升(单变量步)
static MultiPoly lifting_error_coefficient(const MultiPoly &error, const std::string &lift_var, int lift_var_idx, const Rational &eval_point, int k, const std::vector< MultiPoly > &shift_powers, const std::vector< std::string > &vars)
static bool diophantine_target(const MultiPoly &target, const std::string &var, const Rational &eval_point, const std::string &main_var, Polynomial< Rational > &target_uni)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
static bool apply_hensel_lift_steps(const MultiPoly &poly, std::vector< MultiPoly > &factors, const std::string &lift_var, int lift_var_idx, const Rational &eval_point, int degree_bound, int factor_count)
static std::vector< MultiPoly > embed_without_lifting(const std::vector< Polynomial< Rational > > &univariate_factors, const std::vector< std::string > &vars)
std::vector< MultiPoly > multivariate_diophantine(const std::vector< MultiPoly > &factors, const MultiPoly &target, const std::string &var, const Rational &eval_point, int degree_bound)
多元丢番图方程求解器
static MultiPoly embed_hensel_terms(const MultiPoly &polynomial, const std::vector< std::string > &variables)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & t
const std::string & main_var
static std::vector< MultiPoly > evaluated_lifting_cofactors(const std::vector< MultiPoly > &factors, const std::string &lift_var, const Rational &eval_point, const std::vector< std::string > &vars)