erk_3sweep_export.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ACADO Toolkit.
3  *
4  * ACADO Toolkit -- A Toolkit for Automatic Control and Dynamic Optimization.
5  * Copyright (C) 2008-2014 by Boris Houska, Hans Joachim Ferreau,
6  * Milan Vukov, Rien Quirynen, KU Leuven.
7  * Developed within the Optimization in Engineering Center (OPTEC)
8  * under supervision of Moritz Diehl. All rights reserved.
9  *
10  * ACADO Toolkit is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 3 of the License, or (at your option) any later version.
14  *
15  * ACADO Toolkit is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with ACADO Toolkit; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 
26 
27 
36 
37 using namespace std;
38 
40 
41 //
42 // PUBLIC MEMBER FUNCTIONS:
43 //
44 
46  const std::string& _commonHeaderName
47  ) : AdjointERKExport( _userInteraction,_commonHeaderName )
48 {
49 }
50 
51 
53  ) : AdjointERKExport( arg )
54 {
55 }
56 
57 
59 {
60  clear( );
61 }
62 
63 
64 
66 {
67  int sensGen;
68  get( DYNAMIC_SENSITIVITY,sensGen );
69 
70  OnlineData dummy0;
71  Control dummy1;
72  DifferentialState dummy2;
73  AlgebraicState dummy3;
75  dummy0.clearStaticCounters();
76  dummy1.clearStaticCounters();
77  dummy2.clearStaticCounters();
78  dummy3.clearStaticCounters();
79  dummy4.clearStaticCounters();
80 
81  x = DifferentialState("", NX, 1);
83  z = AlgebraicState("", NXA, 1);
84  u = Control("", NU, 1);
85  od = OnlineData("", NOD, 1);
86 
87  if( NDX > 0 && NDX != NX ) {
89  }
90  if( rhs_.getNumRows() != (NX+NXA) ) {
92  }
93 
94  DifferentialEquation f, g, h, f_ODE;
95  // add usual ODE
96  f_ODE << rhs_;
97  if( f_ODE.getNDX() > 0 ) {
99  }
100 
101  uint numX = NX*(NX+1)/2.0;
102  uint numU = NU*(NU+1)/2.0;
103  uint numZ = (NX+NU)*(NX+NU+1)/2.0;
104  if( (ExportSensitivityType)sensGen == SYMMETRIC ) {
105  // SWEEP 1:
106  // ---------
107  f << rhs_;
108 
109 
110  // SWEEP 2:
111  // ---------
112  DifferentialState lx("", NX,1);
113 
114  Expression tmp = backwardDerivative(rhs_, x, lx);
115  g << tmp;
116 
117 
118  // SWEEP 3:
119  // ---------
120  DifferentialState Gx("", NX,NX), Gu("", NX,NU);
121  DifferentialState H("", numZ,1);
122 
123  Expression S = Gx;
124  S.appendCols(Gu);
125  Expression arg;
126  arg << x;
127  arg << u;
128 
129  // SYMMETRIC DERIVATIVES
130  Expression S_tmp = S;
131  S_tmp.appendRows(zeros<double>(NU,NX).appendCols(eye<double>(NU)));
132 
133  Expression dfS;
134  Expression h_tmp = symmetricDerivative( rhs_, arg, S_tmp, lx, &dfS );
135  h << dfS.getCols(0,NX);
136  h << dfS.getCols(NX,NX+NU);
137  h << returnLowerTriangular( h_tmp );
138 
139  // OLD VERSION:
140 // // add VDE for differential states
141 // h << multipleForwardDerivative( rhs_, x, Gx );
142 //
143 // // add VDE for control inputs
144 // h << multipleForwardDerivative( rhs_, x, Gu ) + forwardDerivative( rhs_, u );
145 //
146 // IntermediateState tmp2 = forwardDerivative(tmp, x);
147 // Expression tmp3 = backwardDerivative(rhs_, u, lx);
148 // Expression tmp4 = multipleForwardDerivative(tmp3, x, Gu);
149 //
150 // // TODO: include a symmetric_AD_operator to strongly improve the symmetric left-right multiplied second order derivative computations !!
152 // h << symmetricDoubleProduct(tmp2, Gx);
153 // h << Gu.transpose()*tmp2*Gx + multipleForwardDerivative(tmp3, x, Gx);
154 // Expression tmp7 = tmp4 + tmp4.transpose() + forwardDerivative(tmp3, u);
155 // h << symmetricDoubleProduct(tmp2, Gu) + returnLowerTriangular(tmp7);
156  }
157  else {
158  return ACADOERROR( RET_INVALID_OPTION );
159  }
160  if( f.getNT() > 0 ) timeDependant = true;
161 
162  return rhs.init(f, "acado_forward", NX, 0, NU, NP, NDX, NOD)
163  & diffs_rhs.init(g, "acado_backward", 2*NX, 0, NU, NP, NDX, NOD)
164  & diffs_sweep3.init(h, "acado_forward_sweep3", 2*NX + NX*(NX+NU) + numX + NX*NU + numU, 0, NU, NP, NDX, NOD);
165 }
166 
167 
169 {
170  int sensGen;
171  get( DYNAMIC_SENSITIVITY,sensGen );
173 
174  // NOT SUPPORTED: since the forward sweep needs to be saved
176 
177  // NOT SUPPORTED: since the adjoint derivatives could be 'arbitrarily bad'
179 
180  LOG( LVL_DEBUG ) << "Preparing to export ThreeSweepsERKExport... " << endl;
181 
182  // export RK scheme
183  uint numX = NX*(NX+1)/2.0;
184  uint numU = NU*(NU+1)/2.0;
185  uint rhsDim = NX + NX + NX*(NX+NU) + numX + NX*NU + numU;
186  inputDim = rhsDim + NU + NOD;
187  const uint rkOrder = getNumStages();
188 
189  double h = (grid.getLastTime() - grid.getFirstTime())/grid.getNumIntervals();
190 
191  ExportVariable Ah ( "A*h", DMatrix( AA )*=h );
192  ExportVariable b4h( "b4*h", DMatrix( bb )*=h );
193 
194  rk_index = ExportVariable( "rk_index", 1, 1, INT, ACADO_LOCAL, true );
195  rk_eta = ExportVariable( "rk_eta", 1, inputDim );
196 // seed_backward.setup( "seed", 1, NX );
197 
198  int useOMP;
199  get(CG_USE_OPENMP, useOMP);
200  ExportStruct structWspace;
201  structWspace = useOMP ? ACADO_LOCAL : ACADO_WORKSPACE;
202 
203  rk_ttt.setup( "rk_ttt", 1, 1, REAL, structWspace, true );
204  uint timeDep = 0;
205  if( timeDependant ) timeDep = 1;
206 
207  rk_xxx.setup("rk_xxx", 1, inputDim+timeDep, REAL, structWspace);
208  uint numK = NX*(NX+NU)+numX+NX*NU+numU;
209  rk_kkk.setup("rk_kkk", rkOrder, numK, REAL, structWspace);
210  rk_forward_sweep.setup("rk_sweep1", 1, grid.getNumIntervals()*rkOrder*NX, REAL, structWspace);
211  rk_backward_sweep.setup("rk_sweep2", 1, grid.getNumIntervals()*rkOrder*NX, REAL, structWspace);
212 
213  if ( useOMP )
214  {
215  ExportVariable auxVar;
216 
218  auxVar.setName( "odeAuxVar" );
219  auxVar.setDataStruct( ACADO_LOCAL );
221  }
222 
223  ExportIndex run( "run1" );
224 
225  // setup INTEGRATE function
226  integrate = ExportFunction( "integrate", rk_eta, reset_int );
228  rk_eta.setDoc( "Working array to pass the input values and return the results." );
229  reset_int.setDoc( "The internal memory of the integrator can be reset." );
230  rk_index.setDoc( "Number of the shooting interval." );
231  error_code.setDoc( "Status code of the integrator." );
232  integrate.doc( "Performs the integration and sensitivity propagation for one shooting interval." );
233  integrate.addIndex( run );
234 
236 
237  if( inputDim > rhsDim ) {
238  // initialize sensitivities:
239 // integrate.addStatement( rk_eta.getCols( NX,2*NX ) == seed_backward );
240  DMatrix idX = eye<double>( NX );
241  DMatrix zeroXU = zeros<double>( NX,NU );
242  integrate.addStatement( rk_eta.getCols( 2*NX,NX*(2+NX) ) == idX.makeVector().transpose() );
243  integrate.addStatement( rk_eta.getCols( NX*(2+NX),NX*(2+NX+NU) ) == zeroXU.makeVector().transpose() );
244 
245  integrate.addStatement( rk_eta.getCols( NX*(2+NX+NU),rhsDim ) == zeros<double>( 1,numX+NX*NU+numU ) );
246  // FORWARD SWEEP FIRST
247  integrate.addStatement( rk_xxx.getCols( NX,NX+NU+NOD ) == rk_eta.getCols( rhsDim,inputDim ) );
248  }
250 
251  // integrator loop: FORWARD SWEEP
252  ExportForLoop loop = ExportForLoop( run, 0, grid.getNumIntervals() );
253  for( uint run1 = 0; run1 < rkOrder; run1++ )
254  {
255  loop.addStatement( rk_xxx.getCols( 0,NX ) == rk_eta.getCols( 0,NX ) + Ah.getRow(run1)*rk_kkk.getCols( 0,NX ) );
256  // save forward trajectory
257  loop.addStatement( rk_forward_sweep.getCols( run*rkOrder*NX+run1*NX,run*rkOrder*NX+(run1+1)*NX ) == rk_xxx.getCols( 0,NX ) );
258  if( timeDependant ) loop.addStatement( rk_xxx.getCol( NX+NU+NOD ) == rk_ttt + ((double)cc(run1))/grid.getNumIntervals() );
260  }
261  loop.addStatement( rk_eta.getCols( 0,NX ) += b4h^rk_kkk.getCols( 0,NX ) );
262  loop.addStatement( rk_ttt += DMatrix(1.0/grid.getNumIntervals()) );
263  // end of integrator loop: FORWARD SWEEP
264  integrate.addStatement( loop );
265 
266  if( inputDim > rhsDim ) {
267  // BACKWARD SWEEP NEXT
268  integrate.addStatement( rk_xxx.getCols( 2*NX,2*NX+NU+NOD ) == rk_eta.getCols( rhsDim,inputDim ) );
269  }
270  // integrator loop: BACKWARD SWEEP
271  ExportForLoop loop2 = ExportForLoop( run, 0, grid.getNumIntervals() );
272  for( uint run1 = 0; run1 < rkOrder; run1++ )
273  {
274  // load forward trajectory
275  loop2.addStatement( rk_xxx.getCols( 0,NX ) == rk_forward_sweep.getCols( (grid.getNumIntervals()-run)*rkOrder*NX-(run1+1)*NX,(grid.getNumIntervals()-run)*rkOrder*NX-run1*NX ) );
276  loop2.addStatement( rk_xxx.getCols( NX,2*NX ) == rk_eta.getCols( NX,2*NX ) + Ah.getRow(run1)*rk_kkk.getCols( 0,NX ) );
277  // save backward trajectory
278  loop2.addStatement( rk_backward_sweep.getCols( run*rkOrder*NX+run1*NX,run*rkOrder*NX+(run1+1)*NX ) == rk_xxx.getCols( NX,2*NX ) );
279  if( timeDependant ) loop2.addStatement( rk_xxx.getCol( 2*NX+NU+NOD ) == rk_ttt - ((double)cc(run1))/grid.getNumIntervals() );
281  }
282  loop2.addStatement( rk_eta.getCols( NX,2*NX ) += b4h^rk_kkk.getCols( 0,NX ) );
283  loop2.addStatement( rk_ttt -= DMatrix(1.0/grid.getNumIntervals()) );
284  // end of integrator loop: BACKWARD SWEEP
285  integrate.addStatement( loop2 );
286 
287  if( inputDim > rhsDim ) {
288  // THIRD SWEEP NEXT
289  integrate.addStatement( rk_xxx.getCols( rhsDim,inputDim ) == rk_eta.getCols( rhsDim,inputDim ) );
290  }
291  // integrator loop: THIRD SWEEP
292  ExportForLoop loop3 = ExportForLoop( run, 0, grid.getNumIntervals() );
293  for( uint run1 = 0; run1 < rkOrder; run1++ )
294  {
295  // load forward trajectory
296  loop3.addStatement( rk_xxx.getCols( 0,NX ) == rk_forward_sweep.getCols( run*rkOrder*NX+run1*NX,run*rkOrder*NX+(run1+1)*NX ) );
297  // load backward trajectory
298  loop3.addStatement( rk_xxx.getCols( NX,2*NX ) == rk_backward_sweep.getCols( (grid.getNumIntervals()-run)*rkOrder*NX-(run1+1)*NX,(grid.getNumIntervals()-run)*rkOrder*NX-run1*NX ) );
299  loop3.addStatement( rk_xxx.getCols( 2*NX,rhsDim ) == rk_eta.getCols( 2*NX,rhsDim ) + Ah.getRow(run1)*rk_kkk.getCols( 0,NX*(NX+NU)+numX+NX*NU+numU ) );
300  if( timeDependant ) loop3.addStatement( rk_xxx.getCol( inputDim ) == rk_ttt + ((double)cc(run1))/grid.getNumIntervals() );
302  }
303  loop3.addStatement( rk_eta.getCols( 2*NX,rhsDim ) += b4h^rk_kkk.getCols( 0,NX*(NX+NU)+numX+NX*NU+numU ) );
304  loop3.addStatement( rk_ttt += DMatrix(1.0/grid.getNumIntervals()) );
305  // end of integrator loop: THIRD SWEEP
306  integrate.addStatement( loop3 );
307 
309 
310  LOG( LVL_DEBUG ) << "done" << endl;
311 
312  return SUCCESSFUL_RETURN;
313 }
314 
315 
317  ExportStruct dataStruct
318  ) const
319 {
320  AdjointERKExport::getDataDeclarations( declarations, dataStruct );
321 
322  declarations.addDeclaration( rk_backward_sweep,dataStruct );
323 
324  return SUCCESSFUL_RETURN;
325 }
326 
327 
329  )
330 {
331  int useOMP;
332  get(CG_USE_OPENMP, useOMP);
333  if ( useOMP )
334  {
336 
337  code << "#pragma omp threadprivate( "
338  << getAuxVariable().getFullName() << ", "
339  << rk_xxx.getFullName() << ", "
340  << rk_ttt.getFullName() << ", "
341  << rk_kkk.getFullName() << ", "
342  << rk_forward_sweep.getFullName() << ", "
344  << " )\n\n";
345  }
346 
347  int sensGen;
348  get( DYNAMIC_SENSITIVITY,sensGen );
349  if( exportRhs ) {
350  code.addFunction( rhs );
351  code.addFunction( diffs_rhs );
352  code.addFunction( diffs_sweep3 );
353  }
354 
355  double h = (grid.getLastTime() - grid.getFirstTime())/grid.getNumIntervals();
356  code.addComment(std::string("Fixed step size:") + toString(h));
357  code.addFunction( integrate );
358 
359  return SUCCESSFUL_RETURN;
360 }
361 
362 
364 // std::cout << "returnLowerTriangular with " << expr.getNumRows() << " rows and " << expr.getNumCols() << " columns\n";
365  ASSERT( expr.getNumRows() == expr.getNumCols() );
366 
367  Expression new_expr;
368  for( uint i = 0; i < expr.getNumRows(); i++ ) {
369  for( uint j = 0; j <= i; j++ ) {
370  new_expr << expr(i,j);
371  }
372  }
373  return new_expr;
374 }
375 
376 
378 
379  // NOTE: the speedup of the three-sweeps-propagation approach is strongly dependent on the support for this specific operator which shows many symmetries
380  uint dim = arg.getNumCols();
381  uint dim2 = arg.getNumRows();
382 
383  IntermediateState inter_res = zeros<double>(dim2,dim);
384  for( uint i = 0; i < dim; i++ ) {
385  for( uint k1 = 0; k1 < dim2; k1++ ) {
386  for( uint k2 = 0; k2 <= k1; k2++ ) {
387  inter_res(k1,i) += expr(k1,k2)*arg(k2,i);
388  }
389  for( uint k2 = k1+1; k2 < dim2; k2++ ) {
390  inter_res(k1,i) += expr(k2,k1)*arg(k2,i);
391  }
392  }
393  }
394 
395  Expression new_expr;
396  for( uint i = 0; i < dim; i++ ) {
397  for( uint j = 0; j <= i; j++ ) {
398  Expression new_tmp = 0;
399  for( uint k1 = 0; k1 < dim2; k1++ ) {
400  new_tmp = new_tmp+arg(k1,i)*inter_res(k1,j);
401  }
402  new_expr << new_tmp;
403  }
404  }
405  return new_expr;
406 // return returnLowerTriangular(arg.transpose()*expr*arg, dim);
407 }
408 
409 
411 {
412  ExportVariable max;
414  if( diffs_rhs.getGlobalExportVariable().getDim() > max.getDim() ) {
416  }
419  }
420  return max;
421 }
422 
423 // PROTECTED:
424 
425 
426 
428 
429 // end of file.
#define LOG(level)
Just define a handy macro for getting the logger.
Lowest level, the debug level.
virtual returnValue setup()
Expression symmetricDerivative(const Expression &arg1, const Expression &arg2, const Expression &forward_seed, const Expression &backward_seed, Expression *forward_result, Expression *backward_result)
ThreeSweepsERKExport(UserInteraction *_userInteraction=0, const std::string &_commonHeaderName="")
virtual returnValue getCode(ExportStatementBlock &code)
ExportVariable getRow(const ExportIndex &idx) const
Expression backwardDerivative(const Expression &arg1, const Expression &arg2)
ExportVariable getGlobalExportVariable() const
double getFirstTime() const
ExportVariable & setup(const std::string &_name, uint _nRows=1, uint _nCols=1, ExportType _type=REAL, ExportStruct _dataStruct=ACADO_LOCAL, bool _callItByValue=false, const std::string &_prefix=std::string())
ExportAcadoFunction diffs_rhs
int getNDX() const
Definition: function.cpp:217
ExportVariable rk_index
Allows to pass back messages to the calling function.
ExportVariable rk_kkk
Definition: rk_export.hpp:189
GenericMatrix & makeVector()
Definition: matrix.cpp:124
DifferentialState x
uint getNumCols() const
uint getNumRows() const
returnValue addComment(const std::string &_comment)
BEGIN_NAMESPACE_ACADO typedef unsigned int uint
Definition: acado_types.hpp:42
Allows to export code of a for-loop.
Expression getCols(const uint &colIdx1, const uint &colIdx2) const
Definition: expression.cpp:582
string toString(T const &value)
returnValue setName(const std::string &_name)
Definition: export_data.cpp:61
#define CLOSE_NAMESPACE_ACADO
GenericMatrix< double > DMatrix
Definition: matrix.hpp:457
const std::string getNameDiffsRHS() const
Defines a scalar-valued index variable to be used for exporting code.
virtual returnValue setDifferentialEquation(const Expression &rhs)
Expression returnLowerTriangular(const Expression &expr)
Base class for all variables within the symbolic expressions family.
Definition: expression.hpp:56
virtual returnValue setDoc(const std::string &_doc)
ExportVariable rk_eta
ExportStruct
virtual ExportFunction & doc(const std::string &_doc)
ExportVariable getCols(const ExportIndex &idx1, const ExportIndex &idx2) const
virtual returnValue getDataDeclarations(ExportStatementBlock &declarations, ExportStruct dataStruct=ACADO_ANY) const
const std::string getNameRHS() const
ExportVariable reset_int
ExportVariable rk_forward_sweep
Expression & appendRows(const Expression &arg)
Definition: expression.cpp:141
Encapsulates all user interaction for setting options, logging data and plotting results.
Allows to export code of an arbitrary function.
virtual uint getDim() const
returnValue setDataStruct(ExportStruct _dataStruct)
Definition: export_data.cpp:80
returnValue addStatement(const ExportStatement &_statement)
virtual returnValue getDataDeclarations(ExportStatementBlock &declarations, ExportStruct dataStruct=ACADO_ANY) const
int getNT() const
Definition: function.cpp:251
ExportFunction integrate
std::string getFullName() const
returnValue addLinebreak(uint num=1)
#define ASSERT(x)
ExportFunction & setReturnValue(const ExportVariable &_functionReturnValue, bool _returnAsPointer=false)
uint getNumIntervals() const
returnValue setGlobalExportVariable(const ExportVariable &var)
ExportVariable rk_backward_sweep
ExportVariable rk_xxx
DifferentialStateDerivative dx
std::string getName() const
returnValue addDeclaration(const ExportVariable &_data, ExportStruct _dataStruct=ACADO_ANY)
double getLastTime() const
ExportAcadoFunction diffs_sweep3
ExportVariable rk_ttt
ExportVariable getAuxVariable() const
#define BEGIN_NAMESPACE_ACADO
ExportVariable error_code
returnValue clearStaticCounters()
Definition: expression.hpp:398
Allows to export a tailored explicit Runge-Kutta integrator with three-sweeps second order sensitivit...
returnValue addFunction(const ExportFunction &_function)
Expression & appendCols(const Expression &arg)
Definition: expression.cpp:162
virtual returnValue clear()
Allows to export code for a block of statements.
Allows to export a tailored explicit Runge-Kutta integrator with adjoint first order sensitivity prop...
ExportArgument getAddress(const ExportIndex &_rowIdx, const ExportIndex &_colIdx=emptyConstExportIndex) const
Expression symmetricDoubleProduct(const Expression &expr, const Expression &arg)
ExportVariable getCol(const ExportIndex &idx) const
returnValue init(const Function &_f, const std::string &_name="acadoFcn", const uint _numX=0, const uint _numXA=0, const uint _numU=0, const uint _numP=0, const uint _numDX=0, const uint _numOD=0)
ExportFunction & addIndex(const ExportIndex &_index)
#define ACADOERROR(retval)
virtual bool equidistantControlGrid() const
Defines a matrix-valued variable to be used for exporting code.
ExportAcadoFunction rhs
returnValue addFunctionCall(const std::string &_fName, const ExportArgument &_argument1=emptyConstExportArgument, const ExportArgument &_argument2=emptyConstExportArgument, const ExportArgument &_argument3=emptyConstExportArgument, const ExportArgument &_argument4=emptyConstExportArgument, const ExportArgument &_argument5=emptyConstExportArgument, const ExportArgument &_argument6=emptyConstExportArgument, const ExportArgument &_argument7=emptyConstExportArgument, const ExportArgument &_argument8=emptyConstExportArgument, const ExportArgument &_argument9=emptyConstExportArgument)
Allows to setup and evaluate differential equations (ODEs and DAEs) based on SymbolicExpressions.
BooleanType is_symmetric
Definition: rk_export.hpp:194


acado
Author(s): Milan Vukov, Rien Quirynen
autogenerated on Mon Jun 10 2019 12:34:33