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 OperatorRaw GIACDescription
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 ~ forcing

Important 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 expected

Initial 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 GIAC

Systems 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_env

Limitations

  • ODEs only: GIAC's desolve is designed for ordinary differential equations. For PDEs, consider Symbolics.jl + MethodOfLines.jl or other specialized packages.
  • Symbolic solutions: desolve finds closed-form analytical solutions when possible. For numerical solutions of ODEs, use DifferentialEquations.jl.

API Reference

Giac.DFunction
D(expr::GiacExpr) -> DerivativeExpr
D(expr::GiacExpr, n::Int) -> DerivativeExpr
D(d::DerivativeExpr) -> DerivativeExpr

Derivative 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 type
  • desolve: Solving differential equations (via Giac.Commands)
source
Giac.DerivativeExprType
DerivativeExpr

Represents 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)) or D(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 = 0

See also

  • D: The derivative operator function
  • @giac_var: For creating function variables
source
Giac.DerivativePointType
DerivativePoint

Represents 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 order
  • point_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"
source
Giac.DerivativeConditionType
DerivativeCondition

Represents 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)
source