- 3.0.2 core module.
DiscreteSystemLinearizerADCGTest.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 
9 
13 TEST(DiscreteSystemLinearizerADCG, JITCompilationTest)
14 {
15  // define the dimensions of the system
16  const size_t state_dim = TestDiscreteNonlinearSystem::STATE_DIM;
17  const size_t control_dim = TestDiscreteNonlinearSystem::CONTROL_DIM;
18 
19  // typedefs for the auto-differentiable codegen system
20  typedef DiscreteSystemLinearizerADCG<state_dim, control_dim>::ADCGScalar ADCGScalar;
21  typedef typename ADCGScalar::value_type AD_ValueType;
22  typedef tpl::TestDiscreteNonlinearSystem<ADCGScalar> TestDiscreteNonlinearSystemAD;
23 
24  // handy typedefs for the Jacobian
27 
28  // create two nonlinear systems, one regular one and one auto-differentiable
29  const double rate = 100.0;
30  shared_ptr<TestDiscreteNonlinearSystem> oscillator(new TestDiscreteNonlinearSystem(rate));
31  shared_ptr<TestDiscreteNonlinearSystemAD> oscillatorAD(
32  new tpl::TestDiscreteNonlinearSystem<ADCGScalar>(AD_ValueType(rate)));
33 
34  // create two nonlinear systems, one regular one and one auto-diff codegen
35  DiscreteSystemLinearizer<state_dim, control_dim> systemLinearizer(oscillator);
36  DiscreteSystemLinearizerADCG<state_dim, control_dim> adLinearizer(oscillatorAD);
37 
38  // do just in time compilation of the Jacobians
39  std::cout << "compiling..." << std::endl;
40  adLinearizer.compileJIT("ADCGCodegenLib");
41  std::cout << "... done!" << std::endl;
42 
43  std::shared_ptr<DiscreteSystemLinearizerADCG<state_dim, control_dim>> adLinearizerClone(adLinearizer.clone());
44 
45  // make sure the underlying dynamic libraries are not identical (dynamic library cloned correctly)
46  if (adLinearizerClone->getLinearizer().getDynamicLib() == adLinearizer.getLinearizer().getDynamicLib())
47  {
48  std::cout << "FATAL ERROR: dynamic library not cloned correctly in JIT." << std::endl;
49  ASSERT_TRUE(false);
50  }
51 
52  // create state, control and time variables
53  StateVector<state_dim> x;
54  ControlVector<control_dim> u;
55  int n = 0;
56 
57  for (size_t i = 0; i < 1000; i++)
58  {
59  // set a random state
60  x.setRandom();
61  u.setRandom();
62 
63  // use the numerical differentiation linearizer
64  A_type A_system;
65  B_type B_system;
66  systemLinearizer.getAandB(x, u, x, n, 1, A_system, B_system);
67 
68  // use the auto diff codegen linearzier
69  A_type A_ad;
70  B_type B_ad;
71  adLinearizer.getAandB(x, u, x, n, 1, A_ad, B_ad);
72 
73  A_type A_adCloned;
74  B_type B_adCloned;
75  adLinearizerClone->getAandB(x, u, x, n, 1, A_adCloned, B_adCloned);
76 
77  // verify the result
78  ASSERT_LT((A_system - A_ad).array().abs().maxCoeff(), 1e-5);
79  ASSERT_LT((B_system - B_ad).array().abs().maxCoeff(), 1e-5);
80 
81  ASSERT_LT((A_system - A_adCloned).array().abs().maxCoeff(), 1e-5);
82  ASSERT_LT((B_system - B_adCloned).array().abs().maxCoeff(), 1e-5);
83  }
84 }
85 
86 
90 TEST(DiscreteSystemLinearizerADCG, CodegenTest)
91 {
92  // define the dimensions of the system
93  const size_t state_dim = TestDiscreteNonlinearSystem::STATE_DIM;
94  const size_t control_dim = TestDiscreteNonlinearSystem::CONTROL_DIM;
95 
96  // typedefs for the auto-differentiable codegen system
97  typedef DiscreteSystemLinearizerADCG<state_dim, control_dim>::ADCGScalar ADCGScalar;
98  typedef typename ADCGScalar::value_type AD_ValueType;
99  typedef tpl::TestDiscreteNonlinearSystem<ADCGScalar> TestDiscreteNonlinearSystemAD;
100 
101  // create two nonlinear systems, one regular one and one auto-differentiable
102  const double rate = 100.0;
103  shared_ptr<TestDiscreteNonlinearSystemAD> oscillatorAD(
104  new tpl::TestDiscreteNonlinearSystem<ADCGScalar>(AD_ValueType(rate)));
105 
106  // create two nonlinear systems, one regular one and one auto-diff codegen
107  DiscreteSystemLinearizerADCG<state_dim, control_dim> adLinearizer(oscillatorAD);
108 
109  try
110  {
111  std::cout << "generating code..." << std::endl;
112  // generate code for the Jacobians
113  adLinearizer.generateCode("TestDiscreteNonlinearSystemLinearized");
114  std::cout << "... done!" << std::endl;
115  } catch (const std::runtime_error& e)
116  {
117  std::cout << "code generation failed: " << e.what() << std::endl;
118  ASSERT_TRUE(false);
119  }
120 }
121 
122 TEST(DiscreteSystemLinearizerADCGMP, JITCompilationTestMP)
123 {
124  // define the dimensions of the system
125  const size_t state_dim = TestDiscreteNonlinearSystem::STATE_DIM;
126  const size_t control_dim = TestDiscreteNonlinearSystem::CONTROL_DIM;
127 
128  // typedefs for the auto-differentiable codegen system
129  typedef DiscreteSystemLinearizerADCG<state_dim, control_dim>::ADCGScalar ADCGScalar;
130  typedef typename ADCGScalar::value_type AD_ValueType;
131  typedef tpl::TestDiscreteNonlinearSystem<ADCGScalar> TestDiscreteNonlinearSystemAD;
132 
133  // handy typedefs for the Jacobian
136 
137  // create two nonlinear systems, one regular one and one auto-differentiable
138  const double rate = 100.0;
139  shared_ptr<TestDiscreteNonlinearSystem> oscillator(new TestDiscreteNonlinearSystem(rate));
140  shared_ptr<TestDiscreteNonlinearSystemAD> oscillatorAD(
141  new tpl::TestDiscreteNonlinearSystem<ADCGScalar>(AD_ValueType(rate)));
142 
143  // create two nonlinear systems, one regular one and one auto-diff codegen
144  DiscreteSystemLinearizer<state_dim, control_dim> systemLinearizer(oscillator);
145  DiscreteSystemLinearizerADCG<state_dim, control_dim> adLinearizer(oscillatorAD);
146  adLinearizer.compileJIT("ADMPTestLib");
147 
148  size_t nThreads = 4;
149  std::vector<std::shared_ptr<DiscreteSystemLinearizerADCG<state_dim, control_dim>>> adLinearizers;
150  std::vector<std::shared_ptr<DiscreteSystemLinearizer<state_dim, control_dim>>> systemLinearizers;
151 
152  for (size_t i = 0; i < nThreads; ++i)
153  {
154  adLinearizers.push_back(
155  std::shared_ptr<DiscreteSystemLinearizerADCG<state_dim, control_dim>>(adLinearizer.clone()));
156  adLinearizers.back()->compileJIT();
157  systemLinearizers.push_back(
158  std::shared_ptr<DiscreteSystemLinearizer<state_dim, control_dim>>(systemLinearizer.clone()));
159  }
160 
161 
162  size_t runs = 100000;
163 
164  for (size_t n = 0; n < runs; ++n)
165  {
166  std::vector<std::thread> threads;
167 
168  for (size_t i = 0; i < nThreads; ++i)
169  {
170  threads.push_back(std::thread([i, &adLinearizers, &systemLinearizers]() {
171  StateVector<TestDiscreteNonlinearSystem::STATE_DIM> x;
172  ControlVector<TestDiscreteNonlinearSystem::CONTROL_DIM> u;
173  int n = 0;
174 
175  x.setRandom();
176  u.setRandom();
177 
178  // use the numerical differentiation linearizer
179  A_type A_system;
180  B_type B_system;
181  systemLinearizers[i]->getAandB(x, u, x, n, 1, A_system, B_system);
182 
183  // use the auto diff codegen linearzier
184  A_type A_ad;
185  B_type B_ad;
186  adLinearizers[i]->getAandB(x, u, x, n, 1, A_ad, B_ad);
187 
188  // verify the result
189  ASSERT_LT((A_system - A_ad).array().abs().maxCoeff(), 1e-5);
190  ASSERT_LT((B_system - B_ad).array().abs().maxCoeff(), 1e-5);
191  }));
192  }
193 
194 
195  for (auto& thr : threads)
196  thr.join();
197  }
198 }
199 
200 TEST(DiscreteSystemLinearizerADCG, FloatTest)
201 {
202  // define the dimensions of the system
203  const size_t state_dim = TestDiscreteNonlinearSystem::STATE_DIM;
204  const size_t control_dim = TestDiscreteNonlinearSystem::CONTROL_DIM;
205 
206  // typedefs for the auto-differentiable codegen system
207  typedef DiscreteSystemLinearizerADCG<state_dim, control_dim, float>::ADCGScalar ADCGScalarFloat;
208  typedef DiscreteSystemLinearizerADCG<state_dim, control_dim, double>::ADCGScalar ADCGScalarDouble;
209 
210  typedef typename ADCGScalarFloat::value_type AD_ValueTypeFloat;
211  typedef typename ADCGScalarDouble::value_type AD_ValueTypeDouble;
212 
213  typedef tpl::TestDiscreteNonlinearSystem<ADCGScalarFloat> TestDiscreteNonlinearSystemADFloat;
214  typedef tpl::TestDiscreteNonlinearSystem<ADCGScalarDouble> TestDiscreteNonlinearSystemADDouble;
215 
216  // handy typedefs for the Jacobian
217  typedef ct::core::StateMatrix<state_dim, float> A_typeFloat;
218  typedef ct::core::StateMatrix<state_dim, double> A_typeDouble;
219 
222 
223  // create two nonlinear systems, one regular one and one auto-differentiable
224  const float rateFloat = 100.0;
225  const double rateDouble = static_cast<double>(rateFloat);
226 
227  shared_ptr<TestDiscreteNonlinearSystemADFloat> oscillatorADFloat(
228  new tpl::TestDiscreteNonlinearSystem<ADCGScalarFloat>(AD_ValueTypeFloat(rateFloat)));
229  shared_ptr<TestDiscreteNonlinearSystemADDouble> oscillatorADDouble(
230  new tpl::TestDiscreteNonlinearSystem<ADCGScalarDouble>(AD_ValueTypeDouble(rateDouble)));
231 
232  DiscreteSystemLinearizerADCG<state_dim, control_dim, float> adLinearizerFloat(oscillatorADFloat);
233  DiscreteSystemLinearizerADCG<state_dim, control_dim, double> adLinearizerDouble(oscillatorADDouble);
234 
235  // do just in time compilation of the Jacobians
236  std::cout << "compiling..." << std::endl;
237  adLinearizerFloat.compileJIT("ADCGCodegenLibFloat");
238  adLinearizerDouble.compileJIT("ADCGCodegenLibDouble");
239  std::cout << "... done compiling!" << std::endl;
240 
241  // create state, control and time variables
242  StateVector<state_dim, float> xFloat;
243  StateVector<state_dim, double> xDouble;
244  ControlVector<control_dim, float> uFloat;
245  ControlVector<control_dim, double> uDouble;
246  int n = 0;
247 
248  for (size_t i = 0; i < 1000; i++)
249  {
250  // set a random state
251  xFloat.setRandom();
252  xDouble = xFloat.cast<double>();
253  uFloat.setRandom();
254  uDouble = uFloat.cast<double>();
255 
256  A_typeFloat A_Float;
257  B_typeFloat B_Float;
258  adLinearizerFloat.getAandB(xFloat, uFloat, xFloat, n, 1, A_Float, B_Float);
259 
260  A_typeDouble A_Double;
261  B_typeDouble B_Double;
262  adLinearizerDouble.getAandB(xDouble, uDouble, xDouble, n, 1, A_Double, B_Double);
263 
264  // verify the result //FIXME: this tolerance is too high
265  ASSERT_LT((A_Double - A_Float.cast<double>()).array().abs().maxCoeff(), 1e-5);
266  ASSERT_LT((B_Double - B_Float.cast<double>()).array().abs().maxCoeff(), 1e-5);
267  }
268 
269  try
270  {
271  std::cout << "generating code..." << std::endl;
272  // generate code for the Jacobians
273  adLinearizerFloat.generateCode("TestDiscreteNonlinearSystemLinearizedFloat");
274  adLinearizerDouble.generateCode("TestDiscreteNonlinearSystemLinearizedDouble");
275  std::cout << "... done!" << std::endl;
276  } catch (const std::runtime_error& e)
277  {
278  std::cout << "code generation failed: " << e.what() << std::endl;
279  ASSERT_TRUE(false);
280  }
281 }
ct::core::ControlVector< control_dim > u
Definition: StateMatrix.h:12
TEST(DiscreteSystemLinearizerADCG, JITCompilationTest)
Definition: DiscreteSystemLinearizerADCGTest.h:13
constexpr size_t n
Definition: MatrixInversionTest.cpp:14
const size_t state_dim
Definition: SymplecticIntegrationTest.cpp:14
for i
tpl::TestDiscreteNonlinearSystem< double > TestDiscreteNonlinearSystem
Definition: TestDiscreteNonlinearSystem.h:56
const size_t control_dim
Definition: SymplecticIntegrationTest.cpp:17
ct::core::StateVector< state_dim > x
SCALAR::value_type AD_ValueType
Definition: StateControlMatrix.h:12