You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/manual-initial-guess.md
+150Lines changed: 150 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -56,6 +56,7 @@ nothing # hide
56
56
57
57
- The `@init` macro uses the **labels** declared in the `@def` block. For `ocp1`, you can use `x`, `x₁`, `x₂`, and `u`. For `ocp2`, you can use `x`, `q`, `v`, `u`, and `tf`.
58
58
- The `@init` macro uses the **time variable name** from the `@def` block. For `ocp1`, use `t` (e.g., `x(t) := ...`). For `ocp2`, use `s` (e.g., `q(s) := ...`).
59
+
- When components are **not explicitly named** in `@def` (as in `ocp1` with `x ∈ R²`), they receive **default labels with subscripted indices**: `x₁`, `x₂`, etc. These default names are usable in `@init` just like custom labels.
59
60
- This allows for more readable initial guess specifications that match your problem definition.
60
61
61
62
## Default initial guess
@@ -156,6 +157,43 @@ where `T = [0.0, 0.5, 1.0]` is the time grid.
156
157
- **Variables** and **aliases**: no time argument
157
158
- **Constant functions**: use either `u(t) := 2` or the simplified `u := 2`
158
159
160
+
### Syntax rules
161
+
162
+
The left-hand side of `:=` and `=` follow strict rules.
163
+
164
+
**Left-hand side of `:=`** : only **labels declared in the optimal control problem**:
165
+
166
+
- the **time variable name** declared in `@def` (`t`, `s`, ...), used as the argument of state/control functions
167
+
- the **state, control or variable** label, either its global name (`x`, `u`, `tf`) or the name of one of its **components** (`q`, `v`, `x₁`, `x₂`, ...)
168
+
169
+
**Left-hand side of `=`** : arbitrary **alias names**, local to the `@init` block. Aliases are not labels of the problem; they are just convenient names to factor out constants or subexpressions.
170
+
171
+
**Right-hand side** : any Julia expression, which may reference the time variable, previously defined aliases, and other labels defined earlier in the block (see [Cross-spec substitution](@ref cross-spec-substitution)).
172
+
173
+
#### Default component names
174
+
175
+
When components are not explicitly named in `@def`, they receive default labels with subscripted indices. For example, `ocp1` declares `x ∈ R²` without naming the components, so the default labels `x₁` and `x₂` are used:
176
+
177
+
```@example main
178
+
# use default component names x₁, x₂
179
+
ig = @init ocp1 begin
180
+
x₁(t) := -1.0 + t/10
181
+
x₂(t) := 0.0
182
+
u(t) := -0.2
183
+
end
184
+
185
+
sol = solve(ocp1; init=ig, display=false)
186
+
println("Number of iterations: ", iterations(sol))
187
+
nothing # hide
188
+
```
189
+
190
+
#### No indexed syntax
191
+
192
+
The indexed syntax `x[i](t)` or `x[i:j](t)` is **not supported** on the left-hand side of `:=`. `@init` works at the level of labels, not array indices.
Specifications inside a single `@init` block can **reference each other**, from top to bottom. A label defined on an earlier line can be reused in the right-hand side of a later specification.
319
+
320
+
Rules:
321
+
322
+
- A reference only resolves to a label (or alias) defined **earlier** in the block.
323
+
- Substitution happens by name: the referenced label is replaced by its definition when the later expression is evaluated.
324
+
- References across different grid arguments are **not substituted** (see note at the end of this section).
325
+
326
+
#### Temporal → temporal
327
+
328
+
A time-dependent spec can reference another time-dependent spec:
329
+
330
+
```@example main
331
+
# v depends on q
332
+
ig = @init ocp2 begin
333
+
q(s) := sin(s)
334
+
v(s) := 1.0 + q(s)
335
+
u(s) := 0.0
336
+
tf := 2.0
337
+
end
338
+
339
+
sol = solve(ocp2; init=ig, display=false)
340
+
println("Number of iterations: ", iterations(sol))
println("Number of iterations: ", iterations(sol))
359
+
nothing # hide
360
+
```
361
+
362
+
#### Constant → temporal
363
+
364
+
A temporal spec can reference a constant-valued component defined earlier:
365
+
366
+
```@example main
367
+
# v(s) uses the constant value of q
368
+
ig = @init ocp2 begin
369
+
q := -1.0
370
+
v(s) := q + sin(s)
371
+
u(s) := 0.0
372
+
tf := 2.0
373
+
end
374
+
375
+
sol = solve(ocp2; init=ig, display=false)
376
+
println("Number of iterations: ", iterations(sol))
377
+
nothing # hide
378
+
```
379
+
380
+
#### Constant → constant
381
+
382
+
A constant spec can reference another constant, including for variable components. Here we define a small OCP whose variable has two components `(tf, a)`:
383
+
384
+
```@example main
385
+
ocp_var2 = @def begin
386
+
w = (tf, a) ∈ R², variable
387
+
t ∈ [0, 1], time
388
+
x ∈ R, state
389
+
u ∈ R, control
390
+
x(0) == 0
391
+
x(1) == a
392
+
ẋ(t) == u(t)
393
+
∫(0.5u(t)^2) → min
394
+
end
395
+
396
+
ig = @init ocp_var2 begin
397
+
tf := 1.0
398
+
a := tf + 0.5
399
+
end
400
+
401
+
w = variable(ig)
402
+
println("tf = ", w[1], ", a = ", w[2])
403
+
nothing # hide
404
+
```
405
+
406
+
#### Mixing aliases and cross-spec references
407
+
408
+
Aliases (with `=`) and cross-spec references (with `:=`) can be freely combined:
409
+
410
+
```@example main
411
+
ig = @init ocp2 begin
412
+
A = 2.0 # alias
413
+
q(s) := A * sin(s) # uses alias
414
+
v(s) := q(s) + 1.0 # references q
415
+
u(s) := 0.0
416
+
tf := 2.0
417
+
end
418
+
419
+
sol = solve(ocp2; init=ig, display=false)
420
+
println("Number of iterations: ", iterations(sol))
421
+
nothing # hide
422
+
```
423
+
424
+
!!! note "No substitution across grid specs"
425
+
426
+
When a spec uses a **grid argument** (e.g. `q(T) := Dq` with `T` a time vector), it is not substituted into other temporal specs written with the time variable (`v(s) := ...`). The two live in different evaluation contexts. Use either temporal functions throughout, or grids throughout, when you need to chain references.
427
+
278
428
## Vector initial guess (interpolated)
279
429
280
430
You can provide initial values on a time grid using the syntax `label(T) := data`, where `T` is a time vector and `data` contains the corresponding values.
0 commit comments