11#include "lmmc/config.h"
12#include "lmmc/numeric.h"
29 const std::shared_ptr<const SymbolicNode>& node) {
30 if (
const auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
31 std::vector<std::shared_ptr<const SymbolicNode>> factors;
32 factors.reserve(product->operands().size());
33 for (
const auto& factor : product->operands()) {
38 if (
const auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
41 std::dynamic_pointer_cast<const NumberNode>(power->exponent()),
exponent)) {
57 auto y_expr = SymbolicExpr::variable(y);
58 auto positive = ctx->is_positive_checked(*y_expr,
context);
64static std::shared_ptr<SymbolicExpr>
make_abs(std::shared_ptr<SymbolicExpr> expr) {
74 const std::string& y,
const AssumptionContext* ctx) {
77 (
context).limits().max_ast_nodes,
"transform");
83 std::shared_ptr<SymbolicExpr> f;
84 std::shared_ptr<SymbolicExpr> g;
88 g = SymbolicExpr::number(1);
90 f = SymbolicExpr::number(1);
94 const auto& product =
static_cast<const MultiplyNode&
>(*root);
95 std::vector<std::shared_ptr<const SymbolicNode>> x_factors;
96 std::vector<std::shared_ptr<const SymbolicNode>> y_factors;
97 for (
const auto& factor : product.operands()) {
99 factors.push_back(factor);
108 if (!integrated_y) {
throw integrated_y.error(); }
109 auto int_y = std::make_shared<SymbolicExpr>(std::move(integrated_y.value()));
113 if (!integrated_x) {
throw integrated_x.error(); }
114 auto int_x = std::make_shared<SymbolicExpr>(std::move(integrated_x.value()));
116 int_y, SymbolicExpr::multiply(SymbolicExpr::number(-1), int_x))), transform_budget));
120 if (!positive) {
throw positive.error(); }
121 if (positive.value()) {
132 const std::string& y,
const AssumptionContext* ctx) {
136 if (!integrated_p) {
throw integrated_p.error(); }
137 auto intP = std::make_shared<SymbolicExpr>(std::move(integrated_p.value()));
138 auto mu = SymbolicExpr::exp(intP);
140 auto Qmu = SymbolicExpr::multiply(Qx, mu);
142 if (!integrated_q) {
throw integrated_q.error(); }
143 auto intQmu = std::make_shared<SymbolicExpr>(std::move(integrated_q.value()));
145 auto C = SymbolicExpr::variable(
"C");
146 auto num = SymbolicExpr::add(intQmu, C);
147 auto result = SymbolicExpr::divide(
num, mu);
151 if (!positive) {
throw positive.error(); }
152 if (positive.value()) {
163 const std::vector<ode_root_detail::CharRoot>&
roots,
164 const std::string& x) {
165 auto variable = SymbolicExpr::variable(x);
166 auto solution = SymbolicExpr::number(0);
167 int constant_index = 1;
168 for (
const auto& root :
roots) {
169 auto exponential = SymbolicExpr::exp(
170 SymbolicExpr::multiply(
171 SymbolicExpr::number(root.real_part),
variable));
172 if (root.is_complex) {
173 auto argument = SymbolicExpr::multiply(
174 SymbolicExpr::number(root.imag_part),
variable);
175 auto cosine_basis = SymbolicExpr::multiply(
176 exponential, SymbolicExpr::cos(argument));
177 auto sine_basis = SymbolicExpr::multiply(
178 exponential, SymbolicExpr::sin(argument));
179 auto cosine_term = SymbolicExpr::multiply(
180 SymbolicExpr::variable(
181 "C" + std::to_string(constant_index++)),
183 auto sine_term = SymbolicExpr::multiply(
184 SymbolicExpr::variable(
185 "C" + std::to_string(constant_index++)),
187 solution = SymbolicExpr::add(
188 solution, SymbolicExpr::add(cosine_term, sine_term));
191 for (
int power = 0; power < root.multiplicity; ++power) {
192 auto basis = exponential;
194 basis = SymbolicExpr::multiply(
196 variable, SymbolicExpr::number(power)),
199 solution = SymbolicExpr::add(
201 SymbolicExpr::multiply(
202 SymbolicExpr::variable(
203 "C" + std::to_string(constant_index++)),
210static Result<std::shared_ptr<SymbolicExpr>>
212 double a,
double b,
double c,
213 const std::string& x,
214 const std::string& y,
219 (
context).limits().max_ast_nodes,
"transform");
220 if (!std::isfinite(
a) || !std::isfinite(
b) || !std::isfinite(
c)) {
223 "solve_linear2_ode: coefficients must be finite",
224 kSolveLinear2OdeOperation);
231 "solve_linear2_ode: leading and first-derivative coefficients are both zero",
232 kSolveLinear2OdeOperation);
234 const double normalized_c =
c /
b;
235 if (!std::isfinite(normalized_c)) {
238 "solve_linear2_ode: degenerate coefficient normalization is non-finite",
239 kSolveLinear2OdeOperation);
242 solution = SymbolicExpr::multiply(SymbolicExpr::variable(
"C"),
243 SymbolicExpr::exp(SymbolicExpr::multiply(
244 SymbolicExpr::number(-normalized_c), SymbolicExpr::variable(x))));
247 {
a,
b,
c}, kSolveLinear2OdeOperation);
256 if (positive.value()) {
260 std::move(solution));
261}
catch (
const CasError& error) {
262 return Result<std::shared_ptr<SymbolicExpr>>::failure(error);
263}
catch (
const std::bad_alloc&) {
265}
catch (
const std::length_error& error) {
267}
catch (
const std::exception& error) {
272 double a,
double b,
double c,
273 std::shared_ptr<SymbolicExpr> fx,
274 const std::string& x,
275 const std::string& y,
276 const AssumptionContext* ctx
280 throw std::invalid_argument(
281 "solve_linear2_ode: forcing expression must not be null");
283 if (!fx->is_zero()) {
284 throw std::logic_error(
285 "solve_linear2_ode: non-homogeneous case is outside the current support domain");
290 throw std::invalid_argument(solution.error().message);
293 throw std::overflow_error(solution.error().message);
295 throw std::logic_error(solution.error().message);
297 return std::move(solution.value());
301 double a,
double b,
double c,
302 std::shared_ptr<SymbolicExpr> fx,
303 const std::string& x,
304 const std::string& y,
306 const AssumptionContext* ctx
308 auto step =
context.consume_steps(1, kSolveLinear2OdeOperation);
316 "forcing expression must not be null",
317 kSolveLinear2OdeOperation);
319 if (x.empty() || y.empty()) {
322 "ODE variables must not be empty",
323 kSolveLinear2OdeOperation);
327 if (!fx->is_zero()) {
330 "non-homogeneous second-order constant-coefficient ODEs are outside the current support domain",
331 kSolveLinear2OdeOperation);
335 }
catch (
const std::invalid_argument& ex) {
338 }
catch (
const std::bad_alloc&) {
341 "ODE solving allocation failed",
342 kSolveLinear2OdeOperation);
343 }
catch (
const std::logic_error& ex) {
346 }
catch (
const std::exception& ex) {
353 double a,
double b,
double c,
354 std::shared_ptr<SymbolicExpr> fx,
355 const std::string& x,
356 const std::string& y,
357 const AssumptionContext* ctx
AssumptionContext class with scoped push/pop management.
static Result failure(CasErrc code, std::string message, std::string operation={})
std::shared_ptr< const SymbolicNode > reciprocal_on_regular_region(const std::shared_ptr< const SymbolicNode > &node)
constexpr const char * kSolveLinear2OdeOperation
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
Result< std::vector< CharRoot > > find_characteristic_roots(const std::vector< double > &coefficients, const std::string &operation)
使用数值方法求解特征多项式的所有根.
std::shared_ptr< SymbolicExpr > num(int value)
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
const VectorField const VectorField & c
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
static std::shared_ptr< SymbolicExpr > make_abs(std::shared_ptr< SymbolicExpr > expr)
Wrap an expression in abs() to signal positive-branch preference.
@ True
Property definitely holds
static std::shared_ptr< SymbolicExpr > linear2_root_basis(const std::vector< ode_root_detail::CharRoot > &roots, const std::string &x)
static Result< bool > dep_var_is_positive(const std::string &y, const AssumptionContext *ctx, ComputationContext &context)
Check if the dependent variable is known Positive in the given context.
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
std::shared_ptr< SymbolicExpr > solve_linear2_ode(double a, double b, double c, std::shared_ptr< SymbolicExpr > fx, const std::string &x, const std::string &y, const AssumptionContext *ctx)
Result< std::shared_ptr< SymbolicExpr > > solve_linear2_ode_checked(double a, double b, double c, std::shared_ptr< SymbolicExpr > fx, const std::string &x, const std::string &y, ComputationContext &context, const AssumptionContext *ctx)
std::shared_ptr< SymbolicExpr > ExprPtr
ExprPtr solve_separable_ode(ExprPtr rhs, const std::string &x, const std::string &y, const AssumptionContext *ctx)
const std::vector< FGLMPoly > & basis
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
static Result< std::shared_ptr< SymbolicExpr > > solve_linear2_homogeneous(double a, double b, double c, const std::string &x, const std::string &y, const AssumptionContext *ctx, ComputationContext &context)
ExprPtr solve_linear1_ode(ExprPtr Px, ExprPtr Qx, const std::string &x, const std::string &y, const AssumptionContext *ctx)
const std::vector< IntegrationStep > Integrator & integrator
bool is_separable(const std::shared_ptr< SymbolicExpr > &rhs, const std::string &x, const std::string &y)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
常微分方程求解:可分离变量,一阶线性,二阶常系数.
统一 ODE 求解引擎:分类,分派,多种求解方法.