LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
ode_first_order.cpp
浏览该文件的文档.
2/**
3 * @file symbolic_ode_engine.cpp
4 * @brief 统一 ODE 求解引擎实现:类型检测与分类.
5 */
8#include "symbolic.hpp"
9#include "poly_utils.hpp"
11#include "lmmc/config.h"
12#include "lmmc/numeric.h"
14#include "integrator.hpp"
16#include <cmath>
17#include <memory>
18#include <string>
19#include <stdexcept>
20
21namespace LMCAS {
22
24 const std::shared_ptr<SymbolicExpr>&,
25 const std::string&, const std::string&, ComputationContext& context);
27 const std::shared_ptr<SymbolicExpr>&,
28 const std::shared_ptr<SymbolicExpr>&,
29 int, const std::string&, const std::string&, ComputationContext& context);
31 const std::shared_ptr<SymbolicExpr>&,
32 const std::shared_ptr<SymbolicExpr>&,
33 const std::string&, const std::string&, ComputationContext& context);
34
35static std::shared_ptr<SymbolicExpr> integrating_factor_from_antiderivative(
36 const std::shared_ptr<SymbolicExpr>& antiderivative,
37 const std::string& variable, ComputationContext& context)
38{
39
40 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
41 (context).limits().max_ast_nodes, "transform");
42 const auto logarithm_of_variable =
43 [&variable](const std::shared_ptr<const SymbolicNode>& node) {
44 const auto function =
45 std::dynamic_pointer_cast<const FunctionNode>(node);
46 if (!function ||
48 function->arguments().size() != 1) {
49 return false;
50 }
51 const auto argument = std::dynamic_pointer_cast<const VariableNode>(
52 function->arguments().front());
53 return argument && !argument->is_constant() && argument->name() == variable;
54 };
55
56 const auto& root = detail::node(antiderivative);
57 if (logarithm_of_variable(root)) {
58 return SymbolicExpr::variable(variable);
59 }
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]);
67 SymbolicExpr::variable(variable), exponent)), transform_budget));
68 }
69 }
70 }
71 return detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::exp(antiderivative)), transform_budget));
72}
73
74
76 const std::shared_ptr<SymbolicExpr>& rhs,
77 const std::string& x,
78 const std::string& y,
80{
81 const std::string operation = "solve_homogeneous_ode";
82 auto valid = validate_ode_expr_var_pair(rhs, x, y, context, operation);
83 if (!valid) {
84 return ODESolutionResult::failure(valid.error());
85 }
86 auto step = context.consume_steps(12, operation);
87 if (!step) {
88 return ODESolutionResult::failure(step.error());
89 }
90
91 try {
92 auto solved = solve_homogeneous_ode_impl(rhs, x, y, context);
93 if (!solved) { return solved; }
94 return wrap_ode_solution(std::move(solved.value()), ODEType::Homogeneous, operation);
95 } catch (const CasError& error) {
96 return ODESolutionResult::failure(error);
97 } catch (const std::bad_alloc&) {
99 "homogeneous ODE allocation failed",
100 operation);
101 } catch (const std::length_error& error) {
102 return ODESolutionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
103 } catch (const std::exception& e) {
105 e.what(),
106 operation);
107 }
108}
109
111 const std::shared_ptr<SymbolicExpr>& rhs,
112 const std::string& x,
113 const std::string& y)
114{
117}
118
120 const std::shared_ptr<SymbolicExpr>& rhs,
121 const std::string& x,
122 const std::string& y, ComputationContext& context)
123{
124
125 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
126 (context).limits().max_ast_nodes, "transform");
127 ODESolution result;
129 result.constants = {"C"};
130
131 /// 齐次方程 y' = f(y/x)
132 /// 令 v = y/x,则 y = v*x,y' = v + x*v'
133 /// 代入: v + x*v' = f(v)
134 /// 即: x*v' = f(v) - v
135 /// 分离变量: dv/(f(v) - v) = dx/x
136
137 /// 将 rhs 中的 y 替换为 v*x,得到 f 关于 v 和 x 的表达式
138 /// 由于齐次性,f(x, vx) = f(1, v)(令 t=1/x 缩放)
139 /// 所以直接用 x=1, y=v 代入得到 f(v)
140 std::string v_name = "v";
141 auto v_var = SymbolicExpr::variable(v_name);
142 auto x_var = SymbolicExpr::variable(x);
143
144 /// f(v) = rhs(1, v):将 x=1, y=v 代入
145 auto f_v = detail::make_expression_ptr(detail::substitute_node(detail::node(rhs), x, detail::node(SymbolicExpr::number(1)), transform_budget));
146 f_v = detail::make_expression_ptr(detail::substitute_node(detail::node(f_v), y, detail::node(v_var), transform_budget));
148
149 /// 分离变量方程: dv/(f(v) - v) = dx/x
150 /// 积分: integral dv/(f(v) - v) = integral dx/x = ln|x| + C
152 SymbolicExpr::multiply(SymbolicExpr::number(-1), v_var))), transform_budget))
153 ->cancel()), transform_budget));
154
155 auto v_replacement = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(
156 SymbolicExpr::variable(y), x_var)), transform_budget));
157 if (f_minus_v->is_zero()) {
158 result.general_solution = v_replacement;
159 return ODESolutionResult::success(std::move(result));
160 }
161
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);
166 if (reciprocal &&
167 reciprocal->exponent()->compare(*detail::node(minus_one)) == 0) {
168 integrand = detail::make_expression_ptr(reciprocal->base());
169 } else {
170 integrand = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(
171 SymbolicExpr::number(1), f_minus_v)), transform_budget));
172 }
173 Integrator integrator;
174 auto integrated = integrator.integrate_checked(*integrand, v_name, context);
175 if (!integrated) { return ODESolutionResult::failure(integrated.error()); }
176 auto lhs_integral = std::make_shared<SymbolicExpr>(std::move(integrated.value()));
177
178 /// 右端: ln(x)
179 auto rhs_integral = SymbolicExpr::ln(x_var);
180
181 /// 解为: lhs_integral = ln(x) + C
182 /// 即: lhs_integral - ln(x) = C
183 /// 回代 v = y/x
184
185 auto solution = detail::make_expression_ptr(detail::substitute_node(detail::node(lhs_integral), v_name, detail::node(v_replacement), transform_budget));
186 solution = SymbolicExpr::add(solution,
187 SymbolicExpr::multiply(SymbolicExpr::number(-1), rhs_integral));
188 solution = detail::make_expression_ptr(detail::normalize_node(detail::node(solution), transform_budget));
189
190 /// 返回隐式解形式: F(x,y) = C
191 result.general_solution = solution;
192 return ODESolutionResult::success(std::move(result));
193}
194
195
197 const std::shared_ptr<SymbolicExpr>& P,
198 const std::shared_ptr<SymbolicExpr>& Q,
199 int n,
200 const std::string& x,
201 const std::string& y,
203{
204 const std::string operation = "solve_bernoulli_ode";
205 auto valid = validate_ode_pair_var_pair(P, Q, x, y, context, operation);
206 if (!valid) {
207 return ODESolutionResult::failure(valid.error());
208 }
209 if (n == 0 || n == 1) {
211 "Bernoulli exponent must not be 0 or 1",
212 operation);
213 }
214 auto step = context.consume_steps(14, operation);
215 if (!step) {
216 return ODESolutionResult::failure(step.error());
217 }
218
219 try {
220 auto solved = solve_bernoulli_ode_impl(P, Q, n, x, y, context);
221 if (!solved) { return solved; }
222 return wrap_ode_solution(std::move(solved.value()), ODEType::Bernoulli, operation);
223 } catch (const CasError& error) {
224 return ODESolutionResult::failure(error);
225 } catch (const std::bad_alloc&) {
227 "Bernoulli ODE allocation failed",
228 operation);
229 } catch (const std::length_error& error) {
230 return ODESolutionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
231 } catch (const std::exception& e) {
233 e.what(),
234 operation);
235 }
236}
237
239 const std::shared_ptr<SymbolicExpr>& P,
240 const std::shared_ptr<SymbolicExpr>& Q,
241 int n,
242 const std::string& x,
243 const std::string& y)
244{
246 return solve_bernoulli_ode_checked(P, Q, n, x, y, context);
247}
248
250 const std::shared_ptr<SymbolicExpr>& P,
251 const std::shared_ptr<SymbolicExpr>& Q,
252 int n,
253 const std::string& x,
254 const std::string&, ComputationContext& context)
255{
256
257 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
258 (context).limits().max_ast_nodes, "transform");
259 ODESolution result;
261 result.constants = {"C"};
262
263 /// Bernoulli 方程: y' + P(x)*y = Q(x)*y^n (n != 0, 1)
264 /// 令 v = y^(1-n),则 v' = (1-n)*y^(-n)*y'
265 /// 从原方程: y' = -P(x)*y + Q(x)*y^n
266 /// 两边乘以 (1-n)*y^(-n):
267 /// (1-n)*y^(-n)*y' = (1-n)*(-P(x)*y^(1-n) + Q(x))
268 /// v' = (1-n)*(-P(x)*v + Q(x))
269 /// v' + (1-n)*P(x)*v = (1-n)*Q(x)
270 /// 这是关于 v 的一阶线性 ODE
271
272 int one_minus_n = 1 - n;
273 auto coeff = SymbolicExpr::number(one_minus_n);
274
275 /// 线性 ODE 的系数: P_linear = (1-n)*P(x), Q_linear = (1-n)*Q(x)
276 auto P_linear = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(coeff, P)->cancel()), transform_budget));
277 auto Q_linear = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(coeff, Q)->cancel()), transform_budget));
278
279 /// 用积分因子法求解线性 ODE: v' + P_linear*v = Q_linear
280 /// 积分因子 mu = exp(integralP_linear dx)
281 Integrator integrator;
282 auto integrated_p = integrator.integrate_checked(*P_linear, x, context);
283 if (!integrated_p) { return ODESolutionResult::failure(integrated_p.error()); }
284 auto intP = std::make_shared<SymbolicExpr>(std::move(integrated_p.value()));
286 auto Q_mu = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(Q_linear, mu)->cancel()), transform_budget));
287 auto integrated_q = integrator.integrate_checked(*Q_mu, x, context);
288 if (!integrated_q) { return ODESolutionResult::failure(integrated_q.error()); }
289 auto int_Q_mu = std::make_shared<SymbolicExpr>(std::move(integrated_q.value()));
290
291 auto C_const = SymbolicExpr::variable("C");
292 auto numerator = SymbolicExpr::add(int_Q_mu, C_const);
293 auto v_solution = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(numerator, mu)), transform_budget));
294
295 /// 回代: v = y^(1-n),所以 y = v^(1/(1-n))
296 /// y^(1-n) = v_solution
297 /// y = v_solution^(1/(1-n))
298 auto exponent = SymbolicExpr::divide(
299 SymbolicExpr::number(1),
300 SymbolicExpr::number(one_minus_n));
301 auto y_solution = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::power(v_solution, exponent)), transform_budget));
302
303 result.general_solution = y_solution;
304 return ODESolutionResult::success(std::move(result));
305}
306
307
309 const std::shared_ptr<SymbolicExpr>& ratio,
310 const std::string& variable, const std::string& excluded_variable,
311 Integrator& integrator, ComputationContext& context) {
313 LMCAS::detail::node(ratio), excluded_variable)) {
314 return std::shared_ptr<SymbolicExpr>{};
315 }
316 auto integrated = integrator.integrate_checked(*ratio, variable, context);
317 if (!integrated) { return ExpressionResult::failure(integrated.error()); }
319 std::make_shared<SymbolicExpr>(std::move(integrated.value())),
321}
322
324 const std::shared_ptr<SymbolicExpr>& M,
325 const std::shared_ptr<SymbolicExpr>& N,
326 const std::string& x, const std::string& y, ComputationContext& context)
327{
328 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
329 (context).limits().max_ast_nodes, "transform");
330 if (!M || !N) {
331 return std::shared_ptr<SymbolicExpr>{};
332 }
333
334 /// 计算 partialM/partialy - partialN/partialx
335 auto dM_dy = detail::make_expression_ptr(detail::differentiate_node(detail::node(M), y, transform_budget));
336 auto dN_dx = detail::make_expression_ptr(detail::differentiate_node(detail::node(N), x, transform_budget));
337
338 auto diff = SymbolicExpr::add(dM_dy,
339 SymbolicExpr::multiply(SymbolicExpr::number(-1), dN_dx));
340 diff = detail::make_expression_ptr(detail::normalize_node(detail::node(diff), transform_budget));
341
342 auto exact = check_zero_residual(diff, context);
343 if (!exact) { return ExpressionResult::failure(exact.error()); }
344 if (std::holds_alternative<ProvedZeroResidual>(exact.value())) {
345 /// 已经恰当,积分因子为 1
346 return SymbolicExpr::number(1);
347 }
348
349 Integrator integrator;
350 /// 尝试 mu = mu(x): (partialM/partialy - partialN/partialx) / N 仅依赖 x
351 if (N && !N->is_zero()) {
352 auto ratio_x = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(diff, N)), transform_budget));
353 auto factor = integrating_factor_from_ratio(ratio_x, x, y, integrator, context);
354 if (!factor || factor.value()) { return factor; }
355 }
356
357 /// 尝试 mu = mu(y): (partialN/partialx - partialM/partialy) / M 仅依赖 y
358 if (M && !M->is_zero()) {
359 auto neg_diff = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(SymbolicExpr::number(-1), diff)), transform_budget));
360 auto ratio_y = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(neg_diff, M)), transform_budget));
361 auto factor = integrating_factor_from_ratio(ratio_y, y, x, integrator, context);
362 if (!factor || factor.value()) { return factor; }
363 }
364
365 return std::shared_ptr<SymbolicExpr>{};
366}
367
368std::shared_ptr<SymbolicExpr> find_integrating_factor(
369 const std::shared_ptr<SymbolicExpr>& M,
370 const std::shared_ptr<SymbolicExpr>& N,
371 const std::string& x, const std::string& y)
372{
374 auto result = find_integrating_factor_impl(M, N, x, y, context);
375 if (!result) { throw result.error(); }
376 return std::move(result.value());
377}
378
379
381 const std::shared_ptr<SymbolicExpr>& M,
382 const std::shared_ptr<SymbolicExpr>& N,
383 const std::string& x,
384 const std::string& y,
386{
387 const std::string operation = "solve_exact_ode";
388 auto valid = validate_ode_pair_var_pair(M, N, x, y, context, operation);
389 if (!valid) {
390 return ODESolutionResult::failure(valid.error());
391 }
392 auto step = context.consume_steps(18, operation);
393 if (!step) {
394 return ODESolutionResult::failure(step.error());
395 }
396
397 try {
398 auto solved = solve_exact_ode_impl(M, N, x, y, context);
399 if (!solved) { return solved; }
400 return wrap_ode_solution(std::move(solved.value()), ODEType::Exact, operation);
401 } catch (const CasError& error) {
402 return ODESolutionResult::failure(error);
403 } catch (const std::bad_alloc&) {
405 "exact ODE allocation failed",
406 operation);
407 } catch (const std::length_error& error) {
408 return ODESolutionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
409 } catch (const std::exception& e) {
411 e.what(),
412 operation);
413 }
414}
415
417 const std::shared_ptr<SymbolicExpr>& M,
418 const std::shared_ptr<SymbolicExpr>& N,
419 const std::string& x,
420 const std::string& y)
421{
423 return solve_exact_ode_checked(M, N, x, y, context);
424}
425
427 const std::shared_ptr<SymbolicExpr>& M,
428 const std::shared_ptr<SymbolicExpr>& N,
429 const std::string& x,
430 const std::string& y, ComputationContext& context)
431{
432
433 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
434 (context).limits().max_ast_nodes, "transform");
435 ODESolution result;
437 result.constants = {"C"};
438
439 auto M_eff = M;
440 auto N_eff = N;
441
442 auto factor = find_integrating_factor_impl(M, N, x, y, context);
443 if (!factor) { return ODESolutionResult::failure(factor.error()); }
444 if (!factor.value()) {
445 return ODESolutionResult::success(std::move(result));
446 }
447 auto mu = std::move(factor.value());
448 if (!mu->is_one()) {
449 M_eff = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(mu, M)), transform_budget));
450 N_eff = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(mu, N)), transform_budget));
451 }
452
453 /// 恰当方程: partialF/partialx = M, partialF/partialy = N
454 /// F(x,y) = integral M dx + g(y)
455 /// 对 F 关于 y 求导: partialF/partialy = partial/partialy(integral M dx) + g'(y) = N
456 /// 所以 g'(y) = N - partial/partialy(integral M dx)
457
458 /// 步骤 1: 计算 integral M dx(将 y 视为常数)
459 Integrator integrator;
460 auto integrated_m = integrator.integrate_checked(*M_eff, x, context);
461 if (!integrated_m) { return ODESolutionResult::failure(integrated_m.error()); }
462 auto F_partial = std::make_shared<SymbolicExpr>(std::move(integrated_m.value()));
463
464 /// 步骤 2: 对 F_partial 关于 y 求导
465 auto dF_dy = detail::make_expression_ptr(detail::differentiate_node(detail::node(F_partial), y, transform_budget));
466 dF_dy = detail::make_expression_ptr(detail::normalize_node(detail::node(dF_dy), transform_budget));
467
468 /// 步骤 3: g'(y) = N - dF_dy
469 auto g_prime = SymbolicExpr::add(N_eff,
470 SymbolicExpr::multiply(SymbolicExpr::number(-1), dF_dy));
471 g_prime = detail::make_expression_ptr(detail::normalize_node(detail::node(g_prime), transform_budget));
472
473 /// 步骤 4: g(y) = integral g'(y) dy
474 auto integrated_g = integrator.integrate_checked(*g_prime, y, context);
475 if (!integrated_g) { return ODESolutionResult::failure(integrated_g.error()); }
476 auto g_y = std::make_shared<SymbolicExpr>(std::move(integrated_g.value()));
477
478 /// 步骤 5: F(x,y) = F_partial + g(y)
479 auto F_total = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(F_partial, g_y)), transform_budget));
480
481 /// 解为 F(x,y) = C
482 result.general_solution = F_total;
483 return ODESolutionResult::success(std::move(result));
484}
485
486} // namespace LMCAS
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)
ExprResult e()
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)
const ExprPtr & exponent
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)
const ExprPtr & rhs
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 及其工厂方法,运算接口.
内部 AST 定义。
统一 ODE 求解引擎:分类,分派,多种求解方法.