LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_factor.cpp
浏览该文件的文档.
2#include <map>
3#include <vector>
4#include <string>
5#include <algorithm>
6#include <set>
7#include <optional>
8#include "symbolic.hpp"
10#include "poly_utils.hpp"
15#include "solve_polynomial.hpp"
16#include "solve_strategies.hpp"
18
19namespace LMCAS {
20
21namespace {
22
23
24/// 多元因式分解辅助函数
25
26static std::optional<int> polynomial_exponent(
27 const std::shared_ptr<const SymbolicNode>& node) {
28 auto number = std::dynamic_pointer_cast<const NumberNode>(node);
29 if (!number) { return std::nullopt; }
30 BigInt exponent;
31 if (std::holds_alternative<BigInt>(number->value())) {
32 exponent = std::get<BigInt>(number->value());
33 } else {
34 const auto& rational = std::get<Rational>(number->value());
35 if (!rational.is_integer()) { return std::nullopt; }
36 exponent = rational.to_bigint();
37 }
38 if (exponent.is_negative() || exponent > BigInt(100)) { return std::nullopt; }
39 return static_cast<int>(exponent.try_to_int64().value());
40}
41
42static bool is_poly_expr_node(const std::shared_ptr<const SymbolicNode>& node) {
43 if (!node) { return false; }
44 if (std::dynamic_pointer_cast<const NumberNode>(node)) { return true; }
45 if (auto variable = std::dynamic_pointer_cast<const VariableNode>(node)) {
46 return !variable->is_constant();
47 }
48
49 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
50 for (const auto& op : add->operands()) {
51 if (!is_poly_expr_node(op)) { return false; }
52 }
53 return true;
54 }
55
56 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
57 for (const auto& op : mul->operands()) {
58 if (!is_poly_expr_node(op)) { return false; }
59 }
60 return true;
61 }
62
63 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
64 return polynomial_exponent(pow->exponent()).has_value() &&
65 is_poly_expr_node(pow->base());
66 }
67
68 return false;
69}
70
71}
72
73static LMCAS::MultiPoly symbolic_node_to_multipoly(
74 const std::shared_ptr<const SymbolicNode>& node,
75 const std::vector<std::string>& vars)
76{
77 if (!node) { return LMCAS::MultiPoly(Rational(0), vars); }
78
79 if (auto num = std::dynamic_pointer_cast<const NumberNode>(node)) {
80 return LMCAS::MultiPoly(exact_number_as_rational(*num), vars);
81 }
82
83 if (auto var_node = std::dynamic_pointer_cast<const VariableNode>(node)) {
84 LMCAS::Monomial mono(vars.size(), 0);
85 for (size_t i = 0; i < vars.size(); ++i) {
86 if (vars[i] == var_node->name()) {
87 mono[i] = 1;
88 break;
89 }
90 }
91 std::vector<LMCAS::MultiPoly::Term> terms;
92 terms.push_back({mono, Rational(1)});
93 return LMCAS::MultiPoly(std::move(terms), vars);
94 }
95
96 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
97 LMCAS::MultiPoly result(Rational(0), vars);
98 for (const auto& op : add->operands()) {
99 result = result + symbolic_node_to_multipoly(op, vars);
100 }
101 return result;
102 }
103
104 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
105 LMCAS::MultiPoly result(Rational(1), vars);
106 for (const auto& op : mul->operands()) {
107 result = result * symbolic_node_to_multipoly(op, vars);
108 }
109 return result;
110 }
111
112 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
113 auto base_poly = symbolic_node_to_multipoly(pow->base(), vars);
114 const int exp_val = polynomial_exponent(pow->exponent()).value();
115 if (exp_val == 0) { return LMCAS::MultiPoly(Rational(1), vars); }
116 LMCAS::MultiPoly result(Rational(1), vars);
117 for (int i = 0; i < exp_val; ++i) {
118 result = result * base_poly;
119 }
120 return result;
121 }
122
123 return LMCAS::MultiPoly(Rational(0), vars);
124}
125
126static std::shared_ptr<SymbolicExpr> multipoly_to_symbolic(const LMCAS::MultiPoly& poly, ComputationContext& context) {
127
128 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
129 (context).limits().max_ast_nodes, "transform");
130 if (poly.is_zero()) { return SymbolicExpr::number(0); }
131
132 const auto& vars = poly.variables();
133 const auto& terms = poly.terms();
134
135 std::vector<std::shared_ptr<SymbolicExpr>> term_exprs;
136 term_exprs.reserve(terms.size());
137
138 for (const auto& [mono, coeff] : terms) {
139 term_exprs.push_back(
141 }
142
143 if (term_exprs.empty()) { return SymbolicExpr::number(0); }
144 if (term_exprs.size() == 1) { return detail::make_expression_ptr(detail::normalize_node(detail::node(term_exprs[0]), transform_budget)); }
145
146 auto result = term_exprs[0];
147 for (size_t i = 1; i < term_exprs.size(); ++i) {
148 result = SymbolicExpr::add(result, term_exprs[i]);
149 }
150 return detail::make_expression_ptr(detail::normalize_node(detail::node(result), transform_budget));
151}
152
153static std::optional<ExpressionResult> factor_numeric_content(
154 const std::shared_ptr<SymbolicExpr>& simp,
155 const std::shared_ptr<const AddNode>& add_node, ComputationContext& context) {
156 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
157 (context).limits().max_ast_nodes, "transform");
158 auto content_result =
160 if (!content_result) {
161 if (content_result.error().code == CasErrc::UnsupportedExpression) {
162 return std::nullopt;
163 }
165 content_result.error());
166 }
167 const Rational content_value = content_result.value();
168 if (content_value != Rational(0) && content_value != Rational(1)) {
169 auto content = content_value.is_integer()
170 ? SymbolicExpr::number(content_value.to_bigint())
171 : SymbolicExpr::number(content_value);
172 const Rational inverse_value = Rational(1) / content_value;
173 auto inverse_content = inverse_value.is_integer()
174 ? SymbolicExpr::number(inverse_value.to_bigint())
175 : SymbolicExpr::number(inverse_value);
176 std::vector<std::shared_ptr<const SymbolicNode>> primitive_terms;
177 primitive_terms.reserve(add_node->operands().size());
178 for (const auto& operand : add_node->operands()) {
179 auto term = LMCAS::detail::make_expression_ptr(operand);
180 auto primitive_term = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(term, inverse_content)), transform_budget));
181 primitive_terms.push_back(LMCAS::detail::node(primitive_term));
182 }
183 auto primitive_sum = LMCAS::detail::make_expression_ptr(
184 LMCAS::detail::make_node<AddNode>(primitive_terms));
185 auto factored_primitive =
186 primitive_sum->factor_checked(context);
187 if (!factored_primitive) { return factored_primitive; }
189 content, factored_primitive.value())), transform_budget));
190 }
191 return std::nullopt;
192}
193
194static std::optional<ExpressionResult> factor_common_polynomial(
195 const std::shared_ptr<const AddNode>& add_node, ComputationContext& context) {
196 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
197 (context).limits().max_ast_nodes, "transform");
198 std::shared_ptr<SymbolicExpr> common = nullptr;
199 for (const auto& op : add_node->operands()) {
201 if (!common) {
202 common = expr_op;
203 } else {
204 auto gcd = LMCAS::symbolic_polynomial_gcd(*common, *expr_op, context);
205 if (!gcd) {
206 if (gcd.error().code == CasErrc::UnsupportedExpression) {
207 return std::nullopt;
208 }
209 return gcd;
210 }
211 common = std::move(gcd.value());
212 }
213 }
214
215 if (common && !common->is_one() && !common->is_zero()) {
216 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
217 for (const auto& op : add_node->operands()) {
219
220 auto inv_common = SymbolicExpr::power(common, SymbolicExpr::number(-1));
221 auto quot = SymbolicExpr::multiply(term, inv_common);
222 quot = detail::make_expression_ptr(detail::normalize_node(detail::node(quot), transform_budget));
223 new_ops.push_back(LMCAS::detail::node(quot));
224 }
226
227 auto factored_sum = new_sum->factor_checked(context);
228 if (!factored_sum) { return factored_sum; }
229
230 std::vector<std::shared_ptr<const SymbolicNode>> final_ops = {
231 LMCAS::detail::node(common),
232 LMCAS::detail::node(factored_sum.value())};
234 }
235 return std::nullopt;
236}
237
238static std::vector<std::shared_ptr<const SymbolicNode>> rational_root_factors(
239 const std::vector<Rational>& roots, const Rational& leading,
240 const std::shared_ptr<SymbolicExpr>& x_node, ComputationContext& context) {
241
242 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
243 (context).limits().max_ast_nodes, "transform");
244 std::vector<std::shared_ptr<const SymbolicNode>> factors;
245
246 if (!(leading == Rational(1))) {
247 factors.push_back(LMCAS::detail::node(SymbolicExpr::number(leading)));
248 }
249
250 for (const auto& r : roots) {
251 std::shared_ptr<SymbolicExpr> linear_factor;
252 if (r == Rational(0)) {
253 linear_factor = x_node;
254 } else {
255 auto neg_r = SymbolicExpr::number(Rational(0) - r);
256 linear_factor = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(x_node, neg_r)), transform_budget));
257 }
258 factors.push_back(LMCAS::detail::node(linear_factor));
259 }
260 return factors;
261}
262
264 const std::vector<Rational>& roots, const Rational& leading,
265 const std::string& var) {
266 LMCAS::Polynomial<Rational> factored_product({leading}, var);
267 for (const auto& r : roots) {
268 LMCAS::Polynomial<Rational> lin({Rational(0) - r, Rational(1)}, var);
269 factored_product = factored_product * lin;
270 }
271 return factored_product;
272}
273
275 std::vector<std::shared_ptr<const SymbolicNode>> factors;
278};
279
281 const Polynomial<Rational>& polynomial,
282 const std::vector<Rational>& roots, const std::string& variable, ComputationContext& context) {
283 auto symbol =
285 const auto leading = polynomial.lead_coeff();
286 auto factors = rational_root_factors(roots, leading, symbol, context);
287 auto product = rational_root_product(roots, leading, variable);
288 auto [quotient, remainder] = polynomial.div_mod(product);
289 return {
290 std::move(factors), std::move(quotient), std::move(remainder)};
291}
292
293static std::optional<ExpressionResult> factor_rational_univariate(
294 const std::shared_ptr<SymbolicExpr>& simp, const std::string& var,
296 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
297 (context).limits().max_ast_nodes, "transform");
298 try {
299 auto converted = symbolic_to_poly<Rational>(simp, var);
300 if (!converted) {
301 if (converted.error().code == CasErrc::UnsupportedExpression) return std::nullopt;
302 return ExpressionResult::failure(converted.error());
303 }
304 const auto& poly = converted.value();
305 if (poly.degree() < 2) { return std::nullopt; }
306 auto roots = find_rational_roots(poly);
307 if (roots.empty()) { return std::nullopt; }
308 auto reconstruction =
310 if (!reconstruction.remainder.is_zero()) return std::nullopt;
311 auto& factors = reconstruction.factors;
312 auto& quotient = reconstruction.quotient;
313 if (quotient.degree() >= 1) {
314 auto q_expr = detail::make_expression_ptr(detail::normalize_node(detail::node(poly_to_symbolic(quotient)), transform_budget));
315 if (quotient.degree() >= 2) {
316 auto q_factored = q_expr->factor_checked(context);
317 if (!q_factored) { return q_factored; }
318 factors.push_back(detail::node(q_factored.value()));
319 } else {
320 factors.push_back(detail::node(q_expr));
321 }
322 }
323 if (factors.size() > 1) {
325 }
326 if (factors.size() == 1) { return detail::make_expression_ptr(factors[0]); }
327 } catch (const std::invalid_argument&) {
328 return std::nullopt;
329 } catch (const std::out_of_range&) {
330 return std::nullopt;
331 }
332 return std::nullopt;
333}
334
335static std::optional<ExpressionResult> factor_symbolic_quadratic(
336 const std::shared_ptr<SymbolicExpr>& simp, const std::string& var,
338 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
339 (context).limits().max_ast_nodes, "transform");
340 try {
341 auto converted = LMCAS::symbolic_to_poly<LMCAS::SymbolicPolyCoeff>(simp, var);
342 if (!converted) {
343 if (converted.error().code == CasErrc::UnsupportedExpression) return std::nullopt;
344 return ExpressionResult::failure(converted.error());
345 }
346 const auto& poly = converted.value();
347 if (poly.degree() == 2) {
348 auto solved =
350 if (!solved) {
352 solved.error());
353 }
354 auto solutions = std::move(solved.value());
355 if (solutions.size() == 2) {
356 auto leading = poly.coeffs[2].val;
357 if (!leading) { leading = SymbolicExpr::number(1); }
358 leading = detail::make_expression_ptr(detail::normalize_node(detail::node(leading), transform_budget));
359
361
362 auto t1 = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(x_node, SymbolicExpr::multiply(solutions[0], SymbolicExpr::number(-1)))), transform_budget));
363 auto t2 = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(x_node, SymbolicExpr::multiply(solutions[1], SymbolicExpr::number(-1)))), transform_budget));
364
365 std::vector<std::shared_ptr<const SymbolicNode>> factors;
366 if (!leading->is_one()) { factors.push_back(LMCAS::detail::node(leading)); }
367 factors.push_back(LMCAS::detail::node(t1));
368 factors.push_back(LMCAS::detail::node(t2));
369
371 }
372 }
373 } catch (const std::invalid_argument&) {
374 return std::nullopt;
375 } catch (const std::out_of_range&) {
376 return std::nullopt;
377 }
378 return std::nullopt;
379}
380
381static std::shared_ptr<SymbolicExpr> multivariate_factor_expression(
383 std::vector<std::shared_ptr<const SymbolicNode>> factor_nodes;
384
385 if (!(result.constant == Rational(1))) {
386 factor_nodes.push_back(
387 LMCAS::detail::node(SymbolicExpr::number(result.constant)));
388 }
389
390 for (size_t i = 0; i < result.factors.size(); ++i) {
391 auto factor_expr = multipoly_to_symbolic(result.factors[i], context);
392 if (!factor_expr || factor_expr->is_zero()) { continue; }
393
394 int mult = (i < result.multiplicities.size())
395 ? result.multiplicities[i] : 1;
396
397 if (mult == 1) {
398 factor_nodes.push_back(LMCAS::detail::node(factor_expr));
399 } else {
400 auto pow_expr = SymbolicExpr::power(
401 factor_expr, SymbolicExpr::number(mult));
402 factor_nodes.push_back(LMCAS::detail::node(pow_expr));
403 }
404 }
405
406 if (factor_nodes.size() > 1) {
408 LMCAS::detail::make_node<MultiplyNode>(std::move(factor_nodes)));
409 } else if (factor_nodes.size() == 1) {
410 return LMCAS::detail::make_expression_ptr(factor_nodes[0]);
411 }
412 return nullptr;
413}
414
415static std::optional<ExpressionResult> factor_multivariate_expression(
416 const std::shared_ptr<SymbolicExpr>& simp,
417 const std::set<std::string>& factor_variables, ComputationContext& context) {
418 if (!is_poly_expr_node(detail::node(simp))) { return std::nullopt; }
419 try {
420 std::vector<std::string> var_list(
421 factor_variables.begin(), factor_variables.end());
422 auto mpoly = symbolic_node_to_multipoly(LMCAS::detail::node(simp), var_list);
423
424 if (!mpoly.is_zero() && !mpoly.is_constant()) {
425 auto factorization =
427 mpoly, context);
428 if (!factorization) {
430 factorization.error());
431 }
432 const auto& checked = factorization.value();
433 if (checked.completeness !=
435 return simp;
436 }
437 const auto& result = checked.value;
438
439 if (!result.factors.empty()) {
440 auto expression = multivariate_factor_expression(result, context);
441 if (expression) { return expression; }
442 }
443 }
444 } catch (const std::invalid_argument&) {
445 return std::nullopt;
446 } catch (const std::out_of_range&) {
447 return std::nullopt;
448 }
449 return std::nullopt;
450}
451
452static std::optional<ExpressionResult> reconstruct_rational_root_factors(
453 const Polynomial<Rational>& polynomial, const std::vector<Rational>& roots,
454 const std::string& var, ComputationContext& context) {
455
456 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
457 (context).limits().max_ast_nodes, "transform");
458 auto reconstruction =
459 reconstruct_rational_roots(polynomial, roots, var, context);
460 auto& factors = reconstruction.factors;
461 auto& quotient = reconstruction.quotient;
462 const auto& remainder = reconstruction.remainder;
463 if (remainder.is_zero() && quotient.degree() >= 1) {
464 auto q_expr = detail::make_expression_ptr(detail::normalize_node(detail::node(LMCAS::poly_to_symbolic(quotient)), transform_budget));
465 factors.push_back(LMCAS::detail::node(q_expr));
466 } else if (remainder.is_zero() && !quotient.is_zero() && quotient.degree() == 0) {
467 if (!(quotient.coeffs[0] == Rational(1))) {
468 factors.push_back(
469 LMCAS::detail::node(SymbolicExpr::number(quotient.coeffs[0])));
470 }
471 }
472 if (factors.size() > 1) {
475 }
476 return std::nullopt;
477}
478
479static std::optional<ExpressionResult> factor_variable_rational_roots(
480 const std::shared_ptr<SymbolicExpr>& simp, const std::string& var, ComputationContext& context) {
481 try {
482 auto poly = LMCAS::symbolic_to_poly<LMCAS::SymbolicPolyCoeff>(simp, var);
483 if (!poly) {
484 if (poly.error().code == CasErrc::UnsupportedExpression) { return std::nullopt; }
485 return ExpressionResult::failure(poly.error());
486 }
487 if (poly.value().degree() >= 2) {
488 auto converted = LMCAS::symbolic_to_poly<Rational>(simp, var);
489 if (!converted) {
490 if (converted.error().code == CasErrc::UnsupportedExpression) { return std::nullopt; }
491 return ExpressionResult::failure(converted.error());
492 }
493 const auto& poly_r = converted.value();
494 auto roots = LMCAS::find_rational_roots(poly_r);
495 if (!roots.empty()) {
496 return reconstruct_rational_root_factors(poly_r, roots, var, context);
497 }
498 }
499 } catch (const std::invalid_argument&) {
500 return std::nullopt;
501 } catch (const std::out_of_range&) {
502 return std::nullopt;
503 }
504 return std::nullopt;
505}
506
508 const std::shared_ptr<SymbolicExpr>& simp,
510 const auto transform_variables = LMCAS::free_variables(LMCAS::detail::node(simp));
511 if (transform_variables.empty()) { return simp; }
512
513 auto converted = LMCAS::factor_transcendental(
514 simp, *transform_variables.begin(), context);
515 if (!converted) { return ExpressionResult::failure(converted.error()); }
516 const auto& trans_factors = converted.value();
517 if (trans_factors.size() > 1) {
518 std::vector<std::shared_ptr<const SymbolicNode>> factor_nodes;
519 factor_nodes.reserve(trans_factors.size());
520 for (const auto& factor : trans_factors) {
521 if (factor && LMCAS::detail::node(factor)) {
522 factor_nodes.push_back(LMCAS::detail::node(factor));
523 }
524 }
525 if (factor_nodes.size() > 1) {
527 LMCAS::detail::make_node<MultiplyNode>(std::move(factor_nodes)));
528 }
529 }
530 return simp;
531}
532
533LMCAS::ExpressionResult SymbolicExpr::factor_impl(
535 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
536 context.limits().max_ast_nodes, "factor");
537 auto simp = detail::make_expression_ptr(
538 detail::normalize_node(detail::node(*this), budget));
539 auto add_node = std::dynamic_pointer_cast<const AddNode>(detail::node(simp));
540 if (!add_node) { return factor_transcendental_expression(simp, context); }
541
542 auto content = factor_numeric_content(simp, add_node, context);
543 if (content) { return std::move(*content); }
544 auto common = factor_common_polynomial(add_node, context);
545 if (common) { return std::move(*common); }
546
547 auto variables = free_variables(detail::node(simp));
548 if (variables.size() == 1) {
549 const auto& variable = *variables.begin();
551 if (rational) { return std::move(*rational); }
552 auto quadratic = factor_symbolic_quadratic(simp, variable, context);
553 if (quadratic) { return std::move(*quadratic); }
554 }
555 if (variables.size() > 1) {
556 auto multivariate = factor_multivariate_expression(simp, variables, context);
557 if (multivariate) { return std::move(*multivariate); }
558 for (const auto& variable : variables) {
559 auto factored = factor_variable_rational_roots(simp, variable, context);
560 if (factored) { return std::move(*factored); }
561 }
562 }
564}
565
566LMCAS::ExpressionResult SymbolicExpr::factor_checked(
567 LMCAS::ComputationContext& context) const
568{
569 constexpr const char* operation = "factor";
570 auto budget = context.consume_steps(1, operation);
571 if (!budget) { return LMCAS::ExpressionResult::failure(budget.error()); }
572 try {
573 return factor_impl(context);
574 } catch (const CasError& error) {
576 } catch (const std::bad_alloc&) {
579 "allocation failed while factoring expression", operation);
580 } catch (const std::length_error& error) {
582 LMCAS::CasErrc::ResourceLimit, error.what(), operation);
583 } catch (const std::exception& ex) {
585 LMCAS::CasErrc::InternalInvariant, ex.what(), operation);
586 }
587}
588
589LMCAS::ExpressionResult SymbolicExpr::factor_checked() const
590{
591 LMCAS::ComputationContext context;
592 return factor_checked(context);
593}
594
595
596}
一元多项式模板类
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
CoeffType lead_coeff() const
获取首项系数
static Result failure(CasErrc code, std::string message, std::string operation={})
多元多项式因式分解器公共 API。
static std::optional< int > polynomial_exponent(const std::shared_ptr< const SymbolicNode > &node)
多元因式分解辅助函数
static bool is_poly_expr_node(const std::shared_ptr< const SymbolicNode > &node)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
ComputationContext const std::string & operation
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr< SymbolicExpr > multipoly_term_to_expression(const Monomial &monomial, const Rational &coefficient, const std::vector< std::string > &variables)
std::shared_ptr< SymbolicExpr > num(int value)
static std::optional< ExpressionResult > factor_multivariate_expression(const std::shared_ptr< SymbolicExpr > &simp, const std::set< std::string > &factor_variables, ComputationContext &context)
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
const std::string & variable
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
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
__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
SymbolicGcdResult symbolic_polynomial_gcd(const SymbolicExpr &lhs, const SymbolicExpr &rhs, ComputationContext &context)
std::vector< std::shared_ptr< const SymbolicNode > > factors
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::vector< MultiPoly > factors
精确因子列表(各因子本原)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
static std::optional< ExpressionResult > reconstruct_rational_root_factors(const Polynomial< Rational > &polynomial, const std::vector< Rational > &roots, const std::string &var, ComputationContext &context)
MultiFactorCheckedResult factor_multivariate_checked(const MultiPoly &poly, ComputationContext &context)
static std::optional< ExpressionResult > factor_numeric_content(const std::shared_ptr< SymbolicExpr > &simp, const std::shared_ptr< const AddNode > &add_node, ComputationContext &context)
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
static std::vector< std::shared_ptr< const SymbolicNode > > rational_root_factors(const std::vector< Rational > &roots, const Rational &leading, const std::shared_ptr< SymbolicExpr > &x_node, ComputationContext &context)
static std::optional< ExpressionResult > factor_rational_univariate(const std::shared_ptr< SymbolicExpr > &simp, const std::string &var, ComputationContext &context)
static std::optional< ExpressionResult > factor_common_polynomial(const std::shared_ptr< const AddNode > &add_node, ComputationContext &context)
static std::optional< ExpressionResult > factor_variable_rational_roots(const std::shared_ptr< SymbolicExpr > &simp, const std::string &var, ComputationContext &context)
static RationalRootReconstruction reconstruct_rational_roots(const Polynomial< Rational > &polynomial, const std::vector< Rational > &roots, const std::string &variable, ComputationContext &context)
const ExprPtr RelationOp op
static std::shared_ptr< SymbolicExpr > multipoly_to_symbolic(const LMCAS::MultiPoly &poly, ComputationContext &context)
const ExprPtr & exponent
Result< std::vector< std::shared_ptr< SymbolicExpr > > > factor_transcendental(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context)
LMCAS::FiniteSolveResult solve_finite_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
static LMCAS::MultiPoly symbolic_node_to_multipoly(const std::shared_ptr< const SymbolicNode > &node, const std::vector< std::string > &vars)
std::set< std::string > free_variables(const detail::SymbolicNodePtr &expression, detail::RewriteBudget *budget)
static std::optional< ExpressionResult > factor_symbolic_quadratic(const std::shared_ptr< SymbolicExpr > &simp, const std::string &var, ComputationContext &context)
std::vector< Rational > find_rational_roots(const Polynomial< Rational > &poly)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
Rational exact_number_as_rational(const NumberNode &node)
Result< Rational > symbolic_polynomial_content(const SymbolicExpr &expression, ComputationContext &context)
Rational constant
数值常数因子
static std::shared_ptr< SymbolicExpr > multivariate_factor_expression(const MultiFactorResult &result, ComputationContext &context)
ExprResult rational(const Rational &value)
static ExpressionResult factor_transcendental_expression(const std::shared_ptr< SymbolicExpr > &simp, ComputationContext &context)
static Polynomial< Rational > rational_root_product(const std::vector< Rational > &roots, const Rational &leading, const std::string &var)
std::vector< int > multiplicities
各因子的重数
多项式转换与精确符号多项式代数。
方程求解策略调度器 solve_dispatch 及相关选项结构体.
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
内部 AST 定义。
混合超越方程不可约因式分解器公共 API.