26 const std::shared_ptr<SymbolicExpr>& expr,
58 const std::shared_ptr<SymbolicExpr>& expr,
61 if (unresolved_parameters) {
64 "equation depends on unresolved parameters but not the solve variable"});
70 if (!evaluated || !std::isfinite(evaluated.value().value)) {
73 "constant equation could not be evaluated in the real domain"});
75 if (std::abs(evaluated.value().value) <= opts.
tolerance) {
78 "equation is identically zero; every real value satisfies it"});
94 const bool literal_offset = sum && sum->operands().size() == 2 &&
95 std::any_of(sum->operands().begin(), sum->operands().end(),
96 [](
const auto& operand) {
97 return dynamic_cast<const NumberNode*>(operand.get()) != nullptr;
99 auto pattern = literal_offset
103 ? std::dynamic_pointer_cast<const VariableNode>(
detail::node(pattern->inner))
105 auto coefficient = pattern && pattern->coefficient
110 coefficient && (*coefficient == Rational(1) || *coefficient == Rational(-1))) {
113 if (!inverted)
return inverted.error();
114 auto finite = std::get_if<FiniteSolutions>(&inverted.value());
115 if (finite && finite->values.size() == 1 &&
116 finite->values.front().conditions.empty()) {
117 const auto&
target = finite->values.front().value;
130 if (!factored)
return factored.error();
131 auto factors = std::move(factored.value());
132 if (factors.empty()) {
133 factors.push_back(
expr_);
136 for (
const auto& factor : factors) {
151 struct RepresentedRoot {
153 std::shared_ptr<SymbolicExpr> expression;
157 std::vector<RepresentedRoot> values;
160 values.push_back({root.value, std::move(root.expression),
true});
162 for (
const auto value : numeric_values) {
164 {
value, SymbolicExpr::number(
static_cast<double>(
value)),
false});
166 std::sort(values.begin(), values.end(),
167 [](
const RepresentedRoot& left,
const RepresentedRoot&
right) {
168 if (left.value != right.value) { return left.value < right.value; }
169 return left.symbolic && !
right.symbolic;
171 const auto threshold = 10.0 * opts_.tolerance;
172 std::vector<RepresentedRoot> unique;
173 unique.reserve(values.size());
174 for (
auto& root : values) {
175 if (!unique.empty() &&
176 std::fabs(root.value - unique.back().value) < threshold) {
177 if (root.symbolic && !unique.back().symbolic) {
178 unique.back() = std::move(root);
182 unique.push_back(std::move(root));
184 if (opts_.max_roots > 0 &&
185 unique.size() >
static_cast<std::size_t
>(opts_.max_roots)) {
186 unique.resize(
static_cast<std::size_t
>(opts_.max_roots));
189 std::vector<std::shared_ptr<SymbolicExpr>> results;
190 results.reserve(unique.size());
191 for (
auto& root : unique) {
192 results.push_back(std::move(root.expression));
194 return MixedTranscendentalResult::success(
195 MathResult<std::vector<std::shared_ptr<SymbolicExpr>>>{
197 complete_ ? Completeness::Complete : Completeness::Inconclusive,
198 complete_ ? std::string{} :
"有界数值隔离未能证明排除全部未检测根"});
204 polish.has_initial_guess =
true;
205 polish.initial_guess =
value;
213 for (
const auto& candidate : refined.value()) {
215 const auto candidate_residual = std::fabs(
217 if (std::isfinite(candidate_residual) && candidate_residual < residual) {
218 value = candidate.value;
219 residual = candidate_residual;
220 iterations += candidate.iterations;
229 if (std::isfinite(residual) && residual >
opts_.tolerance) {
232 if (!std::isfinite(residual) || residual >
opts_.tolerance) {
252 std::shared_ptr<SymbolicExpr> simplified,
253 lmmc_real_t
value,
bool inverse_identity) {
255 std::optional<detail::AssumptionFacts> assumptions;
257 assumptions.emplace(*
context_.assumptions());
260 ?
static_cast<const FactsQuery&
>(*assumptions)
286 if (!std::holds_alternative<ProvedZeroResidual>(
288 if (!inverse_identity)
return std::nullopt;
300 bool inverse_identity =
false;
318 const auto value = evaluated.value().value;
319 if (!std::isfinite(
value)) {
337 for (
const auto& solution : solutions.
values) {
338 if (!solution.conditions.empty()) {
353 auto polynomial = symbolic_to_poly<SymbolicPolyCoeff>(factor,
var_);
367 if (std::holds_alternative<EmptySolutions>(solved.value()))
return true;
368 auto finite = std::get_if<FiniteSolutions>(&solved.value());
377 std::optional<detail::AssumptionFacts> assumptions;
378 if (
context_.assumptions()) { assumptions.emplace(*
context_.assumptions()); }
381 if (!nonzero) {
return nonzero.error(); }
397 if (std::holds_alternative<EmptySolutions>(symbolic.value())) {
401 std::get_if<FiniteSolutions>(&symbolic.value())) {
409 const std::shared_ptr<SymbolicExpr>& factor,
420 return polynomial.error();
422 if (polynomial.value()) {
427 return symbolic.error();
429 if (symbolic.value()) {
436 return std::move(numeric.error());
438 for (
const auto& root : numeric.value()) {
449 const std::shared_ptr<SymbolicExpr>&
expr_;
464 const std::shared_ptr<SymbolicExpr>& expr,
const std::string& var,
471 if (variables.find(var) == variables.end()) {
489 return collection.
finish();
495 const std::shared_ptr<SymbolicExpr>& expr,
const std::string& var,
497 auto invalid = validate_mixed_input(expr, var, opts);
502 return solve_mixed_equation(expr, var, opts,
context);
505 }
catch (
const std::bad_alloc&) {
508 }
catch (
const std::length_error& error) {
510 }
catch (
const std::exception& error) {
516 const std::shared_ptr<SymbolicExpr>& expr,
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(MathResult< std::vector< std::shared_ptr< SymbolicExpr > > > value)
std::shared_ptr< SymbolicExpr > exponential_target_
const SearchInterval & interval_
std::vector< SymbolicRoot > symbolic_roots_
std::optional< bool > accept_symbolic_witness(std::shared_ptr< SymbolicExpr > simplified, lmmc_real_t value, bool inverse_identity)
MixedTranscendentalResult finish()
std::shared_ptr< SymbolicExpr > exponential_inner_
std::vector< NumericRoot > roots_
const SolveOptions & opts_
detail::RewriteBudget budget_
bool accept_value(lmmc_real_t value, int iterations)
Result< bool > solve_polynomial_factor(const ExprPtr &factor, ComputationContext &context)
std::optional< CasError > solve(ComputationContext &context)
Result< bool > accept_finite_solutions(const FiniteSolutions &solutions)
std::optional< CasError > solve_factor(const std::shared_ptr< SymbolicExpr > &factor, ComputationContext &context)
const std::shared_ptr< SymbolicExpr > & expr_
ComputationContext & context_
bool accept_symbolic(const std::shared_ptr< SymbolicExpr > &root)
Result< bool > solve_transcendental_factor(const ExprPtr &factor, ComputationContext &context)
std::optional< CasError > check_constant_factor(const ExprPtr &factor)
std::shared_ptr< SymbolicExpr > expression
MixedRootCollection(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SearchInterval &interval, const SolveOptions &opts, ComputationContext &context)
std::optional< CasError > failure_
bool handle_symbolic_evaluation_error(const CasError &error)
void polish_value(lmmc_real_t &value, lmmc_real_t &residual, int &iterations)
MixedTranscendentalResult classify_constant_equation(const std::shared_ptr< SymbolicExpr > &expr, bool unresolved_parameters, const SolveOptions &opts, ComputationContext &context)
MixedTranscendentalResult solve_mixed_equation(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts, ComputationContext &context)
bool is_mixed_terminal_error(CasErrc code)
std::optional< CasError > validate_mixed_input(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts)
constexpr const char * mixed_operation
std::optional< InversePattern > decompose_trig_exp_pattern(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
SolveResult invert_function(const InversePattern &pattern, const ExprPtr &original, const std::string &var, ComputationContext &context, const SolveOptions &options)
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
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
const FactsQuery & no_facts() noexcept
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
std::optional< Rational > exact_rational_value(const NumberNode &number)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
Result< std::vector< NumericRoot > > mixed_numerical_path(const std::shared_ptr< SymbolicExpr > &factor, const std::string &var, const SearchInterval &interval, const SolveOptions &opts, RewriteBudget &budget, bool &complete)
隔离并精化单个因子的数值根。
lmmc_real_t mixed_evaluate_at(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, lmmc_real_t x, RewriteBudget &budget)
Result< MathResult< std::vector< std::shared_ptr< SymbolicExpr > > > > MixedTranscendentalResult
受检混合超越方程求解结果.
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
bool has_search_interval
是否指定了搜索区间
std::vector< lmmc_real_t > deduplicate_roots(std::vector< NumericRoot > &roots, lmmc_real_t tolerance, int max_roots)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
@ 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::optional< SearchInterval > determine_search_interval(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts)
lmmc_real_t tolerance
收敛容差
std::vector< FiniteSolution > values
lmmc_real_t search_lo
搜索区间下界(默认 -10)
Result< std::vector< std::shared_ptr< SymbolicExpr > > > factor_transcendental(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context)
std::set< std::string > free_variables(const detail::SymbolicNodePtr &expression, detail::RewriteBudget *budget)
std::shared_ptr< SymbolicExpr > ExprPtr
lmmc_real_t search_hi
搜索区间上界(默认 10)
ResidualCheckResult check_zero_residual(const ExprPtr &residual, ComputationContext &context, const LMCAS::EqvOptions &options)
const std::string const ExprPtr & value
int max_roots
数值候选数量预算;精确解集和整数解族保持完整。
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
MixedTranscendentalResult solve_mixed_transcendental_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts, ComputationContext &context)
int max_newton_iterations
Newton 迭代最大次数
NumericRootsResult solve_numeric_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts)
bool contains_transcendental_of_var(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
detail::SymbolicNodePtr substitute_free(const detail::SymbolicNodePtr &expression, const std::string &variable, const detail::SymbolicNodePtr &replacement, detail::RewriteBudget *budget)
数值求根:Newton-Raphson 迭代,二分法,Sturm 实根隔离.
混合超越方程求解:符号预处理 + 自适应根隔离 + Newton-Raphson 精化.