LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
complex_analysis.cpp
浏览该文件的文档.
1#include <stdexcept>
3#include "limit_result.hpp"
4/**
5 * @file complex_analysis.cpp
6 * @brief 复变函数分析实现。
7 */
9#include "poly_utils.hpp"
11#include "symbolic.hpp"
14#include <cmath>
15#include <optional>
16
17namespace LMCAS {
18
19namespace {
20
21Result<void> validate_complex_expr_input(const std::shared_ptr<SymbolicExpr>& expr,
23 const std::string& operation)
24{
25 auto step = context.consume_steps(1, operation);
26 if (!step) return step;
27 if (!expr || !LMCAS::detail::node(expr)) {
29 "expression cannot be null", operation);
30 }
31 return Result<void>::success();
32}
33
35 const std::shared_ptr<SymbolicExpr>& expr,
36 const std::string& z,
37 const std::shared_ptr<SymbolicExpr>& z0,
38 int order,
40 const std::string& operation)
41{
42 auto step = context.consume_steps(1, operation);
43 if (!step) return step;
44 if (!expr || !LMCAS::detail::node(expr) || !z0 || !LMCAS::detail::node(z0)) {
46 "complex-analysis expressions cannot be null",
47 operation);
48 }
49 if (z.empty()) {
51 "complex variable name cannot be empty",
52 operation);
53 }
54 if (order < 1 || order > 13) {
56 "complex-analysis order must be between 1 and 13",
57 operation);
58 }
59 return Result<void>::success();
60}
61
63public:
64 explicit FunctionDependencyFinder(const std::string& variable)
66
67 bool found() const noexcept { return found_; }
68
69 void visit(const FunctionNode& node) override {
70 visit_function(node.arguments());
71 }
72
73 void visit(const UninterpretedFunctionNode& node) override {
74 visit_function(node.arguments());
75 }
76
77 void visit(const SummationNode& node) override { visit_binder(node); }
78 void visit(const ProductNode& node) override { visit_binder(node); }
79 void visit(const IntegralNode& node) override { visit_binder(node); }
80 void visit(const TransformNode& node) override { visit_binder(node); }
81 void visit(const QuantifierNode& node) override { visit_binder(node); }
82 void visit(const SetBuilderNode& node) override { visit_binder(node); }
83 void visit(const LimitNode& node) override { visit_binder(node); }
84
85protected:
86 void visit_child(const detail::SymbolicNodePtr& child) override {
87 if (!found_) RecursiveSymbolicVisitor::visit_child(child);
88 }
89
90private:
91 void visit_function(const std::vector<detail::SymbolicNodePtr>& arguments) {
92 if (!is_bound_) {
93 for (const auto& argument : arguments) {
95 found_ = true;
96 return;
97 }
98 }
99 }
100 visit_children(arguments);
101 }
102
103 void visit_binder(const SymbolicNode& node) {
104 const auto binder = detail::binder_view(node);
105 visit_children(binder->outside_scope);
106 const bool previous = is_bound_;
107 is_bound_ = is_bound_ || binder->bound_name == variable_;
108 visit_child(binder->scoped_body);
109 is_bound_ = previous;
110 }
111
112 const std::string& variable_;
113 bool is_bound_ = false;
114 bool found_ = false;
115};
116
118public:
119 bool found() const noexcept { return found_; }
120
121
122 void visit(const ComplexNode&) override { found_ = true; }
123
124protected:
125 void visit_child(const detail::SymbolicNodePtr& child) override {
126 if (!found_) RecursiveSymbolicVisitor::visit_child(child);
127 }
128
129private:
130 bool found_ = false;
131};
132
134 if (!node) return false;
136 node->accept(finder);
137 return finder.found();
138}
139
141public:
142 bool found() const noexcept { return found_; }
143
144 void visit(const FunctionNode& node) override {
145 visit_function(node.arguments());
146 }
147
148 void visit(const UninterpretedFunctionNode& node) override {
149 visit_function(node.arguments());
150 }
151
152protected:
153 void visit_child(const detail::SymbolicNodePtr& child) override {
154 if (!found_) RecursiveSymbolicVisitor::visit_child(child);
155 }
156
157private:
158 void visit_function(const std::vector<detail::SymbolicNodePtr>& arguments) {
159 for (const auto& argument : arguments) {
160 if (contains_explicit_complex(argument)) {
161 found_ = true;
162 return;
163 }
164 }
165 visit_children(arguments);
166 }
167
168 bool found_ = false;
169};
170
172 const std::string& z) {
173 if (!node) return false;
174 FunctionDependencyFinder finder(z);
175 node->accept(finder);
176 return finder.found();
177}
178
180 if (!node) return false;
182 node->accept(finder);
183 return finder.found();
184}
185
186} // namespace
187
189 const std::shared_ptr<SymbolicExpr>&,
190 const std::string&,
191 const std::shared_ptr<SymbolicExpr>&,
192 int,
193 ComputationContext&);
195 const std::shared_ptr<SymbolicExpr>&,
196 const std::string&,
197 const std::shared_ptr<SymbolicExpr>&,
198 int, ComputationContext&);
199static bool is_analytic_impl(
200 const std::shared_ptr<SymbolicExpr>&,
201 const std::string&, ComputationContext& context);
202
204 const std::shared_ptr<SymbolicExpr>& f,
205 const std::string& z,
206 const std::shared_ptr<SymbolicExpr>& z0,
207 int order,
209{
210 const std::string operation = "calculate_residue";
211 auto input = validate_complex_expr_point_input(f, z, z0, order, context, operation);
212 if (!input) return ExpressionResult::failure(input.error());
213 auto budget = context.consume_steps(static_cast<std::size_t>(order) * 12 + 12,
214 operation);
215 if (!budget) return ExpressionResult::failure(budget.error());
216
217 try {
218 auto calculated =
220 if (!calculated) return calculated;
221 auto result = std::move(calculated.value());
222 if (!result || !LMCAS::detail::node(result)) {
225 "residue could not be constructed in the supported symbolic domain",
226 operation);
227 }
228 return result;
229 } catch (const std::bad_alloc&) {
231 "allocation failed while calculating residue",
232 operation);
233 } catch (const std::exception& ex) {
235 ex.what(),
236 operation);
237 }
238}
239
241 const std::shared_ptr<SymbolicExpr>& f,
242 const std::string& z,
243 const std::shared_ptr<SymbolicExpr>& z0,
244 int order)
245{
247 return calculate_residue_checked(f, z, z0, order, context);
248}
249
251 const std::shared_ptr<SymbolicExpr>& f,
252 const std::string& z,
253 const std::shared_ptr<SymbolicExpr>& z0,
254 int order,
256 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
257 (context).limits().max_ast_nodes, "transform");
258 if (order < 1) return SymbolicExpr::number(0);
259
260 auto var_z = SymbolicExpr::variable(z);
261 auto z_minus_z0 = SymbolicExpr::add(var_z, SymbolicExpr::multiply(z0, SymbolicExpr::number(-1)));
262 auto pow_term = SymbolicExpr::power(z_minus_z0, SymbolicExpr::number(order));
263
264 auto F = SymbolicExpr::multiply(pow_term, f);
265
266 for (int i = 0; i < order - 1; i++) {
268 }
269
270 auto fact = BigInt::factorial_checked(BigInt(order - 1), context);
271 if (!fact) return ExpressionResult::failure(fact.error());
272
273 F = SymbolicExpr::divide(F, SymbolicExpr::number(fact.value()));
274
277} catch (const CasError& error) {
278 return ExpressionResult::failure(error);
279} catch (const std::bad_alloc&) {
280 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "calculate_residue_impl");
281} catch (const std::length_error& error) {
282 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "calculate_residue_impl");
283} catch (const std::exception& error) {
284 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "calculate_residue_impl");
285}
286
288 const std::shared_ptr<SymbolicExpr>& f,
289 const std::string& z,
290 const std::shared_ptr<SymbolicExpr>& z0,
291 int n,
293{
294 const std::string operation = "cauchy_integral";
295 auto input = validate_complex_expr_point_input(f, z, z0, n, context, operation);
296 if (!input) return ExpressionResult::failure(input.error());
297 auto budget = context.consume_steps(static_cast<std::size_t>(n) * 12 + 12,
298 operation);
299 if (!budget) return ExpressionResult::failure(budget.error());
300
301 try {
302 auto calculated = cauchy_integral_impl(f, z, z0, n, context);
303 if (!calculated) return calculated;
304 auto result = std::move(calculated.value());
305 if (!result || !LMCAS::detail::node(result)) {
308 "Cauchy integral formula could not be constructed in the supported symbolic domain",
309 operation);
310 }
311 return ExpressionResult::success(result);
312 } catch (const std::bad_alloc&) {
314 "allocation failed while applying Cauchy integral formula",
315 operation);
316 } catch (const std::exception& ex) {
318 ex.what(),
319 operation);
320 }
321}
322
324 const std::shared_ptr<SymbolicExpr>& f,
325 const std::string& z,
326 const std::shared_ptr<SymbolicExpr>& z0,
327 int n)
328{
330 return cauchy_integral_checked(f, z, z0, n, context);
331}
332
334 const std::shared_ptr<SymbolicExpr>& f,
335 const std::string& z,
336 const std::shared_ptr<SymbolicExpr>& z0,
337 int n, ComputationContext& context) try {
338 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
339 (context).limits().max_ast_nodes, "transform");
340
341 /// n is the power in the denominator: \oint f(z)/(z-z0)^n dz
342 if (n < 1) return SymbolicExpr::number(0);
343
344 auto deriv = f;
345 for (int i = 0; i < n - 1; i++) {
346 deriv = detail::make_expression_ptr(detail::differentiate_node(detail::node(deriv), z, transform_budget));
347 }
348
349 auto f_n_minus_1_z0 = detail::make_expression_ptr(detail::substitute_node(detail::node(deriv), z, detail::node(z0), transform_budget));
350
351 auto fact = BigInt::factorial_checked(BigInt(n - 1), context);
352 if (!fact) return ExpressionResult::failure(fact.error());
353
354 auto term = SymbolicExpr::divide(f_n_minus_1_z0, SymbolicExpr::number(fact.value()));
355
356 auto pi_node = LMCAS::detail::make_node<VariableNode>("pi", true);
358 LMCAS::detail::node(SymbolicExpr::number(0)),
359 LMCAS::detail::node(SymbolicExpr::number(1)));
360
361 auto pi_expr = LMCAS::detail::make_expression_ptr(pi_node);
362 auto i_expr = LMCAS::detail::make_expression_ptr(i_node);
363
364 auto two_pi_i = SymbolicExpr::multiply(SymbolicExpr::number(2), SymbolicExpr::multiply(pi_expr, i_expr));
365
366 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(two_pi_i, term)), transform_budget));
367} catch (const CasError& error) {
368 return ExpressionResult::failure(error);
369} catch (const std::bad_alloc&) {
370 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "cauchy_integral_impl");
371} catch (const std::length_error& error) {
372 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "cauchy_integral_impl");
373} catch (const std::exception& error) {
374 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "cauchy_integral_impl");
375}
376
377std::shared_ptr<SymbolicExpr> analytic_continuation(
378 const std::shared_ptr<SymbolicExpr>& f,
379 const std::string&) {
381 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
382 (context).limits().max_ast_nodes, "transform");
383 /// Basic analytic continuation via symbolic simplification
384 /// Simplification often reduces locally defined series (if represented)
385 /// to their global analytic forms (e.g. geometric series).
386 if (!f) return f;
388}
389
390namespace {
391
392std::optional<int> bounded_complex_power(
393 const std::shared_ptr<const SymbolicNode>& node) {
394 auto number = std::dynamic_pointer_cast<const NumberNode>(node);
395 if (!number) return std::nullopt;
396 BigInt exponent;
397 if (const auto* integer = std::get_if<BigInt>(&number->value())) {
398 exponent = *integer;
399 } else if (const auto* rational = std::get_if<Rational>(&number->value())) {
400 if (!rational->is_integer()) return std::nullopt;
401 exponent = rational->get_numerator();
402 }
403 if (exponent < BigInt(0) || exponent > BigInt(16)) return std::nullopt;
404 return static_cast<int>(*exponent.try_to_int64());
405}
406
407/// 递归地将表达式分解为 (实部, 虚部),把 ComplexNode 视为 a+bi。
408/// 仅处理加法、乘法、数值与 ComplexNode 组合;其余子表达式视为实值。
409void split_real_imag(const std::shared_ptr<const SymbolicNode>& node,
410 std::shared_ptr<SymbolicExpr>& re,
411 std::shared_ptr<SymbolicExpr>& im, ComputationContext& context) {
412
413 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
414 (context).limits().max_ast_nodes, "transform");
415 re = SymbolicExpr::number(0);
416 im = SymbolicExpr::number(0);
417 if (!node) return;
418
419
420 if (auto cn = std::dynamic_pointer_cast<const ComplexNode>(node)) {
421 re = LMCAS::detail::make_expression_ptr(cn->real());
422 im = LMCAS::detail::make_expression_ptr(cn->imag());
423 return;
424 }
425 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
426 for (const auto& op : add->operands()) {
427 std::shared_ptr<SymbolicExpr> r2, i2;
428 split_real_imag(op, r2, i2, context);
429 re = SymbolicExpr::add(re, r2);
430 im = SymbolicExpr::add(im, i2);
431 }
434 return;
435 }
436 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
437 /// 累乘:(a+bi)(c+di) = (ac-bd) + (ad+bc)i
438 std::shared_ptr<SymbolicExpr> accR = SymbolicExpr::number(1);
439 std::shared_ptr<SymbolicExpr> accI = SymbolicExpr::number(0);
440 for (const auto& op : mul->operands()) {
441 std::shared_ptr<SymbolicExpr> r2, i2;
442 split_real_imag(op, r2, i2, context);
443 auto ac = SymbolicExpr::multiply(accR, r2);
444 auto bd = SymbolicExpr::multiply(accI, i2);
445 auto ad = SymbolicExpr::multiply(accR, i2);
446 auto bc = SymbolicExpr::multiply(accI, r2);
447 accR = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(ac, SymbolicExpr::multiply(SymbolicExpr::number(-1), bd))), transform_budget));
448 accI = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(ad, bc)), transform_budget));
449 }
450 re = accR;
451 im = accI;
452 return;
453 }
454 if (auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
455 /// 对整数次幂,展开为重复乘法以分离实/虚部。
456 auto exponent = bounded_complex_power(pw->exponent());
457 std::shared_ptr<SymbolicExpr> baseR, baseI;
458 split_real_imag(pw->base(), baseR, baseI, context);
459 bool base_real = LMCAS::detail::node(baseI) && LMCAS::detail::node(baseI)->is_zero();
460 if (exponent && !base_real) {
461 /// (a+bi)^e via repeated complex multiplication
462 std::shared_ptr<SymbolicExpr> accR = SymbolicExpr::number(1);
463 std::shared_ptr<SymbolicExpr> accI = SymbolicExpr::number(0);
464 for (int k = 0; k < *exponent; ++k) {
465 auto ac = SymbolicExpr::multiply(accR, baseR);
466 auto bd = SymbolicExpr::multiply(accI, baseI);
467 auto ad = SymbolicExpr::multiply(accR, baseI);
468 auto bc = SymbolicExpr::multiply(accI, baseR);
469 accR = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(ac, SymbolicExpr::multiply(SymbolicExpr::number(-1), bd))), transform_budget));
470 accI = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(ad, bc)), transform_budget));
471 }
472 re = accR; im = accI;
473 return;
474 }
475 /// 实底数或非整数指数:视为实值
476 if (base_real) {
478 im = SymbolicExpr::number(0);
479 return;
480 }
481 /// 退化情形:原样返回为实部
483 im = SymbolicExpr::number(0);
484 return;
485 }
486 /// 默认:视为实值表达式
488 im = SymbolicExpr::number(0);
489}
490
491} // namespace
492
493ExpressionResult real_part_checked(const std::shared_ptr<SymbolicExpr>& expr,
495 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
496 (context).limits().max_ast_nodes, "transform");
497 const std::string operation = "real_part";
498 auto input = validate_complex_expr_input(expr, context, operation);
499 if (!input) return ExpressionResult::failure(input.error());
500 if (has_function_of_explicit_complex(LMCAS::detail::node(expr))) {
503 "real part of functions with complex arguments is outside the current support domain",
504 operation);
505 }
506
507 std::shared_ptr<SymbolicExpr> re, im;
508 split_real_imag(LMCAS::detail::node(expr), re, im, context);
509 auto simplified = re ? detail::make_expression_ptr(detail::normalize_node(detail::node(re), transform_budget)) : nullptr;
510 if (!simplified || !LMCAS::detail::node(simplified)) {
512 "real part construction failed",
513 operation);
514 }
515 return ExpressionResult::success(simplified);
516} catch (const CasError& error) {
517 return ExpressionResult::failure(error);
518} catch (const std::bad_alloc&) {
519 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "real_part");
520} catch (const std::length_error& error) {
521 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "real_part");
522} catch (const std::exception& error) {
523 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "real_part");
524}
525
526ExpressionResult real_part_checked(const std::shared_ptr<SymbolicExpr>& expr) {
528 return real_part_checked(expr, context);
529}
530
531
532ExpressionResult imag_part_checked(const std::shared_ptr<SymbolicExpr>& expr,
534 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
535 (context).limits().max_ast_nodes, "transform");
536 const std::string operation = "imag_part";
537 auto input = validate_complex_expr_input(expr, context, operation);
538 if (!input) return ExpressionResult::failure(input.error());
539 if (has_function_of_explicit_complex(LMCAS::detail::node(expr))) {
542 "imaginary part of functions with complex arguments is outside the current support domain",
543 operation);
544 }
545
546 std::shared_ptr<SymbolicExpr> re, im;
547 split_real_imag(LMCAS::detail::node(expr), re, im, context);
548 auto simplified = im ? detail::make_expression_ptr(detail::normalize_node(detail::node(im), transform_budget)) : nullptr;
549 if (!simplified || !LMCAS::detail::node(simplified)) {
551 "imaginary part construction failed",
552 operation);
553 }
554 return ExpressionResult::success(simplified);
555} catch (const CasError& error) {
556 return ExpressionResult::failure(error);
557} catch (const std::bad_alloc&) {
558 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "imag_part");
559} catch (const std::length_error& error) {
560 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "imag_part");
561} catch (const std::exception& error) {
562 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "imag_part");
563}
564
565ExpressionResult imag_part_checked(const std::shared_ptr<SymbolicExpr>& expr) {
567 return imag_part_checked(expr, context);
568}
569
570
571ExpressionResult conjugate_checked(const std::shared_ptr<SymbolicExpr>& expr,
573 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
574 (context).limits().max_ast_nodes, "transform");
575 const std::string operation = "conjugate";
576 auto input = validate_complex_expr_input(expr, context, operation);
577 if (!input) return ExpressionResult::failure(input.error());
578 if (has_function_of_explicit_complex(LMCAS::detail::node(expr))) {
581 "conjugate of functions with complex arguments is outside the current support domain",
582 operation);
583 }
584
585 std::shared_ptr<SymbolicExpr> re, im;
586 split_real_imag(LMCAS::detail::node(expr), re, im, context);
587 /// conj(a+bi) = a - bi
588 auto neg_im = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(SymbolicExpr::number(-1), im)), transform_budget));
589 if (!re || !LMCAS::detail::node(re) || !neg_im || !LMCAS::detail::node(neg_im)) {
591 "conjugate construction failed",
592 operation);
593 }
594 if (LMCAS::detail::node(neg_im) && LMCAS::detail::node(neg_im)->is_zero()) {
595 auto simplified_re = detail::make_expression_ptr(detail::normalize_node(detail::node(re), transform_budget));
596 if (!simplified_re || !LMCAS::detail::node(simplified_re)) {
598 "conjugate construction failed",
599 operation);
600 }
601 return ExpressionResult::success(simplified_re);
602 }
604 detail::normalize_node(detail::node(re), transform_budget), LMCAS::detail::node(neg_im));
605 if (!cn) {
607 "conjugate construction failed",
608 operation);
609 }
611} catch (const CasError& error) {
612 return ExpressionResult::failure(error);
613} catch (const std::bad_alloc&) {
614 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "conjugate");
615} catch (const std::length_error& error) {
616 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "conjugate");
617} catch (const std::exception& error) {
618 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "conjugate");
619}
620
621ExpressionResult conjugate_checked(const std::shared_ptr<SymbolicExpr>& expr) {
623 return conjugate_checked(expr, context);
624}
625
626
627ComplexBoolResult is_analytic_checked(const std::shared_ptr<SymbolicExpr>& f,
628 const std::string& z,
630 const std::string operation = "is_analytic";
631 auto input = validate_complex_expr_input(f, context, operation);
632 if (!input) return ComplexBoolResult::failure(input.error());
633 if (z.empty()) {
635 "complex variable name cannot be empty",
636 operation);
637 }
638 try {
639 if (has_z_dependent_function(LMCAS::detail::node(f), z)) {
642 "analyticity of functions depending on the complex variable is outside the current support domain",
643 operation);
644 }
645 auto budget = context.consume_steps(24, operation);
646 if (!budget) return ComplexBoolResult::failure(budget.error());
648 } catch (const CasError& error) {
649 return ComplexBoolResult::failure(error);
650 } catch (const std::bad_alloc&) {
652 "allocation failed while checking analyticity",
653 operation);
654 } catch (const std::length_error& error) {
655 return ComplexBoolResult::failure(CasErrc::ResourceLimit, error.what(), operation);
656 } catch (const std::exception& ex) {
658 ex.what(),
659 operation);
660 }
661}
662
663ComplexBoolResult is_analytic_checked(const std::shared_ptr<SymbolicExpr>& f,
664 const std::string& z) {
666 return is_analytic_checked(f, z, context);
667}
668
669static std::shared_ptr<SymbolicExpr> differentiate_if_dependent(
670 const std::shared_ptr<SymbolicExpr>& expression,
671 const std::string& variable, ComputationContext& context) {
672
673 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
674 (context).limits().max_ast_nodes, "transform");
676 return SymbolicExpr::number(0);
677 }
678 return detail::make_expression_ptr(detail::differentiate_node(detail::node(expression), variable, transform_budget));
679}
680
681static bool is_analytic_impl(const std::shared_ptr<SymbolicExpr>& f, const std::string& z, ComputationContext& context) {
682
683 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
684 (context).limits().max_ast_nodes, "transform");
685 if (!f) return false;
686 /// 将 z 替换为 (z_re + i·z_im),分离 u、v,检验 Cauchy-Riemann。
687 std::string xr = z + "_re";
688 std::string xi = z + "_im";
689 auto zr = SymbolicExpr::variable(xr);
690 auto zi = SymbolicExpr::variable(xi);
693 LMCAS::detail::node(SymbolicExpr::number(0)),
694 LMCAS::detail::node(SymbolicExpr::number(1))));
695 auto z_sub = SymbolicExpr::add(zr, SymbolicExpr::multiply(i_unit, zi));
696
697 auto fz = detail::make_expression_ptr(detail::substitute_node(detail::node(f), z, detail::node(z_sub), transform_budget));
698 if (!fz) return false;
700
701 std::shared_ptr<SymbolicExpr> u, v;
702 split_real_imag(LMCAS::detail::node(fz), u, v, context);
703
704 auto ux = differentiate_if_dependent(u, xr, context);
705 auto uy = differentiate_if_dependent(u, xi, context);
706 auto vx = differentiate_if_dependent(v, xr, context);
707 auto vy = differentiate_if_dependent(v, xi, context);
708
709 /// CR1: ux - vy == 0 ; CR2: uy + vx == 0
710 auto cr1 = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(ux, SymbolicExpr::multiply(SymbolicExpr::number(-1), vy))), transform_budget));
711 auto cr2 = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(uy, vx)), transform_budget));
712
714}
715
717 const std::shared_ptr<SymbolicExpr>& f,
718 const std::string& z,
719 const std::shared_ptr<SymbolicExpr>& z0,
720 int order,
722 return calculate_residue_checked(f, z, z0, order, context);
723}
724
726 const std::shared_ptr<SymbolicExpr>& f,
727 const std::string& z,
728 const std::shared_ptr<SymbolicExpr>& z0,
729 int order) {
730 return calculate_residue_checked(f, z, z0, order);
731}
732
733
734} // namespace LMCAS
复数节点,表示 real + imag * i。
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
连乘节点,表示符号有限/无限连乘 prod_{k=a}^{b} f(k).
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
求和节点,表示符号有限/无限求和 sum_{k=a}^{b} f(k).
static std::shared_ptr< const SymbolicNode > create_complex(std::shared_ptr< const SymbolicNode > real, std::shared_ptr< const SymbolicNode > imag)
创建复数节点,自动简化(若虚部为 0,则返回实部).
virtual void accept(LMCAS::detail::SymbolicVisitor &visitor) const =0
virtual bool is_zero() const
积分变换节点,表示 Laplace,Fourier,Z 变换及其逆变换.
void visit_function(const std::vector< detail::SymbolicNodePtr > &arguments)
void visit_function(const std::vector< detail::SymbolicNodePtr > &arguments)
void visit_children(const Range &children)
复变函数分析:留数计算,柯西积分公式,解析延拓.
微分访问器,对 AST 执行符号求导。
void split_real_imag(const std::shared_ptr< const SymbolicNode > &node, std::shared_ptr< SymbolicExpr > &re, std::shared_ptr< SymbolicExpr > &im, ComputationContext &context)
递归地将表达式分解为 (实部, 虚部),把 ComplexNode 视为 a+bi。 仅处理加法、乘法、数值与 ComplexNode 组合;其余子表达式视为实值。
bool has_function_of_explicit_complex(const detail::SymbolicNodePtr &node)
std::optional< int > bounded_complex_power(const std::shared_ptr< const SymbolicNode > &node)
Result< void > validate_complex_expr_point_input(const std::shared_ptr< SymbolicExpr > &expr, const std::string &z, const std::shared_ptr< SymbolicExpr > &z0, int order, ComputationContext &context, const std::string &operation)
bool contains_explicit_complex(const detail::SymbolicNodePtr &node)
bool has_z_dependent_function(const detail::SymbolicNodePtr &node, const std::string &z)
Result< void > validate_complex_expr_input(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context, const std::string &operation)
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::optional< BinderView > binder_view(const SymbolicNode &node)
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
static ExpressionResult calculate_residue_impl(const std::shared_ptr< SymbolicExpr > &, const std::string &, const std::shared_ptr< SymbolicExpr > &, int, ComputationContext &)
Result< bool > ComplexBoolResult
const std::string & variable
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::string & v
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
const std::vector< FGLMPoly > const MonomialOrder & order
@ Complex
Complex numbers (default, least specific)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
static ExpressionResult cauchy_integral_impl(const std::shared_ptr< SymbolicExpr > &, const std::string &, const std::shared_ptr< SymbolicExpr > &, int, ComputationContext &)
ExpressionResult real_part_checked(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
LimitExpressionResult limit_expression_checked(const LimitExprPtr &expression, const std::string &variable, const LimitExprPtr &point, LimitDirection direction, ComputationContext &context, Domain domain)
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
std::shared_ptr< SymbolicExpr > analytic_continuation(const std::shared_ptr< SymbolicExpr > &f, const std::string &)
const ExprPtr RelationOp op
const ExprPtr & exponent
static bool is_analytic_impl(const std::shared_ptr< SymbolicExpr > &, const std::string &, ComputationContext &context)
ExpressionResult calculate_residue_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &z, const std::shared_ptr< SymbolicExpr > &z0, int order, ComputationContext &context)
ExpressionResult conjugate_checked(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > differentiate_if_dependent(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable, ComputationContext &context)
ExpressionResult imag_part_checked(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context)
ExprResult rational(const Rational &value)
ExpressionResult residue_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &z, const std::shared_ptr< SymbolicExpr > &z0, int order, ComputationContext &context)
ExpressionResult cauchy_integral_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &z, const std::shared_ptr< SymbolicExpr > &z0, int n, ComputationContext &context)
ComplexBoolResult is_analytic_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &z, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & u
多项式转换与精确符号多项式代数。
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
内部 AST 定义。