LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
limit_visitor_composition.cpp
浏览该文件的文档.
7
8namespace LMCAS {
9
10std::shared_ptr<const SymbolicNode> LimitVisitor::infinite_base_power_limit(
11 const std::shared_ptr<const SymbolicNode>& base,
12 const std::shared_ptr<const NumberNode>& number, bool integral, const BigInt& integer) {
13 if (is_neg_inf(base) && !integral) { return nullptr; }
14 if (get_sign(number) < 0) { return detail::make_node<NumberNode>(BigInt(0)); }
15 if (number->is_positive()) { return signed_infinity(is_neg_inf(base) && integer.is_odd() ? -1 : 1); }
16 return nullptr;
17}
18
19namespace {
20std::shared_ptr<const SymbolicNode> collect_log_power_factors(
21 const std::shared_ptr<const SymbolicNode>& exponent,
22 std::vector<std::shared_ptr<const SymbolicNode>>& coefficients) {
23 std::shared_ptr<const SymbolicNode> logarithm;
24 auto collect = [&](const std::shared_ptr<const SymbolicNode>& op) {
25 auto f = std::dynamic_pointer_cast<const FunctionNode>(op);
26 if (!logarithm && f && f->type() == FunctionNode::FuncType::Ln && f->arguments().size() == 1)
27 { logarithm = op; }
28 else { coefficients.push_back(op); }
29 };
30 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(exponent))
31 { for (const auto& op : product->operands()) { collect(op); } }
32 else { collect(exponent); }
33 return logarithm;
34}
35}
36
37
38
39std::shared_ptr<const SymbolicNode> LimitVisitor::linear_exponent_coefficient(
40 const std::shared_ptr<const SymbolicNode>& node) const {
41 if (is_limit_variable(node)) {
43 }
44 auto product = std::dynamic_pointer_cast<const MultiplyNode>(node);
45 if (!product) {
46 return nullptr;
47 }
48 bool has_variable = false;
49 std::vector<std::shared_ptr<const SymbolicNode>> factors;
50 for (const auto& operand : product->operands()) {
51 if (!has_variable && is_limit_variable(operand)) has_variable = true;
52 else factors.push_back(operand);
53 }
54 if (!has_variable) {
55 return nullptr;
56 }
57 return make_product_or_one(factors);
58}
59
60bool LimitVisitor::exponential_power_limit(const PowerNode& node) {
61 auto sum = std::dynamic_pointer_cast<const AddNode>(node.base());
62 if (!sum) {
63 return false;
64 }
65 auto coefficient = linear_exponent_coefficient(node.exponent());
66 if (!coefficient) {
67 return false;
68 }
69 auto term = one_plus_term(*sum);
70 if (!term) {
71 return false;
72 }
73 auto numerator = variable_fraction_numerator(term);
74 if (!numerator) {
75 return false;
76 }
77 if (!is_zero_limit(eval_limit(term))) return false;
79 std::vector<std::shared_ptr<const SymbolicNode>>{numerator, coefficient});
80 auto value = eval_limit(inner);
81 if (!value) return false;
84 std::vector<std::shared_ptr<const SymbolicNode>>{value});
85 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
86 exponential->accept(norm);
87 result = norm.get_result();
88 return true;
89}
90
91std::shared_ptr<const SymbolicNode> LimitVisitor::resolve_exponential_form(
92 const std::shared_ptr<const SymbolicNode>& base,
93 const std::shared_ptr<const SymbolicNode>& exponent) {
95 FunctionNode::FuncType::Ln, std::vector<std::shared_ptr<const SymbolicNode>>{base});
97 std::vector<std::shared_ptr<const SymbolicNode>>{exponent, logarithm});
98 auto value = eval_limit(product);
99 if (!value) {
100 return nullptr;
101 }
102 if (!is_inf(value)) {
104 FunctionNode::FuncType::Exp, std::vector<std::shared_ptr<const SymbolicNode>>{value});
105 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
106 exponential->accept(norm);
107 return norm.get_result();
108 }
109 if (!is_neg_inf(value)) {
110 return signed_infinity(1);
111 }
112 return LMCAS::detail::make_node<NumberNode>(BigInt(0));
113}
114
115std::shared_ptr<const SymbolicNode> LimitVisitor::singular_power_limit(
116 const PowerNode& node, const std::shared_ptr<const SymbolicNode>& base,
117 const std::shared_ptr<const SymbolicNode>& exponent) {
118 auto number = std::dynamic_pointer_cast<const NumberNode>(exponent);
119 if (!number) {
120 return nullptr;
121 }
122 BigInt integer;
123 const bool integral = try_get_integer_value(number, integer);
124 double value = get_numeric_value(number);
125 if (is_inf(base)) {
126 return infinite_base_power_limit(base, number, integral, integer);
127 }
128 if (!is_zero_limit(base) || !(value < 0) || direction.empty()) {
129 return nullptr;
130 }
131 auto sign = determine_sign_near_point(node.base(), direction);
132 if (!sign || *sign == 0) { return nullptr; }
133 if (!integral && *sign < 0) { return nullptr; }
134 return signed_infinity(integral && integer.is_odd() ? *sign : 1);
135}
136
137void LimitVisitor::visit(const PowerNode& node) {
138 if (is_limit_at_neg_infinity()) {
139 auto value = handle_neg_infinity_limit(
140 LMCAS::detail::make_node<PowerNode>(node.base(), node.exponent()));
141 if (value) {
142 result = value;
143 return;
144 }
145 }
146 if (is_limit_at_infinity() && exponential_power_limit(node)) {
147 return;
148 }
149 if (node.base()->is_one() && defined_near_point(node.exponent())) {
150 result = detail::make_node<NumberNode>(BigInt(1));
151 return;
152 }
153 if (node.exponent()->is_zero()) {
154 auto sign = determine_sign_near_point(node.base(), direction);
155 if (sign && *sign != 0) {
156 result = detail::make_node<NumberNode>(BigInt(1));
157 return;
158 }
159 }
160 node.base()->accept(*this);
161 auto base = result;
162 node.exponent()->accept(*this);
163 auto exponent = result;
164 if (!base || !exponent) { result = nullptr; return; }
165 if (classify_power_form(base, exponent) != IndeterminateForm::None) {
166 auto value = resolve_exponential_form(node.base(), node.exponent());
167 if (value) {
168 result = value;
169 return;
170 }
171 }
172 auto singular = singular_power_limit(node, base, exponent);
173 if (singular) {
174 result = singular;
175 return;
176 }
177 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
179 result = norm.get_result();
180}
181
182bool LimitVisitor::infinite_function_limit(FunctionNode::FuncType type, bool negative) {
183 switch (type) {
185 result = negative ? std::static_pointer_cast<const SymbolicNode>(
186 LMCAS::detail::make_node<NumberNode>(BigInt(0))) : signed_infinity(1);
187 return true;
189 result = negative ? nullptr : signed_infinity(1);
190 return !negative;
192 result = LMCAS::detail::make_node<NumberNode>(Rational(negative ? -1 : 1, 2));
194 std::vector<std::shared_ptr<const SymbolicNode>>{
195 result, LMCAS::detail::make_node<VariableNode>("pi", true)});
196 return true;
197 default:
198 return false;
199 }
200}
201
202bool LimitVisitor::composed_function_limit(const FunctionNode& node) {
203 if (node.arguments().size() != 1 ||
205 return false;
206 }
207 auto inner = eval_limit(node.arguments()[0]);
208 if (!inner) {
209 return false;
210 }
211 if (!is_inf(inner)) {
212 auto candidate = LMCAS::detail::make_node<FunctionNode>(node.type(),
213 std::vector<std::shared_ptr<const SymbolicNode>>{inner});
214 std::optional<detail::AssumptionFacts> assumed;
215 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
216 const auto& facts = assumed ? static_cast<const FactsQuery&>(*assumed) : detail::no_facts();
217 auto defined = detail::query_definedness(candidate, facts, Domain::Real, *context_);
218 if (!defined) { throw defined.error(); }
219 if (defined && defined.value() == Tribool::True) {
220 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
221 candidate->accept(norm);
222 result = norm.get_result();
223 return true;
224 }
225 if (node.type() == FunctionNode::FuncType::Ln && is_zero_limit(inner)) {
226 auto sign = determine_sign_near_point(node.arguments()[0], direction);
227 if (sign && *sign > 0) {
228 result = signed_infinity(-1);
229 return true;
230 }
231 }
232 }
233 if (is_inf(inner)) {
234 return infinite_function_limit(node.type(), is_neg_inf(inner));
235 }
236 return false;
237}
238
239std::shared_ptr<const SymbolicNode> LimitVisitor::positive_tail_log_power(const FunctionNode& node) const {
240 if (!is_limit_at_infinity() || node.type() != FunctionNode::FuncType::Exp ||
241 node.arguments().size() != 1) { return nullptr; }
242 std::vector<std::shared_ptr<const SymbolicNode>> coefficients;
243 auto logarithm = collect_log_power_factors(node.arguments()[0], coefficients);
244 if (!logarithm) { return nullptr; }
245 auto f = std::dynamic_pointer_cast<const FunctionNode>(logarithm);
246 std::optional<detail::AssumptionFacts> assumed;
247 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
248 const auto& facts = assumed ? static_cast<const FactsQuery&>(*assumed) : detail::no_facts();
249 auto exponent = make_product_or_one(coefficients);
250 auto real_exponent = detail::query_real_value(exponent, facts, *context_);
251 if (!real_exponent) { throw real_exponent.error(); }
252 if (real_exponent.value() != Tribool::True || !defined_near_point(f->arguments()[0])) { return nullptr; }
253 auto positive = detail::query_positive_value(f->arguments()[0], facts, *context_);
254 if (!positive) { throw positive.error(); }
255 if (positive.value() != Tribool::True) {
256 LimitVisitor witness(var, point, direction, assumption_ctx_, context_);
257 auto sign = witness.determine_sign_near_point(f->arguments()[0], direction);
258 if (!sign || *sign <= 0) { return nullptr; }
259 }
260 return detail::make_node<PowerNode>(f->arguments()[0], exponent);
261}
262
263void LimitVisitor::visit(const FunctionNode& node) {
264 if (is_limit_at_neg_infinity() && node.type() != FunctionNode::FuncType::Infinity) {
265 auto value = handle_neg_infinity_limit(
267 if (value) {
268 result = value;
269 return;
270 }
271 }
272 if (auto rewritten = positive_tail_log_power(node)) {
273 result = eval_limit(rewritten);
274 return;
275 }
276 if (node.type() == FunctionNode::FuncType::Sgn && node.arguments().size() == 1) {
277 auto value = evaluate_sgn_limit(node.arguments()[0]);
278 result = value ? *value : nullptr;
279 return;
280 }
281 if (node.type() == FunctionNode::FuncType::Abs && node.arguments().size() == 1) {
282 auto value = evaluate_abs_limit(node.arguments()[0]);
283 if (value) {
284 result = *value;
285 return;
286 }
287 }
288 if (composed_function_limit(node)) {
289 return;
290 }
291 std::vector<std::shared_ptr<const SymbolicNode>> arguments;
292 for (const auto& argument : node.arguments()) {
293 argument->accept(*this);
294 if (!result) return;
295 arguments.push_back(result);
296 }
297 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
298 LMCAS::detail::make_node<FunctionNode>(node.type(), arguments)->accept(norm);
299 result = norm.get_result();
300}
301
302}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Sgn
符号函数 sgn(x) ∈ {-1, 0, 1}。
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
幂运算节点,表示 base^exponent。
virtual void accept(LMCAS::detail::SymbolicVisitor &visitor) const =0
virtual bool is_zero() const
virtual bool is_one() const
极限访问器,通过代入和 L'Hôpital 法则计算极限。
std::shared_ptr< const SymbolicNode > collect_log_power_factors(const std::shared_ptr< const SymbolicNode > &exponent, std::vector< std::shared_ptr< const SymbolicNode > > &coefficients)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
const FactsQuery & no_facts() noexcept
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< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
const std::string const LimitExprPtr & point
ExprResult integer(Integer)=delete
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
@ Rational
Rational numbers
@ Real
Real numbers
const std::string const LimitExprPtr LimitDirection direction
@ True
Property definitely holds
const ExprPtr RelationOp op
const ExprPtr & exponent
const std::string const ExprPtr & value
符号表达式与一元多项式的转换。