LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
multivariate_factor_evaluation.cpp
浏览该文件的文档.
3#include <algorithm>
4#include <map>
5#include <new>
6#include <optional>
7#include <stdexcept>
8#include <utility>
9
11
13 const MultiPoly& poly,
14 const std::string& main_var,
15 const std::map<std::string, Rational>& eval_points,
16 std::vector<Polynomial<Rational>>& univariate_factors)
17{
18 if (univariate_factors.empty()) { return false; }
19 const Polynomial<Rational> specialized = poly.eval(eval_points).to_univariate();
20 if (specialized.variable_name != main_var) { return false; }
21 Polynomial<Rational> product({Rational(1)}, main_var);
22 for (const auto& factor : univariate_factors) {
23 if (factor.variable_name != main_var || factor.is_zero()) { return false; }
24 product = product * factor;
25 }
26 auto [unit, remainder] = specialized.div_mod(product);
27 if (!remainder.is_zero() || unit.is_zero() || unit.degree() != 0) { return false; }
28 if (!(product * unit == specialized)) { return false; }
29 univariate_factors[0] = univariate_factors[0] * unit;
30 return true;
31}
32
34 const MultiPoly& primitive;
35 const std::string& main_variable;
36 const std::vector<std::string>& auxiliary;
37 const std::map<std::string, Rational>& zero_evaluation;
38 const std::vector<Rational>& base_constants;
40};
41
43 const LinearSamples& input, std::vector<std::vector<Rational>>& samples) {
44 const size_t factor_count = input.base_constants.size();
45 for (const auto& variable : input.auxiliary) {
46 auto sample = input.zero_evaluation;
47 sample[variable] = Rational(1);
48 MultiPoly evaluated = input.primitive.eval(sample);
49 if (evaluated.degree(input.main_variable) != input.primitive.degree(input.main_variable)) {
50 return Result<bool>::success(false);
51 }
52 auto factored = factor_univariate_bridge_checked(evaluated.to_univariate(), input.context);
53 if (!factored) { return Result<bool>::failure(factored.error()); }
54 if (factored.value().value.size() != factor_count) { return Result<bool>::success(false); }
55 std::vector<Rational> constants;
56 for (const auto& factor : factored.value().value) {
57 if (factor.degree() != 1) { return Result<bool>::success(false); }
58 constants.push_back(factor.make_monic().coeffs[0]);
59 }
60 samples.push_back(std::move(constants));
61 }
62 return Result<bool>::success(true);
63}
64
67 const std::vector<std::vector<Rational>>& samples;
68 std::vector<std::vector<size_t>> assignments;
69 std::vector<MultiPoly> found_factors;
70};
71
72static MultiPoly linear_assignment_factor(const LinearAssignments& search, size_t factor_index) {
73 const auto& variables = search.input.primitive.variables();
74 std::vector<MultiPoly::Term> terms;
75 Monomial main_monomial(variables.size(), 0);
76 const size_t main_index = static_cast<size_t>(std::find(
77 variables.begin(), variables.end(), search.input.main_variable) - variables.begin());
78 main_monomial[main_index] = 1;
79 terms.emplace_back(main_monomial, Rational(1));
80 Monomial constant_monomial(variables.size(), 0);
81 const auto& constant = search.input.base_constants[factor_index];
82 if (!constant.is_zero()) terms.emplace_back(constant_monomial, constant);
83 for (size_t variable_index = 0; variable_index < search.input.auxiliary.size(); ++variable_index) {
84 Rational coefficient = search.samples[variable_index]
85 [search.assignments[variable_index][factor_index]] - constant;
86 if (coefficient.is_zero()) { continue; }
87 Monomial monomial(variables.size(), 0);
88 const size_t index = static_cast<size_t>(std::find(
89 variables.begin(), variables.end(), search.input.auxiliary[variable_index]) - variables.begin());
90 monomial[index] = 1;
91 terms.emplace_back(std::move(monomial), coefficient);
92 }
93 return MultiPoly(std::move(terms), variables);
94}
95
97 auto step = search.input.context.consume_steps(1, "factor_multivariate");
98 if (!step) { return Result<bool>::failure(step.error()); }
99 std::vector<MultiPoly> candidates;
100 for (size_t i = 0; i < search.input.base_constants.size(); ++i) {
101 candidates.push_back(linear_assignment_factor(search, i));
102 }
103 MultiPoly product(Rational(1), search.input.primitive.variables());
104 for (const auto& candidate : candidates) product = product * candidate;
105 MultiPoly unit;
106 try {
107 unit = search.input.primitive.exact_div(product);
108 } catch (const std::runtime_error&) {
109 return Result<bool>::success(false);
110 }
111 if (unit.is_zero() || !unit.is_constant() ||
112 product * unit != search.input.primitive) { return Result<bool>::success(false); }
113 search.found_factors = std::move(candidates);
114 return Result<bool>::success(true);
115}
116
118 if (index == search.assignments.size()) { return verify_linear_assignment(search); }
119 auto& permutation = search.assignments[index];
120 std::sort(permutation.begin(), permutation.end());
121 do {
122 auto found = enumerate_linear_assignments(search, index + 1);
123 if (!found || found.value()) { return found; }
124 } while (std::next_permutation(permutation.begin(), permutation.end()));
125 return Result<bool>::success(false);
126}
127
128static std::optional<MultiFactorCheckedResult> factor_linear_assignments(
129 const MultiPoly& original, const LinearSamples& input) {
130 std::vector<std::vector<Rational>> samples;
131 auto collected = collect_linear_samples(input, samples);
132 if (!collected) { return MultiFactorCheckedResult::failure(collected.error()); }
133 if (!collected.value()) { return std::nullopt; }
134 LinearAssignments search{input, samples,
135 std::vector<std::vector<size_t>>(input.auxiliary.size(),
136 std::vector<size_t>(input.base_constants.size())), {}};
137 for (auto& assignment : search.assignments) {
138 for (size_t i = 0; i < assignment.size(); ++i) assignment[i] = i;
139 }
140 auto found = enumerate_linear_assignments(search, 0);
141 if (!found) { return MultiFactorCheckedResult::failure(found.error()); }
142 if (!found.value()) { return std::nullopt; }
143 return assemble_checked_factorization(original, search.found_factors,
144 std::vector<int>(search.found_factors.size(), 1), Completeness::Complete, {});
145}
146
147static std::optional<MultiFactorCheckedResult> factor_linear_hensel(
148 const MultiPoly& poly, const MultiPoly& primitive,
149 const std::string& main_variable, const std::vector<std::string>& auxiliary_variables,
150 const std::map<std::string, Rational>& zero_evaluation,
151 MathResult<std::vector<Polynomial<Rational>>>& base_value, ComputationContext& context) {
152 constexpr const char* operation = "factor_multivariate";
153 const auto& variables = primitive.variables();
154 auto hensel_step = context.consume_steps(
155 static_cast<size_t>(
156 std::max(1, primitive.degree(auxiliary_variables[0]))),
157 operation);
158 if (!hensel_step) {
159 return MultiFactorCheckedResult::failure(hensel_step.error());
160 }
161 std::vector<Polynomial<Rational>> prepared = base_value.value;
163 primitive, main_variable, zero_evaluation, prepared)) { return std::nullopt; }
164 auto lifted = multivariate_hensel_lift(
165 primitive, prepared, auxiliary_variables[0], Rational(0),
166 primitive.degree(auxiliary_variables[0]));
167 MultiPoly lifted_product(Rational(1), variables);
168 for (const auto& factor : lifted) {
169 lifted_product = lifted_product * factor;
170 }
171 if (lifted.size() > 1 && lifted_product == primitive) {
172 const bool all_linear = std::all_of(lifted.begin(), lifted.end(),
173 [](const MultiPoly& factor) { return factor.total_degree() == 1; });
175 poly, lifted, std::vector<int>(lifted.size(), 1),
177 all_linear ? std::string{} : "提升因子的不可约性尚未证明");
178 }
179 return std::nullopt;
180}
181
182std::optional<MultiFactorCheckedResult> factor_evaluated_linear(
183 const MultiPoly& poly, const MultiPoly& primitive,
184 const std::string& main_variable, ComputationContext& context) {
185 const auto& variables = primitive.variables();
186 std::vector<std::string> auxiliary_variables;
187 for (const auto& variable : variables) {
188 if (variable != main_variable) { auxiliary_variables.push_back(variable); }
189 }
190 std::map<std::string, Rational> zero_evaluation;
191 for (const auto& variable : auxiliary_variables) {
192 zero_evaluation[variable] = Rational(0);
193 }
194 MultiPoly evaluated = primitive.eval(zero_evaluation);
195 if (evaluated.degree(main_variable) != primitive.degree(main_variable)) { return std::nullopt; }
196 Polynomial<Rational> base_poly = evaluated.to_univariate();
197 auto base_result =
199 if (!base_result) {
200 return MultiFactorCheckedResult::failure(base_result.error());
201 }
202 auto base_value = std::move(base_result.value());
203 bool all_linear = base_value.value.size() > 1;
204 for (const auto& factor : base_value.value) {
205 all_linear = all_linear && factor.degree() == 1;
206 }
207 if (!all_linear) { return std::nullopt; }
208 if (auxiliary_variables.size() == 1) {
209 auto hensel = factor_linear_hensel(poly, primitive, main_variable,
210 auxiliary_variables, zero_evaluation, base_value, context);
211 if (hensel) { return hensel; }
212 }
213 std::vector<Rational> base_constants;
214 for (const auto& factor : base_value.value) {
215 base_constants.push_back(factor.make_monic().coeffs[0]);
216 }
217 LinearSamples input{primitive, main_variable, auxiliary_variables,
218 zero_evaluation, base_constants, context};
219 return factor_linear_assignments(poly, input);
220}
221
222}
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
一元多项式模板类
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
std::string variable_name
变量名
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static Result< bool > collect_linear_samples(const LinearSamples &input, std::vector< std::vector< Rational > > &samples)
static MultiPoly linear_assignment_factor(const LinearAssignments &search, size_t factor_index)
MultiFactorCheckedResult assemble_checked_factorization(const MultiPoly &original, const std::vector< MultiPoly > &factors, const std::vector< int > &multiplicities, Completeness completeness, std::string reason)
static Result< bool > enumerate_linear_assignments(LinearAssignments &search, size_t index)
std::optional< MultiFactorCheckedResult > factor_evaluated_linear(const MultiPoly &original, const MultiPoly &primitive, const std::string &main_variable, ComputationContext &context)
static Result< bool > verify_linear_assignment(LinearAssignments &search)
static std::optional< MultiFactorCheckedResult > factor_linear_hensel(const MultiPoly &poly, const MultiPoly &primitive, const std::string &main_variable, const std::vector< std::string > &auxiliary_variables, const std::map< std::string, Rational > &zero_evaluation, MathResult< std::vector< Polynomial< Rational > > > &base_value, ComputationContext &context)
static std::optional< MultiFactorCheckedResult > factor_linear_assignments(const MultiPoly &original, const LinearSamples &input)
static bool restore_specialization_unit(const MultiPoly &poly, const std::string &main_var, const std::map< std::string, Rational > &eval_points, std::vector< Polynomial< Rational > > &univariate_factors)
const std::string & variable
std::vector< int > Monomial
单项式类型,以整数向量表示各变量的指数
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
UnivariateFactorResult factor_univariate_bridge_checked(const Polynomial< Rational > &polynomial, ComputationContext &context)
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 提升(单变量步)
const std::string & unit
const std::string & main_var