CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
19namespace CppAD {
20namespace cg {
21
22template<class VectorBool, class Base>
23void 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
44template<class VectorSet>
45inline 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
57template<class VectorSet>
58inline 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
81template<class VectorSet, class VectorSet2>
82inline 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
102template<class VectorSet, class VectorSet2>
103inline void addTransMatrixSparsity(const VectorSet& a,
104 VectorSet2& result) {
105 addTransMatrixSparsity<VectorSet, VectorSet2>(a, a.size(), result);
106}
107
116template<class VectorSet, class VectorSet2>
117inline 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
139template<class VectorSet, class VectorSet2>
140inline 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
156template<class VectorSet, class VectorSet2>
157inline 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
177template<class VectorSet, class VectorSet2>
178inline 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
227template<class VectorSet, class VectorSet2>
228inline 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
296template<class VectorSet, class VectorSet2>
297inline 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
339template<class VectorBool>
340void 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
361template<class VectorSet>
362void 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
404template<class VectorSize>
405void 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
414inline 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
440template<class VectorSizet, class VectorSet>
441inline 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
469template<class Base>
470inline 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
479template<class Base>
480inline 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
489template<class Base>
490inline 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
499template<class Base>
500inline 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
508template<class Base>
509inline 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
517template<class Base>
518inline 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
536template<class Key, class Value>
537void 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
549template<class Key, class Value>
550void 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
567template<class Key, class Value>
568bool 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
589template<class Key, class Value>
590inline 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
614template<class T>
615inline 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
633template<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 **************************************************************************/
644template<class Base>
645inline void print(const Base& v) {
646 std::cout << v;
647}
648
649template<class Key, class Value>
650inline void print(const std::map<Key, Value>& m) {
651 for (const std::pair<Key, Value>& p : m) {
652 std::cout << p.first << " : ";
653 print(p.second);
654 std::cout << std::endl;
655 }
656}
657
658template<class Base>
659inline 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
670template<class Base>
671inline 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
684template<class Base>
685inline 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
696template<class VectorSize, class VectorBase>
697inline 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 **************************************************************************/
723template<class Base>
724inline 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
751inline 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
761inline 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
787inline 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
808inline 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