6bool is_zero(
const SymbolicExpr& expression) {
17 if (primitive && remainder) {
18 std::vector<PiecewiseNode::Branch> branches;
19 branches.reserve(primitive->branches().size());
20 for (std::size_t i = 0; i < primitive->branches().size(); ++i) {
25 branches.push_back({
node(branch), primitive->branches()[i].condition});
28 if (primitive->default_expr()) {
44Integrator::Integrator() : entries_(detail::make_integration_entries()),
45 zero_(*SymbolicExpr::number(0)) {}
46Integrator::~Integrator() =
default;
47Integrator::Integrator(Integrator&&) noexcept = default;
48Integrator& Integrator::operator=(Integrator&&) noexcept = default;
51std::shared_ptr<SymbolicExpr> Integrator::check_cycle(
54 context.limits().max_ast_nodes,
"integrate.cycle");
55 for (
const auto& entry : cycle_state_.history) {
58 return SymbolicExpr::variable(entry.placeholder);
64 return SymbolicExpr::multiply(ratio, SymbolicExpr::variable(entry.placeholder));
70bool Integrator::has_cycle_placeholder(
const SymbolicExpr& expression)
const {
71 for (
const auto& entry : cycle_state_.history) {
82 context.limits().max_ast_nodes,
"integrate.cycle");
84 detail::node(result.primitive), placeholder, budget), budget);
92 bool invertible = exact && !exact->is_zero();
93 if (!exact &&
context.assumptions()) {
96 if (!nonzero) {
throw nonzero.error(); }
99 if (!invertible) {
return false; }
112 using Method = Attempt (Integrator::*)(
const SymbolicExpr&,
const std::string&,
114 constexpr Method methods[] = {
115 &Integrator::try_power_rule, &Integrator::try_table_lookup,
116 &Integrator::try_linear_substitution, &Integrator::try_substitution,
117 &Integrator::try_trig_substitution, &Integrator::try_trig_combination,
118 &Integrator::try_weierstrass, &Integrator::try_rational_decomposition,
119 &Integrator::try_special_function, &Integrator::try_integration_by_parts};
121 context.limits().max_ast_nodes,
"integrate.builtins");
122 const auto placeholder = cycle_state_.history.back().placeholder;
123 std::optional<detail::IntegralParts> partial;
124 for (
auto method : methods) {
125 auto access =
context.consume_steps(1,
"integrate.builtins");
126 if (!access) {
return Attempt::failure(access.error()); }
127 auto attempted = (this->*method)(expr, var,
context,
depth);
128 if (!attempted) {
return attempted; }
129 access =
context.consume_steps(0,
"integrate.builtins");
130 if (!access) {
return Attempt::failure(access.error()); }
131 if (!attempted.value()) {
continue; }
132 auto candidate = std::move(*attempted.value());
133 if (!resolve_cycle(candidate, placeholder, var,
context)) {
continue; }
138 if (
is_zero(candidate.remainder)) {
return Attempt::success(std::move(candidate)); }
139 if (!partial && (!
is_zero(candidate.primitive) ||
141 partial = std::move(candidate);
144 return Attempt::success(std::move(partial));
148 const SymbolicExpr& source,
const std::string& var,
151 auto entered =
context.enter_recursion(
"integrate.recursive");
152 if (!entered) {
return PartsResult::failure(entered.error()); }
153 struct RecursionExit {
155 ~RecursionExit() {
context.leave_recursion(); }
158 context.limits().max_ast_nodes,
"integrate.recursive");
160 const auto& integrand = original ? *original : source;
162 std::vector<PiecewiseNode::Branch> primitives, remainders;
163 for (
const auto& branch : piecewise->branches()) {
165 auto parts = integrate_recursive(term, var,
context,
depth + 1);
166 if (!parts) {
return parts; }
167 primitives.push_back({
detail::node(parts.value().primitive), branch.condition});
168 remainders.push_back({
detail::node(parts.value().remainder), branch.condition});
171 if (piecewise->default_expr()) {
173 auto parts = integrate_recursive(term, var,
context,
depth + 1);
174 if (!parts) {
return parts; }
175 primitive_default =
detail::node(parts.value().primitive);
176 remainder_default =
detail::node(parts.value().remainder);
179 std::move(primitives), primitive_default)),
181 std::move(remainders), remainder_default))});
183 auto linear = apply_linearity(source, var,
context,
depth);
184 if (!linear) {
return PartsResult::failure(linear.error()); }
185 if (linear.value()) {
return PartsResult::success(std::move(*linear.value())); }
187 std::optional<detail::AssumptionFacts>
facts;
191 if (
is_zero(expr)) {
return PartsResult::success({zero_, zero_}); }
193 return PartsResult::success({*SymbolicExpr::multiply(
196 auto cycle = check_cycle(expr, var,
context);
197 if (cycle) {
return PartsResult::success({*cycle, zero_}); }
198 std::string placeholder;
201 placeholder =
"INT_CYCLE_" + std::to_string(cycle_state_.next_placeholder++);
202 }
while (cycle_state_.occupied_names.count(placeholder));
203 cycle_state_.occupied_names.insert(placeholder);
204 cycle_state_.history.push_back({expr, integrand, placeholder});
207 ~CycleExit() { state.history.pop_back(); }
208 } cycle_exit{cycle_state_};
209 auto result = dispatch_builtins(expr, var,
context,
depth);
210 if (!result) {
return PartsResult::failure(result.error()); }
211 if (result.value()) {
212 auto parts = std::move(*result.value());
215 return PartsResult::success(std::move(parts));
218 return PartsResult::success({zero_, integrand});
223 if (var_name.empty()) {
225 "integration variable must not be empty",
"integrate");
227 auto access =
context.consume_steps(1,
"integrate");
230 context.limits().max_ast_nodes,
"integrate");
232 const bool top_level = query_depth_ == 0;
239 integrator.cycle_state_.occupied_names.clear();
244 cycle_state_.history.clear();
245 cycle_state_.next_placeholder = 0;
247 cycle_state_.occupied_names.insert(var_name);
250 cycle_state_.occupied_names, budget);
253 auto recursive = integrate_recursive(expr, var_name,
context, 0, &expr);
255 auto parts = std::move(recursive.value());
256 if (has_cycle_placeholder(parts.primitive) || has_cycle_placeholder(parts.remainder)) {
257 parts = {zero_, expr};
261 access =
context.consume_steps(0,
"integrate");
266}
catch (
const std::bad_alloc&) {
268 "integration allocation failed",
"integrate");
269}
catch (
const std::length_error& error) {
271}
catch (
const std::exception& error) {
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static void collect_names(const AssumptionContext &assumptions, std::set< std::string > &names, RewriteBudget &budget)
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
bool is_zero(const SymbolicExpr &expression)
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
const std::string & variable
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
const FactsQuery & no_facts() noexcept
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
RewriteBudget const FactsQuery & facts
SymbolicExpr materialize_integral(const IntegralParts &parts, const std::string &variable, RewriteBudget &budget)
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)
std::set< std::string > all_variable_names(const SymbolicNodePtr &expression, RewriteBudget *budget=nullptr)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::vector< Polynomial< BigInt > > const BigInt 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)
std::size_t std::size_t depth
const std::string const ExprPtr & value
std::shared_ptr< SymbolicExpr > sym_sub(const SymbolicExpr &lhs, const SymbolicExpr &rhs)
const ExprPtr & denominator
const std::vector< IntegrationStep > Integrator & integrator