LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_definite_algebraic.cpp
浏览该文件的文档.
5
6#include <limits>
7
9static int sign(const Rational& value) {
10 return value < Rational(0) ? -1 : value > Rational(0) ? 1 : 0;
11}
12
13std::optional<Rational> exact_number(const Node& node) {
14 const auto* number = dynamic_cast<const NumberNode*>(node.get());
15 if (!number) return std::nullopt;
16 return exact_number_as_rational(*number);
17}
18
19/**
20 * @brief 识别绝对值节点及公共接口的平方开根表示。
21 * @pre 调用方须先证明参数为实数,再在开区间上使用 |u| = ±u。
22 */
24 Node radicand;
25 if (const auto* function = dynamic_cast<const FunctionNode*>(&node)) {
26 if (function->arguments().size() != 1) return nullptr;
27 if (function->type() == FunctionNode::FuncType::Abs) return function->arguments()[0];
28 if (function->type() != FunctionNode::FuncType::Sqrt) return nullptr;
29 radicand = function->arguments()[0];
30 } else if (const auto* power = dynamic_cast<const PowerNode*>(&node)) {
31 auto exponent = exact_number(power->exponent());
32 if (!exponent || *exponent != Rational(1, 2)) return nullptr;
33 radicand = power->base();
34 } else return nullptr;
35 const auto* square = dynamic_cast<const PowerNode*>(radicand.get());
36 if (!square) return nullptr;
37 auto exponent = exact_number(square->exponent());
38 return exponent && *exponent == Rational(2) ? square->base() : nullptr;
39}
40
41int infinity_sign(const Node& node) {
42 if (const auto* f = dynamic_cast<const FunctionNode*>(node.get())) {
43 if (f->type() == FunctionNode::FuncType::Infinity) return 1;
44 }
45 if (const auto* m = dynamic_cast<const MultiplyNode*>(node.get())) {
46 int result = 1;
47 bool infinity = false;
48 for (const auto& factor : m->operands()) {
49 if (infinity_sign(factor)) {
50 if (infinity) return 0;
51 infinity = true;
52 result *= infinity_sign(factor);
53 } else {
54 auto value = exact_number(factor);
55 if (!value || sign(*value) == 0) return 0;
56 result *= sign(*value);
57 }
58 }
59 return infinity ? result : 0;
60 }
61 return 0;
62}
63
64Result<Boundary> boundary_checked(const SymbolicExpr& expression,
66 if (int infinity = infinity_sign(detail::node(expression)))
67 return Boundary{infinity, {}};
68 if (auto rational = exact_number(detail::node(expression)))
69 return Boundary{0, {Poly({-*rational, Rational(1)}), *rational, *rational, 0, 1}};
70 if (dynamic_cast<const NumberNode*>(detail::node(expression).get()))
72 "nonfinite numeric endpoint requires a typed infinity", operation);
73 if (const auto* root = dynamic_cast<const RootOfNode*>(detail::node(expression).get())) {
75 root->exact_id().polynomial, root->index(), 1, context);
76 if (!value) return Result<Boundary>::failure(value.error());
77 return Boundary{0, std::move(value.value())};
78 }
79 return undecided<Boundary>();
80}
81
84 if (a.infinity || b.infinity)
85 { return a.infinity < b.infinity ? -1 : a.infinity > b.infinity ? 1 : 0; }
86 auto left = a.finite;
87 auto right = b.finite;
88 right.polynomial.variable_name = left.polynomial.variable_name;
89 if (!(left.upper < right.lower) && !(right.upper < left.lower)) {
91 if (!equal) { return Result<int>::failure(equal.error()); }
92 if (equal.value()) { return 0; }
93 while (!(left.upper < right.lower) && !(right.upper < left.lower)) {
95 if (!refined) { return Result<int>::failure(refined.error()); }
97 if (!refined) { return Result<int>::failure(refined.error()); }
98 }
99 }
100 return detail::compare_exact_real_algebraic(std::move(left), std::move(right), context);
101}
102
104 auto terms = context.require_expansion_terms(polynomial.coeffs.size(), operation);
105 if (!terms) return terms;
106 for (const auto& coefficient : polynomial.coeffs) {
107 auto checked = context.require_integer_bits(std::max(
108 coefficient.get_numerator().bit_length(),
109 coefficient.get_denominator().bit_length()), operation);
110 if (!checked) return checked;
111 }
112 return context.consume_steps(polynomial.coeffs.size() + 1, operation);
113}
114
116 const auto size = a.coeffs.size() + b.coeffs.size();
117 auto budget = context.require_expansion_terms(size, operation);
118 if (!budget) return Result<Poly>::failure(budget.error());
119 if (size > static_cast<std::size_t>(std::numeric_limits<int>::max()))
121 "polynomial degree exceeds representation", operation);
122 auto step = context.consume_steps(a.coeffs.size() * b.coeffs.size() + 1, operation);
123 if (!step) return Result<Poly>::failure(step.error());
124 auto value = a * b;
126 if (!budget) return Result<Poly>::failure(budget.error());
127 return value;
128}
129
131 while (!b.is_zero()) {
132 auto step = context.consume_steps(a.coeffs.size() * b.coeffs.size() + 1, operation);
133 if (!step) return Result<Poly>::failure(step.error());
134 auto remainder = a.div_mod(b).second;
135 auto checked = polynomial_budget(remainder, context);
136 if (!checked) return Result<Poly>::failure(checked.error());
137 a = std::move(b);
138 b = std::move(remainder);
139 }
140 return a.make_monic();
141}
142
143static RationalResult rational_operands_checked(const std::vector<Node>& operands,
144 bool sum, const std::string& var, ComputationContext& context) {
145 RationalFunction result{Poly(Rational(sum ? 0 : 1), var), Poly(Rational(1), var)};
146 for (const auto& operand : operands) {
147 auto child = rational_checked(operand, var, context);
148 if (!child || !child.value()) { return child; }
149 auto n = product_checked(result.numerator,
150 sum ? child.value()->denominator : child.value()->numerator, context);
151 if (!n) { return RationalResult::failure(n.error()); }
152 if (sum) {
153 auto other = product_checked(child.value()->numerator, result.denominator, context);
154 if (!other) { return RationalResult::failure(other.error()); }
155 n.value() = n.value() + other.value();
156 }
157 auto d = product_checked(result.denominator, child.value()->denominator, context);
158 if (!d) { return RationalResult::failure(d.error()); }
159 result = {std::move(n.value()), std::move(d.value())};
160 }
161 return std::optional<RationalFunction>{std::move(result)};
162}
163
165 const std::string& var, ComputationContext& context) {
166 auto exponent = exact_number(power.exponent());
167 if (!exponent || !exponent->is_integer()) { return std::optional<RationalFunction>{}; }
168 auto base = rational_checked(power.base(), var, context);
169 if (!base || !base.value()) { return base; }
170 BigInt count = exponent->to_bigint();
171 if (count < BigInt(0)) {
172 std::swap(base.value()->numerator, base.value()->denominator);
173 count = -count;
174 }
175 RationalFunction result{Poly(Rational(1), var), Poly(Rational(1), var)};
176 while (count != BigInt(0)) {
177 if (count % BigInt(2) != BigInt(0)) {
178 auto n = product_checked(result.numerator, base.value()->numerator, context);
179 auto d = product_checked(result.denominator, base.value()->denominator, context);
180 if (!n) { return RationalResult::failure(n.error()); }
181 if (!d) { return RationalResult::failure(d.error()); }
182 result = {std::move(n.value()), std::move(d.value())};
183 }
184 count = count / BigInt(2);
185 if (count == BigInt(0)) { break; }
186 auto n = product_checked(base.value()->numerator, base.value()->numerator, context);
187 auto d = product_checked(base.value()->denominator, base.value()->denominator, context);
188 if (!n) { return RationalResult::failure(n.error()); }
189 if (!d) { return RationalResult::failure(d.error()); }
190 base.value() = RationalFunction{std::move(n.value()), std::move(d.value())};
191 }
192 return std::optional<RationalFunction>{std::move(result)};
193}
194RationalResult rational_checked(const Node& node, const std::string& var,
196 auto entered = context.enter_recursion(operation);
197 if (!entered) { return RationalResult::failure(entered.error()); }
198 struct Leave { ComputationContext& context; ~Leave() { context.leave_recursion(); } } leave{context};
200 if (!polynomial) { return RationalResult::failure(polynomial.error()); }
201 if (polynomial.value()) { return std::optional<RationalFunction>{
202 RationalFunction{std::move(*polynomial.value()), Poly(Rational(1), var)}}; }
203 const auto* sum = dynamic_cast<const AddNode*>(node.get());
204 const auto* product = dynamic_cast<const MultiplyNode*>(node.get());
205 if (sum || product) {
207 sum ? sum->operands() : product->operands(), sum != nullptr, var, context);
208 }
209 if (const auto* power = dynamic_cast<const PowerNode*>(node.get())) {
210 return rational_power_checked(*power, var, context);
211 }
212 return std::optional<RationalFunction>{};
213}
214
215static Result<void> recover_rational_cut(Algebraic& root, const BigInt& denominator_bound,
217 if (root.is_rational()) { return Result<void>::success(); }
218 auto bits = context.require_integer_bits(2 * denominator_bound.bit_length() + 2, operation);
219 if (!bits) { return bits; }
220 const Rational separation(BigInt(1), BigInt(2) * denominator_bound * denominator_bound);
221 while (root.upper - root.lower >= separation) {
223 if (!refined) { return refined; }
224 if (root.is_rational()) { return Result<void>::success(); }
225 }
226 /**
227 * @brief 有理根定理给出分母 q 的上界;当前包围宽度保证根 p/q 位于中点连分数的渐近分数中。
228 * 通过连分数恢复有理分割点,免去整数因子枚举。
229 */
230 const Rational midpoint = (root.lower + root.upper) / Rational(2);
231 BigInt numerator = midpoint.get_numerator(), denominator = midpoint.get_denominator();
232 BigInt old_p(0), p(1), old_q(1), q(0);
233 while (denominator != BigInt(0)) {
234 auto step = context.consume_steps(1, operation);
235 if (!step) { return step; }
236 BigInt quotient = numerator / denominator;
237 BigInt remainder = numerator % denominator;
238 if (remainder < BigInt(0)) { quotient = quotient - BigInt(1); remainder = remainder + denominator; }
239 BigInt next_p = quotient * p + old_p;
240 BigInt next_q = quotient * q + old_q;
241 if (next_q > denominator_bound) { break; }
242 Rational candidate(next_p, next_q);
243 if (candidate >= root.lower && candidate <= root.upper &&
244 root.polynomial.eval(candidate) == Rational(0)) {
245 root.lower = root.upper = candidate;
246 break;
247 }
248 old_p = std::move(p); p = std::move(next_p);
249 old_q = std::move(q); q = std::move(next_q);
250 numerator = std::move(denominator); denominator = std::move(remainder);
251 }
252 return Result<void>::success();
253}
254
256 if (polynomial.degree() <= 0) return std::vector<Algebraic>{};
257 auto repeated = gcd_checked(polynomial, polynomial.differentiate(), context);
258 if (!repeated) return Result<std::vector<Algebraic>>::failure(repeated.error());
259 auto square_free = polynomial.div_mod(repeated.value()).first.make_monic();
260 BigInt denominator_bound(1);
261 for (const auto& coefficient : square_free.coeffs) {
262 const auto& denominator = coefficient.get_denominator();
263 denominator_bound = denominator_bound / BigInt::gcd(denominator_bound, denominator) * denominator;
264 auto checked = context.require_integer_bits(denominator_bound.bit_length(), operation);
265 if (!checked) return Result<std::vector<Algebraic>>::failure(checked.error());
266 }
267 auto isolated = detail::isolate_real_roots_exact(square_free, context, operation);
268 if (!isolated) return Result<std::vector<Algebraic>>::failure(isolated.error());
269 std::vector<Algebraic> roots;
270 for (std::size_t i = 0; i < isolated.value().size(); ++i) {
271 Algebraic root{square_free, isolated.value()[i].first, isolated.value()[i].second, i, 1};
272 auto recovered = recover_rational_cut(root, denominator_bound, context);
273 if (!recovered) return Result<std::vector<Algebraic>>::failure(recovered.error());
274 roots.push_back(std::move(root));
275 }
276 return roots;
277}
278
280 const Boundary& a, const Boundary& b, ComputationContext& context) {
281 if (polynomial.is_zero()) return std::optional<int>{0};
282 if (polynomial.degree() == 0) return std::optional<int>{sign(polynomial.lead_coeff())};
283 auto roots = roots_checked(polynomial, context);
284 if (!roots) return Result<std::optional<int>>::failure(roots.error());
285 for (const auto& root : roots.value()) {
286 auto left = compare_boundaries(a, Boundary{0, root}, context);
287 auto right = compare_boundaries(Boundary{0, root}, b, context);
288 if (!left) return Result<std::optional<int>>::failure(left.error());
289 if (!right) return Result<std::optional<int>>::failure(right.error());
290 if (left.value() < 0 && right.value() < 0) return std::optional<int>{};
291 }
292 if (a.infinity < 0)
293 return std::optional<int>{sign(polynomial.lead_coeff()) *
294 (polynomial.degree() % 2 ? -1 : 1)};
295 if (b.infinity > 0) return std::optional<int>{sign(polynomial.lead_coeff())};
296 auto left = a.finite;
297 auto right = b.finite;
298 while (!(left.upper < right.lower)) {
300 if (!l) return Result<std::optional<int>>::failure(l.error());
302 if (!r) return Result<std::optional<int>>::failure(r.error());
303 }
304 return std::optional<int>{sign(polynomial.eval((left.upper + right.lower) / Rational(2)))};
305}
306
309 if (polynomial.is_zero()) { return 0; }
310 if (root.is_rational()) { return sign(polynomial.eval(root.lower)); }
311 auto common = gcd_checked(polynomial, root.polynomial, context);
312 if (!common) { return Result<int>::failure(common.error()); }
313 if (common.value().degree() > 0) {
314 auto zeros = detail::count_real_roots_exact(common.value(), root.lower, root.upper, context, operation);
315 if (!zeros) { return Result<int>::failure(zeros.error()); }
316 if (zeros.value()) { return 0; }
317 }
318 for (;;) {
319 auto zeros = detail::count_real_roots_exact(polynomial, root.lower, root.upper, context, operation);
320 if (!zeros) { return Result<int>::failure(zeros.error()); }
321 if (!zeros.value()) { return sign(polynomial.eval(root.lower)); }
323 if (!refined) { return Result<int>::failure(refined.error()); }
324 }
325}
326
327static bool include_divergence(int& divergence, int contribution) {
328 if (divergence && divergence != contribution) { return false; }
329 divergence = contribution;
330 return true;
331}
332
334 const Algebraic& root, const Boundary& a, const Boundary& b,
336 auto left = compare_boundaries(a, Boundary{0, root}, context);
337 auto right = compare_boundaries(Boundary{0, root}, b, context);
338 if (!left) { return Result<void>::failure(left.error()); }
339 if (!right) { return Result<void>::failure(right.error()); }
340 if (left.value() > 0 || right.value() > 0) { return Result<void>::success(); }
341 Poly derivative = rational.denominator;
342 std::size_t multiplicity = 0;
343 int denominator_sign = 0;
344 do {
345 derivative = derivative.differentiate();
346 ++multiplicity;
347 auto value = polynomial_at_root_sign(derivative, root, context);
348 if (!value) { return Result<void>::failure(value.error()); }
349 denominator_sign = value.value();
350 } while (!denominator_sign);
351 auto numerator_sign = polynomial_at_root_sign(rational.numerator, root, context);
352 if (!numerator_sign) { return Result<void>::failure(numerator_sign.error()); }
353 int coefficient_sign = numerator_sign.value() * denominator_sign;
354 if (!coefficient_sign) { return Result<void>::failure(CasErrc::InternalInvariant,
355 "reduced rational pole has a zero numerator", operation); }
356 if (left.value() < 0 && !include_divergence(divergence, coefficient_sign * (multiplicity % 2 ? -1 : 1)))
357 { return divergent<void>(); }
358 if (right.value() < 0 && !include_divergence(divergence, coefficient_sign)) { return divergent<void>(); }
359 return Result<void>::success();
360}
361
363 const Boundary& a, const Boundary& b, ComputationContext& context) {
364 if (rational.denominator.is_zero()) { return divergent<int>(); }
365 auto gcd = gcd_checked(rational.numerator, rational.denominator, context);
366 if (!gcd) { return Result<int>::failure(gcd.error()); }
367 rational.numerator = rational.numerator.div_mod(gcd.value()).first;
368 rational.denominator = rational.denominator.div_mod(gcd.value()).first;
369 if (rational.numerator.is_zero()) { return 0; }
370 auto roots = roots_checked(rational.denominator, context);
371 if (!roots) { return Result<int>::failure(roots.error()); }
372 int divergence = 0;
373 for (const auto& root : roots.value()) {
374 auto pole = rational_pole_divergence(rational, root, a, b, divergence, context);
375 if (!pole) { return Result<int>::failure(pole.error()); }
376 }
377 const int degree = rational.numerator.degree() - rational.denominator.degree();
378 if (degree >= -1) {
379 int coefficient = sign(rational.numerator.lead_coeff()) * sign(rational.denominator.lead_coeff());
380 if (a.infinity < 0 && !include_divergence(divergence, coefficient * (degree % 2 ? -1 : 1))) { return divergent<int>(); }
381 if (b.infinity > 0 && !include_divergence(divergence, coefficient)) { return divergent<int>(); }
382 }
383 return divergence;
384}
385}
加法节点,表示多个操作数的求和。
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Sqrt
对数、绝对值、平方根。
乘法节点,表示多个操作数的乘积。
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
Polynomial differentiate() const
求导
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
幂运算节点,表示 base^exponent。
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
const std::shared_ptr< const SymbolicNode > & base() const noexcept
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static Result< void > polynomial_budget(const Poly &polynomial, ComputationContext &context)
Result< int > rational_divergence_checked(RationalFunction &rational, const Boundary &a, const Boundary &b, ComputationContext &context)
Result< std::optional< RationalFunction > > RationalResult
Result< Poly > product_checked(const Poly &a, const Poly &b, ComputationContext &context)
static int sign(const Rational &value)
std::optional< Rational > exact_number(const Node &node)
static bool include_divergence(int &divergence, int contribution)
Result< int > compare_boundaries(const Boundary &a, const Boundary &b, ComputationContext &context)
static Result< void > recover_rational_cut(Algebraic &root, const BigInt &denominator_bound, ComputationContext &context)
static Result< void > rational_pole_divergence(const RationalFunction &rational, const Algebraic &root, const Boundary &a, const Boundary &b, int &divergence, ComputationContext &context)
std::shared_ptr< const SymbolicNode > Node
static RationalResult rational_operands_checked(const std::vector< Node > &operands, bool sum, const std::string &var, ComputationContext &context)
static RationalResult rational_power_checked(const PowerNode &power, const std::string &var, ComputationContext &context)
Result< std::optional< int > > polynomial_sign_checked(const Poly &polynomial, const Boundary &a, const Boundary &b, ComputationContext &context)
Result< Boundary > boundary_checked(const SymbolicExpr &expression, ComputationContext &context)
RationalResult rational_checked(const Node &node, const std::string &var, ComputationContext &context)
Node absolute_argument(const SymbolicNode &node)
识别绝对值节点及公共接口的平方开根表示。
static Result< Poly > gcd_checked(Poly a, Poly b, ComputationContext &context)
Result< std::vector< Algebraic > > roots_checked(const Poly &polynomial, ComputationContext &context)
static Result< int > polynomial_at_root_sign(Poly polynomial, Algebraic root, ComputationContext &context)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< std::vector< RationalInterval > > isolate_real_roots_exact(const Polynomial< Rational > &polynomial, ComputationContext &context, const std::string &operation)
Result< std::size_t > count_real_roots_exact(const Polynomial< Rational > &polynomial, const Rational &lower, const Rational &upper, ComputationContext &context, const std::string &operation)
Result< int > compare_exact_real_algebraic(ExactRealAlgebraic lhs, ExactRealAlgebraic rhs, ComputationContext &context)
std::size_t std::size_t multiplicity
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
Result< void > refine_exact_real_algebraic(ExactRealAlgebraic &value, ComputationContext &context, const std::string &operation)
ExactRealAlgebraicResult make_exact_real_algebraic(Polynomial< Rational > polynomial, std::size_t root_index, std::size_t multiplicity, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
Result< bool > equal_exact_real_algebraic(ExactRealAlgebraic lhs, ExactRealAlgebraic rhs, ComputationContext &context)
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
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
std::shared_ptr< SymbolicExpr > divergence(const VectorField &F, const std::vector< std::string > &vars)
Result< OptionalRationalPolynomial > recognize_rational_polynomial(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
const ExprPtr & right
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
Rational exact_number_as_rational(const NumberNode &node)
const ExprPtr & denominator
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
ExprResult rational(const Rational &value)
符号表达式与一元多项式的转换。
精确 RootOf 标识构造及受检数值求值。