export_arithmetic_statement.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 #include <iomanip>
38 
39 using namespace std;
41 
42 //
43 // PUBLIC MEMBER FUNCTIONS:
44 //
45 
47 {
48  op0 = ESO_UNDEFINED;
49  op1 = ESO_UNDEFINED;
50  op2 = ESO_UNDEFINED;
51 }
52 
55  const ExportVariable& _rhs1,
57  const ExportVariable& _rhs2,
59  const ExportVariable& _rhs3
60  ) : ExportStatement( )
61 {
62  ASSERT( ( _op0 == ESO_UNDEFINED ) || ( _op0 == ESO_ASSIGN ) || ( _op0 == ESO_ADD_ASSIGN ) || ( _op0 == ESO_SUBTRACT_ASSIGN ) );
63  ASSERT( ( _op2 == ESO_UNDEFINED ) || ( _op2 == ESO_ADD ) || ( _op2 == ESO_SUBTRACT ) );
64 
65  lhs = _lhs;
66  rhs1 = _rhs1;
67  rhs2 = _rhs2;
68  rhs3 = _rhs3;
69 
70  op0 = _op0;
71  op1 = _op1;
72  op2 = _op2;
73 }
74 
76 {}
77 
79 {
80  return new ExportArithmeticStatement(*this);
81 }
82 
83 
85 {
86  if ( rhs1.isNull() )
87  return 0;
88 
90  return rhs1->getNumRows( );
91 
92  return rhs1->getNumCols( );
93 }
94 
95 
97 {
98  if ( rhs1.isNull() )
99  return 0;
100 
101  if ( rhs2.isNull() )
102  return rhs1->getNumCols( );
103 
104  return rhs2->getNumCols( );
105 }
106 
107 
109  const std::string& _realString,
110  const std::string& _intString,
111  int _precision
112  ) const
113 {
114  return SUCCESSFUL_RETURN;
115 }
116 
117 
119  const std::string& _realString,
120  const std::string& _intString,
121  int _precision
122  ) const
123 {
124  ASSERT(lhs.isNull() == false);
125 
126  if (lhs.getDim() == 0 || rhs1.getDim() == 0 || rhs2.getDim() == 0)
127  return SUCCESSFUL_RETURN;
128 
129  if (lhs->isGiven() == true && lhs->getDim() > 0)
130  {
131  LOG( LVL_ERROR ) << "Left hand side ('" << lhs.getFullName() << "') of an arithmetic "
132  "expression is given." << endl;
134  }
135 
136  if (memAllocator == 0)
137  return ACADOERRORTEXT(RET_INVALID_ARGUMENTS, "Memory allocator is not defined.");
138 
139  IoFormatter iof( stream );
140  iof.set(_precision, iof.width, iof.flags);
141 
142  switch ( op1 )
143  {
144  case ESO_ADD:
145  return exportCodeAddSubtract(stream, "+", _realString, _intString);
146 
147  case ESO_SUBTRACT:
148  return exportCodeAddSubtract(stream, "-", _realString, _intString);
149 
150  case ESO_ADD_ASSIGN:
151  return exportCodeAssign(stream, "+=", _realString, _intString);
152 
153  case ESO_SUBTRACT_ASSIGN:
154  return exportCodeAssign(stream, "-=", _realString, _intString);
155 
156  case ESO_MULTIPLY:
157  return exportCodeMultiply(stream, false, _realString, _intString);
158 
160  return exportCodeMultiply(stream, true, _realString, _intString);
161 
162  case ESO_ASSIGN:
163  return exportCodeAssign(stream, "=", _realString, _intString);
164 
165  default:
166  return ACADOERROR( RET_UNKNOWN_BUG );
167  }
168 
169  iof.reset();
170 
171  return ACADOERROR( RET_UNKNOWN_BUG );
172 }
173 
174 //
175 // PROTECTED MEMBER FUNCTIONS:
176 //
177 
179  const std::string& _sign,
180  const std::string& _realString,
181  const std::string& _intString
182  ) const
183 {
184  if ( ( rhs1->getNumRows() != rhs2->getNumRows() ) || ( rhs1->getNumCols() != rhs2->getNumCols() ) )
186 
187  if (rhs1->getNumRows() != lhs->getNumRows() || rhs1->getNumCols() != lhs->getNumCols())
188  {
189  LOG( LVL_DEBUG )
190  << "lhs name is " << lhs.getName() << ", size: " << lhs.getNumRows() << " x " << lhs.getNumCols() << endl
191  << "rhs1 name is " << rhs1.getName() << ", size: " << rhs1.getNumRows() << " x " << rhs1.getNumCols() << endl;
192 
194  }
195 
196  //
197  // Rough approximation of flops needed for matrix multiplication
198  //
199  unsigned numberOfFlops = lhs->getNumRows() * lhs->getNumCols();
200 
201  //
202  // Optimization can be performed only if both matrices are not given.
203  // Currently, optimizations cannot be performed on hard-coded matrices.
204  //
205  bool optimizationsAllowed = ( rhs1->isGiven() == false ) && ( rhs2->isGiven() == false );
206 
207  if (numberOfFlops < 4096 || optimizationsAllowed == false)
208  {
209  for( uint i=0; i<getNumRows( ); ++i )
210  for( uint j=0; j<getNumCols( ); ++j )
211  {
212  if ( ( op0 != ESO_ASSIGN ) &&
213  ( rhs1->isGiven(i,j) == true ) && ( rhs2->isGiven(i,j) == true ) )
214  {
215  // check for zero value in case of "+=" or "-="
216  if ( ( op1 == ESO_ADD ) && ( acadoIsZero(rhs1(i, j) + rhs2(i, j)) == true ) )
217  continue;
218 
219  if ( ( op1 == ESO_SUBTRACT ) && ( acadoIsZero( rhs1(i, j) - rhs2(i, j)) == true ) )
220  continue;
221  }
222 
223  stream << lhs.get(i, j) << " " << getAssignString();
224 
225  if ( rhs1->isZero(i, j) == false )
226  {
227  stream << " " << rhs1->get(i, j);
228  if ( rhs2->isZero(i,j) == false )
229  stream << " " << _sign << " " << rhs2->get(i, j) << ";\n";
230  else
231  stream << ";" << endl;
232  }
233  else
234  {
235  if (rhs2->isZero(i, j) == false)
236  stream << " " << _sign << " " << rhs2->get(i, j) << ";\n";
237  else
238  stream << " 0.0;\n";
239  }
240  }
241  }
242  else if ( numberOfFlops < 32768 )
243  {
244  ExportIndex ii;
245  memAllocator->acquire( ii );
246 
247  stream << "for (" << ii.getName() << " = 0; ";
248  stream << ii.getName() << " < " << getNumRows() << "; ";
249  stream << "++" << ii.getName() << ")\n{\n";
250 
251  for(unsigned j = 0; j < getNumCols( ); ++j)
252  {
253  stream << lhs->get(ii, j) << " " << getAssignString();
254  stream << " " << _sign << " " << rhs2->get(ii, j) << ";\n";
255  }
256 
257  stream << "\n{\n";
258 
259  memAllocator->release( ii );
260  }
261  else
262  {
263  ExportIndex ii, jj;
264  memAllocator->acquire( ii );
265  memAllocator->acquire( jj );
266 
267  stream << "for (" << ii.getName() << " = 0; "
268  << ii.getName() << " < " << getNumRows() <<"; "
269  << "++" << ii.getName() << ")\n{\n";
270 
271  stream << "for (" << jj.getName() << " = 0; "
272  << jj.getName() << " < " << getNumCols() <<"; "
273  << "++" << jj.getName() << ")\n{\n";
274 
275  stream << lhs->get(ii, jj) << " " << getAssignString()
276  << _sign << " " << rhs2->get(ii, jj) << ";\n";
277 
278  stream << "\n}\n"
279  << "\n}\n";
280 
281  memAllocator->release( ii );
282  memAllocator->release( jj );
283  }
284 
285  return SUCCESSFUL_RETURN;
286 }
287 
289  bool transposeRhs1,
290  const std::string& _realString,
291  const std::string& _intString
292  ) const
293 {
294  uint nRowsRhs1;
295  uint nColsRhs1;
296 
297  if ( transposeRhs1 == false )
298  {
299  nRowsRhs1 = rhs1->getNumRows( );
300  nColsRhs1 = rhs1->getNumCols( );
301  }
302  else
303  {
304  nRowsRhs1 = rhs1->getNumCols( );
305  nColsRhs1 = rhs1->getNumRows( );
306  }
307 
308  if ( ( nColsRhs1 != rhs2->getNumRows( ) ) ||
309  ( nRowsRhs1 != lhs->getNumRows( ) ) ||
310  ( rhs2->getNumCols( ) != lhs->getNumCols( ) ) )
312 
313  char sign[2] = "+";
314 
315  if ( op2 != ESO_UNDEFINED )
316  {
317  if ( ( rhs3->getNumRows( ) != lhs->getNumRows( ) ) ||
318  ( rhs3->getNumCols( ) != lhs->getNumCols( ) ) )
320 
321  if ( op2 == ESO_SUBTRACT )
322  sign[0] = '-';
323  }
324 
325  bool allZero;
326 
327  ExportIndex ii, iiRhs1;
328  ExportIndex jj, jjRhs1;
329  ExportIndex kk, kkRhs1;
330 
331  //
332  // Rough approximation of flops needed for matrix multiplication
333  //
334  unsigned numberOfFlops = nRowsRhs1 * rhs2->getNumRows( ) * rhs2->getNumCols();
335 
336  //
337  // Optimization can be performed only if both matrices are not given.
338  // Currently, optimizations cannot be performed on hard-coded matrices.
339  //
340  bool optimizationsAllowed =
341  rhs1->isGiven() == false && rhs2->isGiven() == false;
342  if (op2 == ESO_ADD || op2 == ESO_SUBTRACT)
343  optimizationsAllowed &= rhs3.isGiven() == false;
344 
345  //
346  // Depending on the flops count different export strategies are performed
347  //
348  if (numberOfFlops < 4096 || optimizationsAllowed == false)
349  {
350  //
351  // Unroll all loops
352  //
353 
354  for(uint i = 0; i < getNumRows( ); ++i)
355  {
356  ii = i;
357 
358  for(uint j = 0; j < getNumCols( ); ++j)
359  {
360  allZero = true;
361 
362  stream << lhs->get(ii,j) << " " << getAssignString();
363 
364  for(uint k = 0; k < nColsRhs1; ++k)
365  {
366  kk = k;
367  if ( transposeRhs1 == false )
368  {
369  iiRhs1 = ii;
370  kkRhs1 = kk;
371  }
372  else
373  {
374  iiRhs1 = kk;
375  kkRhs1 = ii;
376  }
377 
378  if ( ( rhs1->isZero(iiRhs1,kkRhs1) == false ) &&
379  ( rhs2->isZero(kk,j) == false ) )
380  {
381  allZero = false;
382 
383  if ( rhs1->isOne(iiRhs1,kkRhs1) == false )
384  {
385  stream << " " << sign << " " << rhs1->get(iiRhs1,kkRhs1);
386 
387  if ( rhs2->isOne(kk,j) == false )
388  stream << "*" << rhs2->get(kk, j);
389  }
390  else
391  {
392  if ( rhs2->isOne(kk,j) == false )
393  stream << " " << sign << rhs2->get(kk,j);
394  else
395  stream << " " << sign << " 1.0";
396  }
397  }
398  }
399 
400  if (op2 == ESO_ADD && rhs3->isZero(ii, j) == false)
401  stream << " + " << rhs3->get(ii, j);
402  if (op2 == ESO_SUBTRACT && rhs3->isZero(ii, j) == false)
403  stream << " - " << rhs3->get(ii, j);
404  if (op2 == ESO_UNDEFINED && allZero == true)
405  stream << " 0.0;\n";
406 
407  stream << ";\n";
408  }
409  }
410  }
411 // else if ( numberOfFlops < 32768 )
412 // {
413 // //
414 // // Unroll two inner loops
415 // //
416 //
417 // memAllocator->acquire( ii );
418 //
419 // stream << "for (" << ii.getName() << " = 0; ";
420 // stream << ii.getName() << " < " << getNumRows() <<"; ";
421 // stream << "++" << ii.getName() << ")\n{\n";
422 //
423 // for(uint j = 0; j < getNumCols( ); ++j)
424 // {
425 // allZero = true;
426 //
427 // stream << lhs->get(ii,j) << " " << getAssignString();
428 //
429 // for(uint k = 0; k < nColsRhs1; ++k)
430 // {
431 // kk = k;
432 // if ( transposeRhs1 == false )
433 // {
434 // iiRhs1 = ii;
435 // kkRhs1 = kk;
436 // }
437 // else
438 // {
439 // iiRhs1 = kk;
440 // kkRhs1 = ii;
441 // }
442 //
443 // if ( ( rhs1->isZero(iiRhs1,kkRhs1) == false ) &&
444 // ( rhs2->isZero(kk,j) == false ) )
445 // {
446 // allZero = false;
447 //
448 // if ( rhs1->isOne(iiRhs1,kkRhs1) == false )
449 // {
450 // stream << sign << " " << rhs1->get(iiRhs1,kkRhs1);
451 // if ( rhs2->isOne(kk,j) == false )
452 // stream << "*" << rhs2->get(kk, j);
453 // }
454 // else
455 // {
456 // if ( rhs2->isOne(kk,j) == false )
457 // stream << " " << sign << " " << rhs2->get(kk,j);
458 // else
459 // stream << " " << sign << " 1.0";
460 // }
461 // }
462 // }
463 //
464 // if ( ( op2 == ESO_ADD ) || ( op2 == ESO_SUBTRACT ) )
465 // stream << " + " << rhs3->get(ii,j) << ";\n";
466 //
467 // if ( op2 == ESO_UNDEFINED )
468 // {
469 // if ( allZero == true )
470 // stream << " 0.0;\n";
471 // else
472 // stream << ";\n";
473 // }
474 // }
475 // stream << "\n}\n";
476 //
477 // memAllocator->release( ii );
478 // }
479  else
480  {
481  //
482  // Keep rolled first two outer loops
483  //
484 
485  memAllocator->acquire( ii );
486  memAllocator->acquire( jj );
487  memAllocator->acquire( kk );
488 
489  // First loop
490  stream << "for (" << ii.getName() << " = 0; ";
491  stream << ii.getName() << " < " << getNumRows() <<"; ";
492  stream << "++" << ii.getName() << ")\n{\n";
493 
494  // Second loop
495  stream << "for (" << jj.getName() << " = 0; ";
496  stream << jj.getName() << " < " << getNumCols() <<"; ";
497  stream << "++" << jj.getName() << ")\n{\n";
498 
499  stream << _realString << " t = 0.0;" << endl;
500 
501  // Third loop
502  stream << "for (" << kk.getName() << " = 0; ";
503  stream << kk.getName() << " < " << nColsRhs1 <<"; ";
504  stream << "++" << kk.getName() << ")\n{\n";
505 
506  if ( transposeRhs1 == false )
507  {
508  iiRhs1 = ii;
509  kkRhs1 = kk;
510  }
511  else
512  {
513  iiRhs1 = kk;
514  kkRhs1 = ii;
515  }
516  stream << "t += " << sign << " " << rhs1->get(iiRhs1, kkRhs1) << "*" << rhs2->get(kk, jj) << ";";
517  stream << "\n}\n";
518 
519  if (lhs.isCalledByValue() == true)
520  stream << lhs.getFullName();
521  else
522  stream << lhs->get(ii, jj);
523 
524  stream << " " << getAssignString() << " t";
525 
526  if (op2 == ESO_ADD)
527  {
528  stream << " + " << rhs3->get(ii, jj);
529  }
530  else if (op2 == ESO_SUBTRACT)
531  {
532  stream << " - " << rhs3->get(ii, jj);
533  }
534  stream << ";\n";
535 
536  stream << "}\n";
537  stream << "}\n";
538 
539  memAllocator->release( ii );
540  memAllocator->release( jj );
541  memAllocator->release( kk );
542  }
543 
544  return SUCCESSFUL_RETURN;
545 }
546 
547 
549  const std::string& _op,
550  const std::string& _realString,
551  const std::string& _intString
552  ) const
553 {
554  if ( ( rhs1.getNumRows( ) != lhs.getNumRows( ) ) || ( rhs1.getNumCols( ) != lhs.getNumCols( ) ) )
555  {
556  LOG( LVL_DEBUG ) << "lhs name is " << lhs.getName()
557  << ", size: " << lhs.getNumRows() << " x " << lhs.getNumCols()
558  << "rhs1 name is " << rhs1.getName()
559  << ", size: " << rhs1.getNumRows() << " x " << rhs1.getNumCols() << endl;
560 
562  }
563 
564  unsigned numOps = lhs.getNumRows() * lhs.getNumCols();
565 
566  if ( lhs.isSubMatrix() == false && lhs.getDim() > 1 &&
567  rhs1.isGiven() == true && rhs1.getGivenMatrix().isZero() == true &&
568  _op == "=" )
569  {
570  stream << "{ int lCopy; for (lCopy = 0; lCopy < "<< lhs.getDim() << "; lCopy++) "
571  << lhs.getFullName() << "[ lCopy ] = 0; }" << endl;
572  }
573  else if ((numOps < 128) || (rhs1.isGiven() == true))
574  {
575  for(unsigned i = 0; i < lhs.getNumRows( ); ++i)
576  for(unsigned j = 0; j < lhs.getNumCols( ); ++j)
577  if ( ( _op == "=" ) || ( rhs1.isZero(i,j) == false ) )
578  {
579  stream << lhs->get(i, j) << " " << _op << " ";
580  if (rhs1->isGiven() == true)
581  {
582  if (lhs->getType() == REAL || lhs->getType() == STATIC_CONST_REAL)
583  stream << scientific << rhs1(i, j);
584  else
585  stream << (int)rhs1(i, j);
586 
587  stream << ";\n";
588  }
589  else
590  {
591  stream << rhs1->get(i, j) << ";\n";
592  }
593  }
594  }
595  else
596  {
597  ExportIndex ii, jj;
598 
599  if (lhs.isVector() && rhs1.isVector())
600  {
601  memAllocator->acquire( ii );
602 
603  stream << "for (" << ii.get() << " = 0; " << ii.get() << " < ";
604 
605  if (lhs->getNumCols() == 1)
606  {
607  stream << lhs->getNumRows() << "; ++" << ii.getName() << ")" << endl
608  << lhs.get(ii, 0) << " " << _op << " " << rhs1.get(ii, 0)
609  << ";" << endl << endl;
610  }
611  else
612  {
613  stream << lhs.getNumCols() << "; ++" << ii.getName() << ")" << endl;
614  stream << lhs.get(0, ii) << " " << _op << " " << rhs1.get(0, ii)
615  << ";" << endl << endl;
616  }
617 
618  memAllocator->release( ii );
619  }
620  else
621  {
622  memAllocator->acquire( ii );
623  memAllocator->acquire( jj );
624 
625  stream << "for (" << ii.getName() << " = 0;" << ii.getName() << " < "
626  << lhs->getNumRows() << "; ++" << ii.getName() << ")" << endl;
627 
628  stream << "for (" << jj.getName() << " = 0;" << jj.getName() << " < "
629  << lhs->getNumCols() << "; ++" << jj.getName() << ")" << endl;
630 
631  stream << lhs->get(ii, jj) << " " << _op << " " << rhs1->get(ii, jj) << ";" << endl;
632 
633  memAllocator->release( ii );
634  memAllocator->release( jj );
635  }
636  }
637 
638  return SUCCESSFUL_RETURN;
639 }
640 
641 
643 {
644  switch ( op0 )
645  {
646  case ESO_ASSIGN:
647  return "=";
648 
649  case ESO_ADD_ASSIGN:
650  return "+=";
651 
652  case ESO_SUBTRACT_ASSIGN:
653  return "-=";
654 
655  default:
656  return "foo";
657  }
658 }
659 
661 {
662  memAllocator = allocator;
663 
664  return *this;
665 }
666 
668 
669 // end of file.
#define LOG(level)
Just define a handy macro for getting the logger.
Lowest level, the debug level.
bool isSubMatrix() const
ExportArithmeticStatement & allocate(MemoryAllocatorPtr allocator)
bool isOne(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
bool isGiven(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
Allows to pass back messages to the calling function.
const std::string get(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
bool isGiven(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
BEGIN_NAMESPACE_ACADO typedef unsigned int uint
Definition: acado_types.hpp:42
returnValue exportCodeAddSubtract(std::ostream &stream, const std::string &_sign="+", const std::string &_realString="real_t", const std::string &_intString="int") const
ios_base::fmtflags flags
const DMatrix & getGivenMatrix() const
Returned value is a error.
#define CLOSE_NAMESPACE_ACADO
returnValue exportCodeAssign(std::ostream &stream, const std::string &_op="=", const std::string &_realString="real_t", const std::string &_intString="int") const
Defines a scalar-valued index variable to be used for exporting code.
virtual uint getNumCols() const
Allows to export code of different arithmetic statements.
bool isCalledByValue() const
bool isZero(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
virtual returnValue exportCode(std::ostream &stream, const std::string &_realString="real_t", const std::string &_intString="int", int _precision=16) const
ExportStatementOperator
const std::string get(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
returnValue exportCodeMultiply(std::ostream &stream, bool transposeRhs1=false, const std::string &_realString="real_t", const std::string &_intString="int") const
virtual uint getNumRows() const
ExportType getType() const
Base class for all kind of statements to be exported by the code generation tool. ...
void set(streamsize _precision, streamsize _width, ios_base::fmtflags _flags)
virtual uint getDim() const
bool isZero(const ExportIndex &rowIdx, const ExportIndex &colIdx) const
std::string getFullName() const
bool isVector() const
const std::string get() const
#define ASSERT(x)
BooleanType acadoIsZero(double x, double TOL)
bool isNull() const
Is a null pointer?
virtual uint getNumCols() const
#define BEGIN_NAMESPACE_ACADO
virtual returnValue exportDataDeclaration(std::ostream &stream, const std::string &_realString="real_t", const std::string &_intString="int", int _precision=16) const
virtual ExportStatement * clone() const
std::shared_ptr< MemoryAllocator > MemoryAllocatorPtr
#define ACADOERROR(retval)
Defines a matrix-valued variable to be used for exporting code.
#define ACADOERRORTEXT(retval, text)
std::string getName() const
Definition: export_data.cpp:86
virtual uint getNumRows() const


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