83 const std::vector<CharRoot>&
roots,
85 std::vector<std::string>& constants)
87 auto x_var = SymbolicExpr::variable(x);
88 std::shared_ptr<SymbolicExpr> solution =
nullptr;
91 for (
const auto& root :
roots) {
92 for (
int k = 0; k < root.multiplicity; ++k) {
93 if (!root.is_complex) {
95 std::string c_name =
"C" + std::to_string(const_idx++);
96 constants.push_back(c_name);
97 auto C = SymbolicExpr::variable(c_name);
99 std::shared_ptr<SymbolicExpr> term = C;
103 auto x_pow = SymbolicExpr::power(x_var, SymbolicExpr::number(k));
104 term = SymbolicExpr::multiply(term, x_pow);
108 if (root.real_part != 0.0) {
110 auto exp_arg = SymbolicExpr::multiply(r_expr, x_var);
111 auto exp_term = SymbolicExpr::exp(exp_arg);
112 term = SymbolicExpr::multiply(term, exp_term);
115 solution = solution ? SymbolicExpr::add(solution, term) : term;
120 std::string ca_name =
"C" + std::to_string(const_idx++);
121 std::string cb_name =
"C" + std::to_string(const_idx++);
122 constants.push_back(ca_name);
123 constants.push_back(cb_name);
124 auto Ca = SymbolicExpr::variable(ca_name);
125 auto Cb = SymbolicExpr::variable(cb_name);
128 auto beta_x = SymbolicExpr::multiply(beta_expr, x_var);
129 auto cos_term = SymbolicExpr::cos(beta_x);
130 auto sin_term = SymbolicExpr::sin(beta_x);
133 std::shared_ptr<SymbolicExpr> exp_factor =
nullptr;
134 if (root.real_part != 0.0) {
136 auto exp_arg = SymbolicExpr::multiply(alpha_expr, x_var);
137 exp_factor = SymbolicExpr::exp(exp_arg);
141 std::shared_ptr<SymbolicExpr> x_pow_factor =
nullptr;
143 x_pow_factor = SymbolicExpr::power(x_var, SymbolicExpr::number(k));
149 term_cos = SymbolicExpr::multiply(term_cos, x_pow_factor);
152 term_cos = SymbolicExpr::multiply(term_cos, exp_factor);
154 term_cos = SymbolicExpr::multiply(term_cos, cos_term);
159 term_sin = SymbolicExpr::multiply(term_sin, x_pow_factor);
162 term_sin = SymbolicExpr::multiply(term_sin, exp_factor);
164 term_sin = SymbolicExpr::multiply(term_sin, sin_term);
166 solution = solution ? SymbolicExpr::add(solution, term_cos) : term_cos;
167 solution = SymbolicExpr::add(solution, term_sin);
176 const std::vector<CharRoot>&
roots,
177 const std::string& x,
178 std::vector<std::string>& constants)
180 auto x_var = SymbolicExpr::variable(x);
181 auto ln_x = SymbolicExpr::ln(x_var);
182 std::shared_ptr<SymbolicExpr> solution =
nullptr;
185 for (
const auto& root :
roots) {
186 for (
int k = 0; k < root.multiplicity; ++k) {
187 std::shared_ptr<SymbolicExpr> log_factor =
nullptr;
189 log_factor = SymbolicExpr::power(ln_x, SymbolicExpr::number(k));
192 if (!root.is_complex) {
193 std::string c_name =
"C" + std::to_string(const_idx++);
194 constants.push_back(c_name);
195 auto term = SymbolicExpr::variable(c_name);
198 term = SymbolicExpr::multiply(
200 SymbolicExpr::power(x_var,
exponent));
202 term = SymbolicExpr::multiply(term, log_factor);
204 solution = solution ? SymbolicExpr::add(solution, term) : term;
206 std::string ca_name =
"C" + std::to_string(const_idx++);
207 std::string cb_name =
"C" + std::to_string(const_idx++);
208 constants.push_back(ca_name);
209 constants.push_back(cb_name);
213 auto beta_ln_x = SymbolicExpr::multiply(beta_expr, ln_x);
214 auto trig = SymbolicExpr::add(
215 SymbolicExpr::multiply(SymbolicExpr::variable(ca_name),
216 SymbolicExpr::cos(beta_ln_x)),
217 SymbolicExpr::multiply(SymbolicExpr::variable(cb_name),
218 SymbolicExpr::sin(beta_ln_x)));
219 auto term = SymbolicExpr::multiply(
220 SymbolicExpr::power(x_var, alpha_expr),
223 term = SymbolicExpr::multiply(term, log_factor);
225 solution = solution ? SymbolicExpr::add(solution, term) : term;
234 const std::vector<double>& coeffs,
235 const std::shared_ptr<SymbolicExpr>& forcing,
236 const std::string& x,
237 const std::string& y,
241 (
context).limits().max_ast_nodes,
"transform");
242 const std::string operation =
"solve_higher_order_ode";
252 for (
double coefficient : coeffs) {
253 if (!std::isfinite(coefficient / coeffs.front())) {
256 "normalizing the characteristic polynomial exceeds the finite numeric domain",
261 auto budget =
context.consume_steps(coeffs.size() * 20 + 20, operation);
267 if (nonzero_forcing &&
268 (!forcing->is_number() || coeffs.back() == 0.0)) {
271 "non-homogeneous constant-coefficient ODE currently requires a constant forcing and nonzero y coefficient",
277 coeffs,
nullptr, x, y,
context);
278 if (!solution_result) {
281 auto solution = std::move(solution_result.value());
282 if (nonzero_forcing && solution.general_solution) {
284 forcing, SymbolicExpr::number(coeffs.back()))), transform_budget));
286 solution.general_solution, particular)), transform_budget));
292 }
catch (
const std::bad_alloc&) {
295 "allocation failed while solving higher-order ODE",
303}
catch (
const CasError& error) {
305}
catch (
const std::bad_alloc&) {
307}
catch (
const std::length_error& error) {
309}
catch (
const std::exception& error) {
370 const std::vector<double>& euler_coeffs,
371 const std::shared_ptr<SymbolicExpr>& forcing,
372 const std::string& x,
373 const std::string& y,
377 (
context).limits().max_ast_nodes,
"transform");
378 const std::string operation =
"solve_euler_ode";
389 auto budget =
context.consume_steps(euler_coeffs.size() * 20 + 20, operation);
398 "non-homogeneous Euler ODE currently requires a constant forcing and nonzero y coefficient",
404 euler_coeffs,
nullptr, x, y,
context);
405 if (!solution_result) {
408 auto solution = std::move(solution_result.value());
409 if (nonzero_forcing && solution.general_solution) {
412 SymbolicExpr::number(euler_coeffs.back()))), transform_budget));
414 solution.general_solution, particular)), transform_budget));
420 }
catch (
const std::bad_alloc&) {
423 "allocation failed while solving Euler ODE",
431}
catch (
const CasError& error) {
433}
catch (
const std::bad_alloc&) {
435}
catch (
const std::length_error& error) {
437}
catch (
const std::exception& error) {
452 const std::vector<double>& euler_coeffs,
453 const std::shared_ptr<SymbolicExpr>& forcing,
454 const std::string& x,
459 (
context).limits().max_ast_nodes,
"transform");
460 const std::string operation =
"solve_euler_ode";
464 if ((euler_coeffs.size() != 3 && euler_coeffs.size() != 4) ||
468 "Euler ODE is outside the implemented support domain",
472 std::vector<double> characteristic;
473 if (euler_coeffs.size() == 3) {
474 const double a = euler_coeffs[0];
475 const double b = euler_coeffs[1];
476 const double c = euler_coeffs[2];
477 characteristic = {
a,
b -
a,
c};
479 const double a = euler_coeffs[0];
480 const double b = euler_coeffs[1];
481 const double c = euler_coeffs[2];
482 const double d = euler_coeffs[3];
483 characteristic = {
a,
b - 3.0 *
a, 2.0 *
a -
b +
c, d};
496}
catch (
const CasError& error) {
498}
catch (
const std::bad_alloc&) {
500}
catch (
const std::length_error& error) {
502}
catch (
const std::exception& error) {