11#include "lmmc/config.h"
12#include "lmmc/numeric.h"
42 if (deg < 0 || deg > p.
degree()) {
43 return SymbolicExpr::number(0);
49 const std::shared_ptr<SymbolicExpr>& expr,
50 const std::string& var,
52 const SolveOptions& opts);
78 auto zero = SymbolicExpr::number(0);
82 SymbolicExpr::multiply(
83 leading, SymbolicExpr::variable(
variable)),
84 SymbolicExpr::multiply(
85 SymbolicExpr::number(-1), constant),
103 (
context).limits().max_ast_nodes,
"transform");
105 auto constant =
get_coeff(polynomial, 0);
107 SymbolicExpr::power(linear, SymbolicExpr::number(2)),
108 SymbolicExpr::multiply(
109 SymbolicExpr::number(-4),
110 SymbolicExpr::multiply(leading, constant)))), transform_budget));
120 std::vector<std::shared_ptr<const SymbolicNode>>{
122 auto negative_linear =
123 SymbolicExpr::multiply(SymbolicExpr::number(-1), linear);
125 SymbolicExpr::multiply(SymbolicExpr::number(2), leading);
127 SymbolicExpr::add(negative_linear, radical),
132 SymbolicExpr::multiply(
133 SymbolicExpr::number(-1), radical)),
148 auto zero = SymbolicExpr::number(0);
157}
catch (
const CasError& error) {
159}
catch (
const std::bad_alloc&) {
161}
catch (
const std::length_error& error) {
163}
catch (
const std::exception& error) {
172 (
context).limits().max_ast_nodes,
"transform");
174 std::optional<detail::AssumptionFacts> adapter;
176 adapter.emplace(*
context.assumptions());
181 int degree = polynomial.
degree();
182 while (degree >= 0) {
204 polynomial, leading, facts,
context);
207 SymbolicExpr::multiply(
208 SymbolicExpr::number(-1),
210 leading)), transform_budget));
215}
catch (
const CasError& error) {
217}
catch (
const std::bad_alloc&) {
219}
catch (
const std::length_error& error) {
221}
catch (
const std::exception& error) {
227 std::size_t& multiplicity) {
229 if (
auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
232 std::dynamic_pointer_cast<const NumberNode>(power->exponent()),
exponent)) {
234 if (
exponent > BigInt(
static_cast<std::int64_t
>(std::numeric_limits<int>::max()))) {
237 multiplicity =
static_cast<std::size_t
>(*
exponent.try_to_int64());
245 std::vector<FiniteSolution>& finite) {
247 if (
value.multiplicity > std::numeric_limits<std::size_t>::max() / multiplicity) {
250 value.multiplicity *= multiplicity;
251 auto existing = std::find_if(finite.begin(), finite.end(), [&](
const FiniteSolution& candidate) {
252 return detail::node(candidate.value)->equals(*detail::node(value.value)) &&
253 candidate.conditions.empty() && value.conditions.empty();
255 if (existing == finite.end()) { finite.push_back(std::move(
value)); }
257 if (existing->multiplicity > std::numeric_limits<std::size_t>::max() -
value.multiplicity) {
260 existing->multiplicity +=
value.multiplicity;
267 const std::set<std::string>& original_names, std::vector<ParametricSolution>& families) {
268 for (
auto& family : values.
values) {
269 auto occupied = original_names;
271 occupied.insert(value_names.begin(), value_names.end());
272 for (
auto& parameter : family.integer_parameters) {
273 if (!original_names.count(parameter)) {
continue; }
274 std::string fresh =
"_k";
275 for (std::size_t suffix = 1; occupied.count(fresh); ++suffix) {
276 fresh =
"_k" + std::to_string(suffix);
278 auto symbol = SymbolicExpr::variable(fresh);
280 for (
auto& condition : family.conditions) {
284 occupied.insert(fresh);
286 families.push_back(std::move(family));
292 auto product = std::dynamic_pointer_cast<const MultiplyNode>(
detail::node(expression));
293 if (!product) {
return std::nullopt; }
294 std::vector<FiniteSolution> finite;
295 std::vector<ParametricSolution> families;
297 for (
const auto& node : product->operands()) {
298 std::size_t multiplicity = 1;
304 if (std::holds_alternative<EmptySolutions>(solved.value())) {
continue; }
306 if (
auto values = std::get_if<FiniteSolutions>(&solved.value())) {
309 }
else if (
auto values = std::get_if<ParametricSolutions>(&solved.value())) {
321 constexpr const char* operation =
"solve_equation";
322 std::vector<FiniteSolution> solutions;
323 for (
auto& root :
roots) {
324 auto root_step =
context.consume_steps(1, operation);
331 "polynomial solver produced a null root", operation);
333 auto existing = std::find_if(
334 solutions.begin(), solutions.end(),
336 return LMCAS::detail::node(solution.value)->equals(
337 *LMCAS::detail::node(root));
339 if (existing != solutions.end()) {
340 ++existing->multiplicity;
353 if (remainder.
degree() == 4 &&
354 remainder.
coeffs[3] == Rational(0) &&
355 remainder.
coeffs[1] == Rational(0)) {
357 SymbolicExpr::number(remainder.
coeffs[4]),
358 SymbolicExpr::number(remainder.
coeffs[2]),
361 auto expression = poly_to_symbolic(remainder);
362 std::vector<ExprPtr> represented_roots;
363 for (
int index = 0; index < remainder.
degree(); ++index) {
366 represented_roots.push_back(std::move(root.value()));
368 return represented_roots;
373 std::vector<ExprPtr> factor_roots;
374 const bool bounded_candidates =
376 if (bounded_candidates) {
379 auto division = remainder.
div_mod(divisor);
380 if (!division.second.
is_zero()) {
continue; }
381 factor_roots.push_back(SymbolicExpr::number(root));
382 remainder = std::move(division.first);
385 if (remainder.
degree() == 1) {
386 factor_roots.push_back(SymbolicExpr::number(-remainder.
coeffs[0] / remainder.
coeffs[1]));
387 }
else if (remainder.
degree() == 2) {
389 SymbolicExpr::number(remainder.
coeffs[2]),
390 SymbolicExpr::number(remainder.
coeffs[1]),
393 for (
const auto& root : quadratic.value()) {
397 }
else if (remainder.
degree() > 2) {
400 factor_roots.insert(factor_roots.end(), represented_roots.value().begin(), represented_roots.value().end());
406 const std::string& var,
410 std::vector<ExprPtr>
roots;
412 auto step =
context.consume_steps(1,
"solve.exact");
416 const auto& factor_roots = solved.value();
417 if (factor_roots.size() !=
static_cast<std::size_t
>(factor.first.degree()))
419 "square-free factor root count mismatch",
"solve.exact"); }
420 for (
int copy = 0; copy < factor.second; ++copy)
421 {
roots.insert(
roots.end(), factor_roots.begin(), factor_roots.end()); }
423 if (
roots.size() !=
static_cast<std::size_t
>(exact.
degree()))
425 "polynomial root multiplicities do not cover its degree",
"solve.exact"); }
433 if (polynomial.value()) {
435 if (!solved) {
return solved; }
438 auto symbolic = symbolic_to_poly<SymbolicPolyCoeff>(f_expr, var);
441 if (!solved) {
return solved; }
448 if (!*product) {
return std::move(*product); }
452 if (!solved) {
return solved; }
457 const std::shared_ptr<SymbolicExpr>& expr,
458 const std::string& var,
461 constexpr const char* operation =
"solve_equation";
471 auto step =
context.consume_steps(1, operation);
476 std::shared_ptr<SymbolicExpr> f_expr = expr;
478 if (
relation->op() != RelationalNode::Op::EQ) {
481 "solve_equation accepts equations, not inequalities",
486 f_expr = SymbolicExpr::add(
487 left, SymbolicExpr::multiply(SymbolicExpr::number(-1),
right));
492catch (
const CasError& error) {
494}
catch (
const std::bad_alloc&) {
496 "equation solve allocation failed",
"solve_equation");
497}
catch (
const std::length_error& error) {
499}
catch (
const std::exception& error) {
504 const std::shared_ptr<SymbolicExpr>& expr,
505 const std::string& var,
513 const std::shared_ptr<SymbolicExpr>& f_expr,
const std::string& var,
515 constexpr const char* operation =
"solve_dispatch_vector";
526 "mixed transcendental equation is outside the finite-vector support domain",
538 mixed.value().reason.empty() ?
"mixed transcendental search is incomplete" : mixed.value().reason,
544 if (result.
value().empty()) {
547 std::vector<FiniteSolution> solutions;
548 solutions.reserve(result.
value().size());
556 const std::shared_ptr<SymbolicExpr>& expr,
557 const std::string& var,
561 (
context).limits().max_ast_nodes,
"transform");
562 constexpr const char* operation =
"solve_dispatch_set";
565 "expression cannot be null",
570 "solve variable cannot be empty",
577 "expression simplification failed",
581 std::shared_ptr<SymbolicExpr> f_expr = simplified;
582 if (
auto rel = std::dynamic_pointer_cast<const RelationalNode>(
LMCAS::detail::node(simplified))) {
583 if (rel->op() == RelationalNode::Op::EQ) {
586 f_expr = SymbolicExpr::add(
587 left, SymbolicExpr::multiply(
right, SymbolicExpr::number(-1)));
591 auto polynomial = symbolic_to_poly<SymbolicPolyCoeff>(f_expr, var);
600 if (transcendental)
return transcendental;
611 "expression is outside the supported finite exact solve domain", operation);
612}
catch (
const CasError& error) {
614}
catch (
const std::bad_alloc&) {
616}
catch (
const std::length_error& error) {
618}
catch (
const std::exception& error) {
623 const std::shared_ptr<SymbolicExpr>& expr,
624 const std::string& var,
627 constexpr const char* operation =
"solve_finite_projection";
632 auto solution_set = std::move(solved.value());
633 if (std::holds_alternative<EmptySolutions>(solution_set)) {
636 auto* finite = std::get_if<FiniteSolutions>(&solution_set);
640 "solution set is not finitely enumerable", operation);
642 std::size_t value_count = 0;
643 for (
const auto& solution : finite->values) {
644 if (!solution.conditions.empty()) {
646 "Conditional roots cannot be projected to an unconditional vector", operation);
648 value_count += solution.multiplicity;
650 std::vector<std::shared_ptr<SymbolicExpr>> values;
651 values.reserve(value_count);
652 for (
const auto& solution : finite->values) {
653 for (std::size_t copy = 0; copy < solution.multiplicity; ++copy) {
654 values.push_back(solution.value);
659catch (
const CasError& error) {
661}
catch (
const std::bad_alloc&) {
663 "finite solution projection allocation failed",
"solve_finite_projection");
664}
catch (
const std::length_error& error) {
666}
catch (
const std::exception& error) {
671 const std::shared_ptr<SymbolicExpr>& expression,
681std::vector<std::map<std::string, std::shared_ptr<SymbolicExpr>>>
682SymbolicExpr::solve_system(
683 const std::vector<std::shared_ptr<SymbolicExpr>>& equations,
684 const std::vector<std::string>&
vars) {
686 detail::RewriteBudget transform_budget(
context, (
context).limits().max_recursion_depth,
687 (
context).limits().max_ast_nodes,
"transform");
688 std::vector<SymbolicExpr> values;
689 values.reserve(equations.size());
690 for (
const auto& equation : equations) {
695 std::dynamic_pointer_cast<const RelationalNode>(
697 if (
relation->op() != RelationalNode::Op::EQ) {
700 auto normalized = SymbolicExpr::add(
702 SymbolicExpr::multiply(
703 SymbolicExpr::number(-1),
707 values.push_back(*equation);
711 if (solved.empty()) {
714 std::map<std::string, std::shared_ptr<SymbolicExpr>> projected;
719 return {std::move(projected)};
722std::vector<std::map<std::string, std::shared_ptr<SymbolicExpr>>> SymbolicExpr::solve_system(
723 const std::vector<std::shared_ptr<SymbolicExpr>>& equations,
724 const std::vector<std::string>& unknowns,
725 const std::vector<std::string>& parameters) {
726 return ParametricSolver::solve_system(equations, unknowns, parameters);
730std::shared_ptr<SymbolicExpr> SymbolicExpr::transpose(
const std::shared_ptr<SymbolicExpr>& mat) {
738 size_t r = m_node->rows();
739 size_t c = m_node->cols();
741 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> new_data(
c, std::vector<std::shared_ptr<SymbolicExpr>>(
r));
743 for(
size_t i=0; i<
r; ++i) {
744 for(
size_t j=0; j<
c; ++j) {
749 return SymbolicExpr::matrix(new_data);
AssumptionContext class with scoped push/pop management.
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
int degree() const
获取多项式的次数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static std::shared_ptr< const SymbolicNode > create_complex(std::shared_ptr< const SymbolicNode > real, std::shared_ptr< const SymbolicNode > imag)
创建复数节点,自动简化(若虚部为 0,则返回实部).
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
ExprPtr substitute_raw(const ExprPtr &expression, const std::string &variable, const ExprPtr &value)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
SolveResult finalize_solution_set(const ExprPtr &original, const std::string &variable, SolutionSet solutions, ComputationContext &context, Domain domain, const SolveOptions &options)
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
Result< CartesianQuadraticRoots > real_quadratic_roots_checked(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, ComputationContext &context)
const FactsQuery & no_facts() noexcept
ExprPtr equation_predicate(const ExprPtr &expression)
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::set< std::string > all_variable_names(const SymbolicNodePtr &expression, RewriteBudget *budget=nullptr)
bool bounded_rational_root_search(const Polynomial< Rational > &polynomial)
std::vector< std::shared_ptr< SymbolicExpr > > solve_biquadratic_impl(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, const std::string &variable, ComputationContext &context)
std::map< std::string, SymbolicExpr > project_unconditional_linear_system(const std::vector< SymbolicExpr > &equations, const std::vector< std::string > &variables, ComputationContext &context)
static ExprPtr polynomial_logic(const ExprPtr &left, const ExprPtr &right, LogicalNode::Op op)
LMCAS::Result< std::vector< std::shared_ptr< SymbolicExpr > > > SolveVectorResult
const std::string & variable
static SolveResult dispatch_equation(const ExprPtr &expr, const ExprPtr &f_expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
bool allow_numeric
是否允许数值求解
std::vector< std::pair< Polynomial< Rational >, int > > square_free_factorization(const Polynomial< Rational > &poly)
static ExprPtr polynomial_relation(const ExprPtr &left, const ExprPtr &right, RelationOp op)
static SolveResult solve_exact_polynomial_set(const Polynomial< Rational > &exact, const std::string &var, ComputationContext &context)
ExprPtr substitute_raw(const ExprPtr &expression, const std::string &variable, const ExprPtr &value)
__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
static Result< void > append_product_roots(FiniteSolutions &values, std::size_t multiplicity, std::vector< FiniteSolution > &finite)
__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
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
static SolveResult solve_symbolic_polynomial_set(const Polynomial< SymbolicPolyCoeff > &polynomial, const ExprPtr &original, const std::string &variable, ComputationContext &context)
Result< SolutionSet > SolveResult
static SolveResult conditional_equation(const ExprPtr &original, const std::string &variable)
@ Complex
Complex numbers (default, least specific)
const std::string ComputationContext const SolveOptions & options
const VectorField const VectorField & c
static SolveResult conditional_linear_polynomial(const Polynomial< SymbolicPolyCoeff > &polynomial, const ExprPtr &leading, const std::string &variable)
static SolveVectorResult solve_higher_exact_roots(const Polynomial< Rational > &remainder, const std::string &var, ComputationContext &context)
@ Unknown
Property cannot be determined
@ True
Property definitely holds
@ False
Property definitely does not hold
SolveResult solve_transcendental(const ExprPtr &expr, const std::string &var, ComputationContext &context, const SolveOptions &options)
LMCAS::SolveResult solve_equation(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
std::vector< FiniteSolution > values
RootOfConstructionResult make_rootof_checked(const std::shared_ptr< SymbolicExpr > &polynomial, const std::string &variable, std::size_t index, ComputationContext &context)
static std::optional< SolveVectorResult > solve_finite_mixed(const std::shared_ptr< SymbolicExpr > &f_expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
static std::optional< SolveResult > solve_product_set(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
ExprPtr equation_predicate(const ExprPtr &expression)
LMCAS::FiniteSolveResult solve_finite_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
std::shared_ptr< SymbolicExpr > get_coeff(const Polynomial< SymbolicPolyCoeff > &p, int deg)
static SolveResult solve_symbolic_quadratic(const Polynomial< SymbolicPolyCoeff > &polynomial, const ExprPtr &leading, const FactsQuery &facts, ComputationContext &context)
std::shared_ptr< SymbolicExpr > ExprPtr
Result< OptionalRationalPolynomial > recognize_rational_polynomial(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
Result< std::vector< std::shared_ptr< SymbolicExpr > > > FiniteSolveResult
static SolveResult finite_values_to_set(SolveVectorResult result)
std::vector< Rational > find_rational_roots(const Polynomial< Rational > &poly)
TransSubstitutionResult detect_trans_substitutions(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
为依赖 var 的 Sin、Cos、Exp、Ln、Tan 子表达式构造换元结果。
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
ExprResult relation(const ExprPtr &lhs, const ExprPtr &rhs, RelationOp op)
std::variant< EmptySolutions, UniversalSolutions, FiniteSolutions, IntervalSolutions, ConditionalSolutions, ParametricSolutions > SolutionSet
成功的 SolveResult 表示操作定义域内的完整解集。 完备性未决时返回外层 Inconclusive 错误;EmptySolutions 表示已证明的空解集。
const std::string const ExprPtr & value
static SolveResult collect_exact_solutions(std::vector< std::shared_ptr< SymbolicExpr > > roots, ComputationContext &context)
static SolveVectorResult solve_exact_factor(Polynomial< Rational > remainder, const std::string &var, ComputationContext &context)
static SolveResult solve_product_factor(const detail::SymbolicNodePtr &node, const std::string &variable, ComputationContext &context, const SolveOptions &options, std::size_t &multiplicity)
__attribute__((visibility("default"))) MixedTranscendentalResult solve_mixed_transcendental_checked(const std __attribute__((visibility("default"))) MixedTranscendentalResult solve_mixed_transcendental_checked(const std __attribute__((visibility("default"))) bool contains_transcendental_of_var(const std bool is_polynomial_after_substitution(const TransSubstitutionResult &sub_result)
在调用方计算上下文中执行混合超越方程求解.
const ExprPtr & denominator
static SolveResult solve_set_core(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
MixedTranscendentalResult solve_mixed_transcendental_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts, ComputationContext &context)
static void append_product_families(ParametricSolutions &values, const std::set< std::string > &original_names, std::vector< ParametricSolution > &families)
std::vector< ParametricSolution > values
bool contains_transcendental_of_var(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
conditions 是在操作上下文假设下须同时满足的条件。 空条件保留原表达式定义域且不增加约束;整数参数遍历全体整数。
数值求根:Newton-Raphson 迭代,二分法,Sturm 实根隔离.
含参方程组求解器 ParametricSolver,支持分段解。
混合超越方程求解:符号预处理 + 自适应根隔离 + Newton-Raphson 精化.
方程求解策略调度器 solve_dispatch 及相关选项结构体.
多项式方程组求解器 Solver,包含 Gröbner 基、线性系统求解。
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.