LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
limit_visitor_product_special.cpp
浏览该文件的文档.
3
4namespace LMCAS {
5
6bool LimitVisitor::is_limit_variable(const std::shared_ptr<const SymbolicNode>& node) const {
7 auto variable = std::dynamic_pointer_cast<const VariableNode>(node);
8 return variable && !variable->is_constant() && variable->name() == var;
9}
10
11bool LimitVisitor::is_positive_variable_power(const std::shared_ptr<const SymbolicNode>& node) const {
12 if (is_limit_variable(node)) {
13 return true;
14 }
15 auto power = std::dynamic_pointer_cast<const PowerNode>(node);
16 if (!power) {
17 return false;
18 }
19 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
20 return is_limit_variable(power->base()) && exponent && exponent->is_positive();
21}
22
23bool LimitVisitor::is_variable_reciprocal(const std::shared_ptr<const SymbolicNode>& node) const {
24 auto power = std::dynamic_pointer_cast<const PowerNode>(node);
25 if (!power || !is_limit_variable(power->base())) {
26 return false;
27 }
28 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
29 return exponent && get_numeric_value(exponent) == -1.0;
30}
31
32bool LimitVisitor::is_log_variable(const std::shared_ptr<const SymbolicNode>& node) const {
33 auto function = std::dynamic_pointer_cast<const FunctionNode>(node);
34 if (!function || function->arguments().size() != 1) {
35 return false;
36 }
37 if (function->type() != FunctionNode::FuncType::Ln &&
39 return false;
40 }
41 return is_limit_variable(function->arguments()[0]);
42}
43
44bool LimitVisitor::logarithmic_zero_product(const MultiplyNode& node) const {
45 auto number = std::dynamic_pointer_cast<const NumberNode>(point);
46 if (!number) {
47 return false;
48 }
49 if (!number->is_zero() || direction != "+") {
50 return false;
51 }
52 bool has_power = false;
53 bool has_logarithm = false;
54 for (const auto& operand : node.operands()) {
55 if (!is_positive_variable_power(operand) && !is_log_variable(operand) &&
56 !std::dynamic_pointer_cast<const NumberNode>(operand)) { return false; }
57 has_power = has_power || is_positive_variable_power(operand);
58 has_logarithm = has_logarithm || is_log_variable(operand);
59 }
60 return has_power && has_logarithm;
61}
62
63std::shared_ptr<const SymbolicNode> LimitVisitor::one_plus_term(const AddNode& node) const {
64 bool has_one = false;
65 std::vector<std::shared_ptr<const SymbolicNode>> terms;
66 for (const auto& operand : node.operands()) {
67 if (!has_one && operand->is_one()) has_one = true;
68 else terms.push_back(operand);
69 }
70 if (!has_one || terms.empty()) return nullptr;
71 return terms.size() == 1 ? terms[0] : detail::make_node<AddNode>(std::move(terms));
72}
73
74std::shared_ptr<const SymbolicNode> LimitVisitor::variable_fraction_numerator(
75 const std::shared_ptr<const SymbolicNode>& node) const {
76 if (is_variable_reciprocal(node)) {
78 }
79 auto product = std::dynamic_pointer_cast<const MultiplyNode>(node);
80 if (!product) {
81 return nullptr;
82 }
83 bool has_denominator = false;
84 std::vector<std::shared_ptr<const SymbolicNode>> factors;
85 for (const auto& operand : product->operands()) {
86 if (!has_denominator && is_variable_reciprocal(operand)) has_denominator = true;
87 else factors.push_back(operand);
88 }
89 if (!has_denominator) {
90 return nullptr;
91 }
92 return make_product_or_one(factors);
93}
94
95std::optional<std::shared_ptr<const SymbolicNode>> LimitVisitor::logarithmic_remaining_limit(
96 const MultiplyNode& node, const SymbolicNode* logarithm,
97 const std::shared_ptr<const SymbolicNode>& numerator) {
98 std::vector<std::shared_ptr<const SymbolicNode>> values{numerator};
99 bool has_variable = false;
100 for (const auto& operand : node.operands()) {
101 if (operand.get() == logarithm) {
102 continue;
103 }
104 if (!has_variable && is_limit_variable(operand)) {
105 has_variable = true;
106 continue;
107 }
108 auto value = eval_limit(operand);
109 if (!value) {
110 return std::nullopt;
111 }
112 values.push_back(value);
113 }
114 if (!has_variable) {
115 return std::nullopt;
116 }
117 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
118 make_product_or_one(values)->accept(norm);
119 return norm.get_result();
120}
121
122bool LimitVisitor::logarithmic_product_limit(const MultiplyNode& node) {
123 for (const auto& operand : node.operands()) {
124 auto function = std::dynamic_pointer_cast<const FunctionNode>(operand);
125 if (!function || function->arguments().size() != 1) {
126 continue;
127 }
128 if (function->type() != FunctionNode::FuncType::Ln &&
130 continue;
131 }
132 auto sum = std::dynamic_pointer_cast<const AddNode>(function->arguments()[0]);
133 if (!sum) {
134 continue;
135 }
136 auto small_term = one_plus_term(*sum);
137 if (!small_term) {
138 continue;
139 }
140 if (!is_zero_limit(eval_limit(small_term))) continue;
141 auto numerator = variable_fraction_numerator(small_term);
142 if (!numerator) {
143 continue;
144 }
145 auto value = logarithmic_remaining_limit(node, operand.get(), numerator);
146 if (value) {
147 result = *value;
148 return true;
149 }
150 }
151 return false;
152}
153
154bool LimitVisitor::has_slower_factors(const MultiplyNode& node, const SymbolicNode* exponential) const {
155 for (const auto& operand : node.operands()) {
156 if (operand.get() == exponential) {
157 continue;
158 }
159 if (!polynomial_logarithmic_bound(operand)) {
160 return false;
161 }
162 }
163 return true;
164}
165
166bool LimitVisitor::decaying_exponential_product(const MultiplyNode& node) {
167 for (const auto& operand : node.operands()) {
168 auto function = std::dynamic_pointer_cast<const FunctionNode>(operand);
169 if (!function || function->arguments().size() != 1 ||
171 continue;
172 }
173 auto exponent_limit = eval_limit(function->arguments()[0]);
174 if (!is_neg_inf(exponent_limit)) {
175 continue;
176 }
177 if (proves_superlogarithmic_magnitude(function->arguments()[0]) &&
178 has_slower_factors(node, operand.get())) {
179 return true;
180 }
181 }
182 return false;
183}
184
185std::shared_ptr<const SymbolicNode> LimitVisitor::matching_reciprocal(
186 const MultiplyNode& node, const std::shared_ptr<const SymbolicNode>& argument) const {
187 for (const auto& operand : node.operands()) {
188 auto power = std::dynamic_pointer_cast<const PowerNode>(operand);
189 if (!power) {
190 continue;
191 }
192 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
193 if (!exponent || !power->base() || power->base()->compare(*argument) != 0) {
194 continue;
195 }
196 if (get_numeric_value(exponent) == -1.0) {
197 return operand;
198 }
199 }
200 return nullptr;
201}
202
203std::shared_ptr<const SymbolicNode> LimitVisitor::trigonometric_remaining_limit(
204 const MultiplyNode& node, const SymbolicNode* function, const SymbolicNode* reciprocal) {
205 std::vector<std::shared_ptr<const SymbolicNode>> values;
206 for (const auto& operand : node.operands()) {
207 if (operand.get() == function || operand.get() == reciprocal) {
208 continue;
209 }
210 auto value = eval_limit(operand);
211 if (!value) {
212 return nullptr;
213 }
214 values.push_back(value);
215 }
216 values.push_back(LMCAS::detail::make_node<NumberNode>(BigInt(1)));
217 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
218 make_product_or_one(values)->accept(norm);
219 return norm.get_result();
220}
221
222bool LimitVisitor::trigonometric_product_limit(const MultiplyNode& node) {
223 for (const auto& operand : node.operands()) {
224 auto function = std::dynamic_pointer_cast<const FunctionNode>(operand);
225 if (!function || function->arguments().size() != 1) {
226 continue;
227 }
228 if (function->type() != FunctionNode::FuncType::Sin &&
230 continue;
231 }
232 const auto& argument = function->arguments()[0];
233 auto reciprocal = matching_reciprocal(node, argument);
234 if (!reciprocal) {
235 continue;
236 }
237 auto argument_limit = eval_limit(argument);
238 if (is_zero_limit(argument_limit)) {
239 result = trigonometric_remaining_limit(node, operand.get(), reciprocal.get());
240 return result != nullptr;
241 }
242 }
243 return false;
244}
245
246}
加法节点,表示多个操作数的求和。
乘法节点,表示多个操作数的乘积。
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
极限访问器,通过代入和 L'Hôpital 法则计算极限。
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
const FactsQuery & no_facts() noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
const std::string const LimitExprPtr & point
const std::string & variable
@ Real
Real numbers
const std::string const LimitExprPtr LimitDirection direction
const ExprPtr & exponent
const std::string const ExprPtr & value
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)