LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_substitution.cpp
浏览该文件的文档.
2#include <stdexcept>
6
7namespace LMCAS {
8
9namespace {
10std::optional<SymbolicExpr> substitution_argument(const SymbolicExpr& term) {
11 if (auto power = std::dynamic_pointer_cast<const PowerNode>(detail::node(term))) {
12 return detail::expression_from_node(power->base());
13 }
14 auto function = std::dynamic_pointer_cast<const FunctionNode>(detail::node(term));
15 if (function && !function->arguments().empty()) {
16 return detail::expression_from_node(function->arguments()[0]);
17 }
18 return std::nullopt;
19}
20
22 const SymbolicExpr& candidate_term, const SymbolicExpr& u,
23 const std::string& var, ComputationContext& context) {
24 if (auto power = std::dynamic_pointer_cast<const PowerNode>(detail::node(candidate_term))) {
25 auto primitive = detail::integrate_power_primitive(u,
26 detail::expression_from_node(power->exponent()), var, context);
27 if (!primitive) {
28 return Result<std::shared_ptr<SymbolicExpr>>::failure(primitive.error());
29 }
30 return primitive.value() ? detail::make_expression_ptr(*primitive.value()) : nullptr;
31 }
32 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(detail::node(candidate_term))) {
34 return SymbolicExpr::sin(detail::make_expression_ptr(u));
35 }
37 return SymbolicExpr::multiply(SymbolicExpr::number(-1),
38 SymbolicExpr::cos(detail::make_expression_ptr(u)));
39 }
41 return SymbolicExpr::exp(detail::make_expression_ptr(u));
42 }
43 }
44 return nullptr;
45}
46
48 const SymbolicExpr& expr, const SymbolicExpr& candidate_term,
49 const std::string& var, ComputationContext& computation) try {
50 detail::RewriteBudget transform_budget(computation, (computation).limits().max_recursion_depth,
51 (computation).limits().max_ast_nodes, "transform");
52 auto u = substitution_argument(candidate_term);
53 if (!u || !depends_on_integration_variable(*u, var)) { return nullptr; }
54 auto d_ptr = detail::make_expression_ptr(detail::differentiate_node(detail::node(*u), var, transform_budget));
55 if (!d_ptr) { return nullptr; }
56 auto du = detail::make_expression_ptr(detail::normalize_node(detail::node(d_ptr), transform_budget));
57 if (du->is_zero()) { return nullptr; }
58
59 auto f_u = candidate_term;
60 auto term_times_du = SymbolicExpr::multiply(detail::make_expression_ptr(f_u), detail::make_expression_ptr(*du));
61 auto ratio = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(detail::make_expression_ptr(expr), term_times_du)), transform_budget));
62 if (depends_on_integration_variable(*ratio, var)) { return nullptr; }
63 auto primitive = substitution_primitive(candidate_term, *u, var, computation);
64 if (!primitive) { return primitive; }
65 if (!primitive.value()) { return nullptr; }
66 return SymbolicExpr::multiply(ratio, primitive.value());
67} catch (const CasError& error) {
68 return Result<std::shared_ptr<SymbolicExpr>>::failure(error);
69} catch (const std::bad_alloc&) {
70 return Result<std::shared_ptr<SymbolicExpr>>::failure(CasErrc::ResourceLimit, "allocation failed", "substitute_candidate");
71} catch (const std::length_error& error) {
72 return Result<std::shared_ptr<SymbolicExpr>>::failure(CasErrc::ResourceLimit, error.what(), "substitute_candidate");
73} catch (const std::exception& error) {
74 return Result<std::shared_ptr<SymbolicExpr>>::failure(CasErrc::InternalInvariant, error.what(), "substitute_candidate");
75}
76}
77
78Result<std::optional<detail::IntegralParts>> Integrator::try_substitution(
79 const SymbolicExpr& expr, const std::string& var,
80 ComputationContext& computation, int) {
81 std::vector<std::shared_ptr<const SymbolicNode>> ops;
82 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(LMCAS::detail::node(expr))) {
83 ops = mul->operands();
84 } else {
85 ops.push_back(LMCAS::detail::node(expr));
86 }
87 for (const auto& operand : ops) {
88 auto candidate = detail::expression_from_node(operand);
89 auto result = substitute_candidate(expr, candidate, var, computation);
90 if (!result) {
91 return Result<std::optional<detail::IntegralParts>>::failure(result.error());
92 }
93 if (result.value()) {
94 return std::optional<detail::IntegralParts>{{*result.value(), zero_}};
95 }
96 }
97 return std::optional<detail::IntegralParts>{};
98}
99
100namespace {
104 std::shared_ptr<const FunctionNode> function;
105 std::shared_ptr<const PowerNode> power;
106 std::optional<SymbolicExpr> argument;
107};
108
110 using FT = FunctionNode::FuncType;
111 switch (function.type()) {
112 case FT::Infinity:
113 case FT::Atan2:
114 case FT::Log: return false;
115 default: return function.arguments().size() == 1;
116 }
117}
118
119LinearWrapper classify_linear_wrapper(const SymbolicExpr& expr, const std::string& var) {
120 LinearWrapper wrapper;
121 wrapper.function = std::dynamic_pointer_cast<const FunctionNode>(detail::node(expr));
122 if (wrapper.function) {
123 if (!linear_substitutable_function(*wrapper.function)) { return wrapper; }
124 wrapper.argument = detail::expression_from_node(wrapper.function->arguments()[0]);
126 return wrapper;
127 }
128 wrapper.power = std::dynamic_pointer_cast<const PowerNode>(detail::node(expr));
129 if (!wrapper.power) { return wrapper; }
130 if (expression_depends_on_variable(wrapper.power->exponent(), var)) { return wrapper; }
131 wrapper.function = std::dynamic_pointer_cast<const FunctionNode>(wrapper.power->base());
132 if (wrapper.function) {
133 if (!linear_substitutable_function(*wrapper.function)) { return wrapper; }
134 wrapper.argument = detail::expression_from_node(wrapper.function->arguments()[0]);
136 } else {
137 wrapper.argument = detail::expression_from_node(wrapper.power->base());
139 }
140 return wrapper;
141}
142
143std::shared_ptr<SymbolicExpr> linear_reduced_expression(
144 const LinearWrapper& wrapper, const std::shared_ptr<SymbolicExpr>& variable) {
145 if (wrapper.kind == LinearWrapperKind::PowerOfLinear) {
147 detail::node(variable), wrapper.power->exponent()));
148 }
149 std::vector<std::shared_ptr<const SymbolicNode>> args{detail::node(variable)};
150 auto function = detail::make_node<FunctionNode>(wrapper.function->type(), args);
151 if (wrapper.kind == LinearWrapperKind::Function) {
153 }
155 detail::make_node<PowerNode>(function, wrapper.power->exponent()));
156}
157}
158
159
160Result<std::optional<detail::IntegralParts>> Integrator::try_linear_substitution(
161 const SymbolicExpr& expr, const std::string& var,
162 ComputationContext& computation, int) {
163 detail::RewriteBudget budget(computation, computation.limits().max_recursion_depth,
164 computation.limits().max_ast_nodes, "integrate.linear_substitution");
165 auto wrapper = classify_linear_wrapper(expr, var);
166 if (!wrapper.argument) { return std::optional<detail::IntegralParts>{}; }
167 auto affine = detail::recognize_affine(*wrapper.argument, var, computation);
168 if (!affine) {
169 return Result<std::optional<detail::IntegralParts>>::failure(affine.error());
170 }
171 if (!affine.value()) { return std::optional<detail::IntegralParts>{}; }
173 detail::node(affine.value()->slope), budget));
175 detail::node(affine.value()->offset), budget));
176 if (slope->is_one() && offset->is_zero()) {
177 return std::optional<detail::IntegralParts>{};
178 }
179 std::optional<detail::AssumptionFacts> facts;
180 if (computation.assumptions()) { facts.emplace(*computation.assumptions()); }
181 auto nonzero = detail::query_nonzero_value(detail::node(slope),
182 facts ? static_cast<const FactsQuery&>(*facts) : detail::no_facts(), Domain::Real, computation);
183 if (!nonzero) {
184 return Result<std::optional<detail::IntegralParts>>::failure(nonzero.error());
185 }
186 if (nonzero.value() != Tribool::True) { return std::optional<detail::IntegralParts>{}; }
187 if (wrapper.kind == LinearWrapperKind::Function &&
188 wrapper.function->type() == FunctionNode::FuncType::Abs) {
189 auto real = detail::query_real_value(detail::node(*wrapper.argument),
190 facts ? static_cast<const FactsQuery&>(*facts) : detail::no_facts(), computation);
191 if (!real) {
193 }
194 if (real.value() != Tribool::True) { return std::optional<detail::IntegralParts>{}; }
195 auto primitive = SymbolicExpr::divide(SymbolicExpr::multiply(
197 SymbolicExpr::multiply(SymbolicExpr::number(2), slope));
198 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
199 detail::normalize_node(detail::node(primitive), budget)), zero_}};
200 }
201
202 auto variable = SymbolicExpr::variable(var);
203 auto test = linear_reduced_expression(wrapper, variable);
204 std::shared_ptr<SymbolicExpr> primitive;
205 if (wrapper.kind == LinearWrapperKind::PowerOfLinear) {
207 detail::expression_from_node(wrapper.power->exponent()), var, computation);
208 if (!power) {
209 return Result<std::optional<detail::IntegralParts>>::failure(power.error());
210 }
211 if (power.value()) { primitive = detail::make_expression_ptr(*power.value()); }
212 } else {
213 const auto& query = facts ? static_cast<const FactsQuery&>(*facts) : detail::no_facts();
214 auto real_variable = detail::query_real_value(detail::node(variable), query, computation);
215 if (!real_variable) {
216 return Result<std::optional<detail::IntegralParts>>::failure(real_variable.error());
217 }
218 if (real_variable.value() == Tribool::True) {
219 auto real_argument = detail::query_real_value(
220 detail::node(*wrapper.argument), query, computation);
221 if (!real_argument) {
222 return Result<std::optional<detail::IntegralParts>>::failure(real_argument.error());
223 }
224 if (real_argument.value() != Tribool::True) {
225 return std::optional<detail::IntegralParts>{};
226 }
227 }
228 primitive = lookup_integral(entries_, *test, var, budget,
229 [](std::shared_ptr<SymbolicExpr> candidate) { return candidate; });
230 }
231 if (!primitive) { return std::optional<detail::IntegralParts>{}; }
233 detail::node(primitive), var, detail::node(*wrapper.argument), budget));
235 SymbolicExpr::divide(substituted, slope)), budget));
236 return std::optional<detail::IntegralParts>{{std::move(result), zero_}};
237}
238
239}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
CasError & error()
LinearWrapper classify_linear_wrapper(const SymbolicExpr &expr, const std::string &var)
std::shared_ptr< SymbolicExpr > linear_reduced_expression(const LinearWrapper &wrapper, const std::shared_ptr< SymbolicExpr > &variable)
Result< std::shared_ptr< SymbolicExpr > > substitution_primitive(const SymbolicExpr &candidate_term, const SymbolicExpr &u, const std::string &var, ComputationContext &context)
Result< std::shared_ptr< SymbolicExpr > > substitute_candidate(const SymbolicExpr &expr, const SymbolicExpr &candidate_term, const std::string &var, ComputationContext &computation)
std::optional< SymbolicExpr > substitution_argument(const SymbolicExpr &term)
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
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
const FactsQuery & no_facts() noexcept
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
RewriteBudget const FactsQuery & facts
Result< std::optional< SymbolicExpr > > integrate_power_primitive(const SymbolicExpr &base, const SymbolicExpr &exponent, const std::string &variable, ComputationContext &)
std::shared_ptr< const Node > make_node(Args &&... args)
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
Result< std::optional< AffineForm > > recognize_affine(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
std::shared_ptr< SymbolicExpr > lookup_integral(const std::vector< detail::IntegrationEntry > &table, const SymbolicExpr &matched, const std::string &matched_variable, detail::RewriteBudget &budget, Transform &&transform)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Real
Real numbers
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)
@ True
Property definitely holds
bool depends_on_integration_variable(const SymbolicExpr &expression, const std::string &variable)
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