- 3.0.2 optimal control module.
ConstrainedLQOCSolverTest.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 using namespace ct;
7 using namespace ct::core;
8 using namespace ct::optcon;
9 
10 #include "../../testSystems/LinkedMasses.h"
11 #include "../../testSystems/LinearOscillator.h"
12 
13 bool verbose = false; // optional verbose output
14 
15 template <size_t state_dim, size_t control_dim>
19 {
20  std::cout << "x array:" << std::endl;
21  for (size_t j = 0; j < x.size(); j++)
22  std::cout << x[j].transpose() << std::endl;
23 
24  std::cout << "u array:" << std::endl;
25  for (size_t j = 0; j < u.size(); j++)
26  std::cout << u[j].transpose() << std::endl;
27 
28  std::cout << "K array:" << std::endl;
29  for (size_t j = 0; j < K.size(); j++)
30  std::cout << K[j] << std::endl << std::endl;
31 }
32 
34 template <size_t state_dim, size_t control_dim>
36  const Eigen::VectorXi sparsity,
37  const Eigen::VectorXd u_lb,
38  const Eigen::VectorXd u_ub)
39 {
40  for (int j = 0; j < (static_cast<int>(u.size())); j++)
41  {
42  for (int n = 0; n < sparsity.rows(); n++)
43  {
44  ASSERT_GE(u[j](sparsity(n)), u_lb(n));
45  ASSERT_LE(u[j](sparsity(n)), u_ub(n));
46  }
47  }
48 }
49 
51 template <size_t state_dim, size_t control_dim>
53  const Eigen::VectorXi sparsity,
54  const Eigen::VectorXd x_lb,
55  const Eigen::VectorXd x_ub)
56 {
57  for (size_t j = 0; j < x.size(); j++)
58  {
59  for (int n = 0; n < sparsity.rows(); n++)
60  {
61  ASSERT_GE(x[j](sparsity(n)), x_lb(n));
62  ASSERT_LE(x[j](sparsity(n)), x_ub(n));
63  }
64  }
65 }
66 
67 template <size_t state_dim, size_t control_dim, typename LINEAR_SYSTEM>
71  int nb_u,
72  Eigen::VectorXd u_lb,
73  Eigen::VectorXd u_ub,
74  Eigen::VectorXi u_box_sparsity,
75  int nb_x,
76  Eigen::VectorXd x_lb,
77  Eigen::VectorXd x_ub,
78  Eigen::VectorXi x_box_sparsity)
79 {
80  const size_t N = 5;
81  const double dt = 0.5;
82 
83  // create instances of HPIPM and an unconstrained Gauss-Newton Riccati solver
84  std::shared_ptr<LQOCSolver<state_dim, control_dim>> hpipmSolver(new HPIPMInterface<state_dim, control_dim>);
85  std::shared_ptr<LQOCSolver<state_dim, control_dim>> gnRiccatiSolver(new GNRiccatiSolver<state_dim, control_dim>);
86 
87  NLOptConSettings nloc_settings;
88  nloc_settings.lqoc_solver_settings.num_lqoc_iterations = 50; // allow 50 iterations
89  if (verbose)
90  nloc_settings.lqoc_solver_settings.lqoc_debug_print = true;
91  hpipmSolver->configure(nloc_settings);
92 
93  // create linear-quadratic optimal control problem containers
94  std::shared_ptr<LQOCProblem<state_dim, control_dim>> lqocProblem1(new LQOCProblem<state_dim, control_dim>(N));
95  std::shared_ptr<LQOCProblem<state_dim, control_dim>> lqocProblem2(new LQOCProblem<state_dim, control_dim>(N));
96 
97 
98  // create a continuous-time example system and discretize it
99  std::shared_ptr<core::LinearSystem<state_dim, control_dim>> exampleSystem(new LINEAR_SYSTEM());
102 
103 
104  // define cost function matrices
106  Q.setIdentity();
107  Q *= 2.0;
109  R.setIdentity();
110  R *= 2 * 2.0;
111 
112  // create a cost function
113  std::shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction(
114  new CostFunctionQuadraticSimple<state_dim, control_dim>(Q, R, xf, u0, xf, Q));
115 
116  // solution variables needed later
119 
123 
124  if (verbose)
125  {
126  std::cout << " ================================================== " << std::endl;
127  std::cout << " TEST CASE 1: FULL BOX CONSTRAINTS ON CONTROL INPUT " << std::endl;
128  std::cout << " ================================================== " << std::endl;
129  }
130 
131  // initialize the optimal control problems for both solvers
132  lqocProblem1->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
133  lqocProblem2->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
134 
135  lqocProblem1->setInputBoxConstraints(nb_u, u_lb, u_ub, u_box_sparsity, u_nom);
136  lqocProblem2->setInputBoxConstraints(nb_u, u_lb, u_ub, u_box_sparsity, u_nom);
137 
138  // check that constraint configuration is right
139  ASSERT_TRUE(lqocProblem1->isConstrained());
140  ASSERT_FALSE(lqocProblem1->isGeneralConstrained());
141  ASSERT_TRUE(lqocProblem1->isInputBoxConstrained());
142  ASSERT_FALSE(lqocProblem1->isStateBoxConstrained());
143 
144  // set and try to solve the problem for both solvers
145  hpipmSolver->configureInputBoxConstraints(lqocProblem1);
146  hpipmSolver->setProblem(lqocProblem1);
147  hpipmSolver->initializeAndAllocate();
148  hpipmSolver->solve();
149  hpipmSolver->computeStatesAndControls();
150  hpipmSolver->computeFeedbackMatrices();
151 
152  try
153  {
154  hpipmSolver->compute_lv();
155  ASSERT_TRUE(false); // should never reach to this point
156  } catch (std::exception& e)
157  {
158  std::cout << "HPIPMSolver failed with exception " << e.what() << std::endl;
159  ASSERT_TRUE(true);
160  }
161 
162  try
163  {
164  gnRiccatiSolver->setProblem(lqocProblem2);
165  gnRiccatiSolver->solve();
166  ASSERT_TRUE(false); // should never reach to this point
167  } catch (std::exception& e)
168  {
169  std::cout << "GNRiccatiSolver failed with exception " << e.what() << std::endl;
170  ASSERT_TRUE(true);
171  }
172 
173  // retrieve solutions from hpipm
174  xSol_hpipm = hpipmSolver->getSolutionState();
175  uSol_hpipm = hpipmSolver->getSolutionControl();
176  KSol_hpipm = hpipmSolver->getSolutionFeedback();
177 
178 
179  if (verbose)
180  printSolution<state_dim, control_dim>(xSol_hpipm, uSol_hpipm, KSol_hpipm);
181 
182  // assert that the imposed boundary constraints are respected by the solution
183  assertControlBounds<state_dim, control_dim>(uSol_hpipm, u_box_sparsity, u_lb, u_ub);
184 
185 
186  if (verbose)
187  {
188  std::cout << " ================================================== " << std::endl;
189  std::cout << " TEST CASE 2: FULL BOX CONSTRAINTS ON STATE VECTOR " << std::endl;
190  std::cout << " ================================================== " << std::endl;
191  }
192 
193  // initialize the optimal control problems for both solvers
194  lqocProblem1->setZero();
195  lqocProblem2->setZero();
196  lqocProblem1->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
197  lqocProblem2->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
198 
199  lqocProblem1->setIntermediateStateBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom);
200  lqocProblem2->setIntermediateStateBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom);
201  lqocProblem1->setTerminalBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom.back());
202  lqocProblem2->setTerminalBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom.back());
203 
204  // check that constraint configuration is right
205  ASSERT_TRUE(lqocProblem1->isConstrained());
206  ASSERT_FALSE(lqocProblem1->isGeneralConstrained());
207  ASSERT_TRUE(lqocProblem1->isStateBoxConstrained());
208  ASSERT_FALSE(lqocProblem1->isInputBoxConstrained());
209 
210  // set and try to solve the problem for both solvers
211  hpipmSolver->configureStateBoxConstraints(lqocProblem1);
212  hpipmSolver->setProblem(lqocProblem1);
213  hpipmSolver->initializeAndAllocate();
214  hpipmSolver->solve();
215  hpipmSolver->computeStatesAndControls();
216  hpipmSolver->computeFeedbackMatrices();
217 
218  try
219  {
220  hpipmSolver->compute_lv();
221  ASSERT_TRUE(false); // should never reach to this point
222  } catch (std::exception& e)
223  {
224  std::cout << "HPIPMSolver failed with exception " << e.what() << std::endl;
225  ASSERT_TRUE(true);
226  }
227 
228  try
229  {
230  gnRiccatiSolver->setProblem(lqocProblem2);
231  gnRiccatiSolver->solve();
232  ASSERT_TRUE(false); // should never reach to this point
233  } catch (std::exception& e)
234  {
235  std::cout << "GNRiccatiSolver failed with exception " << e.what() << std::endl;
236  ASSERT_TRUE(true);
237  }
238 
239  // retrieve solutions from hpipm
240  xSol_hpipm = hpipmSolver->getSolutionState();
241  uSol_hpipm = hpipmSolver->getSolutionControl();
242  KSol_hpipm = hpipmSolver->getSolutionFeedback();
243 
244  if (verbose)
245  printSolution<state_dim, control_dim>(xSol_hpipm, uSol_hpipm, KSol_hpipm);
246 
247  // assert that the imposed boundary constraints are respected by the solution
248  assertStateBounds<state_dim, control_dim>(xSol_hpipm, x_box_sparsity, x_lb, x_ub);
249 
250 
251  if (verbose)
252  {
253  std::cout << " ================================================== " << std::endl;
254  std::cout << " TEST CASE 3: BOX CONSTRAINTS ON STATE AND CONTROL " << std::endl;
255  std::cout << " ================================================== " << std::endl;
256  }
257 
258  // initialize the optimal control problems for both solvers
259  lqocProblem1->setZero();
260  lqocProblem2->setZero();
261  lqocProblem1->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
262  lqocProblem2->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
263 
264  // relax box constraints a bit for this test, otherwise there might be no solution
265  x_lb.array() -= 1.0;
266  x_ub.array() += 1.0;
267 
268 
269  // set the combined box constraints
270  lqocProblem1->setInputBoxConstraints(nb_u, u_lb, u_ub, u_box_sparsity, u_nom);
271  lqocProblem2->setInputBoxConstraints(nb_u, u_lb, u_ub, u_box_sparsity, u_nom);
272  lqocProblem1->setIntermediateStateBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom);
273  lqocProblem2->setIntermediateStateBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom);
274  lqocProblem1->setTerminalBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom.back());
275  lqocProblem2->setTerminalBoxConstraints(nb_x, x_lb, x_ub, x_box_sparsity, x_nom.back());
276 
277  // check that constraint configuration is right
278  ASSERT_TRUE(lqocProblem1->isConstrained());
279  ASSERT_FALSE(lqocProblem1->isGeneralConstrained());
280  ASSERT_TRUE(lqocProblem1->isInputBoxConstrained());
281  ASSERT_TRUE(lqocProblem1->isStateBoxConstrained());
282 
283  // set and try to solve the problem for both solvers
284  hpipmSolver->configureInputBoxConstraints(lqocProblem1);
285  hpipmSolver->configureStateBoxConstraints(lqocProblem1);
286  hpipmSolver->setProblem(lqocProblem1);
287  hpipmSolver->initializeAndAllocate();
288  hpipmSolver->solve();
289  hpipmSolver->computeStatesAndControls();
290  hpipmSolver->computeFeedbackMatrices();
291 
292  try
293  {
294  hpipmSolver->compute_lv();
295  ASSERT_TRUE(false); // should never reach to this point
296  } catch (std::exception& e)
297  {
298  std::cout << "HPIPMSolver failed with exception " << e.what() << std::endl;
299  ASSERT_TRUE(true);
300  }
301 
302  try
303  {
304  gnRiccatiSolver->setProblem(lqocProblem2);
305  gnRiccatiSolver->solve();
306  ASSERT_TRUE(false); // should never reach to this point
307  } catch (std::exception& e)
308  {
309  std::cout << "GNRiccatiSolver failed with exception " << e.what() << std::endl;
310  ASSERT_TRUE(true);
311  }
312 
313  // retrieve solutions from hpipm
314  xSol_hpipm = hpipmSolver->getSolutionState();
315  uSol_hpipm = hpipmSolver->getSolutionControl();
316  KSol_hpipm = hpipmSolver->getSolutionFeedback();
317 
318  if (verbose)
319  printSolution<state_dim, control_dim>(xSol_hpipm, uSol_hpipm, KSol_hpipm);
320 
321  // assert that the imposed boundary constraints are respected by the solution
322  assertControlBounds<state_dim, control_dim>(uSol_hpipm, u_box_sparsity, u_lb, u_ub);
323  assertStateBounds<state_dim, control_dim>(xSol_hpipm, x_box_sparsity, x_lb, x_ub);
324 }
325 
326 
327 template <size_t state_dim, size_t control_dim, typename LINEAR_SYSTEM>
331  Eigen::VectorXd d_lb,
332  Eigen::VectorXd d_ub,
333  Eigen::MatrixXd C,
334  Eigen::MatrixXd D)
335 {
336  const size_t N = 5;
337  const double dt = 0.5;
338 
339  // create instances of HPIPM and an unconstrained Gauss-Newton Riccati solver
340  std::shared_ptr<LQOCSolver<state_dim, control_dim>> hpipmSolver(new HPIPMInterface<state_dim, control_dim>);
341  std::shared_ptr<LQOCSolver<state_dim, control_dim>> gnRiccatiSolver(new GNRiccatiSolver<state_dim, control_dim>);
342 
343  NLOptConSettings nloc_settings;
344  nloc_settings.lqoc_solver_settings.num_lqoc_iterations = 50; // allow 50 iterations
345  hpipmSolver->configure(nloc_settings);
346 
347  // create linear-quadratic optimal control problem containers
348  std::shared_ptr<LQOCProblem<state_dim, control_dim>> lqocProblem1(new LQOCProblem<state_dim, control_dim>(N));
349  std::shared_ptr<LQOCProblem<state_dim, control_dim>> lqocProblem2(new LQOCProblem<state_dim, control_dim>(N));
350 
351  // create a continuous-time example system and discretize it
352  std::shared_ptr<core::LinearSystem<state_dim, control_dim>> exampleSystem(new LINEAR_SYSTEM());
355 
356 
357  // define cost function matrices
359  Q.setIdentity();
360  Q *= 2.0;
362  R.setIdentity();
363  R *= 2 * 2.0;
364 
365  // create a cost function
366  std::shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction(
367  new CostFunctionQuadraticSimple<state_dim, control_dim>(Q, R, xf, u0, xf, Q));
368 
369  // solution variables needed later
373 
374  if (verbose)
375  {
376  std::cout << " ================================================== " << std::endl;
377  std::cout << " TEST CASE 1: GENERAL INEQUALITY CONSTRAINTS " << std::endl;
378  std::cout << " ================================================== " << std::endl;
379  }
380 
381  // initialize the optimal control problems for both solvers
382  lqocProblem1->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
383  lqocProblem2->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
384  lqocProblem1->setGeneralConstraints(d_lb, d_ub, C, D);
385  lqocProblem2->setGeneralConstraints(d_lb, d_ub, C, D);
386 
387  // check that constraint configuration is right
388  ASSERT_FALSE(lqocProblem1->isInputBoxConstrained());
389  ASSERT_FALSE(lqocProblem1->isStateBoxConstrained());
390  ASSERT_TRUE(lqocProblem1->isGeneralConstrained());
391  ASSERT_TRUE(lqocProblem1->isConstrained());
392 
393  // set and try to solve the problem for both solvers
394  hpipmSolver->setProblem(lqocProblem1);
395  hpipmSolver->initializeAndAllocate();
396  hpipmSolver->solve();
397  hpipmSolver->computeStatesAndControls();
398  hpipmSolver->computeFeedbackMatrices();
399 
400  try
401  {
402  hpipmSolver->compute_lv();
403  ASSERT_TRUE(false); // should never reach to this point
404  } catch (std::exception& e)
405  {
406  std::cout << "HPIPMSolver failed with exception " << e.what() << std::endl;
407  ASSERT_TRUE(true);
408  }
409 
410  try
411  {
412  gnRiccatiSolver->setProblem(lqocProblem2);
413  gnRiccatiSolver->solve();
414  ASSERT_TRUE(false); // should never reach to this point
415  } catch (std::exception& e)
416  {
417  std::cout << "GNRiccatiSolver failed with exception " << e.what() << std::endl;
418  ASSERT_TRUE(true);
419  }
420 
421  // retrieve solutions from hpipm
422  xSol_hpipm = hpipmSolver->getSolutionState();
423  uSol_hpipm = hpipmSolver->getSolutionControl();
424  KSol_hpipm = hpipmSolver->getSolutionFeedback();
425 
426 
427  if (verbose)
428  printSolution<state_dim, control_dim>(xSol_hpipm, uSol_hpipm, KSol_hpipm);
429 }
430 
431 TEST(ConstrainedLQOCSolverTest, BoxConstrTest_small)
432 {
433  const size_t state_dim = 2;
434  const size_t control_dim = 1;
435 
436  // nominal control
438  u0.setConstant(0);
439 
440  // initial state
442  x0 << 0.0, 0.0;
443 
444  // desired final state
446  xf.setConstant(2.5);
447 
448  // dense control box constraints
449  int nb_u = control_dim;
450  Eigen::VectorXd u_lb(nb_u);
451  Eigen::VectorXd u_ub(nb_u);
452  u_lb.setConstant(-0.5);
453  u_ub.setConstant(0.5);
454  Eigen::VectorXi u_box_sparsity(nb_u);
455  u_box_sparsity << 0;
456 
457  // sparse state box constraints
458  int nb_x = 1;
459  Eigen::VectorXd x_lb(nb_x);
460  Eigen::VectorXd x_ub(nb_x);
461  x_lb << -100;
462  x_ub.setConstant(1.7);
463  Eigen::VectorXi x_box_sparsity(nb_x);
464  x_box_sparsity << 0;
465 
466  boxConstraintsTest<state_dim, control_dim, example::LinearOscillatorLinear>(
467  u0, x0, xf, nb_u, u_lb, u_ub, u_box_sparsity, nb_x, x_lb, x_ub, x_box_sparsity);
468 }
469 
470 TEST(ConstrainedLQOCSolverTest, BoxConstrTest_medium)
471 {
472  const size_t state_dim = 8;
473  const size_t control_dim = 3;
474 
475  // nominal control
477  u0.setConstant(0.0);
478 
479  // initial state
481  x0 << 0, 0, 0, 0, 0, 0, 0, 0; // must start at 0
482 
483  // desired final state
485  xf << 2.5, 2.5, 0, 0, 0, 0, 0, 0;
486 
487  // dense control box constraints
488  int nb_u = control_dim;
489  Eigen::VectorXd u_lb(nb_u);
490  Eigen::VectorXd u_ub(nb_u);
491  u_lb.setConstant(-0.5);
492  u_ub.setConstant(0.5);
493  Eigen::VectorXi u_box_sparsity(nb_u);
494  u_box_sparsity << 0, 1, 2;
495 
496  // sparse state box constraints
497  int nb_x = 2;
498  Eigen::VectorXd x_lb(nb_x);
499  Eigen::VectorXd x_ub(nb_x);
500  x_lb << -100, -100;
501  x_ub.setConstant(1.5);
502  Eigen::VectorXi x_box_sparsity(nb_x);
503  x_box_sparsity << 0, 1;
504 
505  boxConstraintsTest<state_dim, control_dim, LinkedMasses>(
506  u0, x0, xf, nb_u, u_lb, u_ub, u_box_sparsity, nb_x, x_lb, x_ub, x_box_sparsity);
507 }
508 
509 TEST(ConstrainedLQOCSolverTest, GeneralConstrTest_small)
510 {
511  const size_t state_dim = 2;
512  const size_t control_dim = 1;
513 
514  // nominal control
516  u0.setConstant(0);
517 
518  // initial state
520  x0 << 0.0, 0.0;
521 
522  // desired final state
524  xf.setConstant(2.5);
525 
526  // general constraints
527  // this general constraints is again nothing but an input inequality constraint:
528  Eigen::VectorXd d_lb, d_ub;
529  d_lb.resize(1);
530  d_ub.resize(1);
531  d_lb << -0.5;
532  d_ub << 0.5;
533 
534  Eigen::MatrixXd C, D;
535  C.resize(1, 2);
536  D.resize(1, 1);
537  C.setZero();
538  D(0, 0) = 1;
539 
540  generalConstraintsTest<state_dim, control_dim, example::LinearOscillatorLinear>(u0, x0, xf, d_lb, d_ub, C, D);
541 }
542 
543 TEST(ConstrainedLQOCSolverTest, GeneralConstrTest_medium)
544 {
545  const size_t state_dim = 8;
546  const size_t control_dim = 3;
547 
548  // nominal control
550  u0.setConstant(0.1);
551 
552  // initial state
554  x0 << 0.0, 0.0, 0, 0, 0, 0, 0, 0;
555 
556  // desired final state
558  xf.setConstant(1.0);
559 
560  // general constraints
561  // this general constraints is again nothing but an input inequality constraint:
562  Eigen::VectorXd d_lb, d_ub;
563  d_lb.resize(control_dim);
564  d_ub.resize(control_dim);
565  d_lb.setConstant(-0.5);
566  d_ub.setConstant(0.5);
567 
568  Eigen::MatrixXd C, D;
569  C.resize(control_dim, state_dim);
570  D.resize(control_dim, control_dim);
571  C.setZero();
572  D.setIdentity();
573 
574  generalConstraintsTest<state_dim, control_dim, LinkedMasses>(u0, x0, xf, d_lb, d_ub, C, D);
575 }
576 
577 
578 TEST(ConstrainedLQOCSolverTest, BoxConstraintUsingConstraintToolbox)
579 {
580  const size_t state_dim = 8;
581  const size_t control_dim = 3;
582 
583  // nominal control
585  u0.setConstant(0.1);
586 
587  // initial state
589  x0 << 0.0, 0.0, 0, 0, 0, 0, 0, 0;
590 
591  // desired final state
593  xf.setConstant(1.0);
594 
595  // input box constraint boundaries with sparsities in constraint toolbox format
596  Eigen::VectorXi sp_control(control_dim);
597  sp_control << 1, 1, 1; // note the different way of specifying sparsity
598  Eigen::VectorXd u_lb(control_dim);
599  Eigen::VectorXd u_ub(control_dim);
600  u_lb.setConstant(-0.5);
601  u_ub = -u_lb;
602 
603  // state box constraint boundaries with sparsities in constraint toolbox format
604  Eigen::VectorXi sp_state(state_dim);
605  sp_state << 1, 1, 0, 0, 0, 0, 0, 0; // note the different way of specifying sparsity
606  Eigen::VectorXd x_lb(2);
607  x_lb << -0.5, -0.5;
608  Eigen::VectorXd x_ub(2);
609  x_ub.setConstant(std::numeric_limits<double>::max());
610 
611  // constrain terms
612  std::shared_ptr<ControlInputConstraint<state_dim, control_dim>> controlConstraint(
613  new ControlInputConstraint<state_dim, control_dim>(u_lb, u_ub, sp_control));
614  controlConstraint->setName("ControlInputConstraint");
615 
616  std::shared_ptr<StateConstraint<state_dim, control_dim>> stateConstraint(
617  new StateConstraint<state_dim, control_dim>(x_lb, x_ub, sp_state));
618  stateConstraint->setName("StateConstraint");
619 
620  // create constraint container
621  std::shared_ptr<ConstraintContainerAnalytical<state_dim, control_dim>> input_constraints(
623 
624  std::shared_ptr<ConstraintContainerAnalytical<state_dim, control_dim>> state_constraints(
626 
627  // add and initialize constraint terms
628  input_constraints->addIntermediateConstraint(controlConstraint, verbose);
629  state_constraints->addIntermediateConstraint(stateConstraint, verbose);
630  state_constraints->addTerminalConstraint(stateConstraint, verbose);
631  input_constraints->initialize();
632  state_constraints->initialize();
633 
634  //set up lqoc problems and solvers
635  const size_t N = 5;
636  const double dt = 0.5;
637 
638  // create instances of HPIPM and an unconstrained Gauss-Newton Riccati solver
639  std::shared_ptr<LQOCSolver<state_dim, control_dim>> hpipmSolver(new HPIPMInterface<state_dim, control_dim>);
640 
641  NLOptConSettings nloc_settings;
642  nloc_settings.lqoc_solver_settings.num_lqoc_iterations = 50; // allow 50 iterations
643  if (verbose)
644  nloc_settings.lqoc_solver_settings.lqoc_debug_print = true;
645  hpipmSolver->configure(nloc_settings);
646 
647  // create linear-quadratic optimal control problem containers
648  std::shared_ptr<LQOCProblem<state_dim, control_dim>> lqocProblem1(new LQOCProblem<state_dim, control_dim>(N));
649 
650  // create a continuous-time example system and discretize it
651  std::shared_ptr<core::LinearSystem<state_dim, control_dim>> exampleSystem(new LinkedMasses());
654 
655  // define cost function matrices
657  Q.setIdentity();
658  Q *= 2.0;
660  R.setIdentity();
661  R *= 2 * 2.0;
662 
663  // create a cost function
664  std::shared_ptr<CostFunctionQuadratic<state_dim, control_dim>> costFunction(
665  new CostFunctionQuadraticSimple<state_dim, control_dim>(Q, R, xf, u0, xf, Q));
666 
667  // solution variables needed later
671 
674 
675  if (verbose)
676  {
677  std::cout << " ================================================== " << std::endl;
678  std::cout << " LQOC PROBLEM USING CONSTRAINT TOOLBOX " << std::endl;
679  std::cout << " ================================================== " << std::endl;
680  }
681 
682  // initialize the optimal control problems for both solvers
683  lqocProblem1->setZero();
684  lqocProblem1->setFromTimeInvariantLinearQuadraticProblem(discreteExampleSystem, *costFunction, x0, dt);
685 
686  // evaluate relevant quantities using the constraint toolbox
687  int nb_u_intermediate = input_constraints->getJacobianStateNonZeroCountIntermediate() +
688  input_constraints->getJacobianInputNonZeroCountIntermediate();
689  int nb_x_intermediate = state_constraints->getJacobianStateNonZeroCountIntermediate() +
690  state_constraints->getJacobianInputNonZeroCountIntermediate();
691  ASSERT_EQ(nb_u_intermediate + nb_x_intermediate, 5);
692  int nb_x_terminal = state_constraints->getJacobianStateNonZeroCountTerminal();
693  ASSERT_EQ(nb_x_terminal, 2);
694 
695  // get bounds
696  Eigen::VectorXd u_lb_intermediate = input_constraints->getLowerBoundsIntermediate();
697  Eigen::VectorXd u_ub_intermediate = input_constraints->getUpperBoundsIntermediate();
698  Eigen::VectorXd x_lb_intermediate = state_constraints->getLowerBoundsIntermediate();
699  Eigen::VectorXd x_ub_intermediate = state_constraints->getUpperBoundsIntermediate();
700  Eigen::VectorXd x_lb_terminal = state_constraints->getLowerBoundsTerminal();
701  Eigen::VectorXd x_ub_terminal = state_constraints->getUpperBoundsTerminal();
702 
703  // compute sparsity as required by LQOC Solver
704  Eigen::VectorXi foo, u_sparsity_intermediate, x_sparsity_intermediate, x_sparsity_terminal;
705  input_constraints->sparsityPatternInputIntermediate(foo, u_sparsity_intermediate);
706  state_constraints->sparsityPatternStateIntermediate(foo, x_sparsity_intermediate);
707  state_constraints->sparsityPatternStateTerminal(foo, x_sparsity_terminal);
708  if (verbose)
709  {
710  std::cout << "u_sparsity_intermediate" << u_sparsity_intermediate.transpose() << std::endl;
711  std::cout << "x_sparsity_intermediate" << x_sparsity_intermediate.transpose() << std::endl;
712  std::cout << "x_sparsity_terminal" << x_sparsity_terminal.transpose() << std::endl;
713  }
714 
715 
716  // set the combined box constraints to the LQOC problem
717  lqocProblem1->setInputBoxConstraints(
718  nb_u_intermediate, u_lb_intermediate, u_ub_intermediate, u_sparsity_intermediate, u_nom);
719  lqocProblem1->setIntermediateStateBoxConstraints(
720  nb_x_intermediate, x_lb_intermediate, x_ub_intermediate, x_sparsity_intermediate, x_nom);
721  lqocProblem1->setTerminalBoxConstraints(
722  nb_x_terminal, x_lb_terminal, x_ub_terminal, x_sparsity_terminal, x_nom.back());
723 
724  // check that constraint configuration is right
725  ASSERT_TRUE(lqocProblem1->isConstrained());
726  ASSERT_FALSE(lqocProblem1->isGeneralConstrained());
727  ASSERT_TRUE(lqocProblem1->isInputBoxConstrained());
728  ASSERT_TRUE(lqocProblem1->isStateBoxConstrained());
729 
730  // set and try to solve the problem for both solvers
731  hpipmSolver->configureInputBoxConstraints(lqocProblem1);
732  hpipmSolver->configureStateBoxConstraints(lqocProblem1);
733  hpipmSolver->setProblem(lqocProblem1);
734  hpipmSolver->initializeAndAllocate();
735  hpipmSolver->solve();
736  hpipmSolver->computeStatesAndControls();
737  hpipmSolver->computeFeedbackMatrices();
738  try
739  {
740  hpipmSolver->compute_lv();
741  ASSERT_TRUE(false); // should never reach to this point
742  } catch (std::exception& e)
743  {
744  std::cout << "HPIPMSolver failed with exception " << e.what() << std::endl;
745  ASSERT_TRUE(true);
746  }
747 
748  // retrieve solutions from hpipm
749  xSol_hpipm = hpipmSolver->getSolutionState();
750  uSol_hpipm = hpipmSolver->getSolutionControl();
751  KSol_hpipm = hpipmSolver->getSolutionFeedback();
752 
753  if (verbose)
754  printSolution<state_dim, control_dim>(xSol_hpipm, uSol_hpipm, KSol_hpipm);
755 }
void printSolution(const ct::core::StateVectorArray< state_dim > &x, const ct::core::ControlVectorArray< control_dim > &u, const ct::core::FeedbackArray< state_dim, control_dim > &K)
Definition: ConstrainedLQOCSolverTest.h:16
int num_lqoc_iterations
Definition: NLOptConSettings.hpp:160
ct::core::ControlVector< control_dim > u
Definition: LoadFromFileTest.cpp:21
Class for control input box constraint term.
Definition: ControlInputConstraint.h:21
void generalConstraintsTest(ct::core::ControlVector< control_dim > u0, ct::core::StateVector< state_dim > x0, ct::core::StateVector< state_dim > xf, Eigen::VectorXd d_lb, Eigen::VectorXd d_ub, Eigen::MatrixXd C, Eigen::MatrixXd D)
Definition: ConstrainedLQOCSolverTest.h:328
A simple quadratic cost function.
Definition: CostFunctionQuadraticSimple.hpp:23
const size_t state_dim
Definition: ConstraintExampleOutput.cpp:17
TEST(ConstrainedLQOCSolverTest, BoxConstrTest_small)
Definition: ConstrainedLQOCSolverTest.h:431
const double dt
Definition: LQOCSolverTiming.cpp:18
Settings for the NLOptCon algorithm.
Definition: NLOptConSettings.hpp:198
constexpr size_t n
Defines a Linear-Quadratic Optimal Control Problem, which is optionally constrained.
Definition: LQOCProblem.hpp:57
void assertControlBounds(const ct::core::ControlVectorArray< control_dim > &u, const Eigen::VectorXi sparsity, const Eigen::VectorXd u_lb, const Eigen::VectorXd u_ub)
check that control bounds are respected
Definition: ConstrainedLQOCSolverTest.h:35
Contains all the constraints using analytically calculated jacobians.
Definition: ConstraintContainerAnalytical.h:27
ct::core::StateVector< state_dim > x
Definition: LoadFromFileTest.cpp:20
Definition: GNRiccatiSolver.hpp:22
void assertStateBounds(const ct::core::StateVectorArray< state_dim > &x, const Eigen::VectorXi sparsity, const Eigen::VectorXd x_lb, const Eigen::VectorXd x_ub)
check that state bounds are respected
Definition: ConstrainedLQOCSolverTest.h:52
Class for state box constraint.
Definition: StateConstraint.h:22
Definition: LinkedMasses.h:29
bool verbose
Definition: ConstrainedLQOCSolverTest.h:13
void boxConstraintsTest(ct::core::ControlVector< control_dim > u0, ct::core::StateVector< state_dim > x0, ct::core::StateVector< state_dim > xf, int nb_u, Eigen::VectorXd u_lb, Eigen::VectorXd u_ub, Eigen::VectorXi u_box_sparsity, int nb_x, Eigen::VectorXd x_lb, Eigen::VectorXd x_ub, Eigen::VectorXi x_box_sparsity)
Definition: ConstrainedLQOCSolverTest.h:68
StateVector< state_dim > x0
Definition: ConstrainedNLOCTest.cpp:14
LQOCSolverSettings lqoc_solver_settings
the line search settings
Definition: NLOptConSettings.hpp:276
bool lqoc_debug_print
Definition: NLOptConSettings.hpp:159
Definition: exampleDir.h:9
const size_t control_dim
Definition: ConstraintExampleOutput.cpp:18