Skip to content

Commit 6a3d7ce

Browse files
committed
modify the dual solution that stores the slack and dual trajectory
1 parent 666b81d commit 6a3d7ce

File tree

4 files changed

+66
-27
lines changed

4 files changed

+66
-27
lines changed

ocs2_ipm/include/ocs2_ipm/IpmHelpers.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3030
#pragma once
3131

3232
#include <ocs2_core/Types.h>
33+
#include <ocs2_oc/multiple_shooting/Transcription.h>
3334
#include <ocs2_oc/oc_data/DualSolution.h>
3435
#include <ocs2_oc/oc_data/TimeDiscretization.h>
3536
#include <ocs2_oc/oc_problem/OptimalControlProblem.h>
@@ -113,14 +114,16 @@ scalar_t fractionToBoundaryStepSize(const vector_t& v, const vector_t& dv, scala
113114
* Convert the optimized slack or dual trajectories as a DualSolution.
114115
*
115116
* @param time: The time discretization.
117+
* @param constraintsSize: The constraint tems size.
116118
* @param slackStateIneq: The slack variable trajectory of the state inequality constraints.
117119
* @param dualStateIneq: The dual variable trajectory of the state inequality constraints.
118120
* @param slackStateInputIneq: The slack variable trajectory of the state-input inequality constraints.
119121
* @param dualStateInputIneq: The dual variable trajectory of the state-input inequality constraints.
120122
* @return A dual solution.
121123
*/
122-
DualSolution toDualSolution(const std::vector<AnnotatedTime>& time, vector_array_t&& slackStateIneq, vector_array_t&& dualStateIneq,
123-
vector_array_t&& slackStateInputIneq, vector_array_t&& dualStateInputIneq);
124+
DualSolution toDualSolution(const std::vector<AnnotatedTime>& time, const std::vector<multiple_shooting::ConstraintsSize>& constraintsSize,
125+
const vector_array_t& slackStateIneq, const vector_array_t& dualStateIneq,
126+
const vector_array_t& slackStateInputIneq, const vector_array_t& dualStateInputIneq);
124127

125128
/**
126129
* Extracts a slack variable of the state-only and state-input constraints from a MultiplierCollection
@@ -131,7 +134,7 @@ DualSolution toDualSolution(const std::vector<AnnotatedTime>& time, vector_array
131134
* @param[out] slackStateInputIneq: The slack variable of the state-input inequality constraints.
132135
* @param[out] dualStateInputIneq: The dual variable of the state-input inequality constraints.
133136
*/
134-
void toSlackDual(MultiplierCollection&& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq,
137+
void toSlackDual(const MultiplierCollection& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq,
135138
vector_t& slackStateInputIneq, vector_t& dualStateInputIneq);
136139

137140
/**
@@ -141,7 +144,7 @@ void toSlackDual(MultiplierCollection&& multiplierCollection, vector_t& slackSta
141144
* @param[out] slackStateIneq: The slack variable of the state inequality constraints.
142145
* @param[out] dualStateIneq: The dual variable of the state inequality constraints.
143146
*/
144-
void toSlackDual(MultiplierCollection&& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq);
147+
void toSlackDual(const MultiplierCollection& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq);
145148

146149
} // namespace ipm
147150
} // namespace ocs2

ocs2_ipm/include/ocs2_ipm/IpmSolver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3535
#include <ocs2_core/thread_support/ThreadPool.h>
3636

