Getting Started
This chapter provides a high-level overview of how to begin using ChenFliessSeries.jl. It introduces the core workflow, explains the main concepts, and walks through the essential steps for computing Chen–Fliess expansions in practice.
The goal is to give you a clear mental model first, and then guide you through concrete examples.
Contents
Installation
To install the ChenFliessSeries.jl package, run the following command in your terminal.
Using the Julia REPL’s Pkg mode:
1julia> ]
2pkg> add ChenFliessSeries
Or using the Pkg module in the standard REPL:
1julia> using Pkg
2julia> Pkg.add("ChenFliessSeries")
This will download and install the package along with its dependencies. Make sure you have Julia 1.12.3 or higher installed on your system.
Quick sanity check:
1using ChenFliessSeries
2@info "ChenFliessSeries.jl loaded successfully!"
Basic Usage (High-Level Overview)
Once installed, ChenFliessSeries.jl enables you to compute the building blocks of the Chen–Fliess expansion:
Iterated integrals of the input
Lie derivatives of the output along the vector fields
Chen–Fliess coefficients \((c,\eta)\)
Truncated Chen–Fliess series \(F_c^{N}[u](t)\)
Comparison with the true system output
A typical workflow looks like this:
flowchart TD
classDef step fill:#f2f2f2,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
U["Inputs <br/> $$\ u(t)$$"]:::step
E["Iterated integrals<br/> $$\ E^N_\eta[u](t)$$"]:::step
G["Vector fields<br/> $$\ g_i$$"]:::step
L["Lie derivatives<br/> $$\ L_\eta h$$"]:::step
F["Chen–Fliess series<br/> $$\ F_c^N[u](t)$$"]:::step
O["Output of the system<br/>$$\ h(t)$$"]:::step
G --> L --> F
O --> L
U --> E --> F
The sections below walk through each step in detail.
Computing iterated integrals
To compute the iterated integrals \(E_\eta[u](t)\), you must define:
time interval \([0,t_f]\),
input function \(u(t)\),
the integration step \(dt\).
truncation length \(N\)
1 using ChenFliessSeries
2
3 dt = 0.001
4 t = 0:dt:0.1
5
6 u0 = one.(t)
7 u1 = sin.(t)
8 u2 = cos.(t)
9
10 utemp = vcat(u0', u1', u2') # shape: (m+1, length(t))
11
12 Ntrunc = 4
13 E = iter_int(utemp, dt, Ntrunc)
This computes all iterated integrals \(E_\eta[u](t)\) for \(|\eta| \le N\).
The algorithm of the iter_int function is based on Chen’s identity which translates numerically to
where \(u(t)\) is the matrix of inputs stacked horizontally, \(E_{X^k}[u](t)\) is the matrix that stacks horizontally the iterated integrals and the tensor symbol \(\otimes\) represents the column-wise Kronecker product .
The outline of the calculation of the algorithm follows the workflow:
flowchart TD
classDef step fill:#f2f2f2,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
classDef calc fill:#e8f0ff,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
classDef loop fill:#fff4d6,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
A["Start<br/><span> $$\ ( u_{\text{temp}}, dt, N_{\text{trunc}})$$</span>"]:::step
H["Compute first-order integrals: <span> $$\ E_{X^1}[u](t) $$</span>"]:::calc
I{"Loop i = 1 to Ntrunc-1"}:::loop
K["<span> $$\ \text{Etemp} = u(t)\otimes E_{X^{i}}[u](t) $$</span>"]:::calc
M["Compute: <span> $$\ E_{X^{i+1}}[u](t) = \int _0^t \text{Etemp} d\tau $$</span>"]:::calc
N["Store <span> $$\ E_{X^{i+1}}[u](t) $$</span>"]:::step
O["Return the integral block"]:::step
%% Connections
A --> H --> I
I --> K --> M
M --> N --> I
I --> O
Defining vector fields and outputs
To compute Chen–Fliess coefficients \((c,\eta) = L_\eta h\), you must define:
the drift vector field \(g_0(z)\),
the controlled vector fields \(g_i(z)\),
the output function \(h(z)\).
Example:
1using Symbolics
2
3@variables x[1:6]
4z_vec = x
5
6Ntrunc = 4
7
8h = x[1]
9
10# parameters
11gg = 9.81 # Gravitational acceleration (m/s^2)
12m = 0.18 # Mass (kg)
13Ixx = 0.00025 # Mass moment of inertia (kg*m^2)
14L = 0.086 # Arm length (m)
15
16
17g = hcat(
18 [x[4], x[5], x[6], 0, -gg, 0],
19 [0, 0, 0, 1/m*sin(x[3]), 1/m*cos(x[3]), -L/Ixx],
20 [0, 0, 0, 1/m*sin(x[3]), 1/m*cos(x[3]), L/Ixx]
21)
Computing Lie derivatives
Lie derivatives encode the geometric structure of the system.
1x_val = [0.5, 0.0, 0.1, 0.0, 0.0, 0.0] # make it Float64 to avoid promotion issues
2
3# initial evaluator for Ntrunc = 4
4f_L = build_lie_evaluator(h, g, x_vec, Ntrunc)
5L_eval = f_L(x_val) # Vector{Float64}, no Symbolics anywhere
Similarly to the iterated integrals, the outline of the calculation of the algorithm follows the workflow:
flowchart TD
classDef step fill:#f2f2f2,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
classDef calc fill:#e8f0ff,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
classDef loop fill:#fff4d6,stroke:#333,stroke-width:1px,rx:6px,ry:6px,color:black;
A["Start<br/><span> $$\ ( g_i(z), h(z), N_{\text{trunc}})$$</span>"]:::step
H["Compute first-order Lie derivatives: <span> $$\ L_{X^1}h(z) $$</span>"]:::calc
I{"Loop i = 1 to Ntrunc-1"}:::loop
K["<span> $$\ \text{Ltemp} = \frac{\partial}{\partial z}L_{X^i}h(z) $$</span>"]:::calc
M["Compute: <span> $$\ g\otimes \text{Ltemp} $$</span>"]:::calc
N["Store <span> $$\ L_{X^{i+1}}h(z) $$</span>"]:::step
O["Return the Lie derivative block"]:::step
%% Connections
A --> H --> I
I --> K --> M
M --> N --> I
I --> O
Computing truncated Chen–Fliess series
Once iterated integrals and Lie derivatives are available, you can assemble the truncated Chen–Fliess series:
1Fc = z_val[1] .+ vec(L_eval' * E)
This returns a numerical approximation of
Comparing with ODE simulation
To validate the approximation, compare it with the true system output.
1using DifferentialEquations
2
3function twodquad!(dx, x, p, t)
4 # input u1(t)
5 u1 = sin(t) # scalar, t is a Float64 here
6 u2 = cos(t)
7
8 # same dynamics as symbolic g, but numeric
9 dx[1] = x[4]
10 dx[2] = x[5]
11 dx[3] = x[6]
12 dx[4] = 1/m*sin(x[3])*(u1+u2)
13 dx[5] = -gg + (1/m*cos(x[3]))*(u1+u2)
14 dx[6] = (L/Ixx)*(u2-u1)
15end
16
17x0 = [0.0, 0.0, 0.1, 0.0, 0.0, 0.0]
18tspan = (0.0, 0.1)
19
20prob = ODEProblem(twodquad!, x0, tspan)
21sol = solve(prob, Tsit5(), saveat = t)
22
23x1_ode = sol[1, :] # extract x₂(t), since h = x₂
24
25y_true = x1_ode
26y_cfs = Fc
Common pitfalls
Mismatched dimensions: Inputs must have shape (m+1, length(t)).
Transpose required: Use vcat(u0’, u1’, …).
Large truncation depth: Word count grows combinatorially.
Vector fields should be symbolic for compliance.
Indexing inside ODE solvers must match the time grid.
More examples
For more detailed examples and advanced usage, see the examples section of the documentation.