Having multiple solutions, automatic publishing of intermediate solutions is confusing.
One never knows, which one is the final one. If desired, the user should setup a hook for this.
To move a task instance to another one, it's not sufficient to swap all task members,
but we also need to adapt all back pointers, i.e. me_ and parent_ pointers of children,
to point to the (swapped) task instances.
- solutions_, failures_ as SolutionBaseConstPtrs in StagePrivate
- replace processSolutions() / processFailures() by direct const-access to storage containers
- generic sendForward(), sendBackward(), spawn(), connect() methods in StagePrivate
- reuse StagePrivate's sendForward(), sendBackward(), spawn() in containers
- store created InterfaceStates in StagePrivate::states_
- Interface: ordered<InterfaceState*> (only store pointers)
allows for common handling of states of valid and failure solutions
- remove additional state+solution storages
- containers: internal->external state mapping as InterfaceState* -> InterfaceState*
- remove bool return value
- always create a solution trajectory, also in case of failures
- success/failure determined from solution.isFailure()
minor adjustments during cherry-pick
- postpone pruning / interface auto-detection to top task-level
only the task state knows for sure, that it requires its wrapped child to push to both ends
- perform connectivity validation only after pruning
only then, we the interfaces are completely determined
Establishing the interface connections, we face a chicken-egg-problem:
To establish a connection, a predecessors/successors pull interface is
assigned to the current's stage push interface.
However, propagating stages (in auto-detection mode) can only create
their pull interfaces if the corresponding, opposite-side push interface
is present already (because that's the mechanism to determine the supported
propagation directions).
Hence, we need to resolve this by performing two sweeps:
- initialization, assuming both propagation directions should be supported,
thus generating both pull interfaces, i.e. providing the egg
- stripping down the interfaces to the actual context
This context is provided by two stages pushing from both ends
into a (potentially long) sequence of propagating stages (tbd).
Contributions of this PR:
- PropagatingEitherWay: explicitly distinguish AUTO from BOTHWAYS interface
AUTO: auto-derive interface from provided push interfaces
BOTHWAYS: explicitly require both directions
- SerialContainer: (better, but not yet perfect) validation of connectivity
- ParallelContainer: determine interface from what children offer
- basic implementation for StagePrivate
- implementation for Stage calls this
- implementation for ContainerBase recursively calls this
- implementation for Task added
- store "failure" solutions to facilitate debugging
- Introspection assigns solution IDs as soon as they are created in a stage
Thus, solution IDs represent their creation order.
In contrast, the order of publishing (in StageStatistics) should
represent the cost order.
- Storing failures is disabled if Introspection is not available.
While ParallelContainers can directly promote their child solutions as
their own, a Wrapper needs to modify those solutions. Hence, Wrappers
should be derived directly from Container.