LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
limit_visitor_arithmetic.cpp
浏览该文件的文档.
5#include <algorithm>
6
7namespace LMCAS {
8
9bool LimitVisitor::can_rationalize_sum(const AddNode& node,
10 const std::vector<std::shared_ptr<const SymbolicNode>>& values) const {
11 if (!is_limit_at_infinity() || node.operands().size() != 2 || values.size() != 2) {
12 return false;
13 }
14 if (!is_inf(values[0]) || !is_inf(values[1]) ||
15 is_neg_inf(values[0]) == is_neg_inf(values[1])) {
16 return false;
17 }
18 return defined_near_point(node.operands()[0]) && defined_near_point(node.operands()[1]);
19}
20
21std::optional<Polynomial<Rational>> LimitVisitor::square_algebraic_term(
22 const std::shared_ptr<const SymbolicNode>& term) const {
23 charge();
24 std::shared_ptr<const SymbolicNode> radicand;
25 if (auto root = std::dynamic_pointer_cast<const PowerNode>(term)) {
27 if (exponent && exponent.value() == Rational(BigInt(1), BigInt(2)))
28 { radicand = root->base(); }
29 } else if (auto root = std::dynamic_pointer_cast<const FunctionNode>(term)) {
30 if (root->type() == FunctionNode::FuncType::Sqrt && root->arguments().size() == 1)
31 { radicand = root->arguments()[0]; }
32 }
33 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(term)) {
34 Polynomial<Rational> result(std::vector<Rational>{Rational(1)}, var);
35 for (const auto& factor : product->operands()) {
36 auto factor_square = square_algebraic_term(factor);
37 if (!factor_square) { return std::nullopt; }
38 result = result * *factor_square;
39 }
40 return result;
41 }
42 auto polynomial = symbolic_to_poly<Rational>(
43 detail::make_expression_ptr(radicand ? radicand : term), var);
44 if (!polynomial) {
45 if (polynomial.error().code != CasErrc::UnsupportedExpression) { throw polynomial.error(); }
46 return std::nullopt;
47 }
48 return radicand ? polynomial.value() : polynomial.value() * polynomial.value();
49}
50
51std::shared_ptr<const SymbolicNode> LimitVisitor::rationalized_sum_limit(
52 const AddNode& node, const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
53 if (!can_rationalize_sum(node, values)) { return nullptr; }
54 /**
55 * @brief 用 (a+b)(a-b)=a²-b² 有理化两个代数项。
56 * 两项趋向异号无穷,保证共轭式首项系数非零;截断后全零的级数不足以证明该条件。
57 */
58 auto a = square_algebraic_term(node.operands()[0]), b = square_algebraic_term(node.operands()[1]);
59 if (!a || !b) { return nullptr; }
60 if (a->is_zero() || b->is_zero()) { return nullptr; }
61 if (a->lead_coeff() <= Rational(0) || b->lead_coeff() <= Rational(0)) { return nullptr; }
62 auto numerator = *a - *b;
63 if (numerator.is_zero()) { return detail::make_node<NumberNode>(BigInt(0)); }
64 const int degree = std::max(a->degree(), b->degree());
65 const int denominator_sign = is_neg_inf(values[0]) ? -1 : 1;
66 if (2 * numerator.degree() < degree) { return detail::make_node<NumberNode>(BigInt(0)); }
67 if (2 * numerator.degree() > degree) {
68 return signed_infinity((numerator.lead_coeff() > Rational(0) ? 1 : -1) * denominator_sign);
69 }
70 auto leading = [&](const Polynomial<Rational>& polynomial) {
71 return polynomial.degree() == degree ? SymbolicExpr::sqrt(SymbolicExpr::number(polynomial.lead_coeff()))
72 : SymbolicExpr::number(0);
73 };
74 auto denominator = SymbolicExpr::multiply(SymbolicExpr::number(denominator_sign),
75 SymbolicExpr::add(leading(*a), leading(*b)));
76 return detail::normalize_node(detail::node(SymbolicExpr::divide(SymbolicExpr::number(numerator.lead_coeff()), denominator)), *rewrite_budget());
77}
78
79std::pair<std::shared_ptr<const SymbolicNode>, std::shared_ptr<const SymbolicNode>>
80LimitVisitor::combine_sum_ratio(
81 const std::vector<std::shared_ptr<const SymbolicNode>>& numerators,
82 const std::vector<std::shared_ptr<const SymbolicNode>>& denominators) {
83 auto common_denominator = make_product_or_one(denominators);
84 std::vector<std::shared_ptr<const SymbolicNode>> terms;
85 for (std::size_t i = 0; i < numerators.size(); ++i) {
86 std::vector<std::shared_ptr<const SymbolicNode>> factors{numerators[i]};
87 for (std::size_t j = 0; j < denominators.size(); ++j) {
88 if (j != i) { factors.push_back(denominators[j]); }
89 }
90 terms.push_back(make_product_or_one(factors));
91 }
92 auto numerator = terms.size() == 1 ? terms[0] :
93 std::static_pointer_cast<const SymbolicNode>(LMCAS::detail::make_node<AddNode>(terms));
94 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
95 numerator->accept(norm);
96 numerator = norm.get_result();
97 common_denominator->accept(norm);
98 common_denominator = norm.get_result();
99 return {std::move(numerator), std::move(common_denominator)};
100}
101
102
103
104std::shared_ptr<const SymbolicNode> LimitVisitor::denominator_factor(
105 const std::shared_ptr<const SymbolicNode>& node) const {
106 auto power = std::dynamic_pointer_cast<const PowerNode>(node);
107 if (!power) {
108 return nullptr;
109 }
110 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
111 if (!exponent) {
112 return nullptr;
113 }
115 if (!value || value.value() >= Rational(0)) return nullptr;
116 if (value.value() == Rational(-1)) return power->base();
118 power->base(), LMCAS::detail::make_node<NumberNode>(-value.value()));
119}
120
121std::pair<std::shared_ptr<const SymbolicNode>, std::shared_ptr<const SymbolicNode>>
122LimitVisitor::extract_num_den(const std::shared_ptr<const SymbolicNode>& expr) {
123 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(expr)) {
124 std::vector<std::shared_ptr<const SymbolicNode>> numerator, denominator;
125 for (const auto& operand : product->operands()) {
126 auto factor = denominator_factor(operand);
127 if (factor) denominator.push_back(factor);
128 else numerator.push_back(operand);
129 }
130 if (!denominator.empty()) {
131 return {make_product_or_one(numerator), make_product_or_one(denominator)};
132 }
133 }
134 auto denominator = denominator_factor(expr);
135 auto one = LMCAS::detail::make_node<NumberNode>(BigInt(1));
136 if (denominator) {
137 return {one, denominator};
138 }
139 return {expr, one};
140}
141
142std::shared_ptr<const SymbolicNode> LimitVisitor::resolve_zero_infinity_pair(
143 const std::shared_ptr<const SymbolicNode>& zero,
144 const std::shared_ptr<const SymbolicNode>& infinity) {
145 bool prefer_infinity = false;
146 if (is_limit_at_infinity() || is_limit_at_neg_infinity()) {
147 auto zero_growth = classify_growth(zero);
148 auto infinity_growth = classify_growth(infinity);
149 prefer_infinity = zero_growth == GrowthClass::Exponential &&
150 infinity_growth == GrowthClass::Polynomial;
151 }
152 const auto& first = prefer_infinity ? infinity : zero;
153 const auto& second = prefer_infinity ? zero : infinity;
155 second, LMCAS::detail::make_node<NumberNode>(BigInt(-1)));
156 auto value = apply_lhopital(first, inverse);
157 if (value) {
158 return value;
159 }
161 first, LMCAS::detail::make_node<NumberNode>(BigInt(-1)));
162 return apply_lhopital(second, inverse);
163}
164
165std::shared_ptr<const SymbolicNode> LimitVisitor::multiply_remaining_limits(
166 const std::shared_ptr<const SymbolicNode>& value,
167 const std::vector<std::shared_ptr<const SymbolicNode>>& factors) {
168 if (!value || factors.empty()) {
169 return value;
170 }
171 std::vector<std::shared_ptr<const SymbolicNode>> values{value};
172 for (const auto& factor : factors) {
173 auto limit = eval_limit(factor);
174 if (!limit) return nullptr;
175 values.push_back(limit);
176 }
177 if (values.size() == 1) {
178 return values[0];
179 }
180 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
181 LMCAS::detail::make_node<MultiplyNode>(values)->accept(norm);
182 return norm.get_result();
183}
184
185std::shared_ptr<const SymbolicNode> LimitVisitor::resolve_zero_times_inf(
186 const std::vector<std::shared_ptr<const SymbolicNode>>& factors,
187 const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
188 std::vector<std::shared_ptr<const SymbolicNode>> zero, infinity, other;
189 for (std::size_t i = 0; i < factors.size(); ++i) {
190 if (is_zero_limit(values[i])) zero.push_back(factors[i]);
191 else if (is_inf(values[i])) infinity.push_back(factors[i]);
192 else other.push_back(factors[i]);
193 }
194 if (zero.empty() || infinity.empty()) {
195 return nullptr;
196 }
197 auto first = make_product_or_one(zero);
198 auto second = make_product_or_one(infinity);
199 return multiply_remaining_limits(resolve_zero_infinity_pair(first, second), other);
200}
201
202std::shared_ptr<const SymbolicNode> LimitVisitor::resolve_combined_ratio(
203 const std::shared_ptr<const SymbolicNode>& num,
204 const std::shared_ptr<const SymbolicNode>& den) {
205 auto numerator = eval_limit(num);
206 auto denominator = eval_limit(den);
207 bool numerator_zero = is_zero_limit(numerator);
208 bool denominator_zero = is_zero_limit(denominator);
209 if ((numerator_zero && denominator_zero) || (is_inf(numerator) && is_inf(denominator))) {
210 return apply_lhopital(num, den);
211 }
212 if (denominator_zero || is_inf(denominator) || !denominator) {
213 return nullptr;
214 }
216 std::vector<std::shared_ptr<const SymbolicNode>>{
218 den, LMCAS::detail::make_node<NumberNode>(BigInt(-1)))});
219 return eval_limit(ratio);
220}
221
222std::shared_ptr<const SymbolicNode> LimitVisitor::resolve_inf_minus_inf(
223 const AddNode& node, const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
224 auto rationalized = rationalized_sum_limit(node, values);
225 if (rationalized) { return rationalized; }
226 std::vector<std::shared_ptr<const SymbolicNode>> numerators, denominators;
227 bool has_denominator = false;
228 for (const auto& operand : node.operands()) {
229 auto fraction = extract_num_den(operand);
230 numerators.push_back(fraction.first);
231 denominators.push_back(fraction.second);
232 if (!fraction.second->is_one()) { has_denominator = true; }
233 }
234 if (!has_denominator) {
235 auto whole = node.operands().size() == 1 ? node.operands()[0] :
236 std::static_pointer_cast<const SymbolicNode>(LMCAS::detail::make_node<AddNode>(node.operands()));
237 return taylor_fallback(whole, LMCAS::detail::make_node<NumberNode>(BigInt(1)));
238 }
239 auto combined = combine_sum_ratio(numerators, denominators);
240 return resolve_combined_ratio(combined.first, combined.second);
241}
242
243void LimitVisitor::visit(const AddNode& node) {
244 if (is_limit_at_neg_infinity()) {
245 auto value = handle_neg_infinity_limit(LMCAS::detail::make_node<AddNode>(node.operands()));
246 if (value) {
247 result = value;
248 return;
249 }
250 }
251 if (is_limit_at_infinity()) {
252 auto polynomial = LMCAS::detail::make_node<AddNode>(node.operands());
253 if (get_polynomial_degree(polynomial) > 0) {
254 const int sign = get_sign(get_leading_coefficient(polynomial));
255 if (sign != 0) {
256 result = signed_infinity(sign);
257 return;
258 }
259 }
260 }
261 auto squeezed = try_squeeze(LMCAS::detail::make_node<AddNode>(node.operands()));
262 if (squeezed) {
263 result = squeezed;
264 return;
265 }
266 std::vector<std::shared_ptr<const SymbolicNode>> values;
267 for (const auto& operand : node.operands()) {
268 operand->accept(*this);
269 if (!result) return;
270 values.push_back(result);
271 }
272 if (classify_add_form(values) == IndeterminateForm::InfMinusInf) {
273 auto resolved = resolve_inf_minus_inf(node, values);
274 if (resolved) {
275 result = resolved;
276 return;
277 }
278 }
279 NormalizationVisitor norm(*rewrite_budget(), detail::no_facts(), Domain::Real);
280 LMCAS::detail::make_node<AddNode>(values)->accept(norm);
281 result = norm.get_result();
282}
283
284}
加法节点,表示多个操作数的求和。
@ Sqrt
对数、绝对值、平方根。
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
一元多项式模板类
极限访问器,通过代入和 L'Hôpital 法则计算极限。
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
const FactsQuery & no_facts() noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr< SymbolicExpr > num(int value)
@ Rational
Rational numbers
@ Real
Real numbers
Result< T > extract_coeff_value(const std::shared_ptr< SymbolicExpr > &coefficient)
精确提取系数;不支持的值返回错误,保持数值完整。
const MultiPoly & b
const ExprPtr & exponent
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
const std::string const ExprPtr & value
const ExprPtr & denominator
符号表达式与一元多项式的转换。