3737
#include <ocs2_oc/multiple_shooting/ProjectionMultiplierCoefficients.h>
38+
#include <ocs2_oc/multiple_shooting/Transcription.h>
3839
#include <ocs2_oc/oc_data/TimeDiscretization.h>
3940
#include <ocs2_oc/oc_problem/OptimalControlProblem.h>
4041
#include <ocs2_oc/oc_solver/SolverBase.h>
@@ -214,6 +215,9 @@ class IpmSolver : public SolverBase {
214215
std::vector<VectorFunctionLinearApproximation> stateInputIneqConstraints_;
215216
std::vector<VectorFunctionLinearApproximation> constraintsProjection_;
216217

218+
// Constraint terms size
219+
std::vector<multiple_shooting::ConstraintsSize> constraintsSize_;
220+
217221
// Lagrange multipliers
218222
std::vector<multiple_shooting::ProjectionMultiplierCoefficients> projectionMultiplierCoefficients_;
219223

ocs2_ipm/src/IpmHelpers.cpp

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -114,32 +114,61 @@ scalar_t fractionToBoundaryStepSize(const vector_t& v, const vector_t& dv, scala
114114
}
115115

116116
namespace {
117-
MultiplierCollection toMultiplierCollection(vector_t&& slackStateIneq, vector_t&& dualStateIneq,
118-
vector_t&& slackStateInputIneq = vector_t(), vector_t&& dualStateInputIneq = vector_t()) {
117+
MultiplierCollection toMultiplierCollection(const multiple_shooting::ConstraintsSize constraintsSize, const vector_t& slackStateIneq,
118+
const vector_t& dualStateIneq) {
119119
MultiplierCollection multiplierCollection;
120-
multiplierCollection.stateIneq.emplace_back(0.0, std::move(slackStateIneq));
121-
multiplierCollection.stateEq.emplace_back(0.0, std::move(dualStateIneq));
122-
multiplierCollection.stateInputIneq.emplace_back(0.0, std::move(slackStateInputIneq));
123-
multiplierCollection.stateInputEq.emplace_back(0.0, std::move(dualStateInputIneq));
120+
size_t head = 0;
121+
for (const size_t size : constraintsSize.stateIneq) {
122+
multiplierCollection.stateIneq.emplace_back(0.0, slackStateIneq.segment(head, size));
123+
multiplierCollection.stateEq.emplace_back(0.0, dualStateIneq.segment(head, size));
124+
head += size;
125+
}
126+
return multiplierCollection;
127+
}
128+
129+
MultiplierCollection toMultiplierCollection(const multiple_shooting::ConstraintsSize constraintsSize, const vector_t& slackStateIneq,
130+
const vector_t& dualStateIneq, const vector_t& slackStateInputIneq,
131+
const vector_t& dualStateInputIneq) {
132+
MultiplierCollection multiplierCollection = toMultiplierCollection(constraintsSize, slackStateIneq, dualStateIneq);
133+
size_t head = 0;
134+
for (const size_t size : constraintsSize.stateInputIneq) {
135+
multiplierCollection.stateInputIneq.emplace_back(0.0, slackStateInputIneq.segment(head, size));
136+
multiplierCollection.stateInputEq.emplace_back(0.0, dualStateInputIneq.segment(head, size));
137+
}
124138
return multiplierCollection;
125139
}
140+
141+
vector_t extractLagrangian(const std::vector<Multiplier>& termsMultiplier) {
142+
size_t n = 0;
143+
std::for_each(termsMultiplier.begin(), termsMultiplier.end(), [&](const Multiplier& m) { n += m.lagrangian.size(); });
144+
145+
vector_t vec(n);
146+
size_t head = 0;
147+
for (const auto& m : termsMultiplier) {
148+
vec.segment(head, m.lagrangian.size()) = m.lagrangian;
149+
head += m.lagrangian.size();
150+
} // end of i loop
151+
152+
return vec;
153+
}
126154
} // namespace
127155

128-
void toSlackDual(MultiplierCollection&& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq,
156+
void toSlackDual(const MultiplierCollection& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq,
129157
vector_t& slackStateInputIneq, vector_t& dualStateInputIneq) {
130-
slackStateIneq = std::move(multiplierCollection.stateIneq.front().lagrangian);
131-
dualStateIneq = std::move(multiplierCollection.stateEq.front().lagrangian);
132-
slackStateInputIneq = std::move(multiplierCollection.stateInputIneq.front().lagrangian);
133-
dualStateInputIneq = std::move(multiplierCollection.stateInputEq.front().lagrangian);
158+
slackStateIneq = extractLagrangian(multiplierCollection.stateIneq);
159+
dualStateIneq = extractLagrangian(multiplierCollection.stateEq);
160+
slackStateInputIneq = extractLagrangian(multiplierCollection.stateInputIneq);
161+
dualStateInputIneq = extractLagrangian(multiplierCollection.stateInputEq);
134162
}
135163

136-
void toSlackDual(MultiplierCollection&& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq) {
137-
slackStateIneq = std::move(multiplierCollection.stateIneq.front().lagrangian);
138-
dualStateIneq = std::move(multiplierCollection.stateEq.front().lagrangian);
164+
void toSlackDual(const MultiplierCollection& multiplierCollection, vector_t& slackStateIneq, vector_t& dualStateIneq) {
165+
slackStateIneq = extractLagrangian(multiplierCollection.stateIneq);
166+
dualStateIneq = extractLagrangian(multiplierCollection.stateEq);
139167
}
140168

141-
DualSolution toDualSolution(const std::vector<AnnotatedTime>& time, vector_array_t&& slackStateIneq, vector_array_t&& dualStateIneq,
142-
vector_array_t&& slackStateInputIneq, vector_array_t&& dualStateInputIneq) {
169+
DualSolution toDualSolution(const std::vector<AnnotatedTime>& time, const std::vector<multiple_shooting::ConstraintsSize>& constraintsSize,
170+
const vector_array_t& slackStateIneq, const vector_array_t& dualStateIneq,
171+
const vector_array_t& slackStateInputIneq, const vector_array_t& dualStateInputIneq) {
143172
// Problem horizon
144173
const int N = static_cast<int>(time.size()) - 1;
145174

@@ -152,14 +181,14 @@ DualSolution toDualSolution(const std::vector<AnnotatedTime>& time, vector_array
152181

153182
for (int i = 0; i < N; ++i) {
154183
if (time[i].event == AnnotatedTime::Event::PreEvent) {
155-
dualSolution.preJumps.emplace_back(toMultiplierCollection(std::move(slackStateIneq[i]), std::move(dualStateIneq[i])));
184+
dualSolution.preJumps.emplace_back(toMultiplierCollection(constraintsSize[i], slackStateIneq[i], dualStateIneq[i]));
156185
dualSolution.intermediates.push_back(dualSolution.intermediates.back()); // no event at the initial node
157186
} else {
158-
dualSolution.intermediates.emplace_back(toMultiplierCollection(std::move(slackStateIneq[i]), std::move(dualStateIneq[i]),
159-
std::move(slackStateInputIneq[i]), std::move(dualStateInputIneq[i])));
187+
dualSolution.intermediates.emplace_back(
188+
toMultiplierCollection(constraintsSize[i], slackStateIneq[i], dualStateIneq[i], slackStateInputIneq[i], dualStateInputIneq[i]));
160189
}
161190
}
162-
dualSolution.final = toMultiplierCollection(std::move(slackStateIneq[N]), std::move(dualStateIneq[N]));
191+
dualSolution.final = toMultiplierCollection(constraintsSize[N], slackStateIneq[N], dualStateIneq[N]);
163192
dualSolution.intermediates.push_back(dualSolution.intermediates.back());
164193

165194
return dualSolution;

ocs2_ipm/src/IpmSolver.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3939
#include <ocs2_oc/multiple_shooting/LagrangianEvaluation.h>
4040
#include <ocs2_oc/multiple_shooting/MetricsComputation.h>
4141
#include <ocs2_oc/multiple_shooting/PerformanceIndexComputation.h>
42-
#include <ocs2_oc/multiple_shooting/Transcription.h>
4342
#include <ocs2_oc/oc_problem/OcpSize.h>
4443
#include <ocs2_oc/trajectory_adjustment/TrajectorySpreadingHelperFunctions.h>
4544

@@ -282,8 +281,8 @@ void IpmSolver::runImpl(scalar_t initTime, const vector_t& initState, scalar_t f
282281
primalSolution_ = toPrimalSolution(timeDiscretization, std::move(x), std::move(u));
283282
costateTrajectory_ = std::move(lmd);
284283
projectionMultiplierTrajectory_ = std::move(nu);
285-
slackDualTrajectory_ = ipm::toDualSolution(timeDiscretization, std::move(slackStateIneq), std::move(dualStateIneq),
286-
std::move(slackStateInputIneq), std::move(dualStateInputIneq));
284+
slackDualTrajectory_ =
285+
ipm::toDualSolution(timeDiscretization, constraintsSize_, slackStateIneq, dualStateIneq, slackStateInputIneq, dualStateInputIneq);
287286
problemMetrics_ = multiple_shooting::toProblemMetrics(timeDiscretization, std::move(metrics));
288287
computeControllerTimer_.endTimer();
289288

@@ -635,6 +634,7 @@ PerformanceIndex IpmSolver::setupQuadraticSubproblem(const std::vector<Annotated
635634
stateInputIneqConstraints_.resize(N + 1);
636635
constraintsProjection_.resize(N);
637636
projectionMultiplierCoefficients_.resize(N);
637+
constraintsSize_.resize(N + 1);
638638
metrics.resize(N + 1);
639639

640640
std::atomic_int timeIndex{0};
@@ -655,6 +655,7 @@ PerformanceIndex IpmSolver::setupQuadraticSubproblem(const std::vector<Annotated
655655
stateInputIneqConstraints_[i].resize(0, x[i].size());
656656
constraintsProjection_[i].resize(0, x[i].size());
657657
projectionMultiplierCoefficients_[i] = multiple_shooting::ProjectionMultiplierCoefficients();
658+
constraintsSize_[i] = std::move(result.constraintsSize);
658659
if (settings_.computeLagrangeMultipliers) {
659660
lagrangian_[i] = multiple_shooting::evaluateLagrangianEventNode(lmd[i], lmd[i + 1], std::move(result.cost), dynamics_[i]);
660661
} else {
@@ -684,6 +685,7 @@ PerformanceIndex IpmSolver::setupQuadraticSubproblem(const std::vector<Annotated
684685
stateInputIneqConstraints_[i] = std::move(result.stateInputIneqConstraints);
685686
constraintsProjection_[i] = std::move(result.constraintsProjection);
686687
projectionMultiplierCoefficients_[i] = std::move(result.projectionMultiplierCoefficients);
688+
constraintsSize_[i] = std::move(result.constraintsSize);
687689
if (settings_.computeLagrangeMultipliers) {
688690
lagrangian_[i] = multiple_shooting::evaluateLagrangianIntermediateNode(lmd[i], lmd[i + 1], nu[i], std::move(result.cost),
689691
dynamics_[i], stateInputEqConstraints_[i]);
@@ -711,6 +713,7 @@ PerformanceIndex IpmSolver::setupQuadraticSubproblem(const std::vector<Annotated
711713
performance[workerId] += ipm::computePerformanceIndex(result, barrierParam, slackStateIneq[N]);
712714
stateInputEqConstraints_[i].resize(0, x[i].size());
713715
stateIneqConstraints_[i] = std::move(result.ineqConstraints);
716+
constraintsSize_[i] = std::move(result.constraintsSize);
714717
if (settings_.computeLagrangeMultipliers) {
715718
lagrangian_[i] = multiple_shooting::evaluateLagrangianTerminalNode(lmd[i], std::move(result.cost));
716719
} else {

0 commit comments

Comments
 (0)