11#include "lmmc/config.h"
12#include "lmmc/numeric.h"
24 const std::shared_ptr<SymbolicExpr>&,
27 const std::shared_ptr<SymbolicExpr>&,
28 const std::shared_ptr<SymbolicExpr>&,
31 const std::shared_ptr<SymbolicExpr>&,
32 const std::shared_ptr<SymbolicExpr>&,
36 const std::shared_ptr<SymbolicExpr>& antiderivative,
41 (
context).limits().max_ast_nodes,
"transform");
42 const auto logarithm_of_variable =
43 [&
variable](
const std::shared_ptr<const SymbolicNode>& node) {
45 std::dynamic_pointer_cast<const FunctionNode>(node);
51 const auto argument = std::dynamic_pointer_cast<const VariableNode>(
53 return argument && !argument->is_constant() && argument->name() ==
variable;
57 if (logarithm_of_variable(root)) {
58 return SymbolicExpr::variable(
variable);
60 const auto product = std::dynamic_pointer_cast<const MultiplyNode>(root);
61 if (product && product->operands().size() == 2) {
62 for (std::size_t index = 0; index < 2; ++index) {
63 if (logarithm_of_variable(product->operands()[index])) {
65 product->operands()[1 - index]);
76 const std::shared_ptr<SymbolicExpr>&
rhs,
81 const std::string operation =
"solve_homogeneous_ode";
86 auto step =
context.consume_steps(12, operation);
93 if (!solved) {
return solved; }
97 }
catch (
const std::bad_alloc&) {
99 "homogeneous ODE allocation failed",
101 }
catch (
const std::length_error& error) {
103 }
catch (
const std::exception&
e) {
111 const std::shared_ptr<SymbolicExpr>&
rhs,
112 const std::string& x,
113 const std::string& y)
120 const std::shared_ptr<SymbolicExpr>&
rhs,
121 const std::string& x,
126 (
context).limits().max_ast_nodes,
"transform");
140 std::string v_name =
"v";
141 auto v_var = SymbolicExpr::variable(v_name);
142 auto x_var = SymbolicExpr::variable(x);
152 SymbolicExpr::multiply(SymbolicExpr::number(-1), v_var))), transform_budget))
153 ->cancel()), transform_budget));
156 SymbolicExpr::variable(y), x_var)), transform_budget));
157 if (f_minus_v->is_zero()) {
162 std::shared_ptr<SymbolicExpr> integrand;
163 const auto reciprocal =
164 std::dynamic_pointer_cast<const PowerNode>(
detail::node(f_minus_v));
165 const auto minus_one = SymbolicExpr::number(-1);
167 reciprocal->exponent()->compare(*
detail::node(minus_one)) == 0) {
171 SymbolicExpr::number(1), f_minus_v)), transform_budget));
176 auto lhs_integral = std::make_shared<SymbolicExpr>(std::move(integrated.value()));
179 auto rhs_integral = SymbolicExpr::ln(x_var);
186 solution = SymbolicExpr::add(solution,
187 SymbolicExpr::multiply(SymbolicExpr::number(-1), rhs_integral));
197 const std::shared_ptr<SymbolicExpr>& P,
198 const std::shared_ptr<SymbolicExpr>& Q,
200 const std::string& x,
201 const std::string& y,
204 const std::string operation =
"solve_bernoulli_ode";
209 if (n == 0 || n == 1) {
211 "Bernoulli exponent must not be 0 or 1",
214 auto step =
context.consume_steps(14, operation);
221 if (!solved) {
return solved; }
225 }
catch (
const std::bad_alloc&) {
227 "Bernoulli ODE allocation failed",
229 }
catch (
const std::length_error& error) {
231 }
catch (
const std::exception&
e) {
239 const std::shared_ptr<SymbolicExpr>& P,
240 const std::shared_ptr<SymbolicExpr>& Q,
242 const std::string& x,
243 const std::string& y)
250 const std::shared_ptr<SymbolicExpr>& P,
251 const std::shared_ptr<SymbolicExpr>& Q,
253 const std::string& x,
258 (
context).limits().max_ast_nodes,
"transform");
272 int one_minus_n = 1 - n;
273 auto coeff = SymbolicExpr::number(one_minus_n);
284 auto intP = std::make_shared<SymbolicExpr>(std::move(integrated_p.value()));
289 auto int_Q_mu = std::make_shared<SymbolicExpr>(std::move(integrated_q.value()));
291 auto C_const = SymbolicExpr::variable(
"C");
292 auto numerator = SymbolicExpr::add(int_Q_mu, C_const);
298 auto exponent = SymbolicExpr::divide(
299 SymbolicExpr::number(1),
300 SymbolicExpr::number(one_minus_n));
309 const std::shared_ptr<SymbolicExpr>& ratio,
310 const std::string&
variable,
const std::string& excluded_variable,
314 return std::shared_ptr<SymbolicExpr>{};
319 std::make_shared<SymbolicExpr>(std::move(integrated.value())),
324 const std::shared_ptr<SymbolicExpr>& M,
325 const std::shared_ptr<SymbolicExpr>& N,
329 (
context).limits().max_ast_nodes,
"transform");
331 return std::shared_ptr<SymbolicExpr>{};
338 auto diff = SymbolicExpr::add(dM_dy,
339 SymbolicExpr::multiply(SymbolicExpr::number(-1), dN_dx));
344 if (std::holds_alternative<ProvedZeroResidual>(exact.value())) {
346 return SymbolicExpr::number(1);
351 if (N && !N->is_zero()) {
354 if (!factor || factor.value()) {
return factor; }
358 if (M && !M->is_zero()) {
362 if (!factor || factor.value()) {
return factor; }
365 return std::shared_ptr<SymbolicExpr>{};
369 const std::shared_ptr<SymbolicExpr>& M,
370 const std::shared_ptr<SymbolicExpr>& N,
371 const std::string& x,
const std::string& y)
375 if (!result) {
throw result.error(); }
376 return std::move(result.value());
381 const std::shared_ptr<SymbolicExpr>& M,
382 const std::shared_ptr<SymbolicExpr>& N,
383 const std::string& x,
384 const std::string& y,
387 const std::string operation =
"solve_exact_ode";
392 auto step =
context.consume_steps(18, operation);
399 if (!solved) {
return solved; }
403 }
catch (
const std::bad_alloc&) {
405 "exact ODE allocation failed",
407 }
catch (
const std::length_error& error) {
409 }
catch (
const std::exception&
e) {
417 const std::shared_ptr<SymbolicExpr>& M,
418 const std::shared_ptr<SymbolicExpr>& N,
419 const std::string& x,
420 const std::string& y)
427 const std::shared_ptr<SymbolicExpr>& M,
428 const std::shared_ptr<SymbolicExpr>& N,
429 const std::string& x,
434 (
context).limits().max_ast_nodes,
"transform");
444 if (!factor.value()) {
447 auto mu = std::move(factor.value());
462 auto F_partial = std::make_shared<SymbolicExpr>(std::move(integrated_m.value()));
469 auto g_prime = SymbolicExpr::add(N_eff,
470 SymbolicExpr::multiply(SymbolicExpr::number(-1), dF_dy));
476 auto g_y = std::make_shared<SymbolicExpr>(std::move(integrated_g.value()));
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(ODESolution value)
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr expand_node(const SymbolicNodePtr &node, 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
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 ODESolutionResult solve_bernoulli_ode_impl(const std::shared_ptr< SymbolicExpr > &, const std::shared_ptr< SymbolicExpr > &, int, const std::string &, const std::string &, ComputationContext &context)
Result< void > validate_ode_expr_var_pair(const std::shared_ptr< SymbolicExpr > &expr, const std::string &x, const std::string &y, ComputationContext &context, const std::string &operation)
ODESolutionResult solve_bernoulli_ode_checked(const std::shared_ptr< SymbolicExpr > &P, const std::shared_ptr< SymbolicExpr > &Q, int n, const std::string &x, const std::string &y, ComputationContext &context)
const std::string & variable
static std::shared_ptr< SymbolicExpr > integrating_factor_from_antiderivative(const std::shared_ptr< SymbolicExpr > &antiderivative, const std::string &variable, ComputationContext &context)
ODESolutionResult wrap_ode_solution(ODESolution solution, ODEType expected_method, const std::string &operation)
ODEType method_used
使用的求解方法
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
@ Bernoulli
Bernoulli 方程 y' + P(x)y = Q(x)y^n
@ Exact
恰当方程 M(x,y)dx + N(x,y)dy = 0
@ Homogeneous
齐次方程 y' = f(y/x)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
std::shared_ptr< SymbolicExpr > find_integrating_factor(const std::shared_ptr< SymbolicExpr > &M, const std::shared_ptr< SymbolicExpr > &N, const std::string &x, const std::string &y)
static ODESolutionResult solve_exact_ode_impl(const std::shared_ptr< SymbolicExpr > &, const std::shared_ptr< SymbolicExpr > &, const std::string &, const std::string &, ComputationContext &context)
static ExpressionResult find_integrating_factor_impl(const std::shared_ptr< SymbolicExpr > &M, const std::shared_ptr< SymbolicExpr > &N, const std::string &x, const std::string &y, ComputationContext &context)
ResidualCheckResult check_zero_residual(const ExprPtr &residual, ComputationContext &context, const LMCAS::EqvOptions &options)
std::shared_ptr< SymbolicExpr > general_solution
通解表达式
ODESolutionResult solve_homogeneous_ode_checked(const std::shared_ptr< SymbolicExpr > &rhs, const std::string &x, const std::string &y, ComputationContext &context)
static ExpressionResult integrating_factor_from_ratio(const std::shared_ptr< SymbolicExpr > &ratio, const std::string &variable, const std::string &excluded_variable, Integrator &integrator, ComputationContext &context)
std::vector< std::string > constants
任意常数名称列表 (C1, C2, ...)
ODESolutionResult solve_exact_ode_checked(const std::shared_ptr< SymbolicExpr > &M, const std::shared_ptr< SymbolicExpr > &N, const std::string &x, const std::string &y, ComputationContext &context)
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
Result< void > validate_ode_pair_var_pair(const std::shared_ptr< SymbolicExpr > &first, const std::shared_ptr< SymbolicExpr > &second, const std::string &x, const std::string &y, ComputationContext &context, const std::string &operation)
Result< ODESolution > ODESolutionResult
const std::vector< IntegrationStep > Integrator & integrator
static ODESolutionResult solve_homogeneous_ode_impl(const std::shared_ptr< SymbolicExpr > &, const std::string &, const std::string &, ComputationContext &context)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
统一 ODE 求解引擎:分类,分派,多种求解方法.