@@ -18,20 +18,20 @@ julia> @variables x, t
1818 x
1919 t
2020
21- julia> eq = LinearODE (x, t, [1, 2, 3], 3exp(4t))
21+ julia> eq = SymbolicLinearODE (x, t, [1, 2, 3], 3exp(4t))
2222(Dt^3)x + (3)(Dt^2)x + (2)(Dt^1)x + (1)(Dt^0)x ~ 3exp(4t)
2323```
2424"""
25- struct LinearODE
25+ struct SymbolicLinearODE
2626 x:: Num
2727 t:: Num
2828 p:: AbstractArray
2929 q:: Any
3030 C:: Vector{Num}
3131
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)))
3333
34- function LinearODE (expr, x, t)
34+ function SymbolicLinearODE (expr, x, t)
3535 if expr isa Equation
3636 expr = expr. lhs - expr. rhs
3737 end
@@ -76,41 +76,41 @@ function is_linear_ode(expr, x, t)
7676 return islinear && all (isempty .(get_variables .(A, x)))
7777end
7878
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)
8181
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 )
8484 (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
8585end
8686
87- function Base. string (eq:: LinearODE )
87+ function Base. string (eq:: SymbolicLinearODE )
8888 " (D$(eq. t) ^$(order (eq)) )$(eq. x) + " *
8989 join (
9090 [" ($(eq. p[length (eq. p)- n]) )(D$(eq. t) ^$(length (eq. p)- n- 1 ) )$(eq. x) "
9191 for n in 0 : (order (eq) - 1 )],
9292 " + " ) * " ~ $(eq. q) "
9393end
9494
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 ) =
9898 isequal (eq1. x, eq2. x) && isequal (eq1. t, eq2. t) &&
9999 isequal (eq1. p, eq2. p) && isequal (eq1. q, eq2. q)
100100
101101""" 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))
103103""" 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)))
105105""" 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 )
107107
108108"""
109109Returns the characteristic polynomial p of `eq` (must have constant coefficients) in terms of variable `r`
110110
111111p(D) = Dⁿ + aₙ₋₁Dⁿ⁻¹ + ... + a₁D + a₀I
112112"""
113- function characteristic_polynomial (eq:: LinearODE , r)
113+ function characteristic_polynomial (eq:: SymbolicLinearODE , r)
114114 poly = 0
115115 @assert has_const_coeffs (eq) " ODE must have constant coefficients to generate characteristic polynomial"
116116 p = [eq. p; 1 ] # add implied coefficient of 1 to highest order
@@ -122,11 +122,11 @@ function characteristic_polynomial(eq::LinearODE, r)
122122end
123123
124124"""
125- symbolic_solve_ode(eq::LinearODE )
125+ symbolic_solve_ode(eq::SymbolicLinearODE )
126126Symbolically solve a linear ordinary differential equation
127127
128128# Arguments
129- - eq: a `LinearODE ` to solve
129+ - eq: a `SymbolicLinearODE ` to solve
130130
131131# Returns
132132Symbolic solution to the ODE
@@ -149,22 +149,22 @@ julia> @variables x, t
149149 t
150150
151151# 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))
153153(C₁ + t^7) / (t^5)
154154
155155# 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)))
157157C₁*exp(3t) + C₂*t*exp(3t) + (2//1)*(t^2)*exp(3t)
158158
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)))
160160C₁*exp(-2t) + C₂*exp(-3t) + (1//5)*cos(t)*exp(-t) + (3//5)*exp(-t)*sin(t)
161161
162162# 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))
164164(11//9) - (2//3)*t + C₁*exp(t) + C₂*exp(-3t)
165165```
166166"""
167- function symbolic_solve_ode (eq:: LinearODE )
167+ function symbolic_solve_ode (eq:: SymbolicLinearODE )
168168 homogeneous_solutions = find_homogeneous_solutions (eq)
169169
170170 if is_homogeneous (eq) && homogeneous_solutions != = nothing
@@ -191,7 +191,7 @@ Symbolically solve an ODE
191191- t: independent variable
192192
193193# 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 )`
195195- Clairaut's equation
196196- Bernoulli equations
197197
@@ -208,7 +208,7 @@ julia> @variables x, t
208208julia> Dt = Differential(t)
209209Differential(t)
210210
211- # LinearODE (via constant coefficients and RRF)
211+ # SymbolicLinearODE (via constant coefficients and RRF)
212212julia> symbolic_solve_ode(9t*x - 6*Dt(x) ~ 4exp(3t), x, t)
213213C₁*exp(3t) + C₂*t*exp(3t) + (2//1)*(t^2)*exp(3t)
214214
@@ -233,7 +233,7 @@ function symbolic_solve_ode(expr::Equation, x, t)
233233 end
234234
235235 if is_linear_ode (expr, x, t)
236- eq = LinearODE (expr, x, t)
236+ eq = SymbolicLinearODE (expr, x, t)
237237 return symbolic_solve_ode (eq)
238238 end
239239end
@@ -243,7 +243,7 @@ Find homogeneous solutions of linear ODE `eq` with integration constants of `eq.
243243
244244Currently only works for constant coefficient ODEs
245245"""
246- function find_homogeneous_solutions (eq:: LinearODE )
246+ function find_homogeneous_solutions (eq:: SymbolicLinearODE )
247247 if has_const_coeffs (eq)
248248 return const_coeff_solve (to_homogeneous (eq))
249249 end
@@ -254,11 +254,11 @@ Find a particular solution to linear ODE `eq`
254254
255255Currently 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))
256256"""
257- function find_particular_solution (eq:: LinearODE )
257+ function find_particular_solution (eq:: SymbolicLinearODE )
258258 # if q has multiple terms, find a particular solution for each and sum together
259259 terms = Symbolics. terms (eq. q)
260260 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))
262262 if any (s -> s === nothing , solutions)
263263 return nothing
264264 end
@@ -287,7 +287,7 @@ Returns homogeneous solutions to linear ODE `eq` with constant coefficients
287287
288288xₕ(t) = C₁e^(r₁t) + C₂e^(r₂t) + ... + Cₙe^(rₙt)
289289"""
290- function const_coeff_solve (eq:: LinearODE )
290+ function const_coeff_solve (eq:: SymbolicLinearODE )
291291 @variables 𝓇
292292 p = characteristic_polynomial (eq, 𝓇)
293293 roots = symbolic_solve (p, 𝓇, dropmultiplicity = false )
319319"""
320320Solve almost any first order ODE using an integrating factor. Requires SymPy!
321321"""
322- function integrating_factor_solve (eq:: LinearODE )
322+ function integrating_factor_solve (eq:: SymbolicLinearODE )
323323 p = eq. p[1 ] # only p
324324 v = 0 # integrating factor
325325 if isempty (Symbolics. get_variables (p))
381381"""
382382For finding particular solution when q(t) = a*e^(rt)*cos(bt) (or sin(bt))
383383"""
384- function exp_trig_particular_solution (eq:: LinearODE )
384+ function exp_trig_particular_solution (eq:: SymbolicLinearODE )
385385 facs = _true_factors (eq. q)
386386
387387 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
432432
433433Resonant Response Formula: If r is a characteristic root, multiply by t and take the derivative of p (possibly multiple times)
434434"""
435- function resonant_response_formula (eq:: LinearODE )
435+ function resonant_response_formula (eq:: SymbolicLinearODE )
436436 @assert has_const_coeffs (eq)
437437
438438 # get a and r from q = a*e^(rt)
@@ -455,7 +455,7 @@ function resonant_response_formula(eq::LinearODE)
455455 (substitute (expand_derivatives ((Ds^ k)(p)), Dict (𝓈 => r)))))
456456end
457457
458- function method_of_undetermined_coefficients (eq:: LinearODE )
458+ function method_of_undetermined_coefficients (eq:: SymbolicLinearODE )
459459 # constant
460460 p = eq. p[1 ]
461461 if isempty (Symbolics. get_variables (p, eq. t)) && isempty (Symbolics. get_variables (eq. q, eq. t))
@@ -526,16 +526,16 @@ end
526526Initial value problem (IVP) for a linear ODE
527527"""
528528struct IVP
529- eq:: LinearODE
529+ eq:: SymbolicLinearODE
530530 initial_conditions:: Vector{Num} # values at t = 0 of nth derivative of x
531531
532- function IVP (eq:: LinearODE , initial_conditions:: Vector{<:Number} )
532+ function IVP (eq:: SymbolicLinearODE , initial_conditions:: Vector{<:Number} )
533533 @assert length (initial_conditions) == order (eq) " # of Initial conditions must match order of ODE"
534534 new (eq, initial_conditions)
535535 end
536536end
537537
538- function solve_IVP (ivp:: IVP )
538+ function solve_symbolic_IVP (ivp:: IVP )
539539 general_solution = symbolic_solve_ode (ivp. eq)
540540 if general_solution === nothing
541541 return nothing
@@ -559,6 +559,35 @@ function solve_IVP(ivp::IVP)
559559 return expand (simplify (substitute (general_solution, symbolic_solve (eqs, ivp. eq. C)[1 ])))
560560end
561561
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+
562591"""
563592Solve Clairaut's equation of the form x = x'*t + f(x').
564593
@@ -602,7 +631,7 @@ function solve_clairaut(expr, x, t)
602631end
603632
604633"""
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)
606635"""
607636function linearize_bernoulli (expr, x, t, v)
608637 Dt = Differential (t)
@@ -643,7 +672,7 @@ function linearize_bernoulli(expr, x, t, v)
643672 p //= leading_coeff
644673 q //= leading_coeff
645674
646- return LinearODE (v, t, [p* (1 - n)], q* (1 - n)), n
675+ return SymbolicLinearODE (v, t, [p* (1 - n)], q* (1 - n)), n
647676end
648677
649678"""
0 commit comments