LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
solve_solution_finalization.cpp
浏览该文件的文档.
1#include <stdexcept>
5#include "root_of_utils.hpp"
10namespace LMCAS {
11
13 if (std::dynamic_pointer_cast<const RelationalNode>(detail::node(expression))) {
14 return expression;
15 }
17 detail::node(expression), detail::node(SymbolicExpr::number(0)), RelationOp::EQ));
18}
19
20ExprPtr detail::substitute_raw(const ExprPtr& expression, const std::string& variable,
21 const ExprPtr& value) {
23 detail::node(expression), variable, detail::node(value)));
24}
25
26namespace {
29
31 if (!options.return_rootof) {
32 if (std::dynamic_pointer_cast<const RootOfNode>(detail::node(root))) {
33 root = rootof_simplify(root);
34 }
37 "complete roots require RootOf representation", "solve.representation");
38 }
39 }
40 return Result<void>::success();
41}
42
43ExprPtr equation_residual(const ExprPtr& expression) {
44 if (auto relation = std::dynamic_pointer_cast<const RelationalNode>(detail::node(expression))) {
45 return SymbolicExpr::add(detail::make_expression_ptr(relation->left()),
46 SymbolicExpr::multiply(SymbolicExpr::number(-1),
48 }
49 return expression;
50}
51
52void append_condition(std::vector<ExprPtr>& conditions, const ExprPtr& condition) {
53 for (const auto& existing : conditions) {
54 if (detail::node(existing)->equals(*detail::node(condition))) { return; }
55 }
56 conditions.push_back(condition);
57}
58
63
64Result<Tribool> solve_condition_truth(const ExprPtr& expression,
66
68 const FactsQuery& facts, ComputationContext& context) {
70 if (!left) { return left; }
71 if (logic.op() == LogicalNode::Op::Not) { return negate_truth(left.value()); }
73 if (!right) { return right; }
74 auto l = left.value();
75 auto r = right.value();
76 if (logic.op() == LogicalNode::Op::Implies) { l = negate_truth(l); }
77 if (logic.op() == LogicalNode::Op::And) {
78 if (l == Tribool::False || r == Tribool::False) { return Tribool::False; }
80 }
81 if (l == Tribool::True || r == Tribool::True) { return Tribool::True; }
83}
84
87 if (nonzero == Tribool::Unknown) {
88 auto residual = check_zero_residual(difference, context);
89 if (!residual) { return Result<Tribool>::failure(residual.error()); }
90 if (std::holds_alternative<ProvedZeroResidual>(residual.value())) { nonzero = Tribool::False; }
91 }
92 if (op == RelationOp::NEQ) { return nonzero; }
93 return negate_truth(nonzero);
94}
95
97 const RelationalNode& relation, const FactsQuery& facts, ComputationContext& context) try {
98 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
99 (context).limits().max_ast_nodes, "transform");
100 auto defined = detail::query_definedness(detail::node(expression), facts, Domain::Complex, context);
101 if (!defined) { return Result<Tribool>::failure(defined.error()); }
102 if (defined.value() != Tribool::True) { return Tribool::Unknown; }
103 auto difference = detail::make_expression_ptr(detail::normalize_node(detail::node(equation_residual(expression)), transform_budget));
104 auto nz = detail::query_nonzero_value(detail::node(difference), facts, Domain::Complex, context);
105 if (!nz) { return nz; }
106 if (relation.op() == RelationOp::EQ || relation.op() == RelationOp::NEQ) {
107 return equality_condition_truth(difference, nz.value(), relation.op(), context);
108 }
109 if (relation.op() == RelationOp::LT || relation.op() == RelationOp::LEQ) {
110 difference = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(SymbolicExpr::number(-1), difference)), transform_budget));
111 }
112 if (relation.op() == RelationOp::GEQ || relation.op() == RelationOp::LEQ) {
113 return detail::query_nonnegative_value(detail::node(difference), facts, context);
114 }
115 return detail::query_positive_value(detail::node(difference), facts, context);
116} catch (const CasError& error) {
117 return Result<Tribool>::failure(error);
118} catch (const std::bad_alloc&) {
119 return Result<Tribool>::failure(CasErrc::ResourceLimit, "allocation failed", "relational_condition_truth");
120} catch (const std::length_error& error) {
121 return Result<Tribool>::failure(CasErrc::ResourceLimit, error.what(), "relational_condition_truth");
122} catch (const std::exception& error) {
123 return Result<Tribool>::failure(CasErrc::InternalInvariant, error.what(), "relational_condition_truth");
124}
126 const FactsQuery& facts, ComputationContext& context) {
127 auto step = context.consume_steps(1, "solve.conditions");
128 if (!step) { return Result<Tribool>::failure(step.error()); }
129 const auto node = detail::node(expression);
130 if (auto logic = std::dynamic_pointer_cast<const LogicalNode>(node)) {
131 return logical_condition_truth(*logic, facts, context);
132 }
133 auto relation = std::dynamic_pointer_cast<const RelationalNode>(node);
134 if (!relation) { return Tribool::Unknown; }
135 return relational_condition_truth(expression, *relation, facts, context);
136}
137
140 const std::string& variable;
145
146 Result<bool> finish_conditions(std::vector<ExprPtr>& conditions) const {
147 std::vector<ExprPtr> remaining;
148 for (const auto& condition : conditions) {
149 auto truth = solve_condition_truth(condition, facts, context);
150 if (!truth) { return Result<bool>::failure(truth.error()); }
151 if (truth.value() == Tribool::False) { return false; }
152 if (truth.value() == Tribool::Unknown) { append_condition(remaining, condition); }
153 }
154 conditions = std::move(remaining);
155 return true;
156 }
157
158 Result<bool> finalize_value(const ExprPtr& value, std::vector<ExprPtr>& conditions) const try {
159 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
160 (context).limits().max_ast_nodes, "transform");
161 for (auto& condition : conditions) {
162 condition = substitute_raw(condition, variable, value);
163 }
164 auto bound = substitute_raw(original, variable, value);
166 if (!defined) { return Result<bool>::failure(defined.error()); }
167 if (defined.value() == Tribool::False) { return false; }
168 auto domain_conditions = detail::domain_constraints(detail::node(bound), facts, domain, context);
169 if (!domain_conditions) { return Result<bool>::failure(domain_conditions.error()); }
170 if (!domain_conditions.value()) {
172 "candidate domain cannot be completely expressed", "solve.finalize");
173 }
174 for (const auto& condition : *domain_conditions.value()) { append_condition(conditions, condition); }
175 auto valid = finish_conditions(conditions);
176 if (!valid || !valid.value()) { return valid; }
177 auto residual = check_zero_residual(equation_residual(bound), context);
178 if (!residual) { return Result<bool>::failure(residual.error()); }
179 if (!std::holds_alternative<ProvedZeroResidual>(residual.value())) {
180 auto pointwise_nonzero = detail::query_nonzero_value(detail::normalize_node(detail::node(equation_residual(bound)), transform_budget), facts, domain, context);
181 if (!pointwise_nonzero) { return Result<bool>::failure(pointwise_nonzero.error()); }
182 if (pointwise_nonzero.value() == Tribool::True) { return false; }
183 if (pointwise_nonzero.value() == Tribool::Unknown) {
184 append_condition(conditions, equation_predicate(bound));
185 }
186 }
187 return true;
188 } catch (const CasError& error) {
189 return Result<bool>::failure(error);
190} catch (const std::bad_alloc&) {
191 return Result<bool>::failure(CasErrc::ResourceLimit, "allocation failed", "finalize_value");
192} catch (const std::length_error& error) {
193 return Result<bool>::failure(CasErrc::ResourceLimit, error.what(), "finalize_value");
194} catch (const std::exception& error) {
195 return Result<bool>::failure(CasErrc::InternalInvariant, error.what(), "finalize_value");
196}
197
198 template<class Solutions>
199 SolveResult filter_values(Solutions& solutions) const {
200 Solutions kept;
201 for (auto& solution : solutions.values) {
202 auto valid = finalize_value(solution.value, solution.conditions);
203 if (!valid) { return SolveResult::failure(valid.error()); }
204 if (valid.value()) {
205 auto represented = apply_root_representation_policy(solution.value, options);
206 if (!represented) { return SolveResult::failure(represented.error()); }
207 kept.values.push_back(std::move(solution));
208 }
209 }
210 if (kept.values.empty()) { return SolutionSet{EmptySolutions{}}; }
211 return SolutionSet{std::move(kept)};
212 }
213
214public:
220
221 SolveResult finish(SolutionSet solutions) const {
222 if (auto finite = std::get_if<FiniteSolutions>(&solutions)) { return filter_values(*finite); }
223 if (auto parametric = std::get_if<ParametricSolutions>(&solutions)) { return filter_values(*parametric); }
225 if (!obligations) { return SolveResult::failure(obligations.error()); }
226 if (!obligations.value()) {
228 "original equation domain cannot be completely expressed", "solve.finalize");
229 }
230 if (auto conditional = std::get_if<ConditionalSolutions>(&solutions)) {
231 for (const auto& condition : *obligations.value()) {
232 append_condition(conditional->value.conditions, condition);
233 }
234 auto valid = finish_conditions(conditional->value.conditions);
235 if (!valid) { return SolveResult::failure(valid.error()); }
236 if (!valid.value()) { return SolutionSet{EmptySolutions{}}; }
237 return solutions;
238 }
239 auto conditions = std::move(*obligations.value());
240 auto valid = finish_conditions(conditions);
241 if (!valid) { return SolveResult::failure(valid.error()); }
242 if (!valid.value()) { return SolutionSet{EmptySolutions{}}; }
243 if (conditions.empty()) { return solutions; }
245 equation_predicate(original), std::move(conditions)}}};
246 }
247};
248}
249
251 const std::string& variable, SolutionSet solutions, ComputationContext& context,
253 if (std::holds_alternative<EmptySolutions>(solutions)) { return solutions; }
254 AssumptionContext local_facts = context.assumptions() ?
255 *context.assumptions() : AssumptionContext{};
256 if (domain == Domain::Real) {
257 auto declared = local_facts.assume_domain_checked(variable, Domain::Real);
258 if (!declared) { return SolveResult::failure(declared.error()); }
259 }
260 if (const auto* families = std::get_if<ParametricSolutions>(&solutions)) {
261 for (const auto& family : families->values) {
262 for (const auto& parameter : family.integer_parameters) {
263 auto declared = local_facts.assume_domain_checked(parameter, Domain::Integer);
264 if (!declared) { return SolveResult::failure(declared.error()); }
265 }
266 }
267 }
268 detail::AssumptionFacts adapter(local_facts);
269 return SolutionFinalizer(original, variable, adapter, context, domain, options).finish(std::move(solutions));
270}
271
272}
AssumptionContext class with scoped push/pop management.
@ Not
一元逻辑非,right 为 nullptr。
@ Implies
逻辑蕴含 A ⇒ B。
Op op() const noexcept
const std::shared_ptr< const SymbolicNode > & right() const noexcept
const std::shared_ptr< const SymbolicNode > & left() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< bool > finalize_value(const ExprPtr &value, std::vector< ExprPtr > &conditions) const
SolutionFinalizer(const ExprPtr &original, const std::string &variable, const FactsQuery &facts, ComputationContext &context, Domain domain, const SolveOptions &options)
ExprPtr substitute_raw(const ExprPtr &expression, const std::string &variable, const ExprPtr &value)
Result< Tribool > relational_condition_truth(const ExprPtr &expression, const RelationalNode &relation, const FactsQuery &facts, ComputationContext &context)
Result< void > apply_root_representation_policy(ExprPtr &root, const SolveOptions &options)
void append_condition(std::vector< ExprPtr > &conditions, const ExprPtr &condition)
Result< Tribool > logical_condition_truth(const LogicalNode &logic, const FactsQuery &facts, ComputationContext &context)
Result< Tribool > equality_condition_truth(const ExprPtr &difference, Tribool nonzero, RelationOp op, ComputationContext &context)
Result< Tribool > solve_condition_truth(const ExprPtr &expression, const FactsQuery &facts, ComputationContext &context)
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)
const std::string & variable
bool contains_node_type(const SymbolicNodePtr &root)
RewriteBudget const FactsQuery Domain domain
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
ExprPtr equation_predicate(const ExprPtr &expression)
std::shared_ptr< const Node > make_node(Args &&... args)
Result< std::optional< std::vector< std::shared_ptr< SymbolicExpr > > > > domain_constraints(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
Result< Tribool > query_nonnegative_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
std::shared_ptr< SymbolicExpr > rootof_simplify(const std::shared_ptr< SymbolicExpr > &rootof_expr)
__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
Result< SolutionSet > SolveResult
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
@ Complex
Complex numbers (default, least specific)
@ Real
Real numbers
const std::string ComputationContext const SolveOptions & options
Tribool
Tri-state logic value for property queries.
@ Unknown
Property cannot be determined
@ True
Property definitely holds
@ False
Property definitely does not hold
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
std::shared_ptr< SymbolicExpr > ExprPtr
const ExprPtr & right
ResidualCheckResult check_zero_residual(const ExprPtr &residual, ComputationContext &context, const LMCAS::EqvOptions &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
detail::SymbolicNodePtr substitute_free(const detail::SymbolicNodePtr &expression, const std::string &variable, const detail::SymbolicNodePtr &replacement, detail::RewriteBudget *budget)
方程求解选项,控制数值求解行为和结果形式.
RootOf 恒等关系、求值及代数闭式化简。