CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
util.hpp
1 #ifndef CPPAD_CG_UTIL_INCLUDED
2 #define CPPAD_CG_UTIL_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2012 Ciengis
6  * Copyright (C) 2020 Joao Leal
7  *
8  * CppADCodeGen is distributed under multiple licenses:
9  *
10  * - Eclipse Public License Version 1.0 (EPL1), and
11  * - GNU General Public License Version 3 (GPL3).
12  *
13  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15  * ----------------------------------------------------------------------------
16  * Author: Joao Leal
17  */
18 
19 namespace CppAD {
20 namespace cg {
21 
22 template<class VectorBool, class Base>
23 void zeroOrderDependency(ADFun<Base>& fun,
24  const VectorBool& vx,
25  VectorBool& vy) {
26  size_t m = fun.Range();
27  CPPADCG_ASSERT_KNOWN(vx.size() >= fun.Domain(), "Invalid vx size")
28  CPPADCG_ASSERT_KNOWN(vy.size() >= m, "Invalid vy size")
29 
30  using VectorSet = std::vector<std::set<size_t> >;
31 
32  const VectorSet jacSparsity = jacobianSparsitySet<VectorSet, Base>(fun);
33 
34  for (size_t i = 0; i < m; i++) {
35  for (size_t j : jacSparsity[i]) {
36  if (vx[j]) {
37  vy[i] = true;
38  break;
39  }
40  }
41  }
42 }
43 
44 template<class VectorSet>
45 inline bool isIdentityPattern(const VectorSet& pattern,
46  size_t mRows) {
47  CPPADCG_ASSERT_UNKNOWN(pattern.size() >= mRows)
48 
49  for (size_t i = 0; i < mRows; i++) {
50  if (pattern[i].size() != 1 || *pattern[i].begin() != i) {
51  return false;
52  }
53  }
54  return true;
55 }
56 
57 template<class VectorSet>
58 inline VectorSet transposePattern(const VectorSet& pattern,
59  size_t mRows,
60  size_t nCols) {
61  CPPADCG_ASSERT_UNKNOWN(pattern.size() >= mRows)
62 
63  VectorSet transpose(nCols);
64  for (size_t i = 0; i < mRows; i++) {
65  for (size_t it : pattern[i]) {
66  transpose[it].insert(i);
67  }
68  }
69  return transpose;
70 }
71 
81 template<class VectorSet, class VectorSet2>
82 inline void addTransMatrixSparsity(const VectorSet& a,
83  size_t mRows,
84  VectorSet2& result) {
85  CPPADCG_ASSERT_UNKNOWN(a.size() >= mRows)
86 
87  for (size_t i = 0; i < mRows; i++) {
88  for (size_t j : a[i]) {
89  result[j].insert(i);
90  }
91  }
92 }
93 
102 template<class VectorSet, class VectorSet2>
103 inline void addTransMatrixSparsity(const VectorSet& a,
104  VectorSet2& result) {
105  addTransMatrixSparsity<VectorSet, VectorSet2>(a, a.size(), result);
106 }
107 
116 template<class VectorSet, class VectorSet2>
117 inline void addMatrixSparsity(const VectorSet& a,
118  size_t mRows,
119  VectorSet2& result) {
120  CPPADCG_ASSERT_UNKNOWN(result.size() >= mRows)
121  CPPADCG_ASSERT_UNKNOWN(a.size() <= mRows)
122 
123  for (size_t i = 0; i < mRows; i++) {
124  if (result[i].empty()) {
125  result[i] = a[i];
126  } else {
127  result[i].insert(a[i].begin(), a[i].end());
128  }
129  }
130 }
131 
139 template<class VectorSet, class VectorSet2>
140 inline void addMatrixSparsity(const VectorSet& a,
141  VectorSet2& result) {
142  CPPADCG_ASSERT_UNKNOWN(result.size() == a.size())
143 
144  addMatrixSparsity<VectorSet, VectorSet2>(a, a.size(), result);
145 }
146 
156 template<class VectorSet, class VectorSet2>
157 inline void multMatrixMatrixSparsity(const VectorSet& a,
158  const VectorSet2& b,
159  CppAD::vector<std::set<size_t> >& result,
160  size_t q) {
161  multMatrixMatrixSparsity(a, b, result, a.size(), b.size(), q);
162 }
163 
177 template<class VectorSet, class VectorSet2>
178 inline void multMatrixMatrixSparsity(const VectorSet& a,
179  const VectorSet2& b,
180  CppAD::vector<std::set<size_t> >& result,
181  size_t m,
182  size_t n,
183  size_t q) {
184  CPPADCG_ASSERT_UNKNOWN(a.size() >= m)
185  CPPADCG_ASSERT_UNKNOWN(b.size() >= n)
186  CPPADCG_ASSERT_UNKNOWN(result.size() >= m)
187 
188  //check if b is identity
189  if (n == q) {
190  if (isIdentityPattern(b, n)) {
191  addMatrixSparsity(a, m, result); // R += A
192  return;
193  }
194  }
195 
196  VectorSet2 bt = transposePattern(b, n, q);
197 
198  for (size_t jj = 0; jj < q; jj++) { //loop columns of b
199  const std::set<size_t>& colB = bt[jj];
200  if (!colB.empty()) {
201  for (size_t i = 0; i < m; i++) {
202  const std::set<size_t>& rowA = a[i];
203  for (size_t rowb : colB) {
204  if (rowA.find(rowb) != rowA.end()) {
205  result[i].insert(jj);
206  break;
207  }
208  }
209  }
210  }
211  }
212 }
213 
227 template<class VectorSet, class VectorSet2>
228 inline void multMatrixTransMatrixSparsity(const VectorSet& a,
229  const VectorSet2& b,
230  CppAD::vector<std::set<size_t> >& result,
231  size_t m,
232  size_t n,
233  size_t q) {
234  CPPADCG_ASSERT_UNKNOWN(a.size() >= m)
235  CPPADCG_ASSERT_UNKNOWN(b.size() >= m)
236  CPPADCG_ASSERT_UNKNOWN(result.size() >= n)
237 
238  //check if B is empty
239  bool empty = true;
240  for (size_t i = 0; i < m; i++) {
241  if (b[i].size() > 0) {
242  empty = false;
243  break;
244  }
245  }
246  if (empty) {
247  return; //nothing to do: R += 0
248  }
249 
250  //check if A is identity
251  if (m == n && isIdentityPattern(a, m)) {
252  addMatrixSparsity(b, n, result); // R += B
253  return;
254  }
255 
256  //check if B is identity
257  if (m == q && isIdentityPattern(b, m)) {
258  addTransMatrixSparsity(a, m, result); // R += A^T
259  return;
260  }
261 
262  VectorSet at = transposePattern(a, m, n);
263  VectorSet2 bt = transposePattern(b, m, q);
264 
265  for (size_t jj = 0; jj < q; jj++) { //loop columns of b
266  const std::set<size_t>& colB = bt[jj];
267  if (!colB.empty()) {
268  for (size_t i = 0; i < n; i++) {
269  const std::set<size_t>& rowAt = at[i];
270  if (!rowAt.empty()) {
271  for (size_t rowb : colB) {
272  if (rowAt.find(rowb) != rowAt.end()) {
273  result[i].insert(jj);
274  break;
275  }
276  }
277  }
278  }
279  }
280  }
281 
282 }
283 
296 template<class VectorSet, class VectorSet2>
297 inline void multMatrixMatrixSparsityTrans(const VectorSet& aT,
298  const VectorSet2& b,
299  CppAD::vector<std::set<size_t> >& rT,
300  size_t m,
301  size_t n,
302  size_t q) {
303  CPPADCG_ASSERT_UNKNOWN(aT.size() >= m)
304  CPPADCG_ASSERT_UNKNOWN(b.size() >= m)
305 
306  //check if b is empty
307  bool empty = true;
308  for (size_t i = 0; i < m; i++) {
309  if (b[i].size() > 0) {
310  empty = false;
311  break;
312  }
313  }
314  if (empty) {
315  return; //nothing to do: R^T += 0
316  }
317 
318  //check if a is identity
319  if (m == q && isIdentityPattern(aT, m)) {
320  addTransMatrixSparsity(b, m, rT); // R^T += B^T
321  return;
322  }
323 
324  VectorSet a = transposePattern(aT, m, q);
325  VectorSet2 bT = transposePattern(b, m, n);
326 
327  for (size_t jj = 0; jj < n; jj++) { //loop columns of b
328  for (size_t i = 0; i < q; i++) {
329  for (size_t it : a[i]) {
330  if (bT[jj].find(it) != bT[jj].end()) {
331  rT[jj].insert(i);
332  break;
333  }
334  }
335  }
336  }
337 }
338 
339 template<class VectorBool>
340 void printSparsityPattern(const VectorBool& sparsity,
341  const std::string& name,
342  size_t m, size_t n) {
343  size_t width = std::ceil(std::log10((m > n) ? m : n));
344  if (!name.empty()) {
345  std::cout << name << " sparsity:\n";
346  }
347  for (size_t i = 0; i < m; i++) {
348  std::cout << " " << std::setw(width) << i << ": ";
349  for (size_t j = 0; j < n; j++) {
350  if (sparsity[i * n + j]) {
351  std::cout << std::setw(width) << j << " ";
352  } else {
353  std::cout << std::setw(width) << " " << " ";
354  }
355  }
356  std::cout << "\n";
357  }
358  std::cout << std::endl;
359 }
360 
361 template<class VectorSet>
362 void printSparsityPattern(const VectorSet& sparsity,
363  const std::string& name,
364  bool printLocationByRow = false) {
365  size_t maxDim = sparsity.size();
366  size_t nnz = 0;
367  for (size_t i = 0; i < sparsity.size(); i++) {
368  if (sparsity[i].size() > 0 && *sparsity[i].rbegin() > maxDim) {
369  maxDim = *sparsity[i].rbegin();
370  }
371  nnz += sparsity[i].size();
372  }
373 
374  size_t width = std::ceil(std::log10(maxDim));
375  size_t width2;
376  size_t width3 = width;
377  if (printLocationByRow) {
378  width2 = std::ceil(std::log10(nnz));
379  width3 += width2 + 1;
380  }
381  if (!name.empty()) {
382  std::cout << name << " sparsity:\n";
383  }
384 
385  size_t e = 0;
386  for (size_t i = 0; i < sparsity.size(); i++) {
387  std::cout << " " << std::setw(width) << i << ": ";
388  long last = -1;
389  for (size_t j : sparsity[i]) {
390  if (j != 0 && long(j) != last + 1) {
391  std::cout << std::setw((j - last - 1) * (width3 + 1)) << " ";
392  }
393  if (printLocationByRow)
394  std::cout << std::setw(width2) << e << ":";
395  std::cout << std::setw(width) << j << " ";
396  last = j;
397  e++;
398  }
399  std::cout << "\n";
400  }
401  std::cout << std::endl;
402 }
403 
404 template<class VectorSize>
405 void printSparsityPattern(const VectorSize& row,
406  const VectorSize& col,
407  const std::string& name,
408  size_t m) {
409  std::vector<std::set<size_t> > sparsity(m);
410  generateSparsitySet(row, col, sparsity);
411  printSparsityPattern(sparsity, name);
412 }
413 
414 inline bool intersects(const std::set<size_t>& a,
415  const std::set<size_t>& b) {
416  if (a.empty() || b.empty()) {
417  return false;
418  } else if (*a.rbegin() < *b.begin() ||
419  *a.begin() > *b.rbegin()) {
420  return false;
421  }
422 
423  if (a.size() < b.size()) {
424  for (size_t ita : a) {
425  if (b.find(ita) != b.end()) {
426  return true;
427  }
428  }
429  } else {
430  for (size_t itb : b) {
431  if (a.find(itb) != a.end()) {
432  return true;
433  }
434  }
435  }
436 
437  return false;
438 }
439 
440 template<class VectorSizet, class VectorSet>
441 inline CppAD::sparse_rc<VectorSizet> toSparsityPattern(const VectorSet& inPattern,
442  size_t m, size_t n) {
443 
444  CppAD::sparse_rc<VectorSizet> pattern;
445 
446  size_t nnz = 0;
447  for (const auto& p: inPattern) {
448  nnz += p.size();
449  }
450 
451  pattern.resize(m, n, nnz);
452 
453  size_t e = 0;
454  for (size_t i = 0; i < inPattern.size(); ++i) {
455  for (size_t j : inPattern[i]) {
456  pattern.set(e++, i, j);
457  }
458  }
459 
460  return pattern;
461 }
462 
469 template<class Base>
470 inline CodeHandler<Base>* findHandler(const std::vector<CG<Base> >& ty) {
471  for (size_t i = 0; i < ty.size(); i++) {
472  if (ty[i].getCodeHandler() != nullptr) {
473  return ty[i].getCodeHandler();
474  }
475  }
476  return nullptr;
477 }
478 
479 template<class Base>
480 inline CodeHandler<Base>* findHandler(const CppAD::vector<CG<Base> >& ty) {
481  for (size_t i = 0; i < ty.size(); i++) {
482  if (ty[i].getCodeHandler() != nullptr) {
483  return ty[i].getCodeHandler();
484  }
485  }
486  return nullptr;
487 }
488 
489 template<class Base>
490 inline CodeHandler<Base>* findHandler(CppAD::cg::ArrayView<const CG<Base> > ty) {
491  for (size_t i = 0; i < ty.size(); i++) {
492  if (ty[i].getCodeHandler() != nullptr) {
493  return ty[i].getCodeHandler();
494  }
495  }
496  return nullptr;
497 }
498 
499 template<class Base>
500 inline Argument<Base> asArgument(const CG<Base>& tx) {
501  if (tx.isParameter()) {
502  return Argument<Base>(tx.getValue());
503  } else {
504  return Argument<Base>(*tx.getOperationNode());
505  }
506 }
507 
508 template<class Base>
509 inline std::vector<Argument<Base> > asArguments(const std::vector<CG<Base> >& tx) {
510  std::vector<Argument<Base> > arguments(tx.size());
511  for (size_t i = 0; i < arguments.size(); i++) {
512  arguments[i] = asArgument(tx[i]);
513  }
514  return arguments;
515 }
516 
517 template<class Base>
518 inline std::vector<Argument<Base> > asArguments(const CppAD::vector<CG<Base> >& tx) {
519  std::vector<Argument<Base> > arguments(tx.size());
520  for (size_t i = 0; i < arguments.size(); i++) {
521  arguments[i] = asArgument(tx[i]);
522  }
523  return arguments;
524 }
525 
526 /***************************************************************************
527  * map related
528  **************************************************************************/
529 
536 template<class Key, class Value>
537 void mapKeys(const std::map<Key, Value>& map, std::set<Key>& keys) {
538  for (const auto& p : map) {
539  keys.insert(keys.end(), p.first);
540  }
541 }
542 
549 template<class Key, class Value>
550 void mapKeys(const std::map<Key, Value>& map, std::vector<Key>& keys) {
551  keys.resize(map.size());
552 
553  size_t i = 0;
554  typename std::map<Key, Value>::const_iterator it;
555  for (it = map.begin(); it != map.end(); ++it, i++) {
556  keys[i] = it->first;
557  }
558 }
559 
567 template<class Key, class Value>
568 bool compareMapKeys(const std::map<Key, Value>& map, const std::set<Key>& keys) {
569  if (map.size() != keys.size())
570  return false;
571 
572  typename std::map<Key, Value>::const_iterator itm = map.begin();
573  typename std::set<Key>::const_iterator itk = keys.begin();
574  for (; itm != map.end(); ++itm, ++itk) {
575  if (itm->first != *itk)
576  return false;
577  }
578 
579  return true;
580 }
581 
589 template<class Key, class Value>
590 inline std::map<Key, Value> filterBykeys(const std::map<Key, Value>& m,
591  const std::set<Key>& keys) {
592  std::map<Key, Value> filtered;
593 
594  typename std::map<Key, Value>::const_iterator itM;
595 
596  for (const Key& k : keys) {
597  itM = m.find(k);
598  if (itM != m.end()) {
599  filtered[itM->first] = itM->second;
600  }
601  }
602  return filtered;
603 }
604 
614 template<class T>
615 inline int compare(const std::set<T>& s1, const std::set<T>& s2) {
616  if (s1.size() < s2.size()) {
617  return -1;
618  } else if (s1.size() > s2.size()) {
619  return 1;
620  } else {
621  typename std::set<T>::const_iterator it1, it2;
622  for (it1 = s1.begin(), it2 = s2.begin(); it1 != s1.end(); ++it1, ++it2) {
623  if (*it1 < *it2) {
624  return -1;
625  } else if (*it1 > *it2) {
626  return 1;
627  }
628  }
629  return 0;
630  }
631 }
632 
633 template<class T>
635 
636  bool operator() (const std::set<T>& lhs, const std::set<T>& rhs) const {
637  return compare(lhs, rhs) == -1;
638  }
639 };
640 
641 /***************************************************************************
642  * Generic functions for printing stl containers
643  **************************************************************************/
644 template<class Base>
645 inline void print(const Base& v) {
646  std::cout << v;
647 }
648 
649 template<class Key, class Value>
650 inline void print(const std::map<Key, Value>& m) {
651  for (const auto& p : m) {
652  std::cout << p.first << " : ";
653  print(p.second);
654  std::cout << std::endl;
655  }
656 }
657 
658 template<class Base>
659 inline void print(const std::set<Base>& s) {
660  std::cout << "[";
661 
662  for (auto itj = s.begin(); itj != s.end(); ++itj) {
663  if (itj != s.begin()) std::cout << " ";
664  print(*itj);
665  }
666  std::cout << "]";
667  std::cout.flush();
668 }
669 
670 template<class Base>
671 inline void print(const std::set<Base*>& s) {
672  std::cout << "[";
673 
674  for (const auto itj = s.begin(); itj != s.end(); ++itj) {
675  if (itj != s.begin()) std::cout << " ";
676  Base* v = *itj;
677  if (v == nullptr) std::cout << "NULL";
678  else print(*v);
679  }
680  std::cout << "]";
681  std::cout.flush();
682 }
683 
684 template<class Base>
685 inline void print(const std::vector<Base>& v) {
686  std::cout << "[";
687 
688  for (size_t i = 0; i < v.size(); i++) {
689  if (i != 0) std::cout << " ";
690  print(v[i]);
691  }
692  std::cout << "]";
693  std::cout.flush();
694 }
695 
696 template<class VectorSize, class VectorBase>
697 inline void printTripletMatrix(const VectorSize &rows,
698  const VectorSize &cols,
699  const VectorBase &values) {
700  size_t n = values.size();
701  assert(rows.size() == n);
702  assert(cols.size() == n);
703 
704  for (size_t i = 0; i < n; ++i) {
705  std::cout << "[ " << rows[i] << ", " << cols[i] << "] -> " << values[i] << std::endl;
706  }
707 }
708 
709 /***************************************************************************
710  * print
711  **************************************************************************/
723 template<class Base>
724 inline CG<Base> makePrintValue(const std::string& before,
725  const CG<Base>& x,
726  const std::string& after = "") {
727  std::cout << before << x << after;
728 
729  if (x.getOperationNode() != nullptr) {
730  auto* handler = x.getCodeHandler();
731  CG<Base> out(*handler->makePrintNode(before, *x.getOperationNode(), after));
732  if (x.isValueDefined())
733  out.setValue(x.getValue());
734  return out;
735  } else {
736  return x;
737  }
738 }
739 
740 /***************************************************************************
741  * String related utilities
742  **************************************************************************/
743 
751 inline void replaceString(std::string& text,
752  const std::string& toReplace,
753  const std::string& replacement) {
754  size_t pos = 0;
755  while ((pos = text.find(toReplace, pos)) != std::string::npos) {
756  text.replace(pos, toReplace.length(), replacement);
757  pos += replacement.length();
758  }
759 }
760 
761 inline std::vector<std::string> explode(const std::string& text,
762  const std::string& delimiter) {
763  std::vector<std::string> matches;
764 
765  const size_t dlen = delimiter.length();
766  if (dlen == 0)
767  return matches;
768 
769  size_t pos = 0;
770  size_t start = 0;
771  while (true) {
772  pos = text.find(delimiter, start);
773  if (pos == std::string::npos) {
774  break;
775  }
776  matches.push_back(text.substr(start, pos - start));
777  start = pos + dlen;
778  }
779 
780  if (start < text.length()) {
781  matches.push_back(text.substr(start, text.length() - start));
782  }
783 
784  return matches;
785 }
786 
787 inline std::string implode(const std::vector<std::string>& text,
788  const std::string& delimiter) {
789  if (text.empty()) {
790  return "";
791  } else if (text.size() == 1) {
792  return text[0];
793  } else {
794  std::string out;
795  size_t n = 0;
796  for (const auto& s: text)
797  n += s.size();
798  out.reserve(n + (text.size() - 1) * delimiter.size());
799  out = text[0];
800  for (size_t i = 1; i < text.size(); ++i) {
801  out += delimiter;
802  out += text[i];
803  }
804  return out;
805  }
806 }
807 
808 inline std::string readStringFromFile(const std::string& path) {
809  std::ifstream iStream;
810  iStream.open(path);
811 
812  std::stringstream strStream;
813  strStream << iStream.rdbuf();
814 
815  return strStream.str();
816 }
817 
818 } // END cg namespace
819 } // END CppAD namespace
820 
821 #endif
const Base & getValue() const
Definition: variable.hpp:45
void setValue(const Base &val)
Definition: variable.hpp:54
bool isValueDefined() const
Definition: variable.hpp:40
CodeHandler< Base > * getCodeHandler() const
Definition: variable.hpp:22