Differential Equations
Giac.jl provides symbolic solving of ordinary differential equations (ODEs) using GIAC's desolve command. The package includes a D operator following SciML/ModelingToolkit conventions for expressing derivatives naturally.
The D Operator
The D operator provides a clean, Julian syntax for expressing derivatives:
using Giac
using Giac.Commands: desolve
@giac_var t u(t)
# Create derivative expressions
D(u) # First derivative u'
D(D(u)) # Second derivative u'' (chained)
D(u, 2) # Second derivative u'' (direct)
D(u, 3) # Third derivative u'''Comparison with Raw Syntax
| D Operator | Raw GIAC | Description |
|---|---|---|
D(u) | diff(u, t) | First derivative |
D(D(u)) | diff(diff(u, t), t) | Second derivative (chained) |
D(u, 2) | diff(u, t, 2) | Second derivative (direct) |
D(u)(0) ~ 1 | "u'(0)=1" | Initial condition for u'(0) |
First-Order ODEs
Basic Example
Solve τu' + u = U₀ with initial condition u(0) = 1:
using Giac
using Giac.Commands: desolve
@giac_var t u(t) tau U0
# Define ODE: τu' + u = U₀
ode = tau * D(u) + u ~ U0
# Initial condition: u(0) = 1
initial = u(0) ~ 1
# Solve
result = desolve([ode, initial], t, :u)
# Returns: U0+(-U0+1)*exp(-t/tau)RC Circuit Example
@giac_var t V(t) R C Vs
# Capacitor voltage ODE: RC·V' + V = Vs
ode = R * C * D(V) + V ~ Vs
initial = V(0) ~ 0
result = desolve([ode, initial], t, :V)
# Returns: Vs*(1-exp(-t/(R*C)))Second-Order ODEs
Harmonic Oscillator
Solve u'' + u = 0 with u(0) = 1, u'(0) = 0:
using Giac
using Giac.Commands: desolve
@giac_var t u(t)
# Define ODE using chained D
ode = D(D(u)) + u ~ 0
# Initial conditions
u0 = u(0) ~ 1 # u(0) = 1
du0 = D(u)(0) ~ 0 # u'(0) = 0
# Solve
result = desolve([ode, u0, du0], t, :u)
# Returns: cos(t)Alternative Syntax with D(u, 2)
# Same ODE using direct order specification
ode = D(u, 2) + u ~ 0
result = desolve([ode, u(0) ~ 1, D(u)(0) ~ 0], t, :u)
# Returns: cos(t)Damped Oscillator
Solve u'' + 2ζω₀u' + ω₀²u = 0:
@giac_var t u(t) zeta omega0
ode = D(u, 2) + 2*zeta*omega0*D(u) + omega0^2*u ~ 0
result = desolve([ode, u(0) ~ 1, D(u)(0) ~ 0], t, :u)Third-Order ODEs
Solve y''' - y = 0 with y(0) = 1, y'(0) = 1, y''(0) = 1:
using Giac
using Giac.Commands: desolve
@giac_var t y(t)
# Define ODE
ode = D(y, 3) - y ~ 0
# Initial conditions
y0 = y(0) ~ 1
dy0 = D(y)(0) ~ 1
d2y0 = D(y, 2)(0) ~ 1
# Solve
result = desolve([ode, y0, dy0, d2y0], t, :y)
# Returns: exp(t)Using D in ODE Expressions
The D operator supports arithmetic operations, making it natural to build ODE expressions:
@giac_var t u(t) a b c
# Build complex ODE expressions
ode1 = D(D(u)) + a*D(u) + b*u ~ c
ode2 = D(u, 2) - 4*D(u) + 4*u ~ 0
# Combine with other GiacExpr
forcing = sin(t)
ode3 = D(D(u)) + u ~ forcingImportant Notes
Function Name as Symbol
When calling desolve, pass the function name as a Symbol (:u, :y) rather than the function expression (u, y):
# Correct
desolve([ode, u(0) ~ 1], t, :u)
# Incorrect - GIAC expects just the name, not u(t)
desolve([ode, u(0) ~ 1], t, u) # May not work as expectedInitial Conditions with D
The D(u)(0) syntax creates an unevaluated derivative condition that GIAC interprets correctly:
D(u)(0) ~ 1 # Creates "u'(0)=1" for GIAC
D(u, 2)(0) ~ 0 # Creates "u''(0)=0" for GIACSystems of ODEs
GIAC can solve systems of first-order ODEs:
@giac_var t x(t) y(t)
# dx/dt = y, dy/dt = -x
sys = [D(x) ~ y, D(y) ~ -x]
initial = [x(0) ~ 1, y(0) ~ 0]
# Solve as a system (pass both variables)
result = desolve([sys..., initial...], t, [:x, :y])Physics Applications
Exponential Decay
Model radioactive decay: dN/dt = -λN
@giac_var t N(t) lambda N0
# Decay equation
ode = D(N) + lambda * N ~ 0
initial = N(0) ~ N0
result = desolve([ode, initial], t, :N)
# Returns: N0*exp(-lambda*t)Population Growth
Exponential growth model: dP/dt = rP
@giac_var t P(t) r P0
ode = D(P) - r * P ~ 0
initial = P(0) ~ P0
result = desolve([ode, initial], t, :P)
# Returns: P0*exp(r*t)Newton's Law of Cooling
Temperature change: dT/dt = -k(T - T_env)
@giac_var t T(t) k T_env T0
ode = D(T) + k * (T - T_env) ~ 0
initial = T(0) ~ T0
result = desolve([ode, initial], t, :T)
# Returns exponential approach to T_envLimitations
- ODEs only: GIAC's
desolveis designed for ordinary differential equations. For PDEs, consider Symbolics.jl + MethodOfLines.jl or other specialized packages. - Symbolic solutions:
desolvefinds closed-form analytical solutions when possible. For numerical solutions of ODEs, use DifferentialEquations.jl.
API Reference
Giac.D — Function
D(expr::GiacExpr) -> DerivativeExpr
D(expr::GiacExpr, n::Int) -> DerivativeExpr
D(d::DerivativeExpr) -> DerivativeExprDerivative operator following SciML/ModelingToolkit conventions.
Creates a DerivativeExpr that can be:
- Used in ODEs:
D(D(u)) + u ~ 0(converts to diff notation) - Called for initial conditions:
D(u)(0) ~ 1(produces prime notation u'(0)=1)
Arguments
expr::GiacExpr: A function expression created with@giac_var u(t)n::Int: Optional derivative order (default: 1)d::DerivativeExpr: A derivative expression to differentiate further
Examples
using Giac
using Giac.Commands: desolve
@giac_var t u(t)
# First derivative
D(u) # Represents u'
# Second derivative (two ways)
D(D(u)) # Chain D operators
D(u, 2) # Specify order directly
# ODE with initial conditions
ode = D(D(u)) + u ~ 0 # u'' + u = 0
u0 = u(0) ~ 1 # u(0) = 1
du0 = D(u)(0) ~ 0 # u'(0) = 0
desolve([ode, u0, du0], t, u) # Returns: cos(t)
# Third order example
@giac_var t y(t)
ode = D(y, 3) - y ~ 0 # y''' - y = 0
desolve([ode, y(0) ~ 1, D(y)(0) ~ 1, D(y,2)(0) ~ 1], t, y)See also
DerivativeExpr: The derivative expression typedesolve: Solving differential equations (viaGiac.Commands)
Giac.DerivativeExpr — Type
DerivativeExprRepresents a derivative expression for use in ODE initial conditions.
This type enables the D operator syntax following SciML conventions:
D(u)represents the first derivative u'D(D(u))orD(u, 2)represents the second derivative u''D(u)(0)produces "u'(0)" for GIAC initial conditions
Fields
base_expr::GiacExpr: The original function expression (e.g., u(t))funcname::String: The function name (e.g., "u")varname::String: The differentiation variable (e.g., "t")order::Int: The derivative order (1 for first derivative, 2 for second, etc.)
Example
@giac_var t u(t)
# Create derivative expressions
du = D(u) # First derivative
d2u = D(D(u)) # Second derivative
d2u = D(u, 2) # Alternative syntax
# Use in initial conditions
D(u)(0) ~ 1 # u'(0) = 1
D(u, 2)(0) ~ 0 # u''(0) = 0
# Use in ODEs (converts to diff notation)
ode = D(D(u)) + u ~ 0 # Equivalent to diff(u,t,2) + u = 0See also
Giac.DerivativePoint — Type
DerivativePointRepresents a derivative evaluated at a specific point, for use in ODE initial conditions.
This type is created when calling a DerivativeExpr with arguments, e.g., D(u)(0). It delays evaluation until used with the ~ operator to create an equation, because GIAC interprets prime notation differently in isolation vs. within desolve.
Fields
funcname::String: The function name (e.g., "u")order::Int: The derivative orderpoint_args::Vector{String}: The point arguments as strings
Example
@giac_var t u(t)
dp = D(u)(0) # Returns DerivativePoint, not GiacExpr
eq = D(u)(0) ~ 1 # Creates equation: "u'(0)=1"Giac.DerivativeCondition — Type
DerivativeConditionRepresents an unevaluated derivative initial condition for ODEs.
This type holds the string representation of a derivative condition (e.g., "u'(0)=1") without evaluating it through GIAC. When passed to desolve in an array, it gets converted to its string form, which GIAC interprets correctly.
Example
@giac_var t u(t)
dc = D(u)(0) ~ 1 # Returns DerivativeCondition: "u'(0)=1"
# Pass to desolve - the string is used directly
desolve([D(D(u)) + u ~ 0, u(0) ~ 1, D(u)(0) ~ 0], t, u)