LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_linearity.cpp
浏览该文件的文档.
3
4namespace LMCAS {
5
6namespace {
7std::shared_ptr<const SymbolicNode> integration_exponential_argument(
8 const std::shared_ptr<const SymbolicNode>& factor) {
9 const auto* power = dynamic_cast<const PowerNode*>(factor.get());
10 const auto& base = power ? power->base() : factor;
11 const auto* function = dynamic_cast<const FunctionNode*>(base.get());
13 function->arguments().size() != 1) {
14 return nullptr;
15 }
16 if (!power) { return function->arguments()[0]; }
17 BigInt integer;
19 std::dynamic_pointer_cast<const NumberNode>(power->exponent()), integer) ||
20 integer.is_zero()) {
21 return nullptr;
22 }
24 {power->exponent(), function->arguments()[0]});
25}
26
27std::shared_ptr<const SymbolicNode> combine_integration_exponentials(
28 const std::vector<std::shared_ptr<const SymbolicNode>>& dependents) {
29 if (dependents.empty() || (dependents.size() == 1 &&
30 !dynamic_cast<const PowerNode*>(dependents[0].get()))) {
31 return nullptr;
32 }
33 std::vector<std::shared_ptr<const SymbolicNode>> exponents;
34 exponents.reserve(dependents.size());
35 for (const auto& dependent : dependents) {
36 auto argument = integration_exponential_argument(dependent);
37 if (!argument) { return nullptr; }
38 exponents.push_back(std::move(argument));
39 }
42 std::vector<std::shared_ptr<const SymbolicNode>>{
43 SymbolicFactory::create_add(std::move(exponents))});
44}
45}
46
48 const detail::SymbolicNodePtr& value, const detail::SymbolicNodePtr& coefficient,
49 detail::RewriteBudget& budget) {
50 detail::RewriteScope scope(&budget);
51 if (const auto* piecewise = dynamic_cast<const PiecewiseNode*>(value.get())) {
52 std::vector<PiecewiseNode::Branch> branches;
53 branches.reserve(piecewise->branches().size());
54 for (const auto& branch : piecewise->branches()) {
55 branches.push_back({scale_integral_field(branch.expression, coefficient, budget),
56 branch.condition});
57 }
58 auto fallback = piecewise->default_expr()
59 ? scale_integral_field(piecewise->default_expr(), coefficient, budget) : nullptr;
60 auto result = detail::make_node<PiecewiseNode>(std::move(branches), fallback);
61 budget.measure(result);
62 return result;
63 }
65 SymbolicFactory::create_multiply({coefficient, value}, &budget), budget);
66}
67
69 detail::RewriteScope scope(&budget);
70 if (value->is_zero()) { return true; }
71 const auto* piecewise = dynamic_cast<const PiecewiseNode*>(value.get());
72 if (!piecewise) { return false; }
73 for (const auto& branch : piecewise->branches()) {
74 if (!zero_remainder(branch.expression, budget)) { return false; }
75 }
76 return !piecewise->default_expr() || zero_remainder(piecewise->default_expr(), budget);
77}
78
79Result<std::optional<detail::IntegralParts>> Integrator::apply_linearity(
80 const SymbolicExpr& expr, const std::string& var,
81 ComputationContext& context, int depth) {
82 using Attempt = Result<std::optional<detail::IntegralParts>>;
83 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
84 context.limits().max_ast_nodes, "integrate.linearity");
85 if (const auto* add = dynamic_cast<const AddNode*>(detail::node(expr).get())) {
86 std::vector<detail::SymbolicNodePtr> primitives, remainders;
87 for (const auto& operand : add->operands()) {
88 auto term = detail::expression_from_node(operand);
89 auto parts = integrate_recursive(term, var, context, depth + 1, &term);
90 if (!parts) { return Attempt::failure(parts.error()); }
91 primitives.push_back(detail::node(parts.value().primitive));
92 if (!zero_remainder(detail::node(parts.value().remainder), budget)) {
93 remainders.push_back(detail::node(parts.value().remainder));
94 }
95 }
96 const auto remainder = remainders.empty() ? detail::node(zero_)
97 : remainders.size() == 1 ? remainders.front()
99 SymbolicFactory::create_add(std::move(remainders), &budget), budget);
100 return Attempt::success(detail::IntegralParts{
102 SymbolicFactory::create_add(std::move(primitives), &budget), budget)),
103 detail::expression_from_node(remainder)});
104 }
105 if (const auto* mul = dynamic_cast<const MultiplyNode*>(detail::node(expr).get())) {
106 std::vector<detail::SymbolicNodePtr> constants, dependents;
107 for (const auto& operand : mul->operands()) {
108 if (detail::integration_depends_on_variable(operand, var, &budget)) {
109 dependents.push_back(operand);
110 }
111 else { constants.push_back(operand); }
112 }
113 auto exponential = combine_integration_exponentials(dependents);
114 if (!constants.empty() || exponential) {
115 auto dependent = exponential ? detail::expression_from_node(exponential)
116 : dependents.empty() ? *SymbolicExpr::number(1)
117 : dependents.size() == 1 ? detail::expression_from_node(dependents.front())
119 auto parts = integrate_recursive(dependent, var, context, depth + 1, &dependent);
120 if (!parts) { return Attempt::failure(parts.error()); }
121 if (constants.empty()) { return Attempt::success(std::move(parts.value())); }
122 auto coefficient = constants.size() == 1 ? constants.front()
123 : detail::make_node<MultiplyNode>(std::move(constants));
124 coefficient = detail::normalize_node(coefficient, budget);
125 auto scale = [&](const SymbolicExpr& value) {
127 detail::node(value), coefficient, budget));
128 };
129 return Attempt::success(detail::IntegralParts{
130 scale(parts.value().primitive), scale(parts.value().remainder)});
131 }
132 }
133 return Attempt::success(std::nullopt);
134}
135
136}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
乘法节点,表示多个操作数的乘积。
分段函数节点,表示条件分支表达式.
const std::shared_ptr< const SymbolicNode > & default_expr() const noexcept
幂运算节点,表示 base^exponent。
const std::shared_ptr< const SymbolicNode > & base() const noexcept
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
std::shared_ptr< const SymbolicNode > integration_exponential_argument(const std::shared_ptr< const SymbolicNode > &factor)
std::shared_ptr< const SymbolicNode > combine_integration_exponentials(const std::vector< std::shared_ptr< const SymbolicNode > > &dependents)
多元 Hensel 提升(单变量步)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
bool integration_depends_on_variable(const SymbolicNodePtr &expression, const std::string &variable, RewriteBudget *budget=nullptr)
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::size_t std::size_t depth
static detail::SymbolicNodePtr scale_integral_field(const detail::SymbolicNodePtr &value, const detail::SymbolicNodePtr &coefficient, detail::RewriteBudget &budget)
static bool zero_remainder(const detail::SymbolicNodePtr &value, detail::RewriteBudget &budget)
const std::string const ExprPtr & value
std::shared_ptr< const SymbolicNode > make_normalized_multiply_node(const std::vector< std::shared_ptr< const SymbolicNode > > &operands, detail::RewriteBudget *budget=nullptr)
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)