LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
limit_visitor_predicates.cpp
浏览该文件的文档.
5#include "symbolic.hpp"
6
7namespace LMCAS {
8
9bool LimitVisitor::is_infinite_product(const MultiplyNode& product) const {
10 bool infinite = false;
11 for (const auto& operand : product.operands()) {
12 if (is_inf(operand)) { infinite = true; }
13 else {
14 auto sign = get_node_sign(operand);
15 if (!sign || !*sign) { return false; }
16 }
17 }
18 return infinite;
19}
20
21bool LimitVisitor::is_infinite_sum(const AddNode& sum) const {
22 int sign = 0;
23 for (const auto& operand : sum.operands()) {
24 if (is_inf(operand)) {
25 int next = is_neg_inf(operand) ? -1 : 1;
26 if (sign && sign != next) { return false; }
27 sign = next;
28 } else if (!std::dynamic_pointer_cast<const NumberNode>(operand)) { return false; }
29 }
30 return sign != 0;
31}
32
33std::optional<int> LimitVisitor::assumed_node_sign(
34 const std::shared_ptr<const SymbolicNode>& node) const {
35 std::optional<detail::AssumptionFacts> assumed;
36 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
37 const auto& facts = assumed ? static_cast<const FactsQuery&>(*assumed) : detail::no_facts();
38 auto nonzero = detail::query_nonzero_value(node, facts, Domain::Real, *context_);
39 if (!nonzero) { throw nonzero.error(); }
40 if (nonzero.value() == Tribool::False) { return 0; }
41 auto positive = detail::query_positive_value(node, facts, *context_);
42 if (!positive) { throw positive.error(); }
43 if (positive.value() == Tribool::True) { return 1; }
44 auto nonnegative = detail::query_nonnegative_value(node, facts, *context_);
45 if (!nonnegative) { throw nonnegative.error(); }
46 if (nonnegative.value() == Tribool::False) {
47 auto real = detail::query_real_value(node, facts, *context_);
48 if (!real) { throw real.error(); }
49 if (real.value() == Tribool::True) { return -1; }
50 }
51 return std::nullopt;
52}
53
54bool LimitVisitor::is_infinite_power(const PowerNode& node) const {
55 auto number = std::dynamic_pointer_cast<const NumberNode>(node.exponent());
56 BigInt integer;
57 return is_inf(node.base()) && number && try_get_integer_value(number, integer) && integer > BigInt(0);
58}
59
60bool LimitVisitor::is_inf(const std::shared_ptr<const SymbolicNode>& node) const {
61 if (!node) { return false; }
62 if (auto f = std::dynamic_pointer_cast<const FunctionNode>(node))
63 { return f->type() == FunctionNode::FuncType::Infinity; }
64 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
65 return is_infinite_product(*product);
66 }
67 if (auto sum = std::dynamic_pointer_cast<const AddNode>(node)) {
68 return is_infinite_sum(*sum);
69 }
70 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) { return is_infinite_power(*power); }
71 return false;
72}
73
74bool LimitVisitor::is_neg_inf(const std::shared_ptr<const SymbolicNode>& node) const {
75 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
76 if (!is_inf(node)) { return false; }
77 int sign = 1;
78 for (const auto& operand : product->operands())
79 { sign *= is_inf(operand) ? (is_neg_inf(operand) ? -1 : 1) : *get_node_sign(operand); }
80 return sign < 0;
81 }
82 if (auto sum = std::dynamic_pointer_cast<const AddNode>(node)) {
83 if (!is_inf(node)) { return false; }
84 for (const auto& operand : sum->operands()) { if (is_inf(operand)) { return is_neg_inf(operand); } }
85 }
86 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
87 BigInt integer;
88 auto number = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
89 return number && try_get_integer_value(number, integer) && integer.is_odd() && is_neg_inf(power->base());
90 }
91 return false;
92}
93
94std::optional<int> LimitVisitor::get_node_sign(
95 const std::shared_ptr<const SymbolicNode>& node) const {
96 if (!node) {
97 return std::nullopt;
98 }
99 if (node->is_zero()) {
100 return 0;
101 }
102 if (std::dynamic_pointer_cast<const NumberNode>(node)) {
103 return get_sign(node);
104 }
105 if (is_inf(node)) {
106 return is_neg_inf(node) ? -1 : 1;
107 }
108 return assumed_node_sign(node);
109}
110
111double LimitVisitor::get_numeric_value(const std::shared_ptr<const NumberNode>& num) const {
112 if (std::holds_alternative<BigInt>(num->value())) {
113 return std::get<BigInt>(num->value()).to_double();
114 }
115 if (std::holds_alternative<Rational>(num->value())) {
116 return std::get<Rational>(num->value()).to_double();
117 }
118 return std::numeric_limits<double>::quiet_NaN();
119}
120
121bool LimitVisitor::is_bounded_product(const MultiplyNode& node) const {
122 bool has_bounded = false;
123 for (const auto& operand : node.operands()) {
124 if (is_bounded(operand)) {
125 has_bounded = true;
126 } else if (!std::dynamic_pointer_cast<const NumberNode>(operand)) {
127 return false;
128 }
129 }
130 return has_bounded;
131}
132
133bool LimitVisitor::defined_near_point(const std::shared_ptr<const SymbolicNode>& node) const {
134 std::optional<detail::AssumptionFacts> assumed;
135 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
136 const auto& facts = assumed ? static_cast<const FactsQuery&>(*assumed) : detail::no_facts();
137 auto& context = *context_;
138 auto obligations = detail::domain_constraints(node, facts, Domain::Real, context);
139 if (!obligations) { throw obligations.error(); }
140 if (!obligations.value()) { return false; }
141 LimitVisitor witness(var, point, direction, assumption_ctx_, &context);
142 for (const auto& condition : *obligations.value())
143 { if (!witness.condition_holds_near_point(detail::node(condition))) { return false; } }
144 return true;
145}
146
147bool LimitVisitor::is_bounded(const std::shared_ptr<const SymbolicNode>& node) const {
148 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
149 return (function->type() == FunctionNode::FuncType::Sin ||
151 function->type() == FunctionNode::FuncType::ArcTan) && defined_near_point(node);
152 }
153 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
154 return is_bounded_product(*product);
155 }
156 auto power = std::dynamic_pointer_cast<const PowerNode>(node);
157 if (!power || !is_bounded(power->base())) {
158 return false;
159 }
160 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
161 return exponent && get_numeric_value(exponent) > 0;
162}
163
164bool LimitVisitor::is_bounded_expression(const std::shared_ptr<const SymbolicNode>& node) const {
165 if (!node) {
166 return false;
167 }
168 if (is_bounded(node)) {
169 return true;
170 }
171 auto sum = std::dynamic_pointer_cast<const AddNode>(node);
172 if (!sum) {
173 return false;
174 }
175 bool has_bounded = false;
176 for (const auto& operand : sum->operands()) {
177 if (is_bounded(operand) || is_bounded_expression(operand)) {
178 has_bounded = true;
179 } else if (!std::dynamic_pointer_cast<const NumberNode>(operand)) {
180 return false;
181 }
182 }
183 return has_bounded;
184}
185
186bool LimitVisitor::is_zero_limit(const std::shared_ptr<const SymbolicNode>& node) const {
187 return node && node->is_zero();
188}
189
190LimitVisitor::IndeterminateForm LimitVisitor::classify_product_form(
191 const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
192 bool zero = false;
193 bool infinity = false;
194 for (const auto& value : values) {
195 if (is_zero_limit(value)) zero = true;
196 if (is_inf(value)) infinity = true;
197 }
198 return zero && infinity ? IndeterminateForm::ZeroTimesInf : IndeterminateForm::None;
199}
200
201LimitVisitor::IndeterminateForm LimitVisitor::classify_power_form(
202 const std::shared_ptr<const SymbolicNode>& base,
203 const std::shared_ptr<const SymbolicNode>& exponent) {
204 if (base && base->is_one() && is_inf(exponent)) {
205 return IndeterminateForm::OnePowInf;
206 }
207 if (!is_zero_limit(exponent)) {
208 return IndeterminateForm::None;
209 }
210 if (is_zero_limit(base)) {
211 return IndeterminateForm::ZeroPowZero;
212 }
213 if (is_inf(base)) {
214 return IndeterminateForm::InfPowZero;
215 }
216 return IndeterminateForm::None;
217}
218
219LimitVisitor::IndeterminateForm LimitVisitor::classify_add_form(
220 const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
221 bool positive = false;
222 bool negative = false;
223 for (const auto& value : values) {
224 if (is_inf(value) && !is_neg_inf(value)) positive = true;
225 if (is_neg_inf(value)) negative = true;
226 }
227 return positive && negative ? IndeterminateForm::InfMinusInf : IndeterminateForm::None;
228}
229
230std::shared_ptr<const SymbolicNode> LimitVisitor::signed_infinity(int sign) const {
232 FunctionNode::FuncType::Infinity, std::vector<std::shared_ptr<const SymbolicNode>>{});
233 if (sign >= 0) {
234 return infinity;
235 }
237 std::vector<std::shared_ptr<const SymbolicNode>>{
238 LMCAS::detail::make_node<NumberNode>(BigInt(-1)), infinity});
239}
240
241}
加法节点,表示多个操作数的求和。
乘法节点,表示多个操作数的乘积。
幂运算节点,表示 base^exponent。
CasError & error()
virtual bool is_zero() const
极限访问器,通过代入和 L'Hôpital 法则计算极限。
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
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)
Result< Tribool > query_nonnegative_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
std::shared_ptr< SymbolicExpr > num(int value)
const std::string const LimitExprPtr & point
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Real
Real numbers
const std::string const LimitExprPtr LimitDirection direction
@ True
Property definitely holds
@ False
Property definitely does not hold
const ExprPtr & exponent
const std::string const ExprPtr & value
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.