- 3.0.2 optimal control module.
CostFunctionTest.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 #define EIGEN_INITIALIZE_MATRICES_BY_NAN
9 #define DEBUG
10 
11 #include "compareCostFunctions.h"
12 
13 
14 const size_t state_dim = 12;
15 const size_t control_dim = 4;
16 
17 namespace ct {
18 namespace optcon {
19 namespace example {
20 
21 
22 template <size_t state_dim, size_t control_dim>
25 {
26  std::cout << "eval intermediate " << std::endl;
27  std::cout << costFunction.evaluateIntermediate() << std::endl << std::endl;
28  std::cout << costFunction2.evaluateIntermediate() << std::endl;
29 
30  std::cout << "eval terminal " << std::endl;
31  std::cout << costFunction.evaluateTerminal() << std::endl << std::endl;
32  std::cout << costFunction2.evaluateTerminal() << std::endl;
33 
34  std::cout << "eval stateDerivativeIntermediate " << std::endl;
35  std::cout << costFunction.stateDerivativeIntermediate() << std::endl << std::endl;
36  std::cout << costFunction2.stateDerivativeIntermediate() << std::endl;
37 
38  std::cout << "eval stateDerivativeIntermediate " << std::endl;
39  std::cout << costFunction.stateDerivativeTerminal() << std::endl << std::endl;
40  std::cout << costFunction2.stateDerivativeTerminal() << std::endl;
41 
42  std::cout << "eval stateSecondDerivativeIntermediate " << std::endl;
43  std::cout << costFunction.stateSecondDerivativeIntermediate() << std::endl << std::endl;
44  std::cout << costFunction2.stateSecondDerivativeIntermediate() << std::endl;
45 
46  std::cout << "eval stateSecondDerivativeTerminal " << std::endl;
47  std::cout << costFunction.stateSecondDerivativeTerminal() << std::endl << std::endl;
48  std::cout << costFunction2.stateSecondDerivativeTerminal() << std::endl;
49 
50  std::cout << "eval controlDerivativeIntermediate " << std::endl;
51  std::cout << costFunction.controlDerivativeIntermediate() << std::endl << std::endl;
52  std::cout << costFunction2.controlDerivativeIntermediate() << std::endl;
53 
54  std::cout << "eval controlDerivativeTerminal " << std::endl;
55  std::cout << costFunction.controlDerivativeTerminal() << std::endl << std::endl;
56  std::cout << costFunction2.controlDerivativeTerminal() << std::endl;
57 
58  std::cout << "eval controlSecondDerivativeIntermediate " << std::endl;
59  std::cout << costFunction.controlSecondDerivativeIntermediate() << std::endl << std::endl;
60  std::cout << costFunction2.controlSecondDerivativeIntermediate() << std::endl;
61 
62  std::cout << "eval controlSecondDerivativeIntermediate " << std::endl;
63  std::cout << costFunction.controlSecondDerivativeTerminal() << std::endl << std::endl;
64  std::cout << costFunction2.controlSecondDerivativeTerminal() << std::endl;
65 
66  std::cout << "eval stateControlDerivativeIntermediate " << std::endl;
67  std::cout << costFunction.stateControlDerivativeIntermediate() << std::endl << std::endl;
68  std::cout << costFunction2.stateControlDerivativeIntermediate() << std::endl;
69 
70  std::cout << "eval stateControlDerivativeTerminal " << std::endl;
71  std::cout << costFunction.stateControlDerivativeTerminal() << std::endl << std::endl;
72  std::cout << costFunction2.stateControlDerivativeTerminal() << std::endl;
73 
74  std::cout << "eval stateSecondDerivativeIntermediate " << std::endl;
75  std::cout << costFunction.stateSecondDerivativeIntermediate() << std::endl << std::endl;
76  std::cout << costFunction.stateSecondDerivativeIntermediate().transpose() << std::endl;
77 
78  std::cout << "eval controlSecondDerivativeIntermediate " << std::endl;
79  std::cout << costFunction.controlSecondDerivativeIntermediate() << std::endl << std::endl;
80  std::cout << costFunction.controlSecondDerivativeIntermediate().transpose() << std::endl;
81 }
82 
83 
84 TEST(CostFunctionTest, ADQuadraticTest)
85 {
86  const size_t nWeights = 2;
87  const size_t nTests = 10;
88 
90  CostFunctionAD<state_dim, control_dim> costFunctionAD;
91 
92  // intermediate cost terms
93  std::shared_ptr<TermQuadratic<state_dim, control_dim, double>> termQuadratic_interm(
95  std::shared_ptr<TermQuadratic<state_dim, control_dim, double, ct::core::ADCGScalar>> termQuadraticAD_interm(
97 
98  // final cost terms
99  std::shared_ptr<TermQuadratic<state_dim, control_dim, double>> termQuadratic_final(
101  std::shared_ptr<TermQuadratic<state_dim, control_dim, double, ct::core::ADCGScalar>> termQuadraticAD_final(
103 
104  costFunction.addIntermediateTerm(termQuadratic_interm, true);
105  costFunctionAD.addIntermediateADTerm(termQuadraticAD_interm, true);
106  costFunction.addFinalTerm(termQuadratic_final, true);
107  costFunctionAD.addFinalADTerm(termQuadraticAD_final, true);
108 
109  Eigen::Matrix<double, state_dim, state_dim> Q_interm;
110  Eigen::Matrix<double, state_dim, state_dim> Q_final;
111  Eigen::Matrix<double, control_dim, control_dim> R;
112 
115 
116  for (size_t i = 0; i < nWeights; i++)
117  {
118  try
119  {
120  Q_interm.setRandom();
121  Q_final.setRandom();
122  R.setRandom();
123  x_ref.setRandom();
124  u_ref.setRandom();
125 
126  if (i == 0)
127  {
128  Q_interm.setZero();
129  Q_final.setZero();
130  R.setZero();
131  x_ref.setZero();
132  u_ref.setZero();
133  }
134 
135  Q_interm += Q_interm.transpose().eval(); // make symmetric
136  R += R.transpose().eval(); // make symmetric
137  Q_final += Q_final.transpose().eval(); // make symmetric
138 
139  termQuadratic_interm->setWeights(Q_interm, R);
140  termQuadraticAD_interm->setWeights(Q_interm, R);
141  termQuadratic_interm->setStateAndControlReference(x_ref, u_ref);
142  termQuadraticAD_interm->setStateAndControlReference(x_ref, u_ref);
143 
144  termQuadratic_final->setWeights(Q_final, R);
145  termQuadraticAD_final->setWeights(Q_final, R);
146  termQuadratic_final->setStateAndControlReference(x_ref, u_ref);
147  termQuadraticAD_final->setStateAndControlReference(x_ref, u_ref);
148 
149  costFunctionAD.initialize();
150 
151  // create cloned cost function
152  std::shared_ptr<CostFunctionAD<state_dim, control_dim>> costFunctionAD_clone(costFunctionAD.clone());
153 
154  for (size_t j = 0; j < nTests; j++)
155  {
158  x.setRandom();
159  u.setRandom();
160 
161  if (j == 0)
162  {
163  x.setZero();
164  u.setZero();
165  }
166 
167  costFunction.setCurrentStateAndControl(x, u, 1.0);
168  costFunctionAD.setCurrentStateAndControl(x, u, 1.0);
169  costFunctionAD_clone->setCurrentStateAndControl(x, u, 1.0);
170 
171  // printCostFunctionOutput(costFunction, costFunctionAD);
172  compareCostFunctionOutput(costFunction, costFunctionAD);
173  compareCostFunctionOutput(costFunction, *costFunctionAD_clone);
174 
175  // now some manual assertions
176  ASSERT_TRUE(costFunction.stateDerivativeIntermediate().isApprox(2 * Q_interm * (x - x_ref)));
177  ASSERT_TRUE(costFunction.stateDerivativeTerminal().isApprox(2 * Q_final * (x - x_ref)));
178 
179  ASSERT_TRUE(costFunction.stateSecondDerivativeIntermediate().isApprox(2 * Q_interm));
180  ASSERT_TRUE(costFunction.stateSecondDerivativeTerminal().isApprox(2 * Q_final));
181 
182  ASSERT_TRUE(costFunction.controlDerivativeIntermediate().isApprox(2 * R * (u - u_ref)));
183 
184  ASSERT_TRUE(costFunction.controlSecondDerivativeIntermediate().isApprox(2 * R));
185  }
186  } catch (std::exception& e)
187  {
188  FAIL();
189  }
190  }
191 }
192 
193 
194 TEST(CostFunctionTest, ADQuadMultTest)
195 {
196  const size_t nWeights = 3;
197  const size_t nTests = 10;
198 
200  CostFunctionAD<state_dim, control_dim> costFunctionAD;
201 
202  std::shared_ptr<TermQuadMult<state_dim, control_dim, double>> termQuadMult(
204  std::shared_ptr<TermQuadMult<state_dim, control_dim, double, ct::core::ADCGScalar>> termQuadMultAD(
206 
207  std::shared_ptr<TermMixed<state_dim, control_dim, double>> termMixed(new TermMixed<state_dim, control_dim, double>);
208  std::shared_ptr<TermMixed<state_dim, control_dim, double, ct::core::ADCGScalar>> termMixedAD(
210 
211  costFunction.addIntermediateTerm(termQuadMult);
212  costFunctionAD.addIntermediateADTerm(termQuadMultAD);
213  costFunctionAD.initialize();
214 
215  Eigen::Matrix<double, state_dim, state_dim> Q;
216  Eigen::Matrix<double, control_dim, control_dim> R;
217  Eigen::Matrix<double, control_dim, state_dim> P;
218 
221 
222  for (size_t i = 0; i < nWeights; i++)
223  {
224  try
225  {
226  Q.setRandom();
227  R.setRandom();
228  P.setRandom();
229  x_ref.setRandom();
230  u_ref.setRandom();
231 
232  if (i == 0)
233  {
234  Q.setZero();
235  R.setZero();
236  P.setZero();
237  x_ref.setZero();
238  u_ref.setZero();
239  }
240 
241  if (i == 1)
242  {
243  Q.setIdentity();
244  R.setIdentity();
245  P.setZero();
246  x_ref.setConstant(10.0);
247  u_ref.setConstant(10.0);
248  }
249 
250  Q += Q.transpose().eval(); // make symmetric
251  R += R.transpose().eval(); // make symmetric
252 
253  termQuadMult->setWeights(Q, R);
254  termQuadMultAD->setWeights(Q, R);
255  termQuadMult->setStateAndControlReference(x_ref, u_ref);
256  termQuadMultAD->setStateAndControlReference(x_ref, u_ref);
257 
258  costFunctionAD.initialize();
259 
260  // create cloned cost function
261  std::shared_ptr<CostFunctionAD<state_dim, control_dim>> costFunctionAD_clone(costFunctionAD.clone());
262 
263  for (size_t j = 0; j < nTests; j++)
264  {
267  x.setRandom();
268  u.setRandom();
269  double t = 3.14;
270 
271  if (j == 0)
272  {
273  x.setZero();
274  u.setZero();
275  }
276 
277  costFunction.setCurrentStateAndControl(x, u, t);
278  costFunctionAD.setCurrentStateAndControl(x, u, t);
279  costFunctionAD_clone->setCurrentStateAndControl(x, u, t);
280 
281  compareCostFunctionOutput(costFunction, costFunctionAD);
282  compareCostFunctionOutput(*costFunctionAD_clone, costFunctionAD);
283  }
284  } catch (std::exception& e)
285  {
286  FAIL();
287  }
288  }
289 }
290 
291 
298 TEST(CostFunctionTest, TrackingTermTest)
299 {
300  const size_t state_dim = 12;
301  const size_t control_dim = 4;
302 
303  // analytical costfunction
304  std::shared_ptr<CostFunctionAnalytical<state_dim, control_dim>> costFunction(
306 
307  Eigen::Matrix<double, state_dim, state_dim> Q;
308  Eigen::Matrix<double, control_dim, control_dim> R;
309  Q.setIdentity();
310  R.setIdentity();
311 
312  // create a reference trajectory and fill it with random values
315  size_t trajSize = 50;
316  bool timeIsAbsolute = true;
317  for (size_t i = 0; i < trajSize; ++i)
318  {
319  stateTraj.push_back(core::StateVector<state_dim>::Random(), double(i), timeIsAbsolute);
320  controlTraj.push_back(core::ControlVector<control_dim>::Random(), double(i), timeIsAbsolute);
321  }
322 
323  std::shared_ptr<TermQuadTracking<state_dim, control_dim>> trackingTerm(new TermQuadTracking<state_dim, control_dim>(
324  Q, R, core::InterpolationType::LIN, core::InterpolationType::ZOH, true));
325 
326  trackingTerm->setStateAndControlReference(stateTraj, controlTraj);
327  costFunction->addIntermediateTerm(trackingTerm);
328 
331  x.setRandom();
332  u.setRandom();
333  double t = 0.0;
334 
335  costFunction->setCurrentStateAndControl(x, u, t);
336 
337  ASSERT_TRUE(costFunction->stateDerivativeIntermediateTest());
338  ASSERT_TRUE(costFunction->controlDerivativeIntermediateTest());
339 }
340 
344 TEST(CostFunctionTest, TermSmoothAbsTest)
345 {
346  const size_t state_dim = 12;
347  const size_t control_dim = 4;
348 
349  // analytical costfunction
350  std::shared_ptr<CostFunctionAnalytical<state_dim, control_dim>> costFunction(
352 
353  // autodiff costfunction
354  using CGScalar = typename CostFunctionAD<state_dim, control_dim>::CGScalar;
355  std::shared_ptr<CostFunctionAD<state_dim, control_dim>> costFunctionAD(
356  new CostFunctionAD<state_dim, control_dim>());
357 
358  Eigen::Matrix<double, state_dim, 1> a, x_ref;
359  a.setRandom();
360  x_ref.setRandom();
361  Eigen::Matrix<double, control_dim, 1> b, u_ref;
362  b.setRandom();
363  u_ref.setRandom();
364  double alpha = 0.5;
365 
366  std::shared_ptr<TermSmoothAbs<state_dim, control_dim>> smoothAbsTerm(
367  new TermSmoothAbs<state_dim, control_dim>(a, x_ref, b, u_ref, alpha));
368 
369  std::shared_ptr<TermSmoothAbs<state_dim, control_dim, double, CGScalar>> smoothAbsTermAD(
370  new TermSmoothAbs<state_dim, control_dim, double, CGScalar>(a, x_ref, b, u_ref, alpha));
371 
372  costFunction->addIntermediateTerm(smoothAbsTerm);
373  costFunctionAD->addIntermediateADTerm(smoothAbsTermAD);
374  costFunctionAD->initialize();
375 
378  x.setRandom();
379  u.setRandom();
380  double t = 0.0;
381 
382  costFunction->setCurrentStateAndControl(x, u, t);
383  ASSERT_TRUE(costFunction->stateDerivativeIntermediateTest());
384  ASSERT_TRUE(costFunction->controlDerivativeIntermediateTest());
385 
386  for (int i = 0; i < 100; i++)
387  {
388  x.setRandom();
389  u.setRandom();
390 
391  costFunction->setCurrentStateAndControl(x, u, t);
392  costFunctionAD->setCurrentStateAndControl(x, u, t);
393 
394  compareCostFunctionOutput(*costFunction, *costFunctionAD);
395  }
396 }
397 
398 
399 } // namespace example
400 } // namespace optcon
401 } // namespace ct
control_vector_t controlDerivativeIntermediate() override
Computes intermediate-cost first-order derivative with respect to control.
Definition: CostFunctionAnalytical-impl.hpp:136
A basic quadratic term of type .
Definition: TermQuadratic.hpp:22
virtual state_vector_t stateDerivativeIntermediate()=0
Computes intermediate-cost first-order derivative with respect to state.
virtual SCALAR evaluateIntermediate()=0
evaluate intermediate costs
virtual void setCurrentStateAndControl(const state_vector_t &x, const control_vector_t &u, const SCALAR &t=SCALAR(0.0))
Definition: CostFunction-impl.hpp:30
ct::core::ControlVector< control_dim > u
Definition: LoadFromFileTest.cpp:21
state_vector_t stateDerivativeTerminal() override
Definition: CostFunctionAnalytical-impl.hpp:115
const size_t state_dim
Definition: ConstraintComparison.h:20
A basic quadratic term of type .
Definition: TermMixed.hpp:21
virtual control_state_matrix_t stateControlDerivativeTerminal()
Computes final-cost derivative with respect to state and control.
Definition: CostFunctionQuadratic-impl.hpp:85
state_matrix_t stateSecondDerivativeTerminal() override
Computes final-cost second-order derivative with respect to state.
Definition: CostFunctionAnalytical-impl.hpp:129
A quadratic tracking term of type .
Definition: TermQuadTracking.hpp:20
A cost function which contains only terms that have analytical derivatives.
Definition: CostFunctionAnalytical.hpp:31
clear all close all load ct GNMSLog0 mat reformat t
Definition: gnmsPlot.m:6
virtual control_matrix_t controlSecondDerivativeIntermediate()=0
Computes intermediate-cost second-order derivative with respect to input.
Describes a cost function with a quadratic approximation, i.e. one that can compute first and second ...
Definition: CostFunctionQuadratic.hpp:29
void printCostFunctionOutput(CostFunctionQuadratic< state_dim, control_dim > &costFunction, CostFunctionQuadratic< state_dim, control_dim > &costFunction2)
Definition: CostFunctionTest.h:23
A multiplicative term of type .
Definition: TermQuadMult.hpp:24
TEST(ConstraintComparison, comparisonAnalyticAD)
Definition: ConstraintComparison.h:158
virtual size_t addIntermediateTerm(std::shared_ptr< TermBase< STATE_DIM, CONTROL_DIM, SCALAR >> term, bool verbose=false)
Adds an intermediate term.
Definition: CostFunctionQuadratic-impl.hpp:279
const size_t control_dim
Definition: CostFunctionTest.h:15
for i
Definition: mpc_unittest_plotting.m:14
ct::core::StateVector< state_dim > x
Definition: LoadFromFileTest.cpp:20
virtual size_t addFinalTerm(std::shared_ptr< TermBase< STATE_DIM, CONTROL_DIM, SCALAR >> term, bool verbose=false)
Adds a final term.
Definition: CostFunctionQuadratic-impl.hpp:294
state_matrix_t stateSecondDerivativeIntermediate() override
Computes intermediate-cost second-order derivative with respect to state.
Definition: CostFunctionAnalytical-impl.hpp:122
control_matrix_t controlSecondDerivativeIntermediate() override
Computes intermediate-cost second-order derivative with respect to input.
Definition: CostFunctionAnalytical-impl.hpp:150
virtual state_vector_t stateDerivativeTerminal()=0
virtual state_matrix_t stateSecondDerivativeIntermediate()=0
Computes intermediate-cost second-order derivative with respect to state.
void push_back(const T &data, const SCALAR &time, const bool timeIsAbsolute)
virtual control_vector_t controlDerivativeIntermediate()=0
Computes intermediate-cost first-order derivative with respect to control.
virtual control_vector_t controlDerivativeTerminal()
Computes terminal-cost first-order derivative with respect to control.
Definition: CostFunctionQuadratic-impl.hpp:71
virtual control_state_matrix_t stateControlDerivativeIntermediate()=0
Computes intermediate-cost derivative with respect to state and control.
virtual SCALAR evaluateTerminal()=0
evaluate terminal costs
void compareCostFunctionOutput(CostFunctionQuadratic< state_dim, control_dim > &costFunction, CostFunctionQuadratic< state_dim, control_dim > &costFunction2)
This method is called from different unit tests in order to compare the cost, first and second order ...
Definition: compareCostFunctions.h:18
const size_t state_dim
Definition: CostFunctionTest.h:14
const size_t control_dim
Definition: ConstraintComparison.h:21
state_vector_t stateDerivativeIntermediate() override
Computes intermediate-cost first-order derivative with respect to state.
Definition: CostFunctionAnalytical-impl.hpp:108
virtual state_matrix_t stateSecondDerivativeTerminal()=0
Computes final-cost second-order derivative with respect to state.
A smooth absolute term of type where this calculation is performed component-wise and summed with in...
Definition: TermSmoothAbs.hpp:23
virtual control_matrix_t controlSecondDerivativeTerminal()
Computes final-cost second-order derivative with respect to input.
Definition: CostFunctionQuadratic-impl.hpp:78