- 3.0.2 core module.
ADCodegenLinearizerTest.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 #include "TestNonlinearSystem.h"
9 
13 TEST(ADCodegenLinearizerTest, JITCompilationTest)
14 {
15  // define the dimensions of the system
16  const size_t state_dim = TestNonlinearSystem::STATE_DIM;
17  const size_t control_dim = TestNonlinearSystem::CONTROL_DIM;
18 
19  // typedefs for the auto-differentiable codegen system
20  typedef ADCodegenLinearizer<state_dim, control_dim>::ADCGScalar Scalar;
21  typedef typename Scalar::value_type AD_ValueType;
22  typedef tpl::TestNonlinearSystem<Scalar> TestNonlinearSystemAD;
23 
24  // handy typedefs for the Jacobian
27 
28  // create two nonlinear systems, one regular one and one auto-differentiable
29  const double w_n = 100.0;
30  shared_ptr<TestNonlinearSystem> oscillator(new TestNonlinearSystem(w_n));
31  shared_ptr<TestNonlinearSystemAD> oscillatorAD(new tpl::TestNonlinearSystem<Scalar>(AD_ValueType(w_n)));
32 
33  // create two nonlinear systems, one regular one and one auto-diff codegen
34  SystemLinearizer<state_dim, control_dim> systemLinearizer(oscillator);
35  ADCodegenLinearizer<state_dim, control_dim> adLinearizer(oscillatorAD);
36 
37  // do just in time compilation of the Jacobians
38  std::cout << "compiling..." << std::endl;
39  adLinearizer.compileJIT("ADCGCodegenLib");
40  std::cout << "... done!" << std::endl;
41 
42  std::shared_ptr<ADCodegenLinearizer<state_dim, control_dim>> adLinearizerClone(adLinearizer.clone());
43  std::cout << "compiling the clone..." << std::endl;
44  adLinearizerClone->compileJIT("ADCGCodegenLibCone");
45  std::cout << "... done!" << std::endl;
46 
47  // create state, control and time variables
48  StateVector<TestNonlinearSystem::STATE_DIM> x;
49  ControlVector<TestNonlinearSystem::CONTROL_DIM> u;
50  double t = 0;
51 
52  for (size_t i = 0; i < 1000; i++)
53  {
54  // set a random state
55  x.setRandom();
56  u.setRandom();
57 
58  // use the numerical differentiation linearizer
59  A_type A_system = systemLinearizer.getDerivativeState(x, u, t);
60  B_type B_system = systemLinearizer.getDerivativeControl(x, u, t);
61 
62  // use the auto diff codegen linearzier
63  A_type A_ad = adLinearizer.getDerivativeState(x, u, t);
64  B_type B_ad = adLinearizer.getDerivativeControl(x, u, t);
65 
66  A_type A_adCloned = adLinearizerClone->getDerivativeState(x, u, t);
67  B_type B_adCloned = adLinearizerClone->getDerivativeControl(x, u, t);
68 
69  // verify the result
70  ASSERT_LT((A_system - A_ad).array().abs().maxCoeff(), 1e-5);
71  ASSERT_LT((B_system - B_ad).array().abs().maxCoeff(), 1e-5);
72 
73  ASSERT_LT((A_system - A_adCloned).array().abs().maxCoeff(), 1e-5);
74  ASSERT_LT((B_system - B_adCloned).array().abs().maxCoeff(), 1e-5);
75  }
76 }
77 
78 
82 TEST(ADCodegenLinearizerTest, JITCloneTest)
83 {
84  // define the dimensions of the system
85  const size_t state_dim = TestNonlinearSystem::STATE_DIM;
86  const size_t control_dim = TestNonlinearSystem::CONTROL_DIM;
87 
88  // typedefs for the auto-differentiable codegen system
89  typedef ADCodegenLinearizer<state_dim, control_dim>::ADCGScalar Scalar;
90  typedef typename Scalar::value_type AD_ValueType;
91  typedef tpl::TestNonlinearSystem<Scalar> TestNonlinearSystemAD;
92 
93  // handy typedefs for the Jacobian
96 
97  // create two nonlinear systems, one regular one and one auto-differentiable
98  const double w_n = 100.0;
99  shared_ptr<TestNonlinearSystem> oscillator(new TestNonlinearSystem(w_n));
100  shared_ptr<TestNonlinearSystemAD> oscillatorAD(new tpl::TestNonlinearSystem<Scalar>(AD_ValueType(w_n)));
101 
102  // create two nonlinear systems, one regular one and one auto-diff codegen
103  SystemLinearizer<state_dim, control_dim> systemLinearizer(oscillator);
104  ADCodegenLinearizer<state_dim, control_dim> adLinearizer(oscillatorAD);
105 
106  // do just in time compilation of the Jacobians
107  std::cout << "compiling..." << std::endl;
108  adLinearizer.compileJIT("ADCGCodegenLib");
109  std::cout << "... done!" << std::endl;
110 
111  // compilation should not even be required
112  std::cout << "cloning without compilation..." << std::endl;
113  std::shared_ptr<ADCodegenLinearizer<state_dim, control_dim>> adLinearizerClone(adLinearizer.clone());
114 
115  // make sure the underlying dynamic libraries are not identical (dynamic library cloned correctly)
116  if (adLinearizerClone->getLinearizer().getDynamicLib() == adLinearizer.getLinearizer().getDynamicLib())
117  {
118  std::cout << "FATAL ERROR: dynamic library not cloned correctly in JIT." << std::endl;
119  ASSERT_TRUE(false);
120  }
121 
122  // create state, control and time variables
123  StateVector<TestNonlinearSystem::STATE_DIM> x;
124  ControlVector<TestNonlinearSystem::CONTROL_DIM> u;
125  double t = 0;
126 
127  for (size_t i = 0; i < 1000; i++)
128  {
129  // set a random state
130  x.setRandom();
131  u.setRandom();
132 
133  // use the numerical differentiation linearizer
134  A_type A_system = systemLinearizer.getDerivativeState(x, u, t);
135  B_type B_system = systemLinearizer.getDerivativeControl(x, u, t);
136 
137  // use the auto diff codegen linearzier
138  A_type A_ad = adLinearizer.getDerivativeState(x, u, t);
139  B_type B_ad = adLinearizer.getDerivativeControl(x, u, t);
140 
141  A_type A_adCloned = adLinearizerClone->getDerivativeState(x, u, t);
142  B_type B_adCloned = adLinearizerClone->getDerivativeControl(x, u, t);
143 
144  // verify the result
145  ASSERT_LT((A_system - A_ad).array().abs().maxCoeff(), 1e-5);
146  ASSERT_LT((B_system - B_ad).array().abs().maxCoeff(), 1e-5);
147 
148  ASSERT_LT((A_system - A_adCloned).array().abs().maxCoeff(), 1e-5);
149  ASSERT_LT((B_system - B_adCloned).array().abs().maxCoeff(), 1e-5);
150  }
151 }
152 
153 
157 TEST(ADCodegenLinearizerTest, CodegenTest)
158 {
159  // define the dimensions of the system
160  const size_t state_dim = TestNonlinearSystem::STATE_DIM;
161  const size_t control_dim = TestNonlinearSystem::CONTROL_DIM;
162 
163  // typedefs for the auto-differentiable codegen system
164  typedef ADCodegenLinearizer<state_dim, control_dim>::ADCGScalar Scalar;
165  typedef typename Scalar::value_type AD_ValueType;
166  typedef tpl::TestNonlinearSystem<Scalar> TestNonlinearSystemAD;
167 
168  // create an auto-differentiable codegen system
169  const double w_n = 100.0;
170  shared_ptr<TestNonlinearSystemAD> oscillatorAD(new tpl::TestNonlinearSystem<Scalar>(AD_ValueType(w_n)));
171 
172  // create a linearizer that uses codegeneration
173  ADCodegenLinearizer<state_dim, control_dim> adLinearizer(oscillatorAD);
174 
175  try
176  {
177  std::cout << "generating code..." << std::endl;
178  // generate code for the Jacobians
179  adLinearizer.generateCode("TestNonlinearSystemLinearized");
180  std::cout << "... done!" << std::endl;
181  } catch (const std::runtime_error& e)
182  {
183  std::cout << "code generation failed: " << e.what() << std::endl;
184  ASSERT_TRUE(false);
185  }
186 }
187 
188 TEST(ADCodegenLinearizerTestMP, JITCompilationTestMP)
189 {
190  const size_t state_dim = TestNonlinearSystem::STATE_DIM;
191  const size_t control_dim = TestNonlinearSystem::CONTROL_DIM;
192 
193  // typedefs for the auto-differentiable codegen system
194  typedef ADCodegenLinearizer<state_dim, control_dim>::ADCGScalar Scalar;
195  typedef typename Scalar::value_type AD_ValueType;
196  typedef tpl::TestNonlinearSystem<Scalar> TestNonlinearSystemAD;
197 
198  // handy typedefs for the Jacobian
199  typedef Eigen::Matrix<double, state_dim, state_dim> A_type;
200  typedef Eigen::Matrix<double, state_dim, control_dim> B_type;
201 
202  // // create two nonlinear systems, one regular one and one auto-differentiable
203  const double w_n = 100.0;
204  shared_ptr<TestNonlinearSystem> oscillator(new TestNonlinearSystem(w_n));
205  shared_ptr<TestNonlinearSystemAD> oscillatorAD(new tpl::TestNonlinearSystem<Scalar>(AD_ValueType(w_n)));
206 
207  // // create two nonlinear systems, one regular one and one auto-diff codegen
208  SystemLinearizer<state_dim, control_dim> systemLinearizer(oscillator);
209 
210  ADCodegenLinearizer<state_dim, control_dim> adLinearizer(oscillatorAD);
211  adLinearizer.compileJIT("ADMPTestLib");
212 
213  size_t nThreads = 4;
214  std::vector<std::shared_ptr<ADCodegenLinearizer<state_dim, control_dim>>> adLinearizers;
215  std::vector<std::shared_ptr<SystemLinearizer<state_dim, control_dim>>> systemLinearizers;
216 
217  for (size_t i = 0; i < nThreads; ++i)
218  {
219  adLinearizers.push_back(std::shared_ptr<ADCodegenLinearizer<state_dim, control_dim>>(adLinearizer.clone()));
220  adLinearizers.back()->compileJIT();
221  systemLinearizers.push_back(
222  std::shared_ptr<SystemLinearizer<state_dim, control_dim>>(systemLinearizer.clone()));
223  }
224 
225 
226  size_t runs = 100000;
227 
228  for (size_t n = 0; n < runs; ++n)
229  {
230  std::vector<std::thread> threads;
231 
232  for (size_t i = 0; i < nThreads; ++i)
233  {
234  threads.push_back(std::thread([i, &adLinearizers, &systemLinearizers]() {
235  StateVector<TestNonlinearSystem::STATE_DIM> x;
236  ControlVector<TestNonlinearSystem::CONTROL_DIM> u;
237  double t = 0;
238 
239  x.setRandom();
240  u.setRandom();
241 
242  // use the numerical differentiation linearizer
243  A_type A_system = systemLinearizers[i]->getDerivativeState(x, u, t);
244  B_type B_system = systemLinearizers[i]->getDerivativeControl(x, u, t);
245 
246  // use the auto differentiation linearzier
247  A_type A_ad = adLinearizers[i]->getDerivativeState(x, u, t);
248  B_type B_ad = adLinearizers[i]->getDerivativeControl(x, u, t);
249 
250  // verify the result
251  ASSERT_LT((A_system - A_ad).array().abs().maxCoeff(), 1e-5);
252  ASSERT_LT((B_system - B_ad).array().abs().maxCoeff(), 1e-5);
253  }));
254  }
255 
256 
257  for (auto& thr : threads)
258  thr.join();
259  }
260 }
tpl::TestNonlinearSystem< double > TestNonlinearSystem
Definition: TestNonlinearSystem.h:53
ct::core::ControlVector< control_dim > u
Definition: StateMatrix.h:12
ct::core::ADCodegenLinearizer< state_dim, control_dim >::ADCGScalar Scalar
const double w_n
clear all close all load ct GNMSLog0 mat reformat t
constexpr size_t n
Definition: MatrixInversionTest.cpp:14
const size_t state_dim
Definition: SymplecticIntegrationTest.cpp:14
for i
const size_t control_dim
Definition: SymplecticIntegrationTest.cpp:17
TEST(ADCodegenLinearizerTest, JITCompilationTest)
Definition: ADCodegenLinearizerTest.h:13
ct::core::StateVector< state_dim > x
SCALAR::value_type AD_ValueType
Definition: StateControlMatrix.h:12