LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
limit_visitor_asymptotic.cpp
浏览该文件的文档.
2#include "symbolic.hpp"
8
9namespace LMCAS {
10
11namespace {
12bool compatible_leading_sign(const std::optional<int>& sign, const std::optional<int>& leading_sign) {
13 if (!sign || !leading_sign) { return false; }
14 return *sign != 0 && *sign == *leading_sign;
15}
16}
17
18
19
20bool LimitVisitor::rational_denominator_supported(
21 const std::shared_ptr<const SymbolicNode>& leading_denominator,
22 const std::shared_ptr<const SymbolicNode>& num,
23 const std::shared_ptr<const SymbolicNode>& den) const {
24 std::optional<detail::AssumptionFacts> assumed;
25 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
26 const auto& facts = assumed ? static_cast<const FactsQuery&>(*assumed) : detail::no_facts();
27 auto denominator_nonzero = detail::query_nonzero_value(leading_denominator, facts, Domain::Real, *context_);
28 if (!denominator_nonzero) { throw denominator_nonzero.error(); }
29 if (denominator_nonzero.value() != Tribool::True) { return false; }
30 if (!defined_near_point(num) || !defined_near_point(den)) { return false; }
31 return true;
32}
33
34std::shared_ptr<const SymbolicNode> LimitVisitor::rational_leading_limit(
35 const std::shared_ptr<const SymbolicNode>& leading_numerator,
36 const std::shared_ptr<const SymbolicNode>& leading_denominator, int degree_difference) {
37 if (degree_difference == 0) {
38 auto ratio = detail::make_node<MultiplyNode>(std::vector<std::shared_ptr<const SymbolicNode>>{
39 leading_numerator, detail::make_node<PowerNode>(leading_denominator, detail::make_node<NumberNode>(BigInt(-1)))});
40 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
41 ratio->accept(norm);
42 return norm.get_result();
43 }
44 auto numerator_sign = get_node_sign(leading_numerator);
45 auto denominator_sign = get_node_sign(leading_denominator);
46 if (!denominator_sign || !*denominator_sign) { return nullptr; }
47 if (!numerator_sign || !*numerator_sign) { return nullptr; }
48 int sign = *numerator_sign * *denominator_sign;
49 if (is_limit_at_neg_infinity() && degree_difference % 2) { sign = -sign; }
50 return signed_infinity(sign);
51}
52
53std::optional<Rational> LimitVisitor::algebraic_sum_growth(const AddNode& sum) const {
54 std::optional<Rational> maximum;
55 std::optional<int> leading_sign;
56 std::size_t leading_count = 0;
57 bool common_sign = true;
58 LimitVisitor witness(var, point, direction, assumption_ctx_, context_);
59 for (const auto& term : sum.operands()) {
60 if (term->is_zero()) { continue; }
61 auto degree = algebraic_growth_degree(term);
62 if (!degree) { return std::nullopt; }
63 if (!maximum || *degree > *maximum) {
64 maximum = *degree;
65 leading_count = 1;
66 leading_sign = witness.determine_sign_near_point(term, direction);
67 common_sign = true;
68 } else if (*degree == *maximum) {
69 ++leading_count;
70 auto sign = witness.determine_sign_near_point(term, direction);
71 common_sign = common_sign && compatible_leading_sign(sign, leading_sign);
72 }
73 }
74 if (maximum && (leading_count == 1 || common_sign)) { return maximum; }
75 return std::nullopt;
76}
77
78std::optional<Rational> LimitVisitor::algebraic_product_growth(const MultiplyNode& product) const {
79 Rational degree(0);
80 for (const auto& operand : product.operands()) {
81 auto d = algebraic_growth_degree(operand);
82 if (!d) { return std::nullopt; }
83 degree = degree + *d;
84 }
85 return degree;
86}
87
88std::optional<Rational> LimitVisitor::algebraic_power_growth(const PowerNode& power) const {
90 auto degree = algebraic_growth_degree(power.base());
91 if (!exponent || !degree) { return std::nullopt; }
92 auto number = std::dynamic_pointer_cast<const NumberNode>(power.exponent());
93 BigInt integer;
94 if (!number || !try_get_integer_value(number, integer)) {
95 LimitVisitor witness(var, point, direction, assumption_ctx_, context_);
96 auto sign = witness.determine_sign_near_point(power.base(), direction);
97 if (!sign || *sign <= 0 || !defined_near_point(power.base())) { return std::nullopt; }
98 }
99 return *degree * exponent.value();
100}
101
102bool LimitVisitor::logarithmic_algebraic_bound(
103 const std::shared_ptr<const SymbolicNode>& expr) const {
104 auto function = std::dynamic_pointer_cast<const FunctionNode>(expr);
105 if (!function || function->type() != FunctionNode::FuncType::Ln ||
106 function->arguments().size() != 1) { return false; }
107 const auto& argument = function->arguments()[0];
108 if (!algebraic_growth_degree(argument) || !defined_near_point(argument)) { return false; }
109 LimitVisitor witness(var, point, direction, assumption_ctx_, context_);
110 auto sign = witness.determine_sign_near_point(argument, direction);
111 return sign && *sign > 0;
112}
113
114bool LimitVisitor::polynomial_logarithmic_operands(
115 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) const {
116 for (const auto& op : operands) {
117 if (!polynomial_logarithmic_bound(op)) { return false; }
118 }
119 return true;
120}
121
122bool LimitVisitor::exponential_dominates(
123 const std::shared_ptr<const SymbolicNode>& exponential,
124 const std::shared_ptr<const SymbolicNode>& other) {
125 auto f = std::dynamic_pointer_cast<const FunctionNode>(exponential);
126 if (!f || f->type() != FunctionNode::FuncType::Exp || f->arguments().size() != 1) {
127 return false;
128 }
129 if (!proves_superlogarithmic_magnitude(f->arguments()[0]) ||
130 !polynomial_logarithmic_bound(other)) { return false; }
131 auto exponent_limit = eval_limit(f->arguments()[0]);
132 return is_inf(exponent_limit) && !is_neg_inf(exponent_limit);
133}
134
135
136
137/**
138 * @brief 判断当前极限点是否为正无穷.
139 * @return 极限点为 +infinity 时返回 true
140 */
141bool LimitVisitor::is_limit_at_infinity() const {
142 if (auto f = std::dynamic_pointer_cast<const FunctionNode>(point)) {
143 return f->type() == FunctionNode::FuncType::Infinity;
144 }
145 return false;
146}
147
148/**
149 * @brief 判断当前极限点是否为负无穷.
150 *
151 * 负无穷表示为 -1 * Infinity 的 MultiplyNode.
152 * @return 极限点为 -infinity 时返回 true
153 */
154bool LimitVisitor::is_limit_at_neg_infinity() const {
155 return is_neg_inf(point);
156}
157
158/**
159 * @brief 转为关于 var 的有理系数多项式并求次数。
160 * @param[in] node AST 节点
161 * @return 多项式次数;空节点或不支持的表达式返回 -1。
162 * @note 其他转换错误原样抛出。
163 */
164int LimitVisitor::get_polynomial_degree(const std::shared_ptr<const SymbolicNode>& node) const {
165 if (!node) return -1;
166 auto polynomial = symbolic_to_poly<Rational>(detail::make_expression_ptr(node), var);
167 if (!polynomial && polynomial.error().code != CasErrc::UnsupportedExpression) throw polynomial.error();
168 return polynomial ? polynomial.value().degree() : -1;
169}
170
171/**
172 * @brief 获取多项式的首项系数.
173 *
174 * 对于多项式 P(x) = a_n * x^n + ... + a_0,返回 a_n.
175 *
176 * @param[in] node AST 节点
177 * @return 首项系数节点;空节点、零多项式或不支持的表达式返回 nullptr。
178 */
179std::shared_ptr<const SymbolicNode> LimitVisitor::get_leading_coefficient(
180 const std::shared_ptr<const SymbolicNode>& node) const {
181 if (!node) return nullptr;
182 auto polynomial = symbolic_to_poly<Rational>(detail::make_expression_ptr(node), var);
183 if (!polynomial && polynomial.error().code != CasErrc::UnsupportedExpression) throw polynomial.error();
184 return polynomial && !polynomial.value().is_zero()
185 ? detail::make_node<NumberNode>(polynomial.value().lead_coeff()) : nullptr;
186}
187
188/**
189 * @brief 通过多项式次数比较计算有理函数在无穷处的极限.
190 *
191 * 对于 P(x)/Q(x):
192 * - deg(P) < deg(Q) -> 0
193 * - deg(P) = deg(Q) -> 首项系数之比
194 * - deg(P) > deg(Q) -> +/-infinity,符号由首项系数及负无穷处次数差的奇偶性决定
195 *
196 * @param[in] num 分子 AST 节点
197 * @param[in] den 分母 AST 节点
198 * @return 极限结果,非有理函数时返回 nullptr
199 */
200std::shared_ptr<const SymbolicNode> LimitVisitor::limit_rational_at_infinity(
201 const std::shared_ptr<const SymbolicNode>& num,
202 const std::shared_ptr<const SymbolicNode>& den) {
203 charge();
204 auto numerator = symbolic_to_poly<SymbolicPolyCoeff>(detail::make_expression_ptr(num), var);
205 auto denominator = symbolic_to_poly<SymbolicPolyCoeff>(detail::make_expression_ptr(den), var);
206 if (!numerator && numerator.error().code != CasErrc::UnsupportedExpression) { throw numerator.error(); }
207 if (!denominator && denominator.error().code != CasErrc::UnsupportedExpression) { throw denominator.error(); }
208 if (!numerator || !denominator || denominator.value().is_zero()) { return nullptr; }
209 auto normalized_denominator = detail::simplify_expression(
210 denominator.value().lead_coeff().val, *context_);
211 if (!normalized_denominator) { throw normalized_denominator.error(); }
212 auto leading_denominator = detail::node(normalized_denominator.value());
213 if (!rational_denominator_supported(leading_denominator, num, den)) { return nullptr; }
214 if (numerator.value().is_zero() || numerator.value().degree() < denominator.value().degree())
215 { return detail::make_node<NumberNode>(BigInt(0)); }
216 auto normalized_numerator = detail::simplify_expression(
217 numerator.value().lead_coeff().val, *context_);
218 if (!normalized_numerator) { throw normalized_numerator.error(); }
219 auto leading_numerator = detail::node(normalized_numerator.value());
220 return rational_leading_limit(leading_numerator, leading_denominator,
221 numerator.value().degree() - denominator.value().degree());
222}
223
224/**
225 * @brief 分类表达式的增长速率.
226 *
227 * 增长速率层次:Exponential > Polynomial > Logarithmic > Constant
228 *
229 * @param[in] node AST 节点
230 * @return 增长速率分类
231 */
232LimitVisitor::GrowthClass LimitVisitor::classify_growth(const std::shared_ptr<const SymbolicNode>& node) const {
233 if (!node) {
234 return GrowthClass::Unknown;
235 }
236
237 if (auto num = std::dynamic_pointer_cast<const NumberNode>(node)) {
238 return GrowthClass::Constant;
239 }
240
241 if (auto v = std::dynamic_pointer_cast<const VariableNode>(node)) {
242 return (!v->is_constant() && v->name() == var)
243 ? GrowthClass::Polynomial : GrowthClass::Constant;
244 }
245
246 if (auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
247 return function_growth(*func);
248 }
249
250 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
251 return power_growth(*pow);
252 }
253
254 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
255 return operands_growth(mul->operands());
256 }
257
258 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
259 return operands_growth(add->operands());
260 }
261
262 return GrowthClass::Unknown;
263}
264
265LimitVisitor::GrowthClass LimitVisitor::function_growth(const FunctionNode& node) const {
266 if (node.type() == FunctionNode::FuncType::Exp) {
267 return GrowthClass::Exponential;
268 }
269 if (node.type() == FunctionNode::FuncType::Ln ||
271 return GrowthClass::Logarithmic;
272 }
273 if (node.type() == FunctionNode::FuncType::Sin ||
275 return GrowthClass::Constant;
276 }
277 return GrowthClass::Unknown;
278}
279
280LimitVisitor::GrowthClass LimitVisitor::power_growth(const PowerNode& node) const {
281 if (is_limit_variable(node.base())) {
282 return GrowthClass::Polynomial;
283 }
284 if (std::dynamic_pointer_cast<const NumberNode>(node.base())) {
285 if (get_polynomial_degree(node.exponent()) > 0) {
286 return GrowthClass::Exponential;
287 }
288 }
289 auto growth = classify_growth(node.base());
290 if (growth == GrowthClass::Exponential) {
291 return growth;
292 }
293 if (growth == GrowthClass::Polynomial) {
294 return growth;
295 }
296 return GrowthClass::Unknown;
297}
298
299LimitVisitor::GrowthClass LimitVisitor::operands_growth(
300 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) const {
301 GrowthClass maximum = GrowthClass::Constant;
302 for (const auto& operand : operands) {
303 auto growth = classify_growth(operand);
304 if (growth == GrowthClass::Unknown) {
305 return growth;
306 }
307 if (static_cast<int>(growth) > static_cast<int>(maximum)) maximum = growth;
308 }
309 return maximum;
310}
311
312
313/**
314 * @brief 求代数增长次数,供指数、多项式、对数增长率比较使用。
315 * 乘积次数相加,幂次数相乘;和式须排除最高次项相消。
316 * 非整数幂要求底数在邻域内有定义且为正。
317 * @param[in] expr 表达式节点
318 * @return 有理增长次数;无法证明时返回 std::nullopt。
319 */
320std::optional<Rational> LimitVisitor::algebraic_growth_degree(
321 const std::shared_ptr<const SymbolicNode>& expr) const {
322 charge();
323 if (!expr) { return std::nullopt; }
324 auto polynomial = symbolic_to_poly<Rational>(detail::make_expression_ptr(expr), var);
325 if (!polynomial && polynomial.error().code != CasErrc::UnsupportedExpression) { throw polynomial.error(); }
326 if (polynomial && !polynomial.value().is_zero())
327 { return Rational(polynomial.value().degree()); }
328 if (auto sum = std::dynamic_pointer_cast<const AddNode>(expr)) {
329 auto cancelled = detail::make_expression_ptr(expr)->cancel();
330 if (cancelled && detail::node(cancelled)->compare(*expr) != 0 && defined_near_point(expr))
331 { return algebraic_growth_degree(detail::node(cancelled)); }
332 return algebraic_sum_growth(*sum);
333 }
334 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(expr)) {
335 return algebraic_product_growth(*product);
336 }
337 if (auto power = std::dynamic_pointer_cast<const PowerNode>(expr)) {
338 return algebraic_power_growth(*power);
339 }
340 return std::nullopt;
341}
342bool LimitVisitor::polynomial_logarithmic_bound(
343 const std::shared_ptr<const SymbolicNode>& expr) const {
344 auto polynomial = symbolic_to_poly<SymbolicPolyCoeff>(detail::make_expression_ptr(expr), var);
345 if (!polynomial && polynomial.error().code != CasErrc::UnsupportedExpression) { throw polynomial.error(); }
346 if (polynomial && defined_near_point(expr)) { return true; }
347 if (algebraic_growth_degree(expr)) { return true; }
348 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(expr)) {
349 return polynomial_logarithmic_operands(product->operands());
350 }
351 if (auto sum = std::dynamic_pointer_cast<const AddNode>(expr)) {
352 return polynomial_logarithmic_operands(sum->operands());
353 }
354 if (auto power = std::dynamic_pointer_cast<const PowerNode>(expr)) {
355 BigInt integer;
356 auto n = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
357 return n && try_get_integer_value(n, integer) && integer > BigInt(0) &&
358 polynomial_logarithmic_bound(power->base());
359 }
360 return logarithmic_algebraic_bound(expr);
361}
362std::shared_ptr<const SymbolicNode> LimitVisitor::limit_by_growth_comparison(
363 const std::shared_ptr<const SymbolicNode>& num,
364 const std::shared_ptr<const SymbolicNode>& den) {
365 if (exponential_dominates(den, num)) { return detail::make_node<NumberNode>(BigInt(0)); }
366 if (exponential_dominates(num, den)) {
367 auto denominator = eval_limit(den);
368 auto sign = get_node_sign(denominator);
369 if (sign && *sign) { return signed_infinity(*sign); }
370 }
371 auto log = std::dynamic_pointer_cast<const FunctionNode>(num);
372 auto denominator_degree = algebraic_growth_degree(den);
373 if (log && log->type() == FunctionNode::FuncType::Ln &&
374 polynomial_logarithmic_bound(num) && denominator_degree && *denominator_degree > Rational(0))
375 { return detail::make_node<NumberNode>(BigInt(0)); }
376 return nullptr;
377}
378
379bool LimitVisitor::proves_superlogarithmic_magnitude(
380 const std::shared_ptr<const SymbolicNode>& expr) const {
381 auto degree = algebraic_growth_degree(expr);
382 return degree && *degree > Rational(0);
383}
384
385
386/**
387 * @brief 处理 x->-infinity 的极限,通过代换 x = -t 转化为 t->+infinity.
388 *
389 * @param[in] expr 原始表达式
390 * @return 极限结果;不支持的表达式返回 nullptr。
391 */
392std::shared_ptr<const SymbolicNode> LimitVisitor::handle_neg_infinity_limit(
393 const std::shared_ptr<const SymbolicNode>& expr) {
394
395 if (!expr) {
396 return nullptr;
397 }
398
399 std::string t_var = "__neg_inf_t__";
400
401 auto substituted = substitute_neg_t(expr, t_var);
402 if (!substituted) {
403 return nullptr;
404 }
405
406 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
407 substituted->accept(norm);
408 substituted = norm.get_result();
409 if (!substituted) {
410 return nullptr;
411 }
412
413 std::vector<std::shared_ptr<const SymbolicNode>> inf_args;
415
416 LimitVisitor sub_vis(t_var, pos_inf, "", assumption_ctx_, context_);
417 sub_vis.lhopital_depth_ = this->lhopital_depth_;
418 substituted->accept(sub_vis);
419 return sub_vis.get_result();
420}
421
422static std::shared_ptr<const SymbolicNode> substitute_negative_variable(
423 const VariableNode& node, const std::string& var, const std::string& t_var) {
424 if (!node.is_constant() && node.name() == var) {
425 std::vector<std::shared_ptr<const SymbolicNode>> ops = {
428 };
430 }
431 return node.clone();
432}
433
434/**
435 * @brief 在表达式中将 var 替换为 -t_var.
436 *
437 * @param[in] node AST 节点
438 * @param[in] t_var 替换变量名
439 * @return 替换后的节点
440 */
441std::shared_ptr<const SymbolicNode> LimitVisitor::substitute_neg_t(
442 const std::shared_ptr<const SymbolicNode>& node, const std::string& t_var) const {
443
444 if (!node) {
445 return nullptr;
446 }
447
448 if (auto num = std::dynamic_pointer_cast<const NumberNode>(node)) {
449 return node->clone();
450 }
451
452 if (auto v = std::dynamic_pointer_cast<const VariableNode>(node)) {
453 return substitute_negative_variable(*v, var, t_var);
454 }
455
456 auto add = std::dynamic_pointer_cast<const AddNode>(node);
457 auto mul = add ? std::shared_ptr<const MultiplyNode>{}
458 : std::dynamic_pointer_cast<const MultiplyNode>(node);
459 if (add || mul) {
460 const auto& operands = add ? add->operands() : mul->operands();
461 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
462 for (const auto& op : operands) {
463 auto sub = substitute_neg_t(op, t_var);
464 if (!sub) {
465 return nullptr;
466 }
467 new_ops.push_back(sub);
468 }
469 if (add) {
470 return LMCAS::detail::make_node<AddNode>(new_ops);
471 }
473 }
474
475 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
476 auto new_base = substitute_neg_t(pow->base(), t_var);
477 auto new_exp = substitute_neg_t(pow->exponent(), t_var);
478 if (!new_base || !new_exp) {
479 return nullptr;
480 }
481 return LMCAS::detail::make_node<PowerNode>(new_base, new_exp);
482 }
483
484 if (auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
485 return substitute_function_neg_t(*func, t_var);
486 }
487 return node->clone();
488}
489
490std::shared_ptr<const SymbolicNode> LimitVisitor::substitute_function_neg_t(
491 const FunctionNode& node, const std::string& t_var) const {
493 return node.clone();
494 }
495 std::vector<std::shared_ptr<const SymbolicNode>> arguments;
496 for (const auto& argument : node.arguments()) {
497 auto substituted = substitute_neg_t(argument, t_var);
498 if (!substituted) {
499 return nullptr;
500 }
501 arguments.push_back(substituted);
502 }
503 return LMCAS::detail::make_node<FunctionNode>(node.type(), arguments);
504}
505
506}
加法节点,表示多个操作数的求和。
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
乘法节点,表示多个操作数的乘积。
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
幂运算节点,表示 base^exponent。
virtual std::shared_ptr< const SymbolicNode > clone() const =0
变量节点,表示一个符号变量。
极限访问器,通过代入和 L'Hôpital 法则计算极限。
bool compatible_leading_sign(const std::optional< int > &sign, const std::optional< int > &leading_sign)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
ExpressionResult simplify_expression(const ExprPtr &expression, ComputationContext &context)
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)
std::shared_ptr< SymbolicExpr > num(int value)
const std::string const LimitExprPtr & point
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::string & v
ExprResult integer(Integer)=delete
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
ExprResult sub(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
@ Rational
Rational numbers
@ Real
Real numbers
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
static std::shared_ptr< const SymbolicNode > substitute_negative_variable(const VariableNode &node, const std::string &var, const std::string &t_var)
std::size_t std::size_t std::size_t growth
const std::string const LimitExprPtr LimitDirection direction
@ True
Property definitely holds
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
Result< T > extract_coeff_value(const std::shared_ptr< SymbolicExpr > &coefficient)
精确提取系数;不支持的值返回错误,保持数值完整。
const ExprPtr RelationOp op
const ExprPtr & exponent
ExprResult log(const ExprPtr &expression, ComputationContext &context)
const ExprPtr & denominator
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
符号表达式与一元多项式的转换。
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.