27 const std::shared_ptr<const SymbolicNode>& node) {
28 auto number = std::dynamic_pointer_cast<const NumberNode>(node);
29 if (!number) {
return std::nullopt; }
31 if (std::holds_alternative<BigInt>(number->value())) {
32 exponent = std::get<BigInt>(number->value());
34 const auto&
rational = std::get<Rational>(number->value());
35 if (!
rational.is_integer()) {
return std::nullopt; }
38 if (
exponent.is_negative() ||
exponent > BigInt(100)) {
return std::nullopt; }
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)) {
49 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
50 for (
const auto&
op :
add->operands()) {
56 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
57 for (
const auto&
op :
mul->operands()) {
63 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
74 const std::shared_ptr<const SymbolicNode>& node,
75 const std::vector<std::string>&
vars)
77 if (!node) {
return LMCAS::MultiPoly(Rational(0),
vars); }
79 if (
auto num = std::dynamic_pointer_cast<const NumberNode>(node)) {
83 if (
auto var_node = std::dynamic_pointer_cast<const VariableNode>(node)) {
85 for (
size_t i = 0; i <
vars.size(); ++i) {
86 if (
vars[i] == var_node->name()) {
91 std::vector<LMCAS::MultiPoly::Term> terms;
92 terms.push_back({mono, Rational(1)});
93 return LMCAS::MultiPoly(std::move(terms),
vars);
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()) {
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()) {
112 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
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;
123 return LMCAS::MultiPoly(Rational(0),
vars);
129 (
context).limits().max_ast_nodes,
"transform");
130 if (poly.is_zero()) {
return SymbolicExpr::number(0); }
132 const auto&
vars = poly.variables();
133 const auto& terms = poly.terms();
135 std::vector<std::shared_ptr<SymbolicExpr>> term_exprs;
136 term_exprs.reserve(terms.size());
138 for (
const auto& [mono, coeff] : terms) {
139 term_exprs.push_back(
143 if (term_exprs.empty()) {
return SymbolicExpr::number(0); }
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]);
154 const std::shared_ptr<SymbolicExpr>& simp,
157 (
context).limits().max_ast_nodes,
"transform");
158 auto content_result =
160 if (!content_result) {
165 content_result.error());
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()) {
185 auto factored_primitive =
186 primitive_sum->factor_checked(
context);
187 if (!factored_primitive) {
return factored_primitive; }
189 content, factored_primitive.value())), transform_budget));
197 (
context).limits().max_ast_nodes,
"transform");
198 std::shared_ptr<SymbolicExpr> common =
nullptr;
199 for (
const auto&
op : add_node->operands()) {
211 common = std::move(gcd.value());
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()) {
220 auto inv_common = SymbolicExpr::power(common, SymbolicExpr::number(-1));
221 auto quot = SymbolicExpr::multiply(term, inv_common);
227 auto factored_sum = new_sum->factor_checked(
context);
228 if (!factored_sum) {
return factored_sum; }
230 std::vector<std::shared_ptr<const SymbolicNode>> final_ops = {
239 const std::vector<Rational>&
roots,
const Rational& leading,
243 (
context).limits().max_ast_nodes,
"transform");
244 std::vector<std::shared_ptr<const SymbolicNode>> factors;
246 if (!(leading == Rational(1))) {
250 for (
const auto&
r :
roots) {
251 std::shared_ptr<SymbolicExpr> linear_factor;
252 if (
r == Rational(0)) {
253 linear_factor = x_node;
255 auto neg_r = SymbolicExpr::number(Rational(0) -
r);
264 const std::vector<Rational>&
roots,
const Rational& leading,
265 const std::string& var) {
267 for (
const auto&
r :
roots) {
269 factored_product = factored_product * lin;
271 return factored_product;
275 std::vector<std::shared_ptr<const SymbolicNode>>
factors;
288 auto [quotient, remainder] = polynomial.
div_mod(product);
290 std::move(factors), std::move(quotient), std::move(remainder)};
294 const std::shared_ptr<SymbolicExpr>& simp,
const std::string& var,
297 (
context).limits().max_ast_nodes,
"transform");
299 auto converted = symbolic_to_poly<Rational>(simp, var);
304 const auto& poly = converted.value();
305 if (poly.degree() < 2) {
return std::nullopt; }
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) {
315 if (quotient.degree() >= 2) {
316 auto q_factored = q_expr->factor_checked(
context);
317 if (!q_factored) {
return q_factored; }
323 if (factors.size() > 1) {
327 }
catch (
const std::invalid_argument&) {
329 }
catch (
const std::out_of_range&) {
336 const std::shared_ptr<SymbolicExpr>& simp,
const std::string& var,
339 (
context).limits().max_ast_nodes,
"transform");
341 auto converted = LMCAS::symbolic_to_poly<LMCAS::SymbolicPolyCoeff>(simp, var);
346 const auto& poly = converted.value();
347 if (poly.degree() == 2) {
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); }
365 std::vector<std::shared_ptr<const SymbolicNode>> factors;
373 }
catch (
const std::invalid_argument&) {
375 }
catch (
const std::out_of_range&) {
383 std::vector<std::shared_ptr<const SymbolicNode>> factor_nodes;
385 if (!(result.
constant == Rational(1))) {
386 factor_nodes.push_back(
390 for (
size_t i = 0; i < result.
factors.size(); ++i) {
392 if (!factor_expr || factor_expr->is_zero()) {
continue; }
400 auto pow_expr = SymbolicExpr::power(
401 factor_expr, SymbolicExpr::number(mult));
406 if (factor_nodes.size() > 1) {
409 }
else if (factor_nodes.size() == 1) {
416 const std::shared_ptr<SymbolicExpr>& simp,
418 if (!is_poly_expr_node(
detail::node(simp))) {
return std::nullopt; }
420 std::vector<std::string> var_list(
421 factor_variables.begin(), factor_variables.end());
424 if (!mpoly.is_zero() && !mpoly.is_constant()) {
428 if (!factorization) {
430 factorization.error());
432 const auto& checked = factorization.value();
433 if (checked.completeness !=
437 const auto& result = checked.value;
439 if (!result.factors.empty()) {
441 if (expression) {
return expression; }
444 }
catch (
const std::invalid_argument&) {
446 }
catch (
const std::out_of_range&) {
457 (
context).limits().max_ast_nodes,
"transform");
458 auto reconstruction =
460 auto& factors = reconstruction.factors;
461 auto& quotient = reconstruction.quotient;
462 const auto& remainder = reconstruction.remainder;
463 if (remainder.is_zero() && quotient.degree() >= 1) {
466 }
else if (remainder.is_zero() && !quotient.is_zero() && quotient.degree() == 0) {
467 if (!(quotient.coeffs[0] == Rational(1))) {
472 if (factors.size() > 1) {
482 auto poly = LMCAS::symbolic_to_poly<LMCAS::SymbolicPolyCoeff>(simp, var);
487 if (poly.value().degree() >= 2) {
488 auto converted = LMCAS::symbolic_to_poly<Rational>(simp, var);
493 const auto& poly_r = converted.value();
495 if (!
roots.empty()) {
499 }
catch (
const std::invalid_argument&) {
501 }
catch (
const std::out_of_range&) {
508 const std::shared_ptr<SymbolicExpr>& simp,
511 if (transform_variables.empty()) {
return simp; }
514 simp, *transform_variables.begin(),
context);
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) {
525 if (factor_nodes.size() > 1) {
535 detail::RewriteBudget budget(
context,
context.limits().max_recursion_depth,
536 context.limits().max_ast_nodes,
"factor");
539 auto add_node = std::dynamic_pointer_cast<const AddNode>(
detail::node(simp));
543 if (content) {
return std::move(*content); }
545 if (common) {
return std::move(*common); }
548 if (variables.size() == 1) {
549 const auto&
variable = *variables.begin();
553 if (quadratic) {
return std::move(*quadratic); }
555 if (variables.size() > 1) {
557 if (multivariate) {
return std::move(*multivariate); }
558 for (
const auto&
variable : variables) {
560 if (factored) {
return std::move(*factored); }
567 LMCAS::ComputationContext&
context)
const
569 constexpr const char*
operation =
"factor";
576 }
catch (
const std::bad_alloc&) {
579 "allocation failed while factoring expression", operation);
580 }
catch (
const std::length_error& error) {
583 }
catch (
const std::exception& ex) {
591 LMCAS::ComputationContext
context;
592 return factor_checked(
context);
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={})
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
精确因子列表(各因子本原)
Polynomial< Rational > remainder
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)
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
Polynomial< Rational > quotient
Rational exact_number_as_rational(const NumberNode &node)
Result< Rational > symbolic_polynomial_content(const SymbolicExpr &expression, ComputationContext &context)
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 及其工厂方法,运算接口.