LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
solve_visitor.cpp
浏览该文件的文档.
1#include <stdexcept>
3#include "symbolic.hpp"
6#include "solver.hpp"
7#include <iostream>
8#include <map>
9#include <set>
10#include <cmath>
11#include "lmmc/config.h"
12#include "lmmc/numeric.h"
14#include "poly_utils.hpp"
15#include "solve_strategies.hpp"
16#include "solve_polynomial.hpp"
20#include "newton_raphson.hpp"
21#include "root_of_utils.hpp"
31#include <limits>
33
34namespace LMCAS {
35
40
41std::shared_ptr<SymbolicExpr> get_coeff(const Polynomial<SymbolicPolyCoeff>& p, int deg) {
42 if (deg < 0 || deg > p.degree()) {
43 return SymbolicExpr::number(0);
44 }
45 return p.coeffs[deg].val;
46}
47
49 const std::shared_ptr<SymbolicExpr>& expr,
50 const std::string& var,
51 ComputationContext& context,
52 const SolveOptions& opts);
53
54
55static SolveResult conditional_equation(const ExprPtr& original, const std::string& variable) {
57}
58
59
66
73
75 const Polynomial<SymbolicPolyCoeff>& polynomial,
76 const ExprPtr& leading, const std::string& variable) {
77 auto constant = get_coeff(polynomial, 0);
78 auto zero = SymbolicExpr::number(0);
79 auto generic = polynomial_logic(
82 SymbolicExpr::multiply(
83 leading, SymbolicExpr::variable(variable)),
84 SymbolicExpr::multiply(
85 SymbolicExpr::number(-1), constant),
88 auto degenerate = polynomial_logic(
89 polynomial_relation(leading, zero, RelationOp::EQ),
90 polynomial_relation(constant, zero, RelationOp::EQ),
94 polynomial_logic(generic, degenerate, LogicalNode::Op::Or),
95 {}}}};
96}
97
99 const Polynomial<SymbolicPolyCoeff>& polynomial,
100 const ExprPtr& leading, const FactsQuery& facts,
102 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
103 (context).limits().max_ast_nodes, "transform");
104 auto linear = get_coeff(polynomial, 1);
105 auto constant = get_coeff(polynomial, 0);
106 auto discriminant = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(
107 SymbolicExpr::power(linear, SymbolicExpr::number(2)),
108 SymbolicExpr::multiply(
109 SymbolicExpr::number(-4),
110 SymbolicExpr::multiply(leading, constant)))), transform_budget));
111 auto nonzero = detail::query_nonzero_value(
112 detail::node(discriminant), facts, Domain::Complex, context);
113 if (!nonzero) {
114 return SolveResult::failure(nonzero.error());
115 }
116
117 auto radical = detail::make_expression_ptr(
120 std::vector<std::shared_ptr<const SymbolicNode>>{
121 detail::node(discriminant)}));
122 auto negative_linear =
123 SymbolicExpr::multiply(SymbolicExpr::number(-1), linear);
124 auto denominator =
125 SymbolicExpr::multiply(SymbolicExpr::number(2), leading);
126 auto positive = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(
127 SymbolicExpr::add(negative_linear, radical),
128 denominator)), transform_budget));
129 auto negative = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(
130 SymbolicExpr::add(
131 negative_linear,
132 SymbolicExpr::multiply(
133 SymbolicExpr::number(-1), radical)),
134 denominator)), transform_budget));
135 auto repeated =
136 detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(negative_linear, denominator)), transform_budget));
137
138 if (nonzero.value() == Tribool::False) {
140 FiniteSolution{repeated, 2, {}}}}};
141 }
142 if (nonzero.value() == Tribool::True) {
144 FiniteSolution{positive, 1, {}},
145 FiniteSolution{negative, 1, {}}}}};
146 }
147
148 auto zero = SymbolicExpr::number(0);
149 auto distinct =
150 polynomial_relation(discriminant, zero, RelationOp::NEQ);
151 auto coincident =
152 polynomial_relation(discriminant, zero, RelationOp::EQ);
154 FiniteSolution{positive, 1, {distinct}},
155 FiniteSolution{negative, 1, {distinct}},
156 FiniteSolution{positive, 2, {coincident}}}}};
157} catch (const CasError& error) {
158 return SolveResult::failure(error);
159} catch (const std::bad_alloc&) {
160 return SolveResult::failure(CasErrc::ResourceLimit, "allocation failed", "solve_symbolic_quadratic");
161} catch (const std::length_error& error) {
162 return SolveResult::failure(CasErrc::ResourceLimit, error.what(), "solve_symbolic_quadratic");
163} catch (const std::exception& error) {
164 return SolveResult::failure(CasErrc::InternalInvariant, error.what(), "solve_symbolic_quadratic");
165}
166
168 const Polynomial<SymbolicPolyCoeff>& polynomial,
169 const ExprPtr& original, const std::string& variable,
171 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
172 (context).limits().max_ast_nodes, "transform");
173
174 std::optional<detail::AssumptionFacts> adapter;
175 if (context.assumptions()) {
176 adapter.emplace(*context.assumptions());
177 }
178 const FactsQuery& facts = adapter
179 ? static_cast<const FactsQuery&>(*adapter)
181 int degree = polynomial.degree();
182 while (degree >= 0) {
183 auto leading = detail::make_expression_ptr(detail::normalize_node(detail::node(get_coeff(polynomial, degree)), transform_budget));
184 auto nonzero = detail::query_nonzero_value(
185 detail::node(leading), facts, Domain::Complex, context);
186 if (!nonzero) {
187 return SolveResult::failure(nonzero.error());
188 }
189 if (nonzero.value() == Tribool::False) {
190 --degree;
191 continue;
192 }
193 if (nonzero.value() == Tribool::Unknown || degree >= 3) {
194 return degree == 1
196 polynomial, leading, variable)
197 : conditional_equation(original, variable);
198 }
199 if (degree == 0) {
200 return SolutionSet{EmptySolutions{}};
201 }
202 if (degree == 2) {
204 polynomial, leading, facts, context);
205 }
207 SymbolicExpr::multiply(
208 SymbolicExpr::number(-1),
209 get_coeff(polynomial, 0)),
210 leading)), transform_budget));
212 FiniteSolution{value, 1, {}}}}};
213 }
215} catch (const CasError& error) {
216 return SolveResult::failure(error);
217} catch (const std::bad_alloc&) {
218 return SolveResult::failure(CasErrc::ResourceLimit, "allocation failed", "solve_symbolic_polynomial_set");
219} catch (const std::length_error& error) {
220 return SolveResult::failure(CasErrc::ResourceLimit, error.what(), "solve_symbolic_polynomial_set");
221} catch (const std::exception& error) {
222 return SolveResult::failure(CasErrc::InternalInvariant, error.what(), "solve_symbolic_polynomial_set");
223}
224
226 const std::string& variable, ComputationContext& context, const SolveOptions& options,
227 std::size_t& multiplicity) {
228 auto factor = detail::make_expression_ptr(node);
229 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
230 BigInt exponent;
232 std::dynamic_pointer_cast<const NumberNode>(power->exponent()), exponent)) {
233 if (exponent <= BigInt(0)) { return SolutionSet{EmptySolutions{}}; }
234 if (exponent > BigInt(static_cast<std::int64_t>(std::numeric_limits<int>::max()))) {
235 return SolveResult::failure(CasErrc::ResourceLimit, "root multiplicity overflow", "solve.product");
236 }
237 multiplicity = static_cast<std::size_t>(*exponent.try_to_int64());
238 factor = detail::make_expression_ptr(power->base());
239 }
240 }
241 return solve_equation(factor, variable, context, options);
242}
243
244static Result<void> append_product_roots(FiniteSolutions& values, std::size_t multiplicity,
245 std::vector<FiniteSolution>& finite) {
246 for (auto& value : values.values) {
247 if (value.multiplicity > std::numeric_limits<std::size_t>::max() / multiplicity) {
248 return Result<void>::failure(CasErrc::ResourceLimit, "root multiplicity overflow", "solve.product");
249 }
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();
254 });
255 if (existing == finite.end()) { finite.push_back(std::move(value)); }
256 else {
257 if (existing->multiplicity > std::numeric_limits<std::size_t>::max() - value.multiplicity) {
258 return Result<void>::failure(CasErrc::ResourceLimit, "root multiplicity overflow", "solve.product");
259 }
260 existing->multiplicity += value.multiplicity;
261 }
262 }
263 return Result<void>::success();
264}
265
267 const std::set<std::string>& original_names, std::vector<ParametricSolution>& families) {
268 for (auto& family : values.values) {
269 auto occupied = original_names;
270 const auto value_names = detail::all_variable_names(detail::node(family.value));
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);
277 }
278 auto symbol = SymbolicExpr::variable(fresh);
279 family.value = substitute_raw(family.value, parameter, symbol);
280 for (auto& condition : family.conditions) {
281 condition = substitute_raw(condition, parameter, symbol);
282 }
283 parameter = fresh;
284 occupied.insert(fresh);
285 }
286 families.push_back(std::move(family));
287 }
288}
289
290static std::optional<SolveResult> solve_product_set(const ExprPtr& expression,
291 const std::string& variable, ComputationContext& context, const SolveOptions& options) {
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;
296 const auto original_names = detail::all_variable_names(detail::node(expression));
297 for (const auto& node : product->operands()) {
298 std::size_t multiplicity = 1;
299 auto solved = solve_product_factor(node, variable, context, options, multiplicity);
300 if (!solved) {
301 if (solved.error().code == CasErrc::Inconclusive) { return conditional_equation(expression, variable); }
302 return SolveResult::failure(solved.error());
303 }
304 if (std::holds_alternative<EmptySolutions>(solved.value())) { continue; }
305 if (std::holds_alternative<UniversalSolutions>(solved.value())) { return conditional_equation(expression, variable); }
306 if (auto values = std::get_if<FiniteSolutions>(&solved.value())) {
307 auto appended = append_product_roots(*values, multiplicity, finite);
308 if (!appended) { return SolveResult::failure(appended.error()); }
309 } else if (auto values = std::get_if<ParametricSolutions>(&solved.value())) {
310 append_product_families(*values, original_names, families);
311 } else { return conditional_equation(expression, variable); }
312 }
313 if (!finite.empty() && !families.empty()) { return conditional_equation(expression, variable); }
314 if (!families.empty()) { return SolveResult::success(SolutionSet{ParametricSolutions{std::move(families)}}); }
315 if (!finite.empty()) { return SolveResult::success(SolutionSet{FiniteSolutions{std::move(finite)}}); }
317}
318
320 std::vector<std::shared_ptr<SymbolicExpr>> roots, ComputationContext& context) {
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);
325 if (!root_step) {
326 return SolveResult::failure(root_step.error());
327 }
328 if (!root || !LMCAS::detail::node(root)) {
331 "polynomial solver produced a null root", operation);
332 }
333 auto existing = std::find_if(
334 solutions.begin(), solutions.end(),
335 [&](const FiniteSolution& solution) {
336 return LMCAS::detail::node(solution.value)->equals(
337 *LMCAS::detail::node(root));
338 });
339 if (existing != solutions.end()) {
340 ++existing->multiplicity;
341 } else {
342 solutions.push_back(
343 FiniteSolution{std::move(root), 1, {}});
344 }
345 }
347 SolutionSet{FiniteSolutions{std::move(solutions)}});
348}
349
350
352 const std::string& var, ComputationContext& context) {
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]),
359 SymbolicExpr::number(remainder.coeffs[0]), var, context);
360 }
361 auto expression = poly_to_symbolic(remainder);
362 std::vector<ExprPtr> represented_roots;
363 for (int index = 0; index < remainder.degree(); ++index) {
364 auto root = make_rootof_checked(expression, var, static_cast<std::size_t>(index), context);
365 if (!root) { return SolveVectorResult::failure(root.error()); }
366 represented_roots.push_back(std::move(root.value()));
367 }
368 return represented_roots;
369}
370
372 const std::string& var, ComputationContext& context) {
373 std::vector<ExprPtr> factor_roots;
374 const bool bounded_candidates =
376 if (bounded_candidates) {
377 for (const auto& root : find_rational_roots(remainder)) {
378 Polynomial<Rational> divisor({-root, Rational(1)}, var);
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);
383 }
384 }
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]),
391 SymbolicExpr::number(remainder.coeffs[0]), context);
392 if (!quadratic) { return SolveVectorResult::failure(quadratic.error()); }
393 for (const auto& root : quadratic.value()) {
394 factor_roots.push_back(detail::make_expression_ptr(
396 }
397 } else if (remainder.degree() > 2) {
398 auto represented_roots = solve_higher_exact_roots(remainder, var, context);
399 if (!represented_roots) { return SolveVectorResult::failure(represented_roots.error()); }
400 factor_roots.insert(factor_roots.end(), represented_roots.value().begin(), represented_roots.value().end());
401 }
402 return factor_roots;
403}
404
406 const std::string& var,
408 if (exact.is_zero()) { return SolutionSet{UniversalSolutions{}}; }
409 if (exact.degree() == 0) { return SolutionSet{EmptySolutions{}}; }
410 std::vector<ExprPtr> roots;
411 for (auto& factor : square_free_factorization(exact)) {
412 auto step = context.consume_steps(1, "solve.exact");
413 if (!step) { return SolveResult::failure(step.error()); }
414 auto solved = solve_exact_factor(factor.first, var, context);
415 if (!solved) { return SolveResult::failure(solved.error()); }
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()); }
422 }
423 if (roots.size() != static_cast<std::size_t>(exact.degree()))
425 "polynomial root multiplicities do not cover its degree", "solve.exact"); }
426 return collect_exact_solutions(std::move(roots), context);
427}
428
429static SolveResult dispatch_equation(const ExprPtr& expr, const ExprPtr& f_expr,
430 const std::string& var, ComputationContext& context, const SolveOptions& opts) {
431 auto polynomial = recognize_rational_polynomial(*f_expr, var, context);
432 if (!polynomial) { return SolveResult::failure(polynomial.error()); }
433 if (polynomial.value()) {
434 auto solved = solve_exact_polynomial_set(*polynomial.value(), var, context);
435 if (!solved) { return solved; }
436 return detail::finalize_solution_set(expr, var, std::move(solved.value()), context, Domain::Complex, opts);
437 }
438 auto symbolic = symbolic_to_poly<SymbolicPolyCoeff>(f_expr, var);
439 if (symbolic) {
440 auto solved = solve_symbolic_polynomial_set(symbolic.value(), f_expr, var, context);
441 if (!solved) { return solved; }
442 return detail::finalize_solution_set(expr, var, std::move(solved.value()), context, Domain::Complex, opts);
443 }
444 if (symbolic.error().code != CasErrc::UnsupportedExpression) {
445 return SolveResult::failure(symbolic.error());
446 }
447 if (auto product = solve_product_set(f_expr, var, context, opts)) {
448 if (!*product) { return std::move(*product); }
449 return detail::finalize_solution_set(expr, var, std::move(product->value()), context, Domain::Real, opts);
450 }
451 auto solved = solve_set_core(f_expr, var, context, opts);
452 if (!solved) { return solved; }
453 return detail::finalize_solution_set(expr, var, std::move(solved.value()), context, Domain::Real, opts);
454}
455
457 const std::shared_ptr<SymbolicExpr>& expr,
458 const std::string& var,
460 const SolveOptions& opts) try {
461 constexpr const char* operation = "solve_equation";
462 if (!expr || !LMCAS::detail::node(expr)) {
464 CasErrc::InvalidArgument, "equation expression cannot be null", operation);
465 }
466 if (var.empty()) {
468 CasErrc::InvalidArgument, "solve variable cannot be empty", operation);
469 }
470
471 auto step = context.consume_steps(1, operation);
472 if (!step) {
473 return SolveResult::failure(step.error());
474 }
475
476 std::shared_ptr<SymbolicExpr> f_expr = expr;
477 if (auto relation = std::dynamic_pointer_cast<const RelationalNode>(LMCAS::detail::node(expr))) {
478 if (relation->op() != RelationalNode::Op::EQ) {
481 "solve_equation accepts equations, not inequalities",
482 operation);
483 }
484 auto left = LMCAS::detail::make_expression_ptr(relation->left());
486 f_expr = SymbolicExpr::add(
487 left, SymbolicExpr::multiply(SymbolicExpr::number(-1), right));
488 }
489
490 return dispatch_equation(expr, f_expr, var, context, opts);
491}
492catch (const CasError& error) {
493 return SolveResult::failure(error);
494} catch (const std::bad_alloc&) {
496 "equation solve allocation failed", "solve_equation");
497} catch (const std::length_error& error) {
498 return SolveResult::failure(CasErrc::ResourceLimit, error.what(), "solve_equation");
499} catch (const std::exception& error) {
500 return SolveResult::failure(CasErrc::InternalInvariant, error.what(), "solve_equation");
501}
502
504 const std::shared_ptr<SymbolicExpr>& expr,
505 const std::string& var,
506 const SolveOptions& opts) {
508 return solve_equation(expr, var, context, opts);
509}
510
511
512static std::optional<SolveVectorResult> solve_finite_mixed(
513 const std::shared_ptr<SymbolicExpr>& f_expr, const std::string& var,
515 constexpr const char* operation = "solve_dispatch_vector";
516 if (!contains_transcendental_of_var(f_expr, var)) {
517 return std::nullopt;
518 }
519 auto substitution = detect_trans_substitutions(f_expr, var);
520 if (!substitution.mappings.empty() && is_polynomial_after_substitution(substitution)) {
521 return std::nullopt;
522 }
523 if (!opts.allow_numeric) {
526 "mixed transcendental equation is outside the finite-vector support domain",
527 operation);
528 }
529 auto mixed = solve_mixed_transcendental_checked(f_expr, var, opts, context);
530 if (!mixed) {
531 return SolveVectorResult::failure(mixed.error());
532 }
533 if (mixed.value().completeness == Completeness::Complete) {
534 return SolveVectorResult::success(std::move(mixed.value().value));
535 }
538 mixed.value().reason.empty() ? "mixed transcendental search is incomplete" : mixed.value().reason,
539 operation);
540}
541
543 if (!result) return SolveResult::failure(result.error());
544 if (result.value().empty()) {
546 }
547 std::vector<FiniteSolution> solutions;
548 solutions.reserve(result.value().size());
549 for (auto& value : result.value()) {
550 solutions.push_back(FiniteSolution{std::move(value), 1, {}});
551 }
552 return SolveResult::success(SolutionSet{FiniteSolutions{std::move(solutions)}});
553}
554
556 const std::shared_ptr<SymbolicExpr>& expr,
557 const std::string& var,
559 const SolveOptions& opts) try {
560 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
561 (context).limits().max_ast_nodes, "transform");
562 constexpr const char* operation = "solve_dispatch_set";
563 if (!expr || !LMCAS::detail::node(expr)) {
565 "expression cannot be null",
566 operation);
567 }
568 if (var.empty()) {
570 "solve variable cannot be empty",
571 operation);
572 }
573
574 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(expr), transform_budget));
575 if (!simplified || !LMCAS::detail::node(simplified)) {
577 "expression simplification failed",
578 operation);
579 }
580
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) {
584 auto left = LMCAS::detail::make_expression_ptr(rel->left());
585 auto right = LMCAS::detail::make_expression_ptr(rel->right());
586 f_expr = SymbolicExpr::add(
587 left, SymbolicExpr::multiply(right, SymbolicExpr::number(-1)));
588 }
589 }
590
591 auto polynomial = symbolic_to_poly<SymbolicPolyCoeff>(f_expr, var);
592 if (polynomial) {
593 return solve_symbolic_polynomial_set(polynomial.value(), expr, var, context);
594 }
595 if (polynomial.error().code != CasErrc::UnsupportedExpression) {
596 return SolveResult::failure(polynomial.error());
597 }
598
599 auto transcendental = solve_transcendental(f_expr, var, context, opts);
600 if (transcendental) return transcendental;
601 if (transcendental.error().code != CasErrc::Inconclusive) {
602 return SolveResult::failure(transcendental.error());
603 }
604
605 if (auto mixed = solve_finite_mixed(f_expr, var, context, opts)) {
606 return finite_values_to_set(std::move(*mixed));
607 }
608
609
611 "expression is outside the supported finite exact solve domain", operation);
612} catch (const CasError& error) {
613 return SolveResult::failure(error);
614} catch (const std::bad_alloc&) {
615 return SolveResult::failure(CasErrc::ResourceLimit, "allocation failed", "solve_dispatch_set");
616} catch (const std::length_error& error) {
617 return SolveResult::failure(CasErrc::ResourceLimit, error.what(), "solve_dispatch_set");
618} catch (const std::exception& error) {
619 return SolveResult::failure(CasErrc::InternalInvariant, error.what(), "solve_dispatch_set");
620}
621
623 const std::shared_ptr<SymbolicExpr>& expr,
624 const std::string& var,
626 const SolveOptions& opts) try {
627 constexpr const char* operation = "solve_finite_projection";
628 auto solved = solve_equation(expr, var, context, opts);
629 if (!solved) {
630 return SolveVectorResult::failure(solved.error());
631 }
632 auto solution_set = std::move(solved.value());
633 if (std::holds_alternative<EmptySolutions>(solution_set)) {
635 }
636 auto* finite = std::get_if<FiniteSolutions>(&solution_set);
637 if (!finite) {
640 "solution set is not finitely enumerable", operation);
641 }
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);
647 }
648 value_count += solution.multiplicity;
649 }
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);
655 }
656 }
657 return SolveVectorResult::success(std::move(values));
658}
659catch (const CasError& error) {
660 return SolveVectorResult::failure(error);
661} catch (const std::bad_alloc&) {
663 "finite solution projection allocation failed", "solve_finite_projection");
664} catch (const std::length_error& error) {
665 return SolveVectorResult::failure(CasErrc::ResourceLimit, error.what(), "solve_finite_projection");
666} catch (const std::exception& error) {
667 return SolveVectorResult::failure(CasErrc::InternalInvariant, error.what(), "solve_finite_projection");
668}
669
671 const std::shared_ptr<SymbolicExpr>& expression,
672 const std::string& variable,
673 const SolveOptions& options) {
676 expression, variable, context, options);
677}
678
679
680
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) {
685 ComputationContext context;
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) {
691 if (!equation) {
692 return {};
693 }
694 if (auto relation =
695 std::dynamic_pointer_cast<const RelationalNode>(
696 LMCAS::detail::node(equation))) {
697 if (relation->op() != RelationalNode::Op::EQ) {
698 return {};
699 }
700 auto normalized = SymbolicExpr::add(
702 SymbolicExpr::multiply(
703 SymbolicExpr::number(-1),
705 values.push_back(*detail::make_expression_ptr(detail::normalize_node(detail::node(normalized), transform_budget)));
706 } else {
707 values.push_back(*equation);
708 }
709 }
711 if (solved.empty()) {
712 return {};
713 }
714 std::map<std::string, std::shared_ptr<SymbolicExpr>> projected;
715 for (auto& [variable, value] : solved) {
716 projected.emplace(
717 variable, std::make_shared<SymbolicExpr>(std::move(value)));
718 }
719 return {std::move(projected)};
720}
721
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);
727}
728
729
730std::shared_ptr<SymbolicExpr> SymbolicExpr::transpose(const std::shared_ptr<SymbolicExpr>& mat) {
731 if (!mat) {
732 return mat;
733 }
734 auto m_node = std::dynamic_pointer_cast<const MatrixNode>(LMCAS::detail::node(mat));
735 if (!m_node) {
736 return mat;
737 }
738 size_t r = m_node->rows();
739 size_t c = m_node->cols();
740
741 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> new_data(c, std::vector<std::shared_ptr<SymbolicExpr>>(r));
742
743 for(size_t i=0; i<r; ++i) {
744 for(size_t j=0; j<c; ++j) {
745 new_data[j][i] = LMCAS::detail::make_expression_ptr(m_node->get(i,j));
746 }
747 }
748
749 return SymbolicExpr::matrix(new_data);
750}
751
752}
AssumptionContext class with scoped push/pop management.
@ Sqrt
对数、绝对值、平方根。
一元多项式模板类
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
获取多项式的次数
CasError & error()
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)
@ Real
Real numbers
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)
const ExprPtr & exponent
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 子表达式构造换元结果。
const ExprPtr & right
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,支持分段解。
多项式转换与精确符号多项式代数。
RootOf 恒等关系、求值及代数闭式化简。
混合超越方程求解:符号预处理 + 自适应根隔离 + Newton-Raphson 精化.
方程求解策略调度器 solve_dispatch 及相关选项结构体.
超越方程求解:三角、指数、对数方程的符号反演。
多项式方程组求解器 Solver,包含 Gröbner 基、线性系统求解。
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.