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) {
14 if (!is_inf(values[0]) || !is_inf(values[1]) ||
15 is_neg_inf(values[0]) == is_neg_inf(values[1])) {
18 return defined_near_point(
node.operands()[0]) && defined_near_point(
node.operands()[1]);
21std::optional<Polynomial<Rational>> LimitVisitor::square_algebraic_term(
22 const std::shared_ptr<const SymbolicNode>& term)
const {
24 std::shared_ptr<const SymbolicNode> radicand;
25 if (
auto root = std::dynamic_pointer_cast<const PowerNode>(term)) {
28 { radicand = root->base(); }
29 }
else if (
auto root = std::dynamic_pointer_cast<const FunctionNode>(term)) {
31 { radicand = root->arguments()[0]; }
33 if (
auto product = std::dynamic_pointer_cast<const MultiplyNode>(term)) {
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;
42 auto polynomial = symbolic_to_poly<Rational>(
48 return radicand ? polynomial.value() : polynomial.value() * polynomial.value();
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; }
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;
64 const int degree = std::max(
a->degree(),
b->degree());
65 const int denominator_sign = is_neg_inf(values[0]) ? -1 : 1;
67 if (2 * numerator.degree() > degree) {
68 return signed_infinity((numerator.lead_coeff() >
Rational(0) ? 1 : -1) * denominator_sign);
71 return polynomial.degree() == degree ? SymbolicExpr::sqrt(SymbolicExpr::number(polynomial.lead_coeff()))
72 : SymbolicExpr::number(0);
74 auto denominator = SymbolicExpr::multiply(SymbolicExpr::number(denominator_sign),
75 SymbolicExpr::add(leading(*
a), leading(*
b)));
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]); }
90 terms.push_back(make_product_or_one(factors));
92 auto numerator = terms.size() == 1 ? terms[0] :
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)};
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);
110 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
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);
128 else numerator.push_back(operand);
131 return {make_product_or_one(numerator), make_product_or_one(
denominator)};
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;
152 const auto& first = prefer_infinity ? infinity : zero;
153 const auto& second = prefer_infinity ? zero : infinity;
156 auto value = apply_lhopital(first, inverse);
162 return apply_lhopital(second, inverse);
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()) {
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);
177 if (values.size() == 1) {
182 return norm.get_result();
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]);
194 if (zero.empty() || infinity.empty()) {
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);
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);
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);
216 std::vector<std::shared_ptr<const SymbolicNode>>{
219 return eval_limit(ratio);
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; }
234 if (!has_denominator) {
235 auto whole =
node.operands().size() == 1 ?
node.operands()[0] :
239 auto combined = combine_sum_ratio(numerators, denominators);
240 return resolve_combined_ratio(combined.first, combined.second);
243void LimitVisitor::visit(
const AddNode& node) {
244 if (is_limit_at_neg_infinity()) {
251 if (is_limit_at_infinity()) {
253 if (get_polynomial_degree(polynomial) > 0) {
254 const int sign = get_sign(get_leading_coefficient(polynomial));
256 result = signed_infinity(sign);
266 std::vector<std::shared_ptr<const SymbolicNode>> values;
267 for (
const auto& operand :
node.operands()) {
268 operand->accept(*
this);
270 values.push_back(result);
272 if (classify_add_form(values) == IndeterminateForm::InfMinusInf) {
273 auto resolved = resolve_inf_minus_inf(node, values);
281 result = norm.get_result();
统一规范化数值幂。 精确操作数保留整数和有理数运算;近似求根要求指数精确等于 1/2。 有限浮点幂直接折叠,省去倒数中间值;非有限结果保留幂表达式。
极限访问器,通过代入和 L'Hôpital 法则计算极限。
int sign(const Rational &value)
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
Result< T > extract_coeff_value(const std::shared_ptr< SymbolicExpr > &coefficient)
精确提取系数;不支持的值返回错误,保持数值完整。
__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