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; }
15 if (number->is_positive()) {
return signed_infinity(is_neg_inf(base) &&
integer.is_odd() ? -1 : 1); }
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);
28 else { coefficients.push_back(
op); }
30 if (
auto product = std::dynamic_pointer_cast<const MultiplyNode>(
exponent))
31 {
for (
const auto&
op : product->operands()) { collect(
op); } }
39std::shared_ptr<const SymbolicNode> LimitVisitor::linear_exponent_coefficient(
40 const std::shared_ptr<const SymbolicNode>& node)
const {
41 if (is_limit_variable(node)) {
44 auto product = std::dynamic_pointer_cast<const MultiplyNode>(node);
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);
57 return make_product_or_one(factors);
60bool LimitVisitor::exponential_power_limit(
const PowerNode& node) {
61 auto sum = std::dynamic_pointer_cast<const AddNode>(
node.base());
65 auto coefficient = linear_exponent_coefficient(
node.exponent());
69 auto term = one_plus_term(*sum);
73 auto numerator = variable_fraction_numerator(term);
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});
86 exponential->accept(norm);
87 result = norm.get_result();
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) {
97 std::vector<std::shared_ptr<const SymbolicNode>>{
exponent, logarithm});
98 auto value = eval_limit(product);
102 if (!is_inf(
value)) {
106 exponential->accept(norm);
107 return norm.get_result();
109 if (!is_neg_inf(
value)) {
110 return signed_infinity(1);
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);
124 double value = get_numeric_value(number);
126 return infinite_base_power_limit(base, number, integral,
integer);
132 if (!sign || *sign == 0) {
return nullptr; }
133 if (!integral && *sign < 0) {
return nullptr; }
134 return signed_infinity(integral &&
integer.is_odd() ? *sign : 1);
137void LimitVisitor::visit(
const PowerNode& node) {
138 if (is_limit_at_neg_infinity()) {
139 auto value = handle_neg_infinity_limit(
146 if (is_limit_at_infinity() && exponential_power_limit(node)) {
149 if (
node.base()->
is_one() && defined_near_point(
node.exponent())) {
155 if (sign && *sign != 0) {
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());
172 auto singular = singular_power_limit(node, base,
exponent);
179 result = norm.get_result();
185 result = negative ? std::static_pointer_cast<const SymbolicNode>(
189 result = negative ? nullptr : signed_infinity(1);
194 std::vector<std::shared_ptr<const SymbolicNode>>{
202bool LimitVisitor::composed_function_limit(
const FunctionNode& node) {
203 if (
node.arguments().size() != 1 ||
207 auto inner = eval_limit(
node.arguments()[0]);
211 if (!is_inf(inner)) {
213 std::vector<std::shared_ptr<const SymbolicNode>>{inner});
214 std::optional<detail::AssumptionFacts> assumed;
215 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
218 if (!defined) {
throw defined.error(); }
221 candidate->accept(norm);
222 result = norm.get_result();
227 if (sign && *sign > 0) {
228 result = signed_infinity(-1);
234 return infinite_function_limit(
node.type(), is_neg_inf(inner));
239std::shared_ptr<const SymbolicNode> LimitVisitor::positive_tail_log_power(
const FunctionNode& node)
const {
241 node.arguments().size() != 1) {
return nullptr; }
242 std::vector<std::shared_ptr<const SymbolicNode>> 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_); }
249 auto exponent = make_product_or_one(coefficients);
251 if (!real_exponent) {
throw real_exponent.error(); }
252 if (real_exponent.value() !=
Tribool::True || !defined_near_point(f->arguments()[0])) {
return nullptr; }
254 if (!positive) {
throw positive.error(); }
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; }
265 auto value = handle_neg_infinity_limit(
272 if (
auto rewritten = positive_tail_log_power(node)) {
273 result = eval_limit(rewritten);
277 auto value = evaluate_sgn_limit(
node.arguments()[0]);
282 auto value = evaluate_abs_limit(
node.arguments()[0]);
288 if (composed_function_limit(node)) {
291 std::vector<std::shared_ptr<const SymbolicNode>> arguments;
292 for (
const auto& argument :
node.arguments()) {
293 argument->accept(*
this);
295 arguments.push_back(result);
299 result = norm.get_result();
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Sgn
符号函数 sgn(x) ∈ {-1, 0, 1}。
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
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)
int sign(const Rational &value)
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
const std::string const LimitExprPtr LimitDirection direction
@ True
Property definitely holds
const ExprPtr RelationOp op
const std::string const ExprPtr & value