LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_definite_segments.cpp
浏览该文件的文档.
1#include <stdexcept>
5#include "limit_result.hpp"
8
9#include <unordered_map>
10
12namespace {
13class SegmentFacts final : public FactsQuery {
14public:
15 SegmentFacts(const AssumptionContext& assumptions, const std::string& variable,
16 const Boundary& lower, const Boundary& upper)
17 : base_(assumptions), var_(variable), lower_(lower), upper_(upper) {}
18
19 mutable std::optional<CasError> error;
21 auto result = value_sign_impl(node, context);
22 if (!result) error = result.error();
23 return result;
24 }
25
27 auto access = context.consume_steps(0, "facts.segment");
28 if (!access) { return Result<std::optional<int>>::failure(access.error()); }
29 const auto found = signs_.find(node);
30 if (found != signs_.end()) return found->second;
32 if (!value) return Result<std::optional<int>>::failure(value.error());
33 if (!value.value()) return std::optional<int>{};
34 auto denominator = polynomial_sign_checked(value.value()->denominator, lower_, upper_, context);
35 if (!denominator) return denominator;
36 if (!denominator.value() || *denominator.value() == 0) return std::optional<int>{};
37 auto numerator = polynomial_sign_checked(value.value()->numerator, lower_, upper_, context);
38 if (!numerator) return numerator;
39 std::optional<int> result;
40 if (numerator.value()) result = *numerator.value() * *denominator.value();
41 signs_.emplace(node, result);
42 return result;
43 }
44
51 if (!value) return Result<Tribool>::failure(value.error());
52 if (value.value()) return Tribool::True;
53 return remember(base_.is_real(node, context));
54 }
55private:
57 if (!result) error = result.error();
58 return result;
59 }
62 if (!value) { return Result<Tribool>::failure(value.error()); }
63 if (value.value()) {
64 int s = *value.value();
65 bool truth = property == 0 ? s > 0 : property == 1 ? s < 0 : property == 2 ? s >= 0 : s != 0;
66 return truth ? Tribool::True : Tribool::False;
67 }
68 switch (property) {
69 case 0: return remember(base_.is_positive(node, context));
70 case 1: return remember(base_.is_negative(node, context));
71 case 2: return remember(base_.is_nonnegative(node, context));
72 default: return remember(base_.is_nonzero(node, context));
73 }
74 }
76 const std::string& var_;
79 mutable std::unordered_map<Node, std::optional<int>> signs_;
80};
81
83
92
95 auto left = predicate_truth(logical.left(), facts, context);
96 if (!left) { return left; }
97 const auto negate = [](Tribool truth) {
98 return truth == Tribool::True ? Tribool::False :
100 };
101 if (logical.op() == LogicalNode::Op::Not) { return negate(left.value()); }
102 auto right = predicate_truth(logical.right(), facts, context);
103 if (!right) { return right; }
104 auto a = left.value(), b = right.value();
105 if (logical.op() == LogicalNode::Op::Implies) { a = negate(a); }
106 return binary_logical_truth(logical.op(), a, b);
107}
108
111 auto difference = sym_sub(detail::expression_from_node(relation.left()),
113 auto value = facts.value_sign(detail::node(difference), context);
114 if (!value) { return Result<Tribool>::failure(value.error()); }
115 if (!value.value()) { return Tribool::Unknown; }
116 const int s = *value.value();
117 bool truth;
118 switch (relation.op()) {
119 case RelationOp::EQ: { truth = s == 0; break; }
120 case RelationOp::NEQ: { truth = s != 0; break; }
121 case RelationOp::LT: { truth = s < 0; break; }
122 case RelationOp::LEQ: { truth = s <= 0; break; }
123 case RelationOp::GT: { truth = s > 0; break; }
124 case RelationOp::GEQ: { truth = s >= 0; break; }
125 default: { return Tribool::Unknown; }
126 }
127 return truth ? Tribool::True : Tribool::False;
128}
129
131 if (const auto* logical = dynamic_cast<const LogicalNode*>(node.get())) {
132 return logical_predicate_truth(*logical, facts, context);
133 }
134 if (const auto* relation = dynamic_cast<const RelationalNode*>(node.get())) {
136 }
137 return Tribool::Unknown;
138}
139
140/**
141 * @brief 在已认证开区间上进行恒等改写,保留对数分支。
142 * 对数分支变更仅由独立的原函数候选生成器处理。
143 */
145public:
147 std::optional<CasError> error;
148 void visit(const PiecewiseNode& piecewise) override {
149 for (const auto& branch : piecewise.branches()) {
150 auto truth = predicate_truth(branch.condition, facts_, context_);
151 if (!truth) { error = truth.error(); set_result(current()); return; }
152 if (truth.value() == Tribool::Unknown) {
153 error = CasError{CasErrc::Inconclusive, "piecewise branch is undecided", operation};
155 return;
156 }
157 if (truth.value() == Tribool::True) {
158 set_result(rewrite(branch.expression));
159 return;
160 }
161 }
162 if (piecewise.default_expr()) set_result(rewrite(piecewise.default_expr()));
163 else {
164 error = CasError{CasErrc::DomainError, "piecewise function has no value on the segment",
165 "integrate.definite.convergence"};
167 }
168 }
169 void visit(const PowerNode& node) override {
170 bool changed = false;
171 auto base = rewrite_child(node.base(), changed);
172 auto exponent = rewrite_child(node.exponent(), changed);
173 auto rewritten = changed ? detail::make_node<PowerNode>(base, exponent) : current();
174 if (!specialize_absolute(absolute_argument(*rewritten))) set_result(rewritten);
175 }
176 void visit(const FunctionNode& node) override {
177 bool changed = false;
178 auto arguments = rewrite_children(node.arguments(), changed);
179 auto rewritten = changed ? detail::make_node<FunctionNode>(node.type(), std::move(arguments)) : current();
180 if (!specialize_absolute(absolute_argument(*rewritten))) set_result(rewritten);
181 }
182private:
183 bool specialize_absolute(const Node& argument) {
184 if (!argument) return false;
185 auto real = detail::query_real_value(argument, facts_, context_);
186 if (!real) { error = real.error(); set_result(current()); return true; }
187 auto value = facts_.value_sign(argument, context_);
188 if (!value) { error = value.error(); set_result(current()); return true; }
189 if (!value.value()) {
190 auto nonnegative = detail::query_nonnegative_value(argument, facts_, context_);
191 if (!nonnegative) { error = nonnegative.error(); set_result(current()); return true; }
192 if (nonnegative.value() == Tribool::True) value.value() = 1;
193 else if (nonnegative.value() == Tribool::False) value.value() = -1;
194 }
195 if (real.value() != Tribool::True || !value.value()) return false;
196 set_result(*value.value() < 0
197 ? detail::node(SymbolicExpr::multiply(SymbolicExpr::number(-1),
198 detail::make_expression_ptr(argument))) : argument);
199 return true;
200 }
203};
204
205}
206
208 class Detector final : public detail::RecursiveSymbolicVisitor {
209 public:
210 bool found = false;
211 void visit(const PiecewiseNode&) override { found = true; }
212 void visit(const FunctionNode& function) override {
213 if (absolute_argument(function)) found = true;
215 }
216 void visit(const PowerNode& power) override {
217 if (absolute_argument(power)) found = true;
219 }
220 } detector;
221 node->accept(detector);
222 return detector.found;
223}
224
225static Result<void> collect_predicate_roots(const Node& condition, const std::string& var,
226 std::vector<Algebraic>& roots, ComputationContext& context) {
227 auto step = context.consume_steps(1, operation);
228 if (!step) { return step; }
229 if (const auto* logical = dynamic_cast<const LogicalNode*>(condition.get())) {
230 auto left = collect_predicate_roots(logical->left(), var, roots, context);
231 if (!left) { return left; }
232 if (logical->right()) { return collect_predicate_roots(logical->right(), var, roots, context); }
233 return Result<void>::success();
234 }
235 const auto* relation = dynamic_cast<const RelationalNode*>(condition.get());
236 if (!relation) { return undecided<void>(); }
237 auto difference = sym_sub(detail::expression_from_node(relation->left()),
239 auto rational = rational_checked(detail::node(difference), var, context);
240 if (!rational) { return Result<void>::failure(rational.error()); }
241 if (!rational.value()) { return undecided<void>(); }
242 for (const auto* polynomial : {&rational.value()->numerator, &rational.value()->denominator}) {
243 if (polynomial->degree() <= 0) { continue; }
244 auto isolated = roots_checked(*polynomial, context);
245 if (!isolated) { return Result<void>::failure(isolated.error()); }
246 roots.insert(roots.end(), isolated.value().begin(), isolated.value().end());
247 }
248 return Result<void>::success();
249}
250
252 AssumptionContext assumptions = context.assumptions() ? *context.assumptions() : AssumptionContext{};
253 assumptions.push();
254 auto real = assumptions.assume_domain_checked(var, Domain::Real);
256 return assumptions;
257}
258
260 std::vector<std::shared_ptr<SymbolicExpr>>& conditions, ComputationContext& context) {
261 auto step = context.consume_steps(1, operation);
262 if (!step) return step;
263 if (const auto* piecewise = dynamic_cast<const PiecewiseNode*>(node.get())) {
264 for (const auto& branch : piecewise->branches()) {
265 conditions.push_back(detail::make_expression_ptr(branch.condition));
266 auto child = original_conditions_checked(branch.expression, facts, conditions, context);
267 if (!child) return child;
268 }
269 if (piecewise->default_expr())
270 return original_conditions_checked(piecewise->default_expr(), facts, conditions, context);
271 return Result<void>::success();
272 }
274 if (!domain) return Result<void>::failure(domain.error());
275 if (!domain.value()) return undecided<void>();
276 conditions.insert(conditions.end(), domain.value()->begin(), domain.value()->end());
277 class AbsoluteBoundaries final : public detail::RecursiveSymbolicVisitor {
278 public:
279 AbsoluteBoundaries(std::vector<std::shared_ptr<SymbolicExpr>>& out, const FactsQuery& facts,
281 : out_(out), facts_(facts), context_(context) {}
282 std::optional<CasError> error;
283 void visit(const FunctionNode& function) override {
284 collect(function);
286 }
287 void visit(const PowerNode& power) override {
288 collect(power);
290 }
291 private:
292 void collect(const SymbolicNode& node) {
293 if (auto argument = absolute_argument(node)) {
294 auto nonnegative = detail::query_nonnegative_value(argument, facts_, context_);
295 if (!nonnegative) { error = nonnegative.error(); return; }
296 auto nonzero = detail::query_nonzero_value(argument, facts_, Domain::Real, context_);
297 if (!nonzero) { error = nonzero.error(); return; }
298 if (nonnegative.value() == Tribool::Unknown && nonzero.value() == Tribool::Unknown)
300 argument, detail::node(SymbolicExpr::number(0)), RelationOp::EQ)));
301 }
302 }
303 std::vector<std::shared_ptr<SymbolicExpr>>& out_;
304 const FactsQuery& facts_;
305 ComputationContext& context_;
306 } boundaries(conditions, facts, context);
307 node->accept(boundaries);
308 if (boundaries.error) return Result<void>::failure(*boundaries.error);
309 return Result<void>::success();
310}
311
313 const std::string& var, const SymbolicExpr& lower, const SymbolicExpr& upper,
315 if (!needs_segment_expression(detail::node(expression))) return expression;
318 if (!a) return Result<SymbolicExpr>::failure(a.error());
319 if (!b) return Result<SymbolicExpr>::failure(b.error());
320 auto assumptions = real_assumptions(var, context);
321 if (!assumptions) return Result<SymbolicExpr>::failure(assumptions.error());
322 SegmentFacts facts(assumptions.value(), var, a.value(), b.value());
323 SegmentExpression rewrite(facts, context);
324 auto selected = rewrite.rewrite(detail::node(expression));
325 if (rewrite.error) return Result<SymbolicExpr>::failure(*rewrite.error);
326 return detail::expression_from_node(selected);
327}
328
330 std::vector<Algebraic>& roots, const Boundary& a, const Boundary& b,
332 std::vector<Algebraic> ordered;
333 for (auto& root : roots) {
334 auto left = compare_boundaries(a, Boundary{0, root}, context);
335 auto right = compare_boundaries(Boundary{0, root}, b, context);
336 if (!left) { return Result<std::vector<Algebraic>>::failure(left.error()); }
337 if (!right) { return Result<std::vector<Algebraic>>::failure(right.error()); }
338 if (left.value() >= 0 || right.value() >= 0) { continue; }
339 auto position = ordered.begin();
340 bool duplicate = false;
341 for (; position != ordered.end(); ++position) {
342 auto comparison = compare_boundaries(Boundary{0, root}, Boundary{0, *position}, context);
343 if (!comparison) { return Result<std::vector<Algebraic>>::failure(comparison.error()); }
344 if (comparison.value() == 0) { duplicate = true; break; }
345 if (comparison.value() < 0) { break; }
346 }
347 if (!duplicate) { ordered.insert(position, std::move(root)); }
348 }
349 return ordered;
350}
351
353 const std::string& var, const SymbolicExpr& lower, const SymbolicExpr& upper,
355 auto assumptions = real_assumptions(var, context);
356 if (!assumptions) { return Result<std::vector<SymbolicExpr>>::failure(assumptions.error()); }
357 detail::AssumptionFacts facts(assumptions.value());
358 std::vector<std::shared_ptr<SymbolicExpr>> conditions;
359 auto captured = original_conditions_checked(detail::node(original), facts, conditions, context);
360 if (!captured) { return Result<std::vector<SymbolicExpr>>::failure(captured.error()); }
361 if (conditions.empty()) { return std::vector<SymbolicExpr>{lower, upper}; }
364 if (!a) { return Result<std::vector<SymbolicExpr>>::failure(a.error()); }
365 if (!b) { return Result<std::vector<SymbolicExpr>>::failure(b.error()); }
366 std::vector<Algebraic> roots;
367 for (const auto& condition : conditions) {
368 auto collected = collect_predicate_roots(detail::node(condition), var, roots, context);
369 if (!collected) { return Result<std::vector<SymbolicExpr>>::failure(collected.error()); }
370 }
371 auto ordered = ordered_partition_roots(roots, a.value(), b.value(), context);
372 if (!ordered) { return Result<std::vector<SymbolicExpr>>::failure(ordered.error()); }
373 std::vector<SymbolicExpr> result{lower};
374 for (const auto& root : ordered.value()) {
375 if (root.is_rational()) { result.push_back(*SymbolicExpr::number(root.lower)); }
376 else {
377 auto expression = make_rootof_checked(poly_to_symbolic(root.polynomial), var, root.root_index, context);
378 if (!expression) { return Result<std::vector<SymbolicExpr>>::failure(expression.error()); }
379 result.push_back(*expression.value());
380 }
381 }
382 result.push_back(upper);
383 return result;
384}
385
389 if (!defined || defined.value() != Tribool::Unknown) { return defined; }
390 const auto* interval = dynamic_cast<const SegmentFacts*>(&facts);
391 if (!interval) { return defined; }
393 if (!conditions) { return Result<Tribool>::failure(conditions.error()); }
394 if (!conditions.value()) { return Tribool::Unknown; }
395 bool unknown = false;
396 for (const auto& condition : *conditions.value()) {
397 auto truth = predicate_truth(detail::node(condition), *interval, context);
398 if (!truth) { return truth; }
399 if (truth.value() == Tribool::False) { return Tribool::False; }
400 unknown |= truth.value() == Tribool::Unknown;
401 }
402 return unknown ? Tribool::Unknown : Tribool::True;
403}
404
406 using F = FunctionNode::FuncType;
407 switch (type) {
408 case F::Sin: { return true; }
409 case F::Cos: { return true; }
410 case F::Exp: { return true; }
411 case F::Abs: { return true; }
412 case F::ArcTan: { return true; }
413 case F::Ln: { return true; }
414 case F::Log: { return true; }
415 case F::Sqrt: { return true; }
416 case F::Sinh: { return true; }
417 case F::Cosh: { return true; }
418 case F::Tan: { return true; }
419 case F::ArcSin: { return true; }
420 case F::ArcCos: { return true; }
421 default: { return false; }
422 }
423}
424
427
428static Result<Tribool> continuous_children(const std::vector<Node>& children,
430 for (const auto& child : children) {
431 auto continuous = structurally_continuous(child, facts, context);
432 if (!continuous || continuous.value() != Tribool::True) { return continuous; }
433 }
434 return Tribool::True;
435}
436
439 auto step = context.consume_steps(1, operation);
440 if (!step) { return Result<Tribool>::failure(step.error()); }
441 auto defined = defined_on_interval(node, facts, context);
442 if (!defined || defined.value() != Tribool::True) { return defined; }
443 if (dynamic_cast<const NumberNode*>(node.get()) || dynamic_cast<const VariableNode*>(node.get()) ||
444 dynamic_cast<const RootOfNode*>(node.get())) { return Tribool::True; }
445 const auto* sum = dynamic_cast<const AddNode*>(node.get());
446 const auto* product = dynamic_cast<const MultiplyNode*>(node.get());
447 const auto* function = dynamic_cast<const FunctionNode*>(node.get());
448 const auto* power = dynamic_cast<const PowerNode*>(node.get());
449 if (power) {
450 auto base = structurally_continuous(power->base(), facts, context);
451 if (!base || base.value() != Tribool::True) { return base; }
452 return structurally_continuous(power->exponent(), facts, context);
453 }
454 if (sum) { return continuous_children(sum->operands(), facts, context); }
455 if (product) { return continuous_children(product->operands(), facts, context); }
456 if (function) {
457 if (!continuous_function_family(function->type())) { return Tribool::Unknown; }
458 return continuous_children(function->arguments(), facts, context);
459 }
460 return Tribool::Unknown;
461}
462
463Result<Tribool> certify_continuity_checked(const SymbolicExpr& expression,
464 const std::string& var, const SymbolicExpr& lower, const SymbolicExpr& upper,
466 auto effective = segment_expression_checked(expression, var, lower, upper, context);
467 if (!effective) { return is_undecided(effective.error()) ? Result<Tribool>(Tribool::Unknown) :
468 Result<Tribool>::failure(effective.error()); }
469 auto assumptions = real_assumptions(var, context);
470 if (!assumptions) { return Result<Tribool>::failure(assumptions.error()); }
471 detail::AssumptionFacts global(assumptions.value());
472 auto everywhere = structurally_continuous(detail::node(effective.value()), global, context);
473 if (!everywhere || everywhere.value() != Tribool::Unknown) { return everywhere; }
477 if (!b) { return is_undecided(b.error()) ? Result<Tribool>(Tribool::Unknown) : Result<Tribool>::failure(b.error()); }
478 SegmentFacts facts(assumptions.value(), var, a.value(), b.value());
479 return structurally_continuous(detail::node(effective.value()), facts, context);
480}
481
482namespace {
484public:
486 std::optional<CasError> error;
487 void visit(const FunctionNode& node) override {
488 bool changed = false;
489 auto arguments = rewrite_children(node.arguments(), changed);
490 if (arguments.size() == 1 && (node.type() == FunctionNode::FuncType::Ln ||
492 auto nonzero = detail::query_nonzero_value(arguments[0], facts_, Domain::Real, context_);
493 if (!nonzero) { error = nonzero.error(); set_result(current()); return; }
494 auto real = detail::query_real_value(arguments[0], facts_, context_);
495 if (!real) { error = real.error(); set_result(current()); return; }
496 auto sign_value = facts_.value_sign(arguments[0], context_);
497 if (!sign_value) { error = sign_value.error(); set_result(current()); return; }
498 if (real.value() == Tribool::True && nonzero.value() == Tribool::True && sign_value.value()) {
499 if (*sign_value.value() < 0) {
500 arguments[0] = detail::node(SymbolicExpr::multiply(SymbolicExpr::number(-1),
501 detail::make_expression_ptr(arguments[0])));
502 changed = true;
503 }
504 if (node.type() == FunctionNode::FuncType::Abs) {
505 set_result(arguments[0]);
506 return;
507 }
508 }
509 }
510 set_result(changed ? detail::make_node<FunctionNode>(node.type(), std::move(arguments)) : current());
511 }
512private:
515};
516
517}
518
519static Result<SymbolicExpr> boundary_value_checked(const SymbolicExpr& primitive,
520 const std::string& var, const SymbolicExpr& point, LimitDirection direction,
523 if (!result) return Result<SymbolicExpr>::failure(result.error());
524 const auto& outcome = result.value().value;
525 if (const auto* finite = std::get_if<FiniteLimit>(&outcome)) return *finite->value;
526 if (std::holds_alternative<PositiveInfinityLimit>(outcome)) return *SymbolicExpr::infinity(1);
527 if (std::holds_alternative<NegativeInfinityLimit>(outcome)) return *SymbolicExpr::infinity(-1);
529}
530
531static Result<void> prepare_segment_primitive(SymbolicExpr& candidate,
532 const std::string& var, const SymbolicExpr& lower, const SymbolicExpr& upper,
536 if (!a && !is_undecided(a.error())) {
537 return Result<void>::failure(a.error());
538 }
539 if (!b && !is_undecided(b.error())) {
540 return Result<void>::failure(b.error());
541 }
542 if (a && b) {
543 auto assumptions = real_assumptions(var, context);
544 if (!assumptions) { return Result<void>::failure(assumptions.error()); }
545 SegmentFacts facts(assumptions.value(), var, a.value(), b.value());
546 RealPrimitiveCandidate rewrite(facts, context);
547 candidate = detail::expression_from_node(rewrite.rewrite(detail::node(candidate)));
548 if (rewrite.error) { return Result<void>::failure(*rewrite.error); }
549 }
550 auto continuous = certify_continuity_checked(candidate, var, lower, upper, context);
551 if (!continuous) { return Result<void>::failure(continuous.error()); }
552 if (continuous.value() != Tribool::True) { return undecided<void>(); }
553 return Result<void>::success();
554} catch (const CasError& error) {
555 return Result<void>::failure(error);
556} catch (const std::bad_alloc&) {
557 return Result<void>::failure(CasErrc::ResourceLimit, "allocation failed", "prepare_segment_primitive");
558} catch (const std::length_error& error) {
559 return Result<void>::failure(CasErrc::ResourceLimit, error.what(), "prepare_segment_primitive");
560} catch (const std::exception& error) {
561 return Result<void>::failure(CasErrc::InternalInvariant, error.what(), "prepare_segment_primitive");
562}
563
564static Result<SymbolicExpr> evaluate_segment_endpoints(const SymbolicExpr& candidate,
565 const std::string& var, const SymbolicExpr& a, const SymbolicExpr& b,
566 bool concrete_endpoints, ComputationContext& context) try {
567 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
568 (context).limits().max_ast_nodes, "transform");
569 if (!concrete_endpoints) {
570 auto high = detail::make_expression_ptr(detail::substitute_node(detail::node(candidate), var, detail::node(b), transform_budget));
571 auto low = detail::make_expression_ptr(detail::substitute_node(detail::node(candidate), var, detail::node(a), transform_budget));
573 "primitive substitution returned no expression", operation); }
574 return *detail::make_expression_ptr(detail::normalize_node(detail::node(sym_sub(*high, *low)), transform_budget));
575 }
576 auto high = boundary_value_checked(candidate, var, b, LimitDirection::FromBelow, context);
577 auto low = boundary_value_checked(candidate, var, a, LimitDirection::FromAbove, context);
578 if (!high) { return high; }
579 if (!low) { return low; }
580 const int hs = infinity_sign(detail::node(high.value()));
581 const int ls = -infinity_sign(detail::node(low.value()));
582 if (hs && ls && hs != ls) { return divergent<SymbolicExpr>(); }
583 if (hs || ls) { return *SymbolicExpr::infinity(hs ? hs : ls); }
584 return *detail::make_expression_ptr(detail::normalize_node(detail::node(sym_sub(high.value(), low.value())), transform_budget));
585} catch (const CasError& error) {
586 return Result<SymbolicExpr>::failure(error);
587} catch (const std::bad_alloc&) {
588 return Result<SymbolicExpr>::failure(CasErrc::ResourceLimit, "allocation failed", "evaluate_segment_endpoints");
589} catch (const std::length_error& error) {
590 return Result<SymbolicExpr>::failure(CasErrc::ResourceLimit, error.what(), "evaluate_segment_endpoints");
591} catch (const std::exception& error) {
592 return Result<SymbolicExpr>::failure(CasErrc::InternalInvariant, error.what(), "evaluate_segment_endpoints");
593}
594
596 const SymbolicExpr& primitive, const std::string& var,
597 const SymbolicExpr& a, const SymbolicExpr& b, ComputationContext& context) {
598 auto continuous = certify_continuity_checked(original, var, a, b, context);
599 if (!continuous) { return Result<SymbolicExpr>::failure(continuous.error()); }
600 if (continuous.value() == Tribool::False) { return divergent<SymbolicExpr>(); }
601 if (continuous.value() != Tribool::True) { return undecided<SymbolicExpr>(); }
602 SymbolicExpr candidate = primitive;
603 auto prepared = prepare_segment_primitive(candidate, var, a, b, context);
604 if (!prepared) { return Result<SymbolicExpr>::failure(prepared.error()); }
607 return evaluate_segment_endpoints(candidate, var, a, b, lower && upper, context);
608}
609}
加法节点,表示多个操作数的求和。
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ 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
乘法节点,表示多个操作数的乘积。
分段函数节点,表示条件分支表达式.
const std::shared_ptr< const SymbolicNode > & default_expr() const noexcept
const std::vector< Branch > & branches() const noexcept
幂运算节点,表示 base^exponent。
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
变量节点,表示一个符号变量。
void visit(const NumberNode &) override
void set_result(SymbolicNodePtr result)
SymbolicNodePtr rewrite(const SymbolicNodePtr &node)
SymbolicNodePtr rewrite_child(const SymbolicNodePtr &child, bool &changed)
std::vector< SymbolicNodePtr > rewrite_children(const Range &children, bool &changed)
SymbolicNodePtr current() const noexcept
Result< Tribool > is_real(const Node &node, ComputationContext &context) const override
Result< Tribool > is_positive(const Node &node, ComputationContext &context) const override
Result< Tribool > is_negative(const Node &node, ComputationContext &context) const override
Result< Tribool > is_nonzero(const Node &node, ComputationContext &context) const override
SegmentFacts(const AssumptionContext &assumptions, const std::string &variable, const Boundary &lower, const Boundary &upper)
Result< std::optional< int > > value_sign_impl(const Node &node, ComputationContext &context) const
Result< Tribool > property(const Node &node, int property, ComputationContext &context) const
Result< std::optional< int > > value_sign(const Node &node, ComputationContext &context) const
Result< Tribool > is_nonnegative(const Node &node, ComputationContext &context) const override
static Result< Tribool > logical_predicate_truth(const LogicalNode &logical, const SegmentFacts &facts, ComputationContext &context)
static Result< Tribool > predicate_truth(const Node &node, const SegmentFacts &facts, ComputationContext &context)
static Result< Tribool > relational_predicate_truth(const RelationalNode &relation, const SegmentFacts &facts, ComputationContext &context)
Result< SymbolicExpr > segment_expression_checked(const SymbolicExpr &expression, const std::string &var, const SymbolicExpr &lower, const SymbolicExpr &upper, ComputationContext &context)
Result< SymbolicExpr > definite_segment_checked(const SymbolicExpr &original, const SymbolicExpr &primitive, const std::string &var, const SymbolicExpr &a, const SymbolicExpr &b, ComputationContext &context)
static Result< Tribool > defined_on_interval(const Node &node, const FactsQuery &facts, ComputationContext &context)
static Result< SymbolicExpr > boundary_value_checked(const SymbolicExpr &primitive, const std::string &var, const SymbolicExpr &point, LimitDirection direction, ComputationContext &context)
static Result< std::vector< Algebraic > > ordered_partition_roots(std::vector< Algebraic > &roots, const Boundary &a, const Boundary &b, ComputationContext &context)
static Result< void > original_conditions_checked(const Node &node, const FactsQuery &facts, std::vector< std::shared_ptr< SymbolicExpr > > &conditions, ComputationContext &context)
Result< Tribool > certify_continuity_checked(const SymbolicExpr &expression, const std::string &var, const SymbolicExpr &lower, const SymbolicExpr &upper, ComputationContext &context)
Result< std::vector< SymbolicExpr > > definite_partition_checked(const SymbolicExpr &original, const std::string &var, const SymbolicExpr &lower, const SymbolicExpr &upper, ComputationContext &context)
static Result< void > prepare_segment_primitive(SymbolicExpr &candidate, const std::string &var, const SymbolicExpr &lower, const SymbolicExpr &upper, ComputationContext &context)
static Result< void > collect_predicate_roots(const Node &condition, const std::string &var, std::vector< Algebraic > &roots, ComputationContext &context)
Result< int > compare_boundaries(const Boundary &a, const Boundary &b, ComputationContext &context)
static Result< Tribool > continuous_children(const std::vector< Node > &children, const FactsQuery &facts, ComputationContext &context)
std::shared_ptr< const SymbolicNode > Node
static Result< SymbolicExpr > evaluate_segment_endpoints(const SymbolicExpr &candidate, const std::string &var, const SymbolicExpr &a, const SymbolicExpr &b, bool concrete_endpoints, ComputationContext &context)
static Result< Tribool > structurally_continuous(const Node &node, const FactsQuery &facts, ComputationContext &context)
Result< std::optional< int > > polynomial_sign_checked(const Poly &polynomial, const Boundary &a, const Boundary &b, ComputationContext &context)
Result< Boundary > boundary_checked(const SymbolicExpr &expression, ComputationContext &context)
RationalResult rational_checked(const Node &node, const std::string &var, ComputationContext &context)
Node absolute_argument(const SymbolicNode &node)
识别绝对值节点及公共接口的平方开根表示。
Result< std::vector< Algebraic > > roots_checked(const Poly &polynomial, ComputationContext &context)
static bool continuous_function_family(FunctionNode::FuncType type)
Result< AssumptionContext > real_assumptions(const std::string &var, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
const std::string & variable
std::shared_ptr< const SymbolicNode > Node
RewriteBudget const FactsQuery Domain domain
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
RewriteBudget const FactsQuery & facts
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)
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, 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
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr< SymbolicExpr > negate(const std::shared_ptr< SymbolicExpr > &expr)
const std::string const LimitExprPtr & point
LimitResult limit_checked(const LimitExprPtr &expression, const std::string &variable, const LimitExprPtr &point, LimitDirection direction, ComputationContext &context, Domain domain)
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
const ExprPtr & lower
@ Real
Real numbers
const std::string const LimitExprPtr LimitDirection direction
Tribool
Tri-state logic value for property queries.
@ Unknown
Property cannot be determined
@ True
Property definitely holds
@ False
Property definitely does not hold
const MultiPoly & b
RootOfConstructionResult make_rootof_checked(const std::shared_ptr< SymbolicExpr > &polynomial, const std::string &variable, std::size_t index, ComputationContext &context)
const ExprPtr RelationOp op
const ExprPtr & exponent
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
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)
const std::string const ExprPtr & value
std::shared_ptr< SymbolicExpr > sym_sub(const SymbolicExpr &lhs, const SymbolicExpr &rhs)
LimitDirection
Direction from which a limit approaches its point.
const ExprPtr & denominator
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
ExprResult rational(const Rational &value)
精确 RootOf 标识构造及受检数值求值。