13 if (!sign || !leading_sign) {
return false; }
14 return *sign != 0 && *sign == *leading_sign;
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_); }
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; }
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) {
42 return norm.get_result();
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);
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) {
66 leading_sign = witness.determine_sign_near_point(term,
direction);
68 }
else if (*degree == *maximum) {
70 auto sign = witness.determine_sign_near_point(term,
direction);
74 if (maximum && (leading_count == 1 || common_sign)) {
return maximum; }
78std::optional<Rational> LimitVisitor::algebraic_product_growth(
const MultiplyNode& product)
const {
80 for (
const auto& operand : product.operands()) {
81 auto d = algebraic_growth_degree(operand);
82 if (!d) {
return std::nullopt; }
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());
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; }
102bool LimitVisitor::logarithmic_algebraic_bound(
103 const std::shared_ptr<const SymbolicNode>& expr)
const {
104 auto function = std::dynamic_pointer_cast<const FunctionNode>(expr);
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);
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; }
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);
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);
141bool LimitVisitor::is_limit_at_infinity()
const {
142 if (
auto f = std::dynamic_pointer_cast<const FunctionNode>(
point)) {
154bool LimitVisitor::is_limit_at_neg_infinity()
const {
155 return is_neg_inf(
point);
164int LimitVisitor::get_polynomial_degree(
const std::shared_ptr<const SymbolicNode>& node)
const {
165 if (!node)
return -1;
168 return polynomial ? polynomial.value().degree() : -1;
179std::shared_ptr<const SymbolicNode> LimitVisitor::get_leading_coefficient(
180 const std::shared_ptr<const SymbolicNode>& node)
const {
181 if (!node)
return nullptr;
184 return polynomial && !polynomial.value().is_zero()
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) {
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())
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());
232LimitVisitor::GrowthClass LimitVisitor::classify_growth(
const std::shared_ptr<const SymbolicNode>& node)
const {
234 return GrowthClass::Unknown;
237 if (
auto num = std::dynamic_pointer_cast<const NumberNode>(node)) {
238 return GrowthClass::Constant;
241 if (
auto v = std::dynamic_pointer_cast<const VariableNode>(node)) {
242 return (!
v->is_constant() &&
v->name() == var)
243 ? GrowthClass::Polynomial : GrowthClass::Constant;
246 if (
auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
247 return function_growth(*func);
250 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
251 return power_growth(*
pow);
254 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
255 return operands_growth(
mul->operands());
258 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
259 return operands_growth(
add->operands());
262 return GrowthClass::Unknown;
265LimitVisitor::GrowthClass LimitVisitor::function_growth(
const FunctionNode& node)
const {
267 return GrowthClass::Exponential;
271 return GrowthClass::Logarithmic;
275 return GrowthClass::Constant;
277 return GrowthClass::Unknown;
280LimitVisitor::GrowthClass LimitVisitor::power_growth(
const PowerNode& node)
const {
281 if (is_limit_variable(
node.base())) {
282 return GrowthClass::Polynomial;
284 if (std::dynamic_pointer_cast<const NumberNode>(
node.base())) {
285 if (get_polynomial_degree(
node.exponent()) > 0) {
286 return GrowthClass::Exponential;
290 if (
growth == GrowthClass::Exponential) {
293 if (
growth == GrowthClass::Polynomial) {
296 return GrowthClass::Unknown;
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) {
307 if (
static_cast<int>(
growth) >
static_cast<int>(maximum)) maximum =
growth;
320std::optional<Rational> LimitVisitor::algebraic_growth_degree(
321 const std::shared_ptr<const SymbolicNode>& expr)
const {
323 if (!expr) {
return std::nullopt; }
326 if (polynomial && !polynomial.value().is_zero())
327 {
return Rational(polynomial.value().degree()); }
328 if (
auto sum = std::dynamic_pointer_cast<const AddNode>(expr)) {
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);
334 if (
auto product = std::dynamic_pointer_cast<const MultiplyNode>(expr)) {
335 return algebraic_product_growth(*product);
337 if (
auto power = std::dynamic_pointer_cast<const PowerNode>(expr)) {
338 return algebraic_power_growth(*power);
342bool LimitVisitor::polynomial_logarithmic_bound(
343 const std::shared_ptr<const SymbolicNode>& expr)
const {
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());
351 if (
auto sum = std::dynamic_pointer_cast<const AddNode>(expr)) {
352 return polynomial_logarithmic_operands(sum->operands());
354 if (
auto power = std::dynamic_pointer_cast<const PowerNode>(expr)) {
356 auto n = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
358 polynomial_logarithmic_bound(power->base());
360 return logarithmic_algebraic_bound(expr);
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) {
366 if (exponential_dominates(
num, den)) {
369 if (sign && *sign) {
return signed_infinity(*sign); }
371 auto log = std::dynamic_pointer_cast<const FunctionNode>(
num);
372 auto denominator_degree = algebraic_growth_degree(den);
374 polynomial_logarithmic_bound(
num) && denominator_degree && *denominator_degree >
Rational(0))
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);
392std::shared_ptr<const SymbolicNode> LimitVisitor::handle_neg_infinity_limit(
393 const std::shared_ptr<const SymbolicNode>& expr) {
399 std::string t_var =
"__neg_inf_t__";
401 auto substituted = substitute_neg_t(expr, t_var);
407 substituted->accept(norm);
408 substituted = norm.get_result();
413 std::vector<std::shared_ptr<const SymbolicNode>> inf_args;
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();
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 = {
441std::shared_ptr<const SymbolicNode> LimitVisitor::substitute_neg_t(
442 const std::shared_ptr<const SymbolicNode>& node,
const std::string& t_var)
const {
448 if (
auto num = std::dynamic_pointer_cast<const NumberNode>(node)) {
452 if (
auto v = std::dynamic_pointer_cast<const VariableNode>(node)) {
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);
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);
467 new_ops.push_back(
sub);
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) {
484 if (
auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
485 return substitute_function_neg_t(*func, t_var);
490std::shared_ptr<const SymbolicNode> LimitVisitor::substitute_function_neg_t(
491 const FunctionNode& node,
const std::string& t_var)
const {
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);
501 arguments.push_back(substituted);
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
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)
int sign(const Rational &value)
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
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
ExprResult log(const ExprPtr &expression, ComputationContext &context)
const ExprPtr & denominator
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.