Skip to content

Commit 39604d3

Browse files
Fix warm-start handling in constrained solvers
Reuse solver state across repeated constrained solves so warm starts can keep their gains, and refresh ALDDP slack controls when a new trajectory seed is supplied. Simplify LogDDP barrier evaluation for single-shooting mode and add regression tests for reseeded trajectories and invalid rollout options.
1 parent fc76f09 commit 39604d3

7 files changed

Lines changed: 419 additions & 496 deletions

File tree

include/cddp-cpp/cddp_core/barrier.hpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ class RelaxedLogBarrier {
5959
* @return Barrier function value.
6060
*/
6161
double evaluate(const Constraint &constraint, const Eigen::VectorXd &state,
62-
const Eigen::VectorXd &control) const {
63-
Eigen::VectorXd g_val = constraint.evaluate(state, control);
62+
const Eigen::VectorXd &control, int index = 0) const {
63+
Eigen::VectorXd g_val = constraint.evaluate(state, control, index);
6464
Eigen::VectorXd L = constraint.getLowerBound();
6565
Eigen::VectorXd U = constraint.getUpperBound();
6666
int constraint_dim = g_val.size();
@@ -99,13 +99,13 @@ class RelaxedLogBarrier {
9999
*/
100100
std::tuple<Eigen::VectorXd, Eigen::VectorXd>
101101
getGradients(const Constraint &constraint, const Eigen::VectorXd &state,
102-
const Eigen::VectorXd &control) const {
102+
const Eigen::VectorXd &control, int index = 0) const {
103103

104-
Eigen::VectorXd g_val = constraint.evaluate(state, control);
104+
Eigen::VectorXd g_val = constraint.evaluate(state, control, index);
105105
Eigen::VectorXd L = constraint.getLowerBound();
106106
Eigen::VectorXd U = constraint.getUpperBound();
107-
Eigen::MatrixXd Gx = constraint.getStateJacobian(state, control);
108-
Eigen::MatrixXd Gu = constraint.getControlJacobian(state, control);
107+
Eigen::MatrixXd Gx = constraint.getStateJacobian(state, control, index);
108+
Eigen::MatrixXd Gu = constraint.getControlJacobian(state, control, index);
109109

110110
int state_dim = state.size();
111111
int control_dim = control.size();
@@ -151,13 +151,13 @@ class RelaxedLogBarrier {
151151
*/
152152
std::tuple<Eigen::MatrixXd, Eigen::MatrixXd, Eigen::MatrixXd>
153153
getHessians(const Constraint &constraint, const Eigen::VectorXd &state,
154-
const Eigen::VectorXd &control) const {
154+
const Eigen::VectorXd &control, int index = 0) const {
155155

156-
Eigen::VectorXd g_val = constraint.evaluate(state, control);
156+
Eigen::VectorXd g_val = constraint.evaluate(state, control, index);
157157
Eigen::VectorXd L = constraint.getLowerBound();
158158
Eigen::VectorXd U = constraint.getUpperBound();
159-
Eigen::MatrixXd Gx = constraint.getStateJacobian(state, control);
160-
Eigen::MatrixXd Gu = constraint.getControlJacobian(state, control);
159+
Eigen::MatrixXd Gx = constraint.getStateJacobian(state, control, index);
160+
Eigen::MatrixXd Gu = constraint.getControlJacobian(state, control, index);
161161

162162
int state_dim = state.size();
163163
int control_dim = control.size();
@@ -171,7 +171,7 @@ class RelaxedLogBarrier {
171171
Gux_constraint_vec;
172172
bool constraint_provides_hessians = true;
173173
try {
174-
auto hess_tuple = constraint.getHessians(state, control);
174+
auto hess_tuple = constraint.getHessians(state, control, index);
175175
Gxx_constraint_vec = std::get<0>(hess_tuple);
176176
Guu_constraint_vec = std::get<1>(hess_tuple);
177177
Gux_constraint_vec = std::get<2>(hess_tuple);
@@ -536,4 +536,4 @@ class DiscreteBarrierState {
536536

537537
} // namespace cddp
538538

539-
#endif // CDDP_BARRIER_HPP
539+
#endif // CDDP_BARRIER_HPP

include/cddp-cpp/cddp_core/logddp_solver.hpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,6 @@ class LogDDPSolver : public CDDPSolverBase {
5656
void printIteration(int iter, const CDDP &context) const override;
5757

5858
private:
59-
// Dynamics storage (forward-simulated trajectory)
60-
std::vector<Eigen::VectorXd> F_;
61-
62-
// Constraint values g(x,u) - g_ub
63-
std::map<std::string, std::vector<Eigen::VectorXd>> G_;
64-
6559
// Log-barrier method
6660
std::unique_ptr<RelaxedLogBarrier> relaxed_log_barrier_;
6761
double mu_;
@@ -70,9 +64,6 @@ class LogDDPSolver : public CDDPSolverBase {
7064
// Filter-based line search
7165
double constraint_violation_;
7266

73-
// Multi-shooting parameters
74-
int ms_segment_length_;
75-
7667
/**
7768
* @brief Evaluate trajectory by computing cost, dynamics, and merit function.
7869
*/
@@ -82,6 +73,22 @@ class LogDDPSolver : public CDDPSolverBase {
8273
* @brief Reset/initialize the filter for line search.
8374
*/
8475
void resetFilter(CDDP &context);
76+
77+
void augmentRunningCostDerivatives(
78+
const CDDP &context, int t, const Eigen::VectorXd &x,
79+
const Eigen::VectorXd &u, Eigen::VectorXd &l_x, Eigen::VectorXd &l_u,
80+
Eigen::MatrixXd &l_xx, Eigen::MatrixXd &l_uu,
81+
Eigen::MatrixXd &l_ux) const;
82+
83+
void augmentTerminalCostDerivatives(const CDDP &context,
84+
const Eigen::VectorXd &x_N,
85+
Eigen::VectorXd &V_x,
86+
Eigen::MatrixXd &V_xx) const;
87+
88+
double computeBarrierMerit(const CDDP &context,
89+
const std::vector<Eigen::VectorXd> &X,
90+
const std::vector<Eigen::VectorXd> &U,
91+
double *max_constraint_violation = nullptr) const;
8592
};
8693

8794
} // namespace cddp

src/cddp_core/alddp_solver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ void ALDDPSolver::initialize(CDDP &context) {
6363
<< std::endl;
6464
}
6565
boxqp_solver_.setOptions(options.box_qp);
66+
// The solver state (gains, multipliers, penalties) is reused, but the
67+
// current seeded trajectory may have changed since the last solve.
68+
// Refresh slack controls so warm starts remain consistent with the
69+
// current X/U pair, including dynamically infeasible reseeds.
70+
initializeSlackControls(context);
6671
if (!context.X_.empty() && !context.U_.empty()) {
6772
computeCost(context);
6873
}

src/cddp_core/cddp_core.cpp

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,26 @@ std::string solverTypeToString(SolverType solver_type) {
269269
return "CLDDP"; // Default fallback
270270
}
271271
}
272+
273+
std::string canonicalizeSolverType(const std::string &solver_type) {
274+
if (solver_type == "CLCDDP" || solver_type == "CLDDP") {
275+
return "CLDDP";
276+
}
277+
if (solver_type == "LogDDP" || solver_type == "LOGDDP") {
278+
return "LogDDP";
279+
}
280+
if (solver_type == "IPDDP") {
281+
return "IPDDP";
282+
}
283+
if (solver_type == "MSIPDDP") {
284+
return "MSIPDDP";
285+
}
286+
if (solver_type == "ALDDP") {
287+
return "ALDDP";
288+
}
289+
290+
return solver_type;
291+
}
272292
} // namespace
273293

274294
CDDPSolution CDDP::solve(SolverType solver_type) {
@@ -302,25 +322,30 @@ CDDP::createSolver(const std::string &solver_type) {
302322

303323
CDDPSolution CDDP::solve(const std::string &solver_type) {
304324
// This is where strategy selection and invocation will happen.
325+
const std::string canonical_solver_type = canonicalizeSolverType(solver_type);
305326

306327
initializeProblemIfNecessary(); // Ensure X_, U_ are sized etc.
307328

308-
// Strategy selection and instantiation
309-
solver_ = createSolver(solver_type);
329+
// Preserve solver state across repeated solves with the same algorithm so
330+
// warm-start options can reuse stored gains.
331+
if (!solver_ || solver_->getSolverName() != canonical_solver_type) {
332+
solver_ = createSolver(canonical_solver_type);
333+
}
310334

311335
if (!solver_) {
312336
// Solver not found - return error solution
313337
CDDPSolution solution;
314-
solution.solver_name = solver_type;
338+
solution.solver_name = canonical_solver_type;
315339
solution.status_message =
316-
"UnknownSolver - No solver registered for '" + solver_type + "'";
340+
"UnknownSolver - No solver registered for '" + canonical_solver_type +
341+
"'";
317342
solution.iterations_completed = 0;
318343
solution.solve_time_ms = 0.0;
319344
solution.final_objective = 0.0;
320345
solution.final_step_length = 1.0;
321346

322347
if (options_.verbose) {
323-
std::cout << "Solver type '" << solver_type
348+
std::cout << "Solver type '" << canonical_solver_type
324349
<< "' not found. Available solvers: ";
325350
auto available = getRegisteredSolvers();
326351
for (const auto &name : available) {

0 commit comments

Comments
 (0)