What to build
With bounds now living directly on each ControlParameter (#92) and TunableParameter (#93) leaf, implement get_bounds as a pure tree-walk over a named ps-shaped NamedTuple (e.g. (; u0 = (node1 = (;x₁=...), ...), controls = (; k=..., u₁=...))), pulling .bounds off each leaf and returning (lb, ub) with exactly the same nested shape as ps itself.
There should be no separate bounds-shaped data structure to keep in sync — lb/ub fall out mechanically from mapping "extract bounds" over the same tree that ps already is, so whatever vectorizer (e.g. the ComponentArrays extension) flattens ps for the optimizer can flatten lb/ub identically.
Acceptance criteria
Blocked by
What to build
With bounds now living directly on each
ControlParameter(#92) andTunableParameter(#93) leaf, implementget_boundsas a pure tree-walk over a namedps-shapedNamedTuple(e.g.(; u0 = (node1 = (;x₁=...), ...), controls = (; k=..., u₁=...))), pulling.boundsoff each leaf and returning(lb, ub)with exactly the same nested shape aspsitself.There should be no separate bounds-shaped data structure to keep in sync —
lb/ubfall out mechanically from mapping "extract bounds" over the same tree thatpsalready is, so whatever vectorizer (e.g. theComponentArraysextension) flattenspsfor the optimizer can flattenlb/ubidentically.Acceptance criteria
get_bounds(ps)returns(lb, ub)congruent in shape/keys topsControlParameterandTunableParameterleaves without per-type special-casing at call sitesu0/controlstreesBlocked by