LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_by_parts.cpp
浏览该文件的文档.
3
4namespace LMCAS {
5
6namespace {
8 const std::shared_ptr<const SymbolicNode>& node, const std::string& var) {
10 if (auto fn = std::dynamic_pointer_cast<const FunctionNode>(node)) {
11 if (fn->type() == FunctionNode::FuncType::Ln || fn->type() == FunctionNode::FuncType::Log) { return 1; }
12 if (fn->type() == FunctionNode::FuncType::ArcSin || fn->type() == FunctionNode::FuncType::ArcTan) { return 2; }
13 if (fn->type() == FunctionNode::FuncType::Sin || fn->type() == FunctionNode::FuncType::Cos) { return 4; }
14 if (fn->type() == FunctionNode::FuncType::Exp) { return 5; }
15 }
16 if (!depends_on_integration_variable(e, var)) { return 10; }
17 if (std::dynamic_pointer_cast<const VariableNode>(node)) { return 3; }
18 if (const auto* power = dynamic_cast<const PowerNode*>(node.get())) {
19 const auto exponent = detail::exact_rational_value(power->exponent());
20 const auto* base = dynamic_cast<const VariableNode*>(power->base().get());
21 if (base && base->name() == var && exponent &&
22 exponent->is_integer() && *exponent > Rational(0)) { return 3; }
23 }
24 return 10;
25}
26
28 const std::vector<std::shared_ptr<const SymbolicNode>>& ops, const std::string& var) {
29 int best_u_idx = -1;
30 int best_score = 10;
31 if (ops.size() == 1) {
32 int s = integration_by_parts_score(ops[0], var);
33 if (s <= 2) best_u_idx = 0;
34 } else {
35 for (size_t i = 0; i < ops.size(); ++i) {
37 int s = integration_by_parts_score(ops[i], var);
38 if (s < best_score) {
39 best_score = s;
40 best_u_idx = (int)i;
41 }
42 }
43 }
44 return best_u_idx;
45}
46
47std::shared_ptr<SymbolicExpr> integration_differential_factor(
48 const std::vector<std::shared_ptr<const SymbolicNode>>& ops, int best_u_idx) {
49 std::vector<std::shared_ptr<const SymbolicNode>> dv_ops;
50 for (size_t i = 0; i < ops.size(); ++i) {
51 if ((int)i != best_u_idx) {
52 dv_ops.push_back(ops[i]);
53 }
54 }
55 if (dv_ops.empty()) {
56 return SymbolicExpr::number(1);
57 }
58 if (dv_ops.size() == 1) {
60 }
62}
63}
64
65Result<std::optional<detail::IntegralParts>> Integrator::try_integration_by_parts(
66 const SymbolicExpr& expr, const std::string& var,
67 ComputationContext& computation, int depth) try {
68 detail::RewriteBudget transform_budget(computation, (computation).limits().max_recursion_depth,
69 (computation).limits().max_ast_nodes, "transform");
70
71 std::vector<std::shared_ptr<const SymbolicNode>> ops;
72 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(LMCAS::detail::node(expr))) {
73 ops = mul->operands();
74 } else {
75 ops.push_back(LMCAS::detail::node(expr));
76 }
77 int best_u_idx = integration_by_parts_choice(ops, var);
78 if (best_u_idx == -1) { return std::optional<detail::IntegralParts>{}; }
79 if (integration_by_parts_score(ops[best_u_idx], var) >= 4) {
80 for (std::size_t i = 0; i < ops.size(); ++i) {
81 if (i == static_cast<std::size_t>(best_u_idx) ||
82 !expression_depends_on_variable(ops[i], var)) { continue; }
83 const auto* function = dynamic_cast<const FunctionNode*>(ops[i].get());
84 if (!function || (function->type() != FunctionNode::FuncType::Sin &&
87 return std::optional<detail::IntegralParts>{};
88 }
89 }
90 }
91
92 auto u = LMCAS::detail::expression_from_node(ops[best_u_idx]);
93 auto dv = integration_differential_factor(ops, best_u_idx);
94
95 auto integrated_v = integrate_recursive(*dv, var, computation, depth + 1);
96 if (!integrated_v) {
97 return Result<std::optional<detail::IntegralParts>>::failure(integrated_v.error());
98 }
99 if (!detail::node(integrated_v.value().remainder)->is_zero()) {
100 return std::optional<detail::IntegralParts>{};
101 }
102 auto v = detail::make_expression_ptr(std::move(integrated_v.value().primitive));
103
105 detail::differentiate_node(detail::node(u), var, transform_budget), transform_budget));
106
107 auto uv = SymbolicExpr::multiply(detail::make_expression_ptr(u), v);
108 auto vdu = SymbolicExpr::multiply(v, du);
109 vdu = detail::make_expression_ptr(detail::normalize_node(detail::node(vdu->cancel()), transform_budget));
110 auto integrated_vdu = integrate_recursive(*vdu, var, computation, depth + 1);
111 if (!integrated_vdu) {
112 return Result<std::optional<detail::IntegralParts>>::failure(integrated_vdu.error());
113 }
114 auto parts = std::move(integrated_vdu.value());
116 detail::node(sym_sub(*uv, parts.primitive)), transform_budget));
118 detail::node(SymbolicExpr::multiply(
119 SymbolicExpr::number(-1), detail::make_expression_ptr(parts.remainder))),
120 transform_budget));
121 return std::optional<detail::IntegralParts>{{std::move(primitive), std::move(remainder)}};
122} catch (const CasError& error) {
123 return Result<std::optional<detail::IntegralParts>>::failure(error);
124}
125
126}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
幂运算节点,表示 base^exponent。
变量节点,表示一个符号变量。
int integration_by_parts_score(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
std::shared_ptr< SymbolicExpr > integration_differential_factor(const std::vector< std::shared_ptr< const SymbolicNode > > &ops, int best_u_idx)
int integration_by_parts_choice(const std::vector< std::shared_ptr< const SymbolicNode > > &ops, const std::string &var)
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
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
std::shared_ptr< const Node > make_node(Args &&... args)
std::optional< Rational > exact_rational_value(const NumberNode &number)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
ExprResult e()
__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
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)
bool depends_on_integration_variable(const SymbolicExpr &expression, const std::string &variable)
const ExprPtr & exponent
std::size_t std::size_t depth
std::shared_ptr< SymbolicExpr > sym_sub(const SymbolicExpr &lhs, const SymbolicExpr &rhs)
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
__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