What to build
Extend the single-node pipeline (#97) to genuine multiple shooting: ps.u0 becomes a collection of named-state NamedTuples, one TunableParameter set per shooting node (#93) — the number of entries equals the number of shooting nodes (1 for plain single shooting). ps.controls stays a single flat/global named collection, not duplicated per node, since control breakpoints don't care where shooting nodes fall.
Build the full pipeline: ps.u0 (N entries) → Vector{TrajectoryInterval} of length N (coarse, one per node) → each split via #97's mechanism using the global ps.controls → Vector{Vector{TrajectoryInterval}} (outer = node, inner = control segment within that node). For this issue, solve the outer vector serially (parallel dispatch is #98).
Matching/continuity constraints between adjacent nodes are a simple pairwise comparison between consecutive nodes' boundary TrajectoryIntervals — last(intervals[i]).output (end state) vs intervals[i+1].ic (the next node's free IC) — touching only the outermost (first/last) elements of each node's inner segment vector. No separate shooting-bookkeeping field is needed (unlike today's Trajectory.shooting, populated during the stitching constructor in multiple_shooting.jl).
Acceptance criteria
Blocked by
What to build
Extend the single-node pipeline (#97) to genuine multiple shooting:
ps.u0becomes a collection of named-stateNamedTuples, oneTunableParameterset per shooting node (#93) — the number of entries equals the number of shooting nodes (1 for plain single shooting).ps.controlsstays a single flat/global named collection, not duplicated per node, since control breakpoints don't care where shooting nodes fall.Build the full pipeline:
ps.u0(N entries) →Vector{TrajectoryInterval}of length N (coarse, one per node) → each split via #97's mechanism using the globalps.controls→Vector{Vector{TrajectoryInterval}}(outer = node, inner = control segment within that node). For this issue, solve the outer vector serially (parallel dispatch is #98).Matching/continuity constraints between adjacent nodes are a simple pairwise comparison between consecutive nodes' boundary
TrajectoryIntervals —last(intervals[i]).output(end state) vsintervals[i+1].ic(the next node's free IC) — touching only the outermost (first/last) elements of each node's inner segment vector. No separateshooting-bookkeeping field is needed (unlike today'sTrajectory.shooting, populated during the stitching constructor inmultiple_shooting.jl).Acceptance criteria
ps.u0holds one named-stateNamedTupleper shooting node;ps.controlsremains global/unduplicatedVector{Vector{TrajectoryInterval}}pipeline builds correctly for 2+ nodesi+1is a pure function of two adjacentTrajectoryIntervals (previous node's last segmentoutput, next node's first segmentic)ps.u0/ps.controlsmatches a forward-mode/finite-difference referenceBlocked by