@@ -18,20 +18,20 @@ julia> @variables x, t
18
18
x
19
19
t
20
20
21
- julia> eq = LinearODE (x, t, [1, 2, 3], 3exp(4t))
21
+ julia> eq = SymbolicLinearODE (x, t, [1, 2, 3], 3exp(4t))
22
22
(Dt^3)x + (3)(Dt^2)x + (2)(Dt^1)x + (1)(Dt^0)x ~ 3exp(4t)
23
23
```
24
24
"""
25
- struct LinearODE
25
+ struct SymbolicLinearODE
26
26
x:: Num
27
27
t:: Num
28
28
p:: AbstractArray
29
29
q:: Any
30
30
C:: Vector{Num}
31
31
32
- LinearODE (x, t, p, q) = new (x, t, p, q, variables (:C , 1 : length (p)))
32
+ SymbolicLinearODE (x, t, p, q) = new (x, t, p, q, variables (:C , 1 : length (p)))
33
33
34
- function LinearODE (expr, x, t)
34
+ function SymbolicLinearODE (expr, x, t)
35
35
if expr isa Equation
36
36
expr = expr. lhs - expr. rhs
37
37
end
@@ -76,41 +76,41 @@ function is_linear_ode(expr, x, t)
76
76
return islinear && all (isempty .(get_variables .(A, x)))
77
77
end
78
78
79
- Dt (eq:: LinearODE ) = Differential (eq. t)
80
- order (eq:: LinearODE ) = length (eq. p)
79
+ Dt (eq:: SymbolicLinearODE ) = Differential (eq. t)
80
+ order (eq:: SymbolicLinearODE ) = length (eq. p)
81
81
82
- """ Generates symbolic expression to represent `LinearODE `"""
83
- function get_expression (eq:: LinearODE )
82
+ """ Generates symbolic expression to represent `SymbolicLinearODE `"""
83
+ function get_expression (eq:: SymbolicLinearODE )
84
84
(Dt (eq)^ order (eq))(eq. x) + sum ([(eq. p[n]) * (Dt (eq)^ (n - 1 ))(eq. x) for n in 1 : length (eq. p)]) ~ eq. q
85
85
end
86
86
87
- function Base. string (eq:: LinearODE )
87
+ function Base. string (eq:: SymbolicLinearODE )
88
88
" (D$(eq. t) ^$(order (eq)) )$(eq. x) + " *
89
89
join (
90
90
[" ($(eq. p[length (eq. p)- n]) )(D$(eq. t) ^$(length (eq. p)- n- 1 ) )$(eq. x) "
91
91
for n in 0 : (order (eq) - 1 )],
92
92
" + " ) * " ~ $(eq. q) "
93
93
end
94
94
95
- Base. print (io:: IO , eq:: LinearODE ) = print (io, string (eq))
96
- Base. show (io:: IO , eq:: LinearODE ) = print (io, eq)
97
- Base. isequal (eq1:: LinearODE , eq2:: LinearODE ) =
95
+ Base. print (io:: IO , eq:: SymbolicLinearODE ) = print (io, string (eq))
96
+ Base. show (io:: IO , eq:: SymbolicLinearODE ) = print (io, eq)
97
+ Base. isequal (eq1:: SymbolicLinearODE , eq2:: SymbolicLinearODE ) =
98
98
isequal (eq1. x, eq2. x) && isequal (eq1. t, eq2. t) &&
99
99
isequal (eq1. p, eq2. p) && isequal (eq1. q, eq2. q)
100
100
101
101
""" Returns true if q(t) = 0 for linear ODE `eq`"""
102
- is_homogeneous (eq:: LinearODE ) = isempty (Symbolics. get_variables (eq. q))
102
+ is_homogeneous (eq:: SymbolicLinearODE ) = isempty (Symbolics. get_variables (eq. q))
103
103
""" Returns true if all coefficient functions p(t) of `eq` are constant"""
104
- has_const_coeffs (eq:: LinearODE ) = all (isempty .(Symbolics. get_variables .(eq. p)))
104
+ has_const_coeffs (eq:: SymbolicLinearODE ) = all (isempty .(Symbolics. get_variables .(eq. p)))
105
105
""" Returns homgeneous version of `eq` where q(t) = 0"""
106
- to_homogeneous (eq:: LinearODE ) = LinearODE (eq. x, eq. t, eq. p, 0 )
106
+ to_homogeneous (eq:: SymbolicLinearODE ) = SymbolicLinearODE (eq. x, eq. t, eq. p, 0 )
107
107
108
108
"""
109
109
Returns the characteristic polynomial p of `eq` (must have constant coefficients) in terms of variable `r`
110
110
111
111
p(D) = Dⁿ + aₙ₋₁Dⁿ⁻¹ + ... + a₁D + a₀I
112
112
"""
113
- function characteristic_polynomial (eq:: LinearODE , r)
113
+ function characteristic_polynomial (eq:: SymbolicLinearODE , r)
114
114
poly = 0
115
115
@assert has_const_coeffs (eq) " ODE must have constant coefficients to generate characteristic polynomial"
116
116
p = [eq. p; 1 ] # add implied coefficient of 1 to highest order
@@ -122,11 +122,11 @@ function characteristic_polynomial(eq::LinearODE, r)
122
122
end
123
123
124
124
"""
125
- symbolic_solve_ode(eq::LinearODE )
125
+ symbolic_solve_ode(eq::SymbolicLinearODE )
126
126
Symbolically solve a linear ordinary differential equation
127
127
128
128
# Arguments
129
- - eq: a `LinearODE ` to solve
129
+ - eq: a `SymbolicLinearODE ` to solve
130
130
131
131
# Returns
132
132
Symbolic solution to the ODE
@@ -149,22 +149,22 @@ julia> @variables x, t
149
149
t
150
150
151
151
# Integrating Factor (note that SymPy is required for integration)
152
- julia> symbolic_solve_ode(LinearODE (x, t, [5/t], 7t))
152
+ julia> symbolic_solve_ode(SymbolicLinearODE (x, t, [5/t], 7t))
153
153
(C₁ + t^7) / (t^5)
154
154
155
155
# Constant Coefficients and RRF (note that Nemo is required to find characteristic roots)
156
- julia> symbolic_solve_ode(LinearODE (x, t, [9, -6], 4exp(3t)))
156
+ julia> symbolic_solve_ode(SymbolicLinearODE (x, t, [9, -6], 4exp(3t)))
157
157
C₁*exp(3t) + C₂*t*exp(3t) + (2//1)*(t^2)*exp(3t)
158
158
159
- julia> symbolic_solve_ode(LinearODE (x, t, [6, 5], 2exp(-t)*cos(t)))
159
+ julia> symbolic_solve_ode(SymbolicLinearODE (x, t, [6, 5], 2exp(-t)*cos(t)))
160
160
C₁*exp(-2t) + C₂*exp(-3t) + (1//5)*cos(t)*exp(-t) + (3//5)*exp(-t)*sin(t)
161
161
162
162
# Method of Undetermined Coefficients
163
- julia> symbolic_solve_ode(LinearODE (x, t, [-3, 2], 2t - 5))
163
+ julia> symbolic_solve_ode(SymbolicLinearODE (x, t, [-3, 2], 2t - 5))
164
164
(11//9) - (2//3)*t + C₁*exp(t) + C₂*exp(-3t)
165
165
```
166
166
"""
167
- function symbolic_solve_ode (eq:: LinearODE )
167
+ function symbolic_solve_ode (eq:: SymbolicLinearODE )
168
168
homogeneous_solutions = find_homogeneous_solutions (eq)
169
169
170
170
if is_homogeneous (eq) && homogeneous_solutions != = nothing
@@ -191,7 +191,7 @@ Symbolically solve an ODE
191
191
- t: independent variable
192
192
193
193
# Supported Methods
194
- - all methods of solving linear ODEs mentioned for `symbolic_solve_ode(eq::LinearODE )`
194
+ - all methods of solving linear ODEs mentioned for `symbolic_solve_ode(eq::SymbolicLinearODE )`
195
195
- Clairaut's equation
196
196
- Bernoulli equations
197
197
@@ -208,7 +208,7 @@ julia> @variables x, t
208
208
julia> Dt = Differential(t)
209
209
Differential(t)
210
210
211
- # LinearODE (via constant coefficients and RRF)
211
+ # SymbolicLinearODE (via constant coefficients and RRF)
212
212
julia> symbolic_solve_ode(9t*x - 6*Dt(x) ~ 4exp(3t), x, t)
213
213
C₁*exp(3t) + C₂*t*exp(3t) + (2//1)*(t^2)*exp(3t)
214
214
@@ -233,7 +233,7 @@ function symbolic_solve_ode(expr::Equation, x, t)
233
233
end
234
234
235
235
if is_linear_ode (expr, x, t)
236
- eq = LinearODE (expr, x, t)
236
+ eq = SymbolicLinearODE (expr, x, t)
237
237
return symbolic_solve_ode (eq)
238
238
end
239
239
end
@@ -243,7 +243,7 @@ Find homogeneous solutions of linear ODE `eq` with integration constants of `eq.
243
243
244
244
Currently only works for constant coefficient ODEs
245
245
"""
246
- function find_homogeneous_solutions (eq:: LinearODE )
246
+ function find_homogeneous_solutions (eq:: SymbolicLinearODE )
247
247
if has_const_coeffs (eq)
248
248
return const_coeff_solve (to_homogeneous (eq))
249
249
end
@@ -254,11 +254,11 @@ Find a particular solution to linear ODE `eq`
254
254
255
255
Currently works for any linear combination of exponentials, sin, cos, or an exponential times sin or cos (e.g. e^2t * cos(-t) + e^-3t + sin(5t))
256
256
"""
257
- function find_particular_solution (eq:: LinearODE )
257
+ function find_particular_solution (eq:: SymbolicLinearODE )
258
258
# if q has multiple terms, find a particular solution for each and sum together
259
259
terms = Symbolics. terms (eq. q)
260
260
if length (terms) != 1
261
- solutions = find_particular_solution .(LinearODE .(Ref (eq. x), Ref (eq. t), Ref (eq. p), terms))
261
+ solutions = find_particular_solution .(SymbolicLinearODE .(Ref (eq. x), Ref (eq. t), Ref (eq. p), terms))
262
262
if any (s -> s === nothing , solutions)
263
263
return nothing
264
264
end
@@ -287,7 +287,7 @@ Returns homogeneous solutions to linear ODE `eq` with constant coefficients
287
287
288
288
xₕ(t) = C₁e^(r₁t) + C₂e^(r₂t) + ... + Cₙe^(rₙt)
289
289
"""
290
- function const_coeff_solve (eq:: LinearODE )
290
+ function const_coeff_solve (eq:: SymbolicLinearODE )
291
291
@variables 𝓇
292
292
p = characteristic_polynomial (eq, 𝓇)
293
293
roots = symbolic_solve (p, 𝓇, dropmultiplicity = false )
319
319
"""
320
320
Solve almost any first order ODE using an integrating factor. Requires SymPy!
321
321
"""
322
- function integrating_factor_solve (eq:: LinearODE )
322
+ function integrating_factor_solve (eq:: SymbolicLinearODE )
323
323
p = eq. p[1 ] # only p
324
324
v = 0 # integrating factor
325
325
if isempty (Symbolics. get_variables (p))
381
381
"""
382
382
For finding particular solution when q(t) = a*e^(rt)*cos(bt) (or sin(bt))
383
383
"""
384
- function exp_trig_particular_solution (eq:: LinearODE )
384
+ function exp_trig_particular_solution (eq:: SymbolicLinearODE )
385
385
facs = _true_factors (eq. q)
386
386
387
387
a = prod (filter (fac -> isempty (Symbolics. get_variables (fac, [eq. t])), facs))
@@ -432,7 +432,7 @@ Exponential Response Formula: x_p(t) = a*e^(rt)/p(r) where p(r) is characteristi
432
432
433
433
Resonant Response Formula: If r is a characteristic root, multiply by t and take the derivative of p (possibly multiple times)
434
434
"""
435
- function resonant_response_formula (eq:: LinearODE )
435
+ function resonant_response_formula (eq:: SymbolicLinearODE )
436
436
@assert has_const_coeffs (eq)
437
437
438
438
# get a and r from q = a*e^(rt)
@@ -455,7 +455,7 @@ function resonant_response_formula(eq::LinearODE)
455
455
(substitute (expand_derivatives ((Ds^ k)(p)), Dict (𝓈 => r)))))
456
456
end
457
457
458
- function method_of_undetermined_coefficients (eq:: LinearODE )
458
+ function method_of_undetermined_coefficients (eq:: SymbolicLinearODE )
459
459
# constant
460
460
p = eq. p[1 ]
461
461
if isempty (Symbolics. get_variables (p, eq. t)) && isempty (Symbolics. get_variables (eq. q, eq. t))
@@ -526,16 +526,16 @@ end
526
526
Initial value problem (IVP) for a linear ODE
527
527
"""
528
528
struct IVP
529
- eq:: LinearODE
529
+ eq:: SymbolicLinearODE
530
530
initial_conditions:: Vector{Num} # values at t = 0 of nth derivative of x
531
531
532
- function IVP (eq:: LinearODE , initial_conditions:: Vector{<:Number} )
532
+ function IVP (eq:: SymbolicLinearODE , initial_conditions:: Vector{<:Number} )
533
533
@assert length (initial_conditions) == order (eq) " # of Initial conditions must match order of ODE"
534
534
new (eq, initial_conditions)
535
535
end
536
536
end
537
537
538
- function solve_IVP (ivp:: IVP )
538
+ function solve_symbolic_IVP (ivp:: IVP )
539
539
general_solution = symbolic_solve_ode (ivp. eq)
540
540
if general_solution === nothing
541
541
return nothing
@@ -559,6 +559,35 @@ function solve_IVP(ivp::IVP)
559
559
return expand (simplify (substitute (general_solution, symbolic_solve (eqs, ivp. eq. C)[1 ])))
560
560
end
561
561
562
+ """
563
+ solve_symbolic_IVP(eq::SymbolicLinearODE, initial_conditions::Vector{<:Number})
564
+
565
+ Solve an initial value problem for a linear ODE with given initial conditions.
566
+
567
+ # Arguments
568
+ - `eq`: A `SymbolicLinearODE` to solve
569
+ - `initial_conditions`: Vector of initial conditions for x(0), x'(0), x''(0), etc.
570
+
571
+ # Returns
572
+ Symbolic solution satisfying the initial conditions
573
+
574
+ # Examples
575
+ ```jldoctest
576
+ julia> using Symbolics
577
+ julia> @variables x, t
578
+ 2-element Vector{Num}:
579
+ x
580
+ t
581
+
582
+ julia> eq = SymbolicLinearODE(x, t, [-3, 2], 0) # d²x/dt² + 2dx/dt - 3x = 0
583
+ julia> solve_symbolic_IVP(eq, [1, -1]) # x(0) = 1, x'(0) = -1
584
+ (1//2)*exp(-3t) + (1//2)*exp(t)
585
+ ```
586
+ """
587
+ function solve_symbolic_IVP (eq:: SymbolicLinearODE , initial_conditions:: Vector{<:Number} )
588
+ return solve_symbolic_IVP (IVP (eq, initial_conditions))
589
+ end
590
+
562
591
"""
563
592
Solve Clairaut's equation of the form x = x'*t + f(x').
564
593
@@ -602,7 +631,7 @@ function solve_clairaut(expr, x, t)
602
631
end
603
632
604
633
"""
605
- Linearize a Bernoulli equation of the form dx/dt + p(t)x = q(t)x^n into a `LinearODE ` of the form dv/dt + (1-n)p(t)v = (1-n)q(t) where v = x^(1-n)
634
+ Linearize a Bernoulli equation of the form dx/dt + p(t)x = q(t)x^n into a `SymbolicLinearODE ` of the form dv/dt + (1-n)p(t)v = (1-n)q(t) where v = x^(1-n)
606
635
"""
607
636
function linearize_bernoulli (expr, x, t, v)
608
637
Dt = Differential (t)
@@ -643,7 +672,7 @@ function linearize_bernoulli(expr, x, t, v)
643
672
p //= leading_coeff
644
673
q //= leading_coeff
645
674
646
- return LinearODE (v, t, [p* (1 - n)], q* (1 - n)), n
675
+ return SymbolicLinearODE (v, t, [p* (1 - n)], q* (1 - n)), n
647
676
end
648
677
649
678
"""
0 commit comments