22template <
typename CoeffType>
27class LMCAS_API LimitVisitor :
public LMCAS::detail::SymbolicVisitor {
29 std::shared_ptr<const SymbolicNode>
point;
31 const LMCAS::AssumptionContext* assumption_ctx_ =
nullptr;
32 std::optional<ComputationContext> local_context_;
33 ComputationContext* context_ =
nullptr;
34 detail::RewriteBudget budget_;
36 if (!context_)
return;
37 auto step = context_->consume_steps(1,
"limit");
38 if (!step)
throw step.error();
40 int lhopital_depth_ = 0;
41 static constexpr int max_lhopital_depth = 5;
42 static int& active_limit_depth();
43 static constexpr int max_active_limit_depth = 128;
45 static std::shared_ptr<const SymbolicNode> make_product_or_one(
46 const std::vector<std::shared_ptr<const SymbolicNode>>& factors);
48 struct EvaluationScope {
52 explicit operator bool() const noexcept {
return entered; }
55 enum class IndeterminateForm {
None, ZeroTimesInf, InfMinusInf, OnePowInf, ZeroPowZero, InfPowZero };
57 bool is_inf(
const std::shared_ptr<const SymbolicNode>& node)
const;
58 bool is_neg_inf(
const std::shared_ptr<const SymbolicNode>& node)
const;
59 std::optional<int> get_node_sign(
const std::shared_ptr<const SymbolicNode>& node)
const;
60 double get_numeric_value(
const std::shared_ptr<const NumberNode>& num)
const;
61 bool is_bounded(
const std::shared_ptr<const SymbolicNode>& node)
const;
62 bool is_bounded_expression(
const std::shared_ptr<const SymbolicNode>& node)
const;
63 bool tends_to_zero(
const std::shared_ptr<const SymbolicNode>& node)
const;
64 std::shared_ptr<const SymbolicNode> eval_limit(
const std::shared_ptr<const SymbolicNode>& expr);
66 IndeterminateForm classify_product_form(
const std::vector<std::shared_ptr<const SymbolicNode>>& vals);
67 IndeterminateForm classify_power_form(
const std::shared_ptr<const SymbolicNode>& bv,
const std::shared_ptr<const SymbolicNode>& ev);
68 IndeterminateForm classify_add_form(
const std::vector<std::shared_ptr<const SymbolicNode>>& vals);
70 std::shared_ptr<const SymbolicNode> try_squeeze(
const std::shared_ptr<const SymbolicNode>& expr);
71 std::pair<std::shared_ptr<const SymbolicNode>, std::shared_ptr<const SymbolicNode>> extract_num_den(
const std::shared_ptr<const SymbolicNode>& expr);
72 std::shared_ptr<const SymbolicNode> resolve_zero_times_inf(
const std::vector<std::shared_ptr<const SymbolicNode>>& factors,
const std::vector<std::shared_ptr<const SymbolicNode>>& factor_vals);
73 std::shared_ptr<const SymbolicNode> resolve_inf_minus_inf(
const AddNode& node,
const std::vector<std::shared_ptr<const SymbolicNode>>& operand_vals);
74 std::shared_ptr<const SymbolicNode> resolve_exponential_form(
const std::shared_ptr<const SymbolicNode>& base,
const std::shared_ptr<const SymbolicNode>& exponent);
75 std::shared_ptr<const SymbolicNode> apply_lhopital(
const std::shared_ptr<const SymbolicNode>& num,
const std::shared_ptr<const SymbolicNode>& den);
77 std::shared_ptr<const SymbolicNode> taylor_fallback(
const std::shared_ptr<const SymbolicNode>& num,
const std::shared_ptr<const SymbolicNode>& den,
int max_order = 8);
78 std::shared_ptr<const SymbolicNode> simplify_and_eval_ratio(
const std::shared_ptr<const SymbolicNode>& ratio_node);
79 std::pair<std::shared_ptr<const SymbolicNode>,
int> find_leading_term(
const std::shared_ptr<SymbolicExpr>& series_expr,
const std::string& expand_var,
const std::shared_ptr<SymbolicExpr>& expand_point,
int max_order);
80 static int get_sign(
const std::shared_ptr<const SymbolicNode>& node);
82 bool is_limit_at_infinity()
const;
83 bool is_limit_at_neg_infinity()
const;
84 int get_polynomial_degree(
const std::shared_ptr<const SymbolicNode>& node)
const;
85 std::shared_ptr<const SymbolicNode> get_leading_coefficient(
const std::shared_ptr<const SymbolicNode>& node)
const;
86 std::shared_ptr<const SymbolicNode> limit_rational_at_infinity(
const std::shared_ptr<const SymbolicNode>& num,
const std::shared_ptr<const SymbolicNode>& den);
87 enum class GrowthClass { Constant, Logarithmic, Polynomial, Exponential,
Unknown };
88 GrowthClass classify_growth(
const std::shared_ptr<const SymbolicNode>& node)
const;
89 std::shared_ptr<const SymbolicNode> limit_by_growth_comparison(
const std::shared_ptr<const SymbolicNode>& num,
const std::shared_ptr<const SymbolicNode>& den);
90 std::shared_ptr<const SymbolicNode> handle_neg_infinity_limit(
const std::shared_ptr<const SymbolicNode>& expr);
91 std::shared_ptr<const SymbolicNode> positive_tail_log_power(
const FunctionNode& node)
const;
92 bool defined_near_point(
const std::shared_ptr<const SymbolicNode>& node)
const;
93 std::shared_ptr<const SymbolicNode> substitute_neg_t(
const std::shared_ptr<const SymbolicNode>& node,
const std::string& t_var)
const;
95 std::optional<int> determine_sign_near_point(
const std::shared_ptr<const SymbolicNode>& expr,
const std::string& dir);
96 bool analytic_at_point(
const std::shared_ptr<const SymbolicNode>& expr)
const;
97 std::optional<Rational> algebraic_growth_degree(
const std::shared_ptr<const SymbolicNode>& expr)
const;
98 bool proves_superlogarithmic_magnitude(
const std::shared_ptr<const SymbolicNode>& expr)
const;
99 bool polynomial_logarithmic_bound(
const std::shared_ptr<const SymbolicNode>& expr)
const;
100 std::optional<std::pair<Rational, int>> exact_leading_at_point(
101 const std::shared_ptr<const SymbolicNode>& expr)
const;
102 std::shared_ptr<const SymbolicNode> select_branch_by_direction(
const PiecewiseNode& node,
const std::string& dir);
103 std::optional<std::shared_ptr<const SymbolicNode>> evaluate_sgn_limit(
const std::shared_ptr<const SymbolicNode>& arg);
104 std::optional<std::shared_ptr<const SymbolicNode>> evaluate_abs_limit(
const std::shared_ptr<const SymbolicNode>& arg);
106 bool is_infinite_power(
const PowerNode& node)
const;
107 bool is_bounded_product(
const MultiplyNode& node)
const;
108 bool is_zero_limit(
const std::shared_ptr<const SymbolicNode>& node)
const;
109 std::shared_ptr<const SymbolicNode> squeeze_product(
const MultiplyNode& node);
110 std::shared_ptr<const SymbolicNode> squeeze_sum(
const AddNode& node);
111 std::shared_ptr<const SymbolicNode> denominator_factor(
const std::shared_ptr<const SymbolicNode>& node)
const;
112 std::shared_ptr<const SymbolicNode> resolve_zero_infinity_pair(
113 const std::shared_ptr<const SymbolicNode>& zero,
114 const std::shared_ptr<const SymbolicNode>& infinity);
115 std::shared_ptr<const SymbolicNode> multiply_remaining_limits(
116 const std::shared_ptr<const SymbolicNode>& value,
117 const std::vector<std::shared_ptr<const SymbolicNode>>& factors);
118 std::shared_ptr<const SymbolicNode> resolve_combined_ratio(
119 const std::shared_ptr<const SymbolicNode>& num,
120 const std::shared_ptr<const SymbolicNode>& den);
121 std::shared_ptr<const SymbolicNode> derivative_limit(
122 const std::shared_ptr<const SymbolicNode>& node,
bool normalize);
123 std::shared_ptr<const SymbolicNode> derivative_ratio_limit(
124 const std::shared_ptr<const SymbolicNode>& num,
125 const std::shared_ptr<const SymbolicNode>& den,
126 const std::shared_ptr<const SymbolicNode>& num_value,
127 const std::shared_ptr<const SymbolicNode>& den_value);
128 std::shared_ptr<const SymbolicNode> signed_infinity(
int sign)
const;
129 bool is_limit_variable(
const std::shared_ptr<const SymbolicNode>& node)
const;
130 bool is_positive_variable_power(
const std::shared_ptr<const SymbolicNode>& node)
const;
131 bool is_variable_reciprocal(
const std::shared_ptr<const SymbolicNode>& node)
const;
132 bool is_log_variable(
const std::shared_ptr<const SymbolicNode>& node)
const;
133 bool logarithmic_zero_product(
const MultiplyNode& node)
const;
134 std::shared_ptr<const SymbolicNode> one_plus_term(
const AddNode& node)
const;
135 std::shared_ptr<const SymbolicNode> variable_fraction_numerator(
136 const std::shared_ptr<const SymbolicNode>& node)
const;
137 bool logarithmic_product_limit(
const MultiplyNode& node);
138 std::optional<std::shared_ptr<const SymbolicNode>> logarithmic_remaining_limit(
139 const MultiplyNode& node,
const SymbolicNode* logarithm,
140 const std::shared_ptr<const SymbolicNode>& numerator);
141 bool has_slower_factors(
const MultiplyNode& node,
const SymbolicNode* exponential)
const;
142 bool decaying_exponential_product(
const MultiplyNode& node);
143 bool trigonometric_product_limit(
const MultiplyNode& node);
144 std::shared_ptr<const SymbolicNode> matching_reciprocal(
145 const MultiplyNode& node,
const std::shared_ptr<const SymbolicNode>& argument)
const;
146 std::shared_ptr<const SymbolicNode> trigonometric_remaining_limit(
147 const MultiplyNode& node,
const SymbolicNode* function,
const SymbolicNode* reciprocal);
148 std::shared_ptr<const SymbolicNode> product_ratio_limit(
149 const std::shared_ptr<const SymbolicNode>& num,
150 const std::shared_ptr<const SymbolicNode>& den);
151 std::shared_ptr<const SymbolicNode> linear_exponent_coefficient(
152 const std::shared_ptr<const SymbolicNode>& node)
const;
153 bool exponential_power_limit(
const PowerNode& node);
154 std::shared_ptr<const SymbolicNode> singular_power_limit(
155 const PowerNode& node,
const std::shared_ptr<const SymbolicNode>& base,
156 const std::shared_ptr<const SymbolicNode>& exponent);
157 bool composed_function_limit(
const FunctionNode& node);
158 bool infinite_function_limit(FunctionNode::FuncType type,
bool negative);
159 GrowthClass function_growth(
const FunctionNode& node)
const;
160 GrowthClass power_growth(
const PowerNode& node)
const;
161 GrowthClass operands_growth(
const std::vector<std::shared_ptr<const SymbolicNode>>& operands)
const;
162 std::shared_ptr<const SymbolicNode> substitute_function_neg_t(
const FunctionNode& node,
const std::string& t_var)
const;
163 std::shared_ptr<const SymbolicNode> leading_terms_limit(
164 const std::pair<std::shared_ptr<const SymbolicNode>,
int>& numerator,
165 const std::pair<std::shared_ptr<const SymbolicNode>,
int>& denominator);
166 std::shared_ptr<const SymbolicNode> taylor_series_limit(
167 const std::shared_ptr<SymbolicExpr>& numerator,
168 const std::shared_ptr<SymbolicExpr>& denominator,
169 const std::string& expand_var,
const std::shared_ptr<SymbolicExpr>& expand_point,
int order);
171 std::shared_ptr<const SymbolicNode> divergent_leading_ratio(
172 const std::shared_ptr<SymbolicExpr>& ratio,
int difference);
173 bool is_infinite_product(
const MultiplyNode& product)
const;
174 bool is_infinite_sum(
const AddNode& sum)
const;
175 std::optional<int> assumed_node_sign(
176 const std::shared_ptr<const SymbolicNode>& node)
const;
177 std::shared_ptr<const SymbolicNode> infinite_base_power_limit(
178 const std::shared_ptr<const SymbolicNode>& base,
179 const std::shared_ptr<const NumberNode>& number,
bool integral,
const BigInt& integer);
180 bool rational_denominator_supported(
181 const std::shared_ptr<const SymbolicNode>& leading_denominator,
182 const std::shared_ptr<const SymbolicNode>& num,
183 const std::shared_ptr<const SymbolicNode>& den)
const;
184 std::shared_ptr<const SymbolicNode> rational_leading_limit(
185 const std::shared_ptr<const SymbolicNode>& leading_numerator,
186 const std::shared_ptr<const SymbolicNode>& leading_denominator,
int degree_difference);
187 std::optional<Rational> algebraic_sum_growth(
const AddNode& sum)
const;
188 std::optional<Rational> algebraic_product_growth(
const MultiplyNode& product)
const;
189 std::optional<Rational> algebraic_power_growth(
const PowerNode& power)
const;
190 bool logarithmic_algebraic_bound(
191 const std::shared_ptr<const SymbolicNode>& expr)
const;
192 bool polynomial_logarithmic_operands(
193 const std::vector<std::shared_ptr<const SymbolicNode>>& operands)
const;
194 bool exponential_dominates(
195 const std::shared_ptr<const SymbolicNode>& exponential,
196 const std::shared_ptr<const SymbolicNode>& other);
197 bool can_rationalize_sum(
const AddNode& node,
198 const std::vector<std::shared_ptr<const SymbolicNode>>& values)
const;
199 std::optional<Polynomial<Rational>> square_algebraic_term(
200 const std::shared_ptr<const SymbolicNode>& term)
const;
201 std::shared_ptr<const SymbolicNode> rationalized_sum_limit(
202 const AddNode& node,
const std::vector<std::shared_ptr<const SymbolicNode>>& values);
203 std::pair<std::shared_ptr<const SymbolicNode>, std::shared_ptr<const SymbolicNode>>
205 const std::vector<std::shared_ptr<const SymbolicNode>>& numerators,
206 const std::vector<std::shared_ptr<const SymbolicNode>>& denominators);
207 std::optional<std::pair<Rational, int>> exact_polynomial_leading(
208 const Polynomial<Rational>& polynomial,
const Rational& point_value,
209 detail::ExactBoundArithmetic& arithmetic)
const;
210 bool analytic_defined_at_point(
211 const std::shared_ptr<const SymbolicNode>& expr,
212 const std::shared_ptr<const SymbolicNode>& positive_base)
const;
213 bool analytic_power_at_point(
const PowerNode& power,
214 const std::shared_ptr<const SymbolicNode>& expr)
const;
215 bool analytic_function_at_point(
const FunctionNode& function,
216 const std::shared_ptr<const SymbolicNode>& expr)
const;
217 bool analytic_operands_at_point(
218 const std::vector<std::shared_ptr<const SymbolicNode>>& operands)
const;
219 std::optional<int> rational_sign_at_infinity(
220 const std::shared_ptr<const SymbolicNode>& expr);
221 std::optional<int> product_sign_near_point(
222 const MultiplyNode& product,
const std::string& dir);
223 std::optional<int> power_sign_near_point(
224 const PowerNode& power,
const std::string& dir);
225 std::optional<int> analytic_sign_near_point(
226 const std::shared_ptr<const SymbolicNode>& expr,
const std::string& dir);
227 std::optional<bool> relation_truth_near_point(
const RelationalNode& relation);
228 std::optional<bool> logical_truth_near_point(
const LogicalNode& logical);
229 std::optional<bool> condition_truth_near_point(
230 const std::shared_ptr<const SymbolicNode>& node);
231 std::shared_ptr<const SymbolicNode> singular_ratio_limit(
232 const std::shared_ptr<const SymbolicNode>& num,
233 const std::shared_ptr<const SymbolicNode>& den);
234 std::optional<std::shared_ptr<const SymbolicNode>> exact_ratio_at_point(
235 const std::shared_ptr<const SymbolicNode>& num,
236 const std::shared_ptr<const SymbolicNode>& den);
237 std::shared_ptr<const SymbolicNode> evaluated_product_ratio(
238 const std::shared_ptr<const SymbolicNode>& num,
239 const std::shared_ptr<const SymbolicNode>& den,
bool at_infinity);
240 bool positive_tail_product_limit(
const MultiplyNode& node);
241 std::shared_ptr<const SymbolicNode> resolve_product_factors(
242 const MultiplyNode& node,
const std::vector<std::shared_ptr<const SymbolicNode>>& values);
245 bool condition_holds_near_point(
const std::shared_ptr<const SymbolicNode>& condition);
246 std::optional<int> sign_near_point(
const std::shared_ptr<const SymbolicNode>& node) {
247 return determine_sign_near_point(node, direction);
249 std::shared_ptr<const SymbolicNode> select_piecewise_near_point(
const PiecewiseNode& node) {
250 return select_branch_by_direction(node, direction);
252 std::shared_ptr<const SymbolicNode> result;
254 LimitVisitor(std::string v, std::shared_ptr<const SymbolicNode> p, std::string dir =
"",
255 const LMCAS::AssumptionContext* ctx =
nullptr, ComputationContext* context =
nullptr)
256 : SymbolicVisitor(&budget_), var(std::move(
v)),
point(std::move(p)),
257 direction(std::move(dir)), assumption_ctx_(ctx),
258 local_context_(
context ? std::nullopt
259 : std::optional<ComputationContext>(std::in_place)),
261 budget_(*context_, context_->limits().max_recursion_depth,
262 context_->limits().max_ast_nodes,
"limit") {
264 auto entered = context_->enter_recursion(
"limit");
265 if (!entered)
throw entered.error();
268 ~LimitVisitor()
override {
if (context_) context_->leave_recursion(); }
269 LimitVisitor(
const LimitVisitor&) =
delete;
270 LimitVisitor& operator=(
const LimitVisitor&) =
delete;
272 std::shared_ptr<const SymbolicNode> get_result()
const;
274 void visit(
const NumberNode& node)
override;
275 void visit(
const VariableNode& node)
override;
276 void visit(
const AddNode& node)
override;
277 void visit(
const MultiplyNode& node)
override;
278 void visit(
const PowerNode& node)
override;
279 void visit(
const FunctionNode& node)
override;
280 void visit(
const UninterpretedFunctionNode& node)
override;
281 void visit(
const MatrixNode& node)
override;
282 void visit(
const RelationalNode& node)
override;
283 void visit(
const LogicalNode& node)
override;
284 void visit(
const PiecewiseNode& node)
override;
285 void visit(
const SummationNode& node)
override;
286 void visit(
const ProductNode& node)
override;
287 void visit(
const TransformNode& node)
override;
288 void visit(
const QuantifierNode& node)
override;
289 void visit(
const SetBuilderNode& node)
override;
290 void visit(
const FiniteSetNode& node)
override;
291 void visit(
const IntervalNode& node)
override;
292 void visit(
const MembershipNode& node)
override;
293 void visit(
const QuantityNode& node)
override;
294 void visit(
const ComplexNode& node)
override;
295 void visit(
const IntegralNode& node)
override;
296 void visit(
const LimitNode& node)
override;
297 void visit(
const RootOfNode& node)
override;
AssumptionContext class with scoped push/pop management.
常数及根式包围区间共用的内部算术策略。 保守界覆盖未约分 Rational 的交叉乘积及结果;受检入口统一捕获 CasError,仅返回完整结果。
const std::string const LimitExprPtr & point
__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
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const std::string const LimitExprPtr LimitDirection direction
@ Unknown
Parity not determined