ADOL-C: Automatic Differentiation in C/C++ 2.7.3
Loading...
Searching...
No Matches
sparsedrivers.h
Go to the documentation of this file.
1/*----------------------------------------------------------------------------
2 ADOL-C -- Automatic Differentiation by Overloading in C++
3 File: sparse/sparsedrivers.h
4 Revision: $Id$
5 Contents: This file contains some "Easy To Use" interfaces of the sparse
6package.
7
8 Copyright (c) Andrea Walther
9
10 This file is part of ADOL-C. This software is provided as open source.
11 Any use, reproduction, or distribution of the software constitutes
12 recipient's acceptance of the terms of the accompanying license file.
13
14----------------------------------------------------------------------------*/
15#ifndef ADOLC_SPARSE_DRIVERS_H
16#define ADOLC_SPARSE_DRIVERS_H
17#include <adolc/adalloc.h>
18#include <adolc/adolcerror.h>
19#include <adolc/interfaces.h>
26#include <cmath>
27#include <cstddef>
28#include <span>
29#include <utility>
30#include <vector>
31
32// Max. number of unsigned ints to store the seed / jacobian matrix strips.
33// Reduce this value to x if your system happens to run out of memory. x < 10
34// makes no sense. x = 50 or 100 is better. x stays for (x * sizeof(size_t) * 8)
35// (block) variables at once
36#define PQ_STRIPMINE_MAX 30
37
38namespace ADOLC::Sparse {
39namespace detail {
40// a word represents an instance of bitword_t every letter of the word gives a
41// bit. This bit represents a depence of the input i (= location of the bit) to
42// the output that corresponds to the word.
43static constexpr int BITS_PER_WORD = 8 * sizeof(bitword_t);
44static constexpr bitword_t MOST_SIGNIFICANT_BIT = static_cast<bitword_t>(1)
45 << (BITS_PER_WORD - 1);
46
60template <BitPatternPropagationDirection BPPD> struct BvpData {
61 int rc_{0};
62 int depen_{-1};
63 int indep_{-1};
68 std::vector<unsigned char>
71 std::vector<double> valuepoint_;
73 std::vector<bitword_t *> seed_;
74 std::vector<bitword_t *>
76
77 BvpData(const BvpData &) = delete;
78 BvpData &operator=(const BvpData &) = delete;
79 BvpData(BvpData &&) = delete;
80 BvpData &operator=(BvpData &&) = delete;
81
86 for (auto &s : seed_)
87 delete[] s;
88 for (auto &j : jacobianBitPattern_)
89 delete[] j;
90 }
91
101 BvpData(int depen, int indep) : depen_(depen), indep_(indep) {
102 int numWordsFullSeed = 0;
103 if constexpr (BPPD == BitPatternPropagationDirection::Forward)
104 numWordsFullSeed =
105 indep_ / BITS_PER_WORD + ((indep_ % BITS_PER_WORD) != 0);
107 numWordsFullSeed = depen / BITS_PER_WORD + ((depen % BITS_PER_WORD) != 0);
108
109 wordsPerBatch_ = (numWordsFullSeed <= PQ_STRIPMINE_MAX) ? numWordsFullSeed
111 bitsPerStrip_ = wordsPerBatch_ * BITS_PER_WORD;
113 (numWordsFullSeed <= PQ_STRIPMINE_MAX)
114 ? 1
115 : numWordsFullSeed / PQ_STRIPMINE_MAX +
116 ((numWordsFullSeed % PQ_STRIPMINE_MAX) != 0);
117
118 if constexpr (BPPD == BitPatternPropagationDirection::Forward) {
119 seed_.resize(indep_);
120 for (auto &s : seed_)
121 s = new bitword_t[wordsPerBatch_];
122
124 for (auto &j : jacobianBitPattern_)
125 j = new bitword_t[wordsPerBatch_];
126
128
129 } else if constexpr (BPPD == BitPatternPropagationDirection::Reverse) {
130 seed_.resize(wordsPerBatch_);
131 for (auto &s : seed_)
132 s = new bitword_t[depen_];
133
135 for (auto &j : jacobianBitPattern_)
136 j = new bitword_t[indep_];
137
139 }
140 }
141};
142
150template <ControlFlowMode CFM>
151void checkBVPInput([[maybe_unused]] const double *basepoint) {};
152
160inline void resetInput(std::span<uint *> &compressedRowStorage) {
161 for (auto &row : compressedRowStorage) {
162 row = nullptr;
163 }
164}
165
174template <BitPatternPropagationDirection BPPD>
175void resetOldSeed(BvpData<BPPD> &data, size_t dim2) {
176 for (auto &s : data.seed_)
177 for (size_t j = 0; j < dim2; ++j)
178 s[j] = 0;
179}
180
188template <BitPatternPropagationDirection BPPD>
189void prepareSeedMatrix(size_t stripIdx, BvpData<BPPD> &data) {
190 if constexpr (BPPD == BitPatternPropagationDirection::Forward) {
191 resetOldSeed(data, data.wordsPerBatch_);
192 createSeed(data, stripIdx, data.indep_);
193 } else if constexpr (BPPD == BitPatternPropagationDirection::Reverse) {
194 resetOldSeed(data, data.depen_);
195 createSeed(data, stripIdx, data.depen_);
196 }
197}
198
208template <BitPatternPropagationDirection BPPD>
209void setSeed(BvpData<BPPD> &data, size_t idx, size_t currentStripWordIdx) {
210 if constexpr (BPPD == BitPatternPropagationDirection::Forward)
211 data.seed_[idx][(idx - currentStripWordIdx) / BITS_PER_WORD] =
212 MOST_SIGNIFICANT_BIT >> ((idx - currentStripWordIdx) % BITS_PER_WORD);
213
214 else if constexpr (BPPD == BitPatternPropagationDirection::Reverse)
215 data.seed_[(idx - currentStripWordIdx) / BITS_PER_WORD][idx] =
216 MOST_SIGNIFICANT_BIT >> ((idx - currentStripWordIdx) % BITS_PER_WORD);
217}
218
228template <BitPatternPropagationDirection BPPD>
229void createSeed(BvpData<BPPD> &data, size_t stripIdx, size_t end) {
230 size_t currentStripWordIdx = stripIdx * data.bitsPerStrip_;
231 size_t nextStripWordIdx = (stripIdx + 1) * data.bitsPerStrip_;
232 if (nextStripWordIdx > end)
233 nextStripWordIdx = end;
234
235 for (size_t idx = currentStripWordIdx; idx < nextStripWordIdx; idx++)
236 setSeed(data, idx, currentStripWordIdx);
237}
238
262void extract(size_t wordIdx, size_t stripIdx, size_t currentStripWordIdx,
264 std::span<uint *> &compressedRowStorage);
265
286void extract(size_t wordIdx, size_t stripIdx,
288 std::span<uint *> &compressedRowStorage);
289
299template <BitPatternPropagationDirection BPPD>
301 std::span<uint *> &compressedRowStorage,
302 BvpData<BPPD> &data) {
303 int currentStripWordIdx = stripIdx * data.bitsPerStrip_;
304 int nextStripWordIdx = (stripIdx + 1) * data.bitsPerStrip_;
305 if constexpr (BPPD == BitPatternPropagationDirection::Forward)
306 for (int wordIdx = 0; wordIdx < data.depen_; wordIdx++) {
307 int idx = 0;
308 bitword_t currentBit = MOST_SIGNIFICANT_BIT;
309 for (int i = 0; i < data.bitsPerStrip_; ++i) {
310 if (currentBit == 0) {
311 currentBit = MOST_SIGNIFICANT_BIT;
312 idx++;
313 }
314 if (currentBit & data.jacobianBitPattern_[wordIdx][idx])
315 data.indepWordHasNonzero_[i] = 1;
316
317 currentBit = currentBit >> 1;
318 }
319 extract(wordIdx, stripIdx, currentStripWordIdx, data,
320 compressedRowStorage);
321 }
322 else if constexpr (BPPD == BitPatternPropagationDirection::Reverse) {
323 if (nextStripWordIdx > data.depen_)
324 nextStripWordIdx = data.depen_;
325 int idx = 0;
326 bitword_t currentBit = MOST_SIGNIFICANT_BIT;
327 for (int wordIdx = currentStripWordIdx; wordIdx < nextStripWordIdx;
328 wordIdx++) {
329 if (currentBit == 0) {
330 currentBit = MOST_SIGNIFICANT_BIT;
331 idx++;
332 }
333 for (int i = 0; i < data.indep_; i++) {
334 if (currentBit & data.jacobianBitPattern_[idx][i]) {
335 data.indepWordHasNonzero_[i] = 1;
336 }
337 }
338 currentBit = currentBit >> 1;
339 extract(wordIdx, stripIdx, data, compressedRowStorage);
340 }
341 }
342}
343
354template <BitPatternPropagationDirection BPPD, ControlFlowMode CFM>
355void prepareADCalls(short tapeId, const double *basepoint,
356 BvpData<BPPD> &data) {
357 if constexpr (BPPD == BitPatternPropagationDirection::Reverse &&
359 data.rc_ = zos_forward(tapeId, data.depen_, data.indep_, 1, basepoint,
360 data.valuepoint_.data());
361}
362
374template <BitPatternPropagationDirection BPPD, ControlFlowMode CFM>
375void ADCalls(short tapeId, const double *basepoint, BvpData<BPPD> &data) {
376 if constexpr (BPPD == BitPatternPropagationDirection::Forward) {
377 if constexpr (CFM == ControlFlowMode::Tight) {
378 data.valuepoint_.resize(data.depen_);
379 data.rc_ = int_forward_tight(tapeId, data.depen_, data.indep_,
380 data.wordsPerBatch_, basepoint,
381 data.seed_.data(), data.valuepoint_.data(),
382 data.jacobianBitPattern_.data());
383 } else if constexpr (CFM == ControlFlowMode::Safe)
384 data.rc_ = int_forward_safe(tapeId, data.depen_, data.indep_,
385 data.wordsPerBatch_, data.seed_.data(),
386 data.jacobianBitPattern_.data());
387
388 } else if constexpr (BPPD == BitPatternPropagationDirection::Reverse) {
389 if constexpr (CFM == ControlFlowMode::Tight)
390 data.rc_ = int_reverse_tight(tapeId, data.depen_, data.indep_,
391 data.wordsPerBatch_, data.seed_.data(),
392 data.jacobianBitPattern_.data());
393 else if constexpr (CFM == ControlFlowMode::Safe)
394 data.rc_ = int_reverse_safe(tapeId, data.depen_, data.indep_,
395 data.wordsPerBatch_, data.seed_.data(),
396 data.jacobianBitPattern_.data());
397 }
398}
399
415template <ControlFlowMode CFM, BitPatternPropagationDirection BPPD>
416int bitVectorPropagation(short tapeId, int depen, int indep,
417 const double *basepoint,
418 std::span<uint *> &compressedRowStorage) {
419 using namespace detail;
420 checkBVPInput<CFM>(basepoint);
421 BvpData<BPPD> data{depen, indep};
422 prepareADCalls<BPPD, CFM>(tapeId, basepoint, data);
423 for (int stripIdx = 0; stripIdx < data.numStripmineBatches_; stripIdx++) {
424 prepareSeedMatrix(stripIdx, data);
425 ADCalls<BPPD, CFM>(tapeId, basepoint, data);
426 extractCompressedRowStorage(stripIdx, compressedRowStorage, data);
427 }
428 return data.rc_;
429}
430
431} // namespace detail
432
479ADOLC_API int bit_vector_propagation(short tapeId, int depen, int indep,
480 const double *basepoint,
481 std::span<uint *> &compressedRowStorage) {
482 using namespace detail;
483 if constexpr (BPPD == BitPatternPropagationDirection::Auto) {
484 // we allow here run-time selection
485 if (depen >= indep / 2)
486 return bitVectorPropagation<CFM, BitPatternPropagationDirection::Forward>(
487 tapeId, depen, indep, basepoint, compressedRowStorage);
488
489 else
490 return bitVectorPropagation<CFM, BitPatternPropagationDirection::Reverse>(
491 tapeId, depen, indep, basepoint, compressedRowStorage);
492 } else
493 return bitVectorPropagation<CFM, BPPD>(tapeId, depen, indep, basepoint,
494 compressedRowStorage);
495}
496
534template <
537ADOLC_API int jac_pat(short tag, int depen, int indep, const double *basepoint,
538 std::span<uint *> &compressedRowStorage) {
539 detail::resetInput(compressedRowStorage);
540 if constexpr (SM == SparseMethod::IndexDomains &&
542 return indopro_forward_tight(tag, depen, indep, basepoint,
543 compressedRowStorage.data());
544 else if constexpr (SM == SparseMethod::IndexDomains &&
546 return indopro_forward_safe(tag, depen, indep, basepoint,
547 compressedRowStorage.data());
548 else if constexpr (SM == SparseMethod::BitPattern)
549 return bit_vector_propagation<CFM, BPPD>(tag, depen, indep, basepoint,
550 compressedRowStorage);
551};
552
575template <PiecewiseLinear>
576ADOLC_API int jac_pat(short tag, int depen, int indep, int numsw,
577 const double *basepoint,
578 std::span<uint *> &compressedRowStorage) {
579 detail::resetInput(compressedRowStorage);
580 return indopro_forward_absnormal(tag, depen, indep, numsw, basepoint,
581 compressedRowStorage.data());
582}
609template <CompressionMode CM>
610ADOLC_API void generate_seed_jac(int m, int n, const std::span<uint *> JP,
611 double ***Seed, int *p) {
612 generateSeedJac<CM>(m, n, JP, Seed, p);
613}
614
615namespace detail {
616
661template <
664int buildJacPatternAndSeed(short tag, int depen, int indep,
665 const double *basepoint) {
666
667 ValueTape &tape = findTape(tag);
668 tape.sJInfos().setJP(std::vector<uint *>(depen));
669 std::span<uint *> JPSpan = tape.sJInfos().getJP();
670 int ret_val = jac_pat<SM, CFM, BPPD>(tag, depen, indep, basepoint, JPSpan);
671
672 if (ret_val < 0) {
673 printf(" ADOL-C error in sparse_jac() \n");
674 return ret_val;
675 }
676
677 tape.sJInfos().depen_ = depen;
678 tape.sJInfos().nnzIn_ = 0;
679 for (int i = 0; i < depen; i++) {
680 for (uint j = 1; j <= tape.sJInfos().JP_[i][0]; j++)
681 tape.sJInfos().nnzIn_++;
682 }
683
684 tape.sJInfos().initColoring(depen, indep);
685
686 if constexpr (CM == CompressionMode::Row) {
687 tape.sJInfos().generateSeedJac("ROW_PARTIAL_DISTANCE_TWO");
688 tape.sJInfos().seedClms_ = indep;
689 ret_val = tape.sJInfos().seedRows_;
690 } else if constexpr (CM == CompressionMode::Column) {
691 tape.sJInfos().generateSeedJac("COLUMN_PARTIAL_DISTANCE_TWO");
692 tape.sJInfos().seedRows_ = depen;
693 ret_val = tape.sJInfos().seedClms_;
694 }
695 return ret_val;
696}
697
708template <PiecewiseLinear>
709int buildJacPatternAndSeed(short tag, int depen, int indep, int numSwitches,
710 const double *basepoint) {
711 auto &tape = findTape(tag);
712 tape.sJInfos().setJP(std::vector<uint *>(depen + numSwitches));
713 std::span<uint *> JPSpan{tape.sJInfos().getJP()};
714
715 int ret_val = jac_pat<PiecewiseLinear{}>(tag, depen, indep, numSwitches,
716 basepoint, JPSpan);
717 if (ret_val < 0) {
718 printf(" ADOL-C error in sparse_jac() \n");
719 return ret_val;
720 }
721
722 tape.sJInfos().depen_ = depen + numSwitches;
723 tape.sJInfos().nnzIn_ = 0;
724 for (int i = 0; i < depen + numSwitches; i++) {
725 for (uint j = 1; j <= tape.sJInfos().getJP()[i][0]; j++) {
726 tape.sJInfos().nnzIn_++;
727 }
728 }
729 tape.sJInfos().initColoring(depen + numSwitches, indep + numSwitches);
730
731 tape.sJInfos().generateSeedJac("ROW_PARTIAL_DISTANCE_TWO");
732 tape.sJInfos().seedClms_ = indep + numSwitches;
733 ret_val = tape.sJInfos().seedRows_;
734
735 return ret_val;
736}
737namespace {
738inline int ensureSparseJacCacheInitialized(const ValueTape &tape) {
739 if (tape.sJInfos().Seed_ == nullptr || tape.sJInfos().seedRows_ == 0 ||
740 tape.sJInfos().seedClms_ == 0) {
741 printf(" ADOL-C error in sparse_jac():"
742 " First call with repeat = 0 \n");
743 return -3;
744 }
745 return 0;
746}
747
748inline int validateManualStorage(const ValueTape &tape,
749 const SparseMatrix &sparseJac) {
750 if (sparseJac.size() != to_size_t(tape.sJInfos().nnzIn_)) {
751 printf(" ADOL-C error in sparse_jac():"
752 " SparseMatrix size mismatch for MemoryHandler::Manual,"
753 " expected %d entries but got %zu \n",
754 tape.sJInfos().nnzIn_, sparseJac.size());
755 return -3;
756 }
757 return 0;
758}
759
760inline SparseShape countSparseANFEntries(const SparseJacInfos &sJInfos,
761 int depen, int indep) {
762 using Coordinates = CoordinateFormatTripled::Coordinates;
763 using coordinate_type = CoordinateFormatTripled::coordinate_type;
765
766 SparseShape counts;
767 for (coordinate_type rowIndex = 0; rowIndex < sJInfos.JP_.size();
768 ++rowIndex) {
769 const auto numOfNonZeros = sJInfos.JP_[rowIndex][0];
770 for (unsigned int j = 1; j <= numOfNonZeros; ++j) {
771 const Coordinates coords{rowIndex, sJInfos.JP_[rowIndex][j]};
772 switch (classifySparseANFBlock(coords, depen, indep)) {
774 ++counts.y;
775 break;
777 ++counts.j;
778 break;
780 ++counts.z;
781 break;
783 ++counts.l;
784 break;
785 }
786 }
787 }
788 return counts;
789}
790
791inline int validateManualStorage(const ValueTape &tape,
792 const SparseANF &sparseANF, int depen,
793 int indep) {
794 const auto counts = countSparseANFEntries(tape.sJInfos(), depen, indep);
795 if (sparseANF.dims().y != counts.y || sparseANF.dims().j != counts.j ||
796 sparseANF.dims().z != counts.z || sparseANF.dims().l != counts.l) {
797 printf(" ADOL-C error in sparse_jac():"
798 " SparseANF block sizes mismatch for MemoryHandler::Manual"
799 " (expected Y=%zu J=%zu Z=%zu L=%zu,"
800 " got Y=%zu J=%zu Z=%zu L=%zu) \n",
801 counts.y, counts.j, counts.z, counts.l, sparseANF.dims().y,
802 sparseANF.dims().j, sparseANF.dims().z, sparseANF.dims().l);
803 return -3;
804 }
805 return 0;
806}
807} // namespace
809template <CompressionMode CM, MemoryHandler MH>
810void recover(const ValueTape &tape, SparseMatrix &sparseJac) {
811 if constexpr (MH == MemoryHandler::Manual) {
812 assert(sparseJac.size() == to_size_t(tape.sJInfos().nnzIn_) &&
813 "Mismatch in allocated size and required size!");
814 if constexpr (CM == CompressionMode::Row) {
815 tape.sJInfos().recoverRowFormatUserMem(sparseJac);
816 } else if constexpr (CM == CompressionMode::Column) {
817 tape.sJInfos().recoverColFormatUserMem(sparseJac);
818 }
819 } else {
820 if constexpr (CM == CompressionMode::Row) {
821 tape.sJInfos().recoverRowFormat(sparseJac);
822 } else if constexpr (CM == CompressionMode::Column) {
823 tape.sJInfos().recoverColFormat(sparseJac);
824 }
825 }
826}
827
829template <MemoryHandler MH>
830void recover(const ValueTape &tape, SparseANF &sparseANF) {
831 const int numInds = static_cast<int>(tape.numInds());
832 const int numSwitches = static_cast<int>(tape.numSwitches());
833 if constexpr (MH == MemoryHandler::Manual) {
834 tape.sJInfos().recoverANFUserMem(sparseANF, numInds, numSwitches);
835 } else {
836 tape.sJInfos().recoverANF(sparseANF, numInds, numSwitches);
837 }
838}
839
887template <CompressionMode CM, MemoryHandler MH>
888int computeSparseJac(short tag, int depen, int indep, const double *basepoint,
889 SparseMatrix &sparseJac) {
890 ValueTape &tape = findTape(tag);
891 int ret_val = 0;
892 myfree2(tape.sJInfos().B_);
893 myfree1(tape.sJInfos().y_);
894 tape.sJInfos().B_ =
895 myalloc2(tape.sJInfos().seedRows_, tape.sJInfos().seedClms_);
896 tape.sJInfos().y_ = myalloc1(depen);
897
898 if constexpr (CM == CompressionMode::Row) {
899 ret_val = zos_forward(tag, depen, indep, 1, basepoint, tape.sJInfos().y_);
900 if (ret_val < 0)
901 return ret_val;
902 MINDEC(ret_val, fov_reverse(tag, depen, indep, tape.sJInfos().seedRows_,
903 tape.sJInfos().Seed_, tape.sJInfos().B_));
904 } else if constexpr (CM == CompressionMode::Column)
905 ret_val =
906 fov_forward(tag, depen, indep, tape.sJInfos().seedClms_, basepoint,
907 tape.sJInfos().Seed_, tape.sJInfos().y_, tape.sJInfos().B_);
908 recover<CM, MH>(tape, sparseJac);
909 return ret_val;
910}
911
921template <MemoryHandler MH>
922int computeSparseJac(short tag, int depen, int indep, int numSwitches,
923 const double *basepoint, SparseANF &sparseANF) {
924 ValueTape &tape = findTape(tag);
925 assert(tape.sJInfos().seedClms_ == indep + numSwitches &&
926 "Row Compression must have a seed with column number equal to indep + "
927 "numSwitches!");
928 int ret_val = 0;
929 myfree2(tape.sJInfos().B_);
930 tape.sJInfos().B_ =
931 myalloc2(tape.sJInfos().seedRows_, tape.sJInfos().seedClms_);
932
933 std::vector<double *> results(tape.sJInfos().seedRows_);
934 std::vector<double *> resultsSwitch(tape.sJInfos().seedRows_);
935
936 std::vector<double *> seedResults(tape.sJInfos().seedRows_);
937 std::vector<double *> seedSwitches(tape.sJInfos().seedRows_);
938
939 for (int i = 0; i < tape.sJInfos().seedRows_; i++) {
940 results[i] = tape.sJInfos().B_[i];
941 resultsSwitch[i] = tape.sJInfos().B_[i] + indep;
942 seedResults[i] = tape.sJInfos().Seed_[i];
943 seedSwitches[i] = tape.sJInfos().Seed_[i] + depen;
944 }
945
946 sparseANF.y.resize(depen);
947 sparseANF.z.resize(numSwitches);
948 ret_val = zos_pl_forward(tag, depen, indep, 1, basepoint, sparseANF.y.data(),
949 sparseANF.z.data());
950 if (ret_val < 0)
951 return ret_val;
952 MINDEC(ret_val, fov_pl_reverse(tag, depen, indep, numSwitches,
953 tape.sJInfos().seedRows_, seedResults.data(),
954 seedSwitches.data(), results.data(),
955 resultsSwitch.data()));
956
957 recover<MH>(tape, sparseANF);
958
959 // update consts
960 sparseANF.updateCy();
961 sparseANF.updateCz();
962
963 return ret_val;
964}
965} // namespace detail
966
1002template <
1008ADOLC_API int sparse_jac(short tag, int depen, int indep, int repeat,
1009 const double *basepoint, SparseMatrix &sparseJac) {
1010 using namespace detail;
1011 int ret_val = 0;
1012 if (repeat == 0)
1013 ret_val =
1014 buildJacPatternAndSeed<SM, CM, CFM, BPPD>(tag, depen, indep, basepoint);
1015 else
1016 ret_val = ensureSparseJacCacheInitialized(findTape(tag));
1017 if (ret_val < 0) {
1018 printf(" ADOL-C error in sparse_jac() \n");
1019 return ret_val;
1020 }
1021 if constexpr (MH == MemoryHandler::Manual) {
1022
1023 ret_val = validateManualStorage(findTape(tag), sparseJac);
1024 if (ret_val < 0)
1025 return ret_val;
1026 }
1027 return computeSparseJac<CM, MH>(tag, depen, indep, basepoint, sparseJac);
1028}
1060template <PiecewiseLinear PL = PiecewiseLinear{},
1062ADOLC_API int sparse_jac(short tag, int depen, int indep, int numSwitches,
1063 int repeat, const double *basepoint,
1064 SparseANF &sparseANF) {
1065
1066 using namespace detail;
1067 int ret_val = 0;
1068 if (repeat == 0)
1069 ret_val =
1070 buildJacPatternAndSeed<PL>(tag, depen, indep, numSwitches, basepoint);
1071 else
1072 ret_val = ensureSparseJacCacheInitialized(findTape(tag));
1073 if (ret_val < 0) {
1074 printf(" ADOL-C error in sparse_jac() \n");
1075 return ret_val;
1076 }
1077 if constexpr (MH == MemoryHandler::Manual) {
1078 ret_val = validateManualStorage(findTape(tag), sparseANF, depen, indep);
1079 if (ret_val < 0)
1080 return ret_val;
1081 }
1082 return computeSparseJac<MH>(tag, depen, indep, numSwitches, basepoint,
1083 sparseANF);
1084}
1085
1122template <ControlFlowMode CFM>
1123ADOLC_API int hess_pat(short tag, int indep, const double *basepoint,
1124 std::span<uint *> &compressedRowStorage) {
1125 detail::resetInput(compressedRowStorage);
1126 if constexpr (CFM == ControlFlowMode::OldTight)
1127 return nonl_ind_old_forward_tight(tag, 1, indep, basepoint,
1128 compressedRowStorage.data());
1129 else if constexpr (CFM == ControlFlowMode::OldSafe)
1130 return nonl_ind_old_forward_safe(tag, 1, indep, basepoint,
1131 compressedRowStorage.data());
1132 else if constexpr (CFM == ControlFlowMode::Tight)
1133 return nonl_ind_forward_tight(tag, 1, indep, basepoint,
1134 compressedRowStorage.data());
1135 else if constexpr (CFM == ControlFlowMode::Safe)
1136 return nonl_ind_forward_safe(tag, 1, indep, basepoint,
1137 compressedRowStorage.data());
1138}
1139
1160template <RecoveryMethod RCM>
1161ADOLC_API void generate_seed_hess(int n, std::span<uint *> HP, double ***Seed,
1162 int *p) {
1163 if constexpr (RCM == RecoveryMethod::Indirect)
1164 generateSeedHess(n, HP, Seed, p, "ACYCLIC_FOR_INDIRECT_RECOVERY");
1165 else if constexpr (RCM == RecoveryMethod::Direct)
1166 generateSeedHess(n, HP, Seed, p, "STAR");
1167}
1168
1169namespace detail {
1170
1206template <ControlFlowMode CFM, RecoveryMethod RCM>
1207int buildHessPatternAndSeed(short tag, int indep, const double *basepoint,
1208 int *nnz) {
1209 ValueTape &tape = findTape(tag);
1210 int ret_val = -1;
1211 // Generate sparsity pattern, determine nnz, allocate memory
1212 tape.sHInfos().setHP(indep, std::vector<uint *>(indep));
1213 std::span<uint *> HPSpan = tape.sHInfos().HP_;
1214 // generate sparsity pattern
1215 ret_val = hess_pat<CFM>(tag, indep, basepoint, HPSpan);
1216
1217 if (ret_val < 0) {
1218 printf(" ADOL-C error in sparse_hess() \n");
1219 return ret_val;
1220 }
1221
1222 tape.sHInfos().indep_ = indep;
1223 tape.sHInfos().nnzIn_ = 0;
1224
1225 for (uint i = 0; i < static_cast<uint>(indep); i++) {
1226 for (uint j = 1; j <= tape.sHInfos().HP_[i][0]; j++)
1227 if (tape.sHInfos().HP_[i][j] >= i)
1228 tape.sHInfos().nnzIn_++;
1229 }
1230
1231 *nnz = tape.sHInfos().nnzIn_;
1232
1233 // compute seed matrix => ColPack library
1234
1235 // Seed is handled by ColPack
1236 double **Seed = nullptr;
1237 tape.sHInfos().initColoring(indep);
1238 if constexpr (RCM == RecoveryMethod::Indirect)
1239 tape.sHInfos().generateSeedHess(&Seed, "ACYCLIC_FOR_INDIRECT_RECOVERY");
1240 else if constexpr (RCM == RecoveryMethod::Direct)
1241 tape.sHInfos().generateSeedHess(&Seed, "STAR");
1242
1243 // data might still be allocated, ensure that its not leaked
1244 myfree2(tape.sHInfos().Hcomp_);
1245 myfree3(tape.sHInfos().Xppp_);
1246 myfree3(tape.sHInfos().Yppp_);
1247 myfree3(tape.sHInfos().Zppp_);
1248 myfree2(tape.sHInfos().Upp_);
1249
1250 tape.sHInfos().Hcomp_ = myalloc2(indep, tape.sHInfos().p_);
1251 tape.sHInfos().Xppp_ = myalloc3(indep, tape.sHInfos().p_, 1);
1252
1253 for (int i = 0; i < indep; i++)
1254 for (int l = 0; l < tape.sHInfos().p_; l++)
1255 tape.sHInfos().Xppp_[i][l][0] = Seed[i][l];
1256
1257 tape.sHInfos().Yppp_ = myalloc3(1, tape.sHInfos().p_, 1);
1258 tape.sHInfos().Zppp_ = myalloc3(tape.sHInfos().p_, indep, 2);
1259 tape.sHInfos().Upp_ = myalloc2(1, 2);
1260 tape.sHInfos().Upp_[0][0] = 1;
1261 tape.sHInfos().Upp_[0][1] = 0;
1262 return ret_val;
1263}
1264
1300template <RecoveryMethod RCM>
1301int computeSparseHess(short tag, int indep, const double *basepoint, int *nnz,
1302 unsigned int **rind, unsigned int **cind,
1303 double **values) {
1304 ValueTape &tape = findTape(tag);
1305 if (tape.sHInfos().Upp_ == nullptr) {
1306 printf(" ADOL-C error in sparse_hess():"
1307 " First call with repeat = 0 \n");
1308 return -3;
1309 }
1310
1311 if (tape.sHInfos().nnzIn_ != *nnz) {
1312 printf(" ADOL-C error in sparse_hess():"
1313 " Number of nonzeros not consistent,"
1314 " new call with repeat = 0 \n");
1315 return -3;
1316 }
1317
1318 // this is the most efficient variant. However, there was somewhere a
1319 // bug in hos_ov_reverse
1320 double y = 0.0;
1321 int ret_val =
1322 hov_wk_forward(tag, 1, indep, 1, 2, tape.sHInfos().p_, basepoint,
1323 tape.sHInfos().Xppp_, &y, tape.sHInfos().Yppp_);
1324 MINDEC(ret_val, hos_ov_reverse(tag, 1, indep, 1, tape.sHInfos().p_,
1325 tape.sHInfos().Upp_, tape.sHInfos().Zppp_));
1326
1327 for (int i = 0; i < tape.sHInfos().p_; ++i)
1328 for (int l = 0; l < indep; ++l)
1329 tape.sHInfos().Hcomp_[l][i] = tape.sHInfos().Zppp_[i][l][1];
1330
1331 if (*values != nullptr && *rind != nullptr && *cind != nullptr) {
1332 // everything is preallocated, we assume correctly
1333 // call usermem versions
1334 if constexpr (RCM == RecoveryMethod::Indirect)
1335 tape.sHInfos().indirectRecoverUserMem(rind, cind, values);
1336 else if constexpr (RCM == RecoveryMethod::Direct)
1337 tape.sHInfos().directRecoverUserMem(rind, cind, values);
1338 } else {
1339 // at least one of rind cind values is not allocated, deallocate others
1340 // and call unmanaged versions
1341 if (*values != nullptr) {
1342 delete[] *values;
1343 *values = nullptr;
1344 }
1345 if (*rind != nullptr) {
1346 delete[] *rind;
1347 *rind = nullptr;
1348 }
1349 if (*cind != nullptr) {
1350 delete[] *cind;
1351 *cind = nullptr;
1352 }
1353 if constexpr (RCM == RecoveryMethod::Indirect)
1354 tape.sHInfos().indirectRecover(rind, cind, values);
1355 else if constexpr (RCM == RecoveryMethod::Direct)
1356 tape.sHInfos().directRecover(rind, cind, values);
1357 }
1358 return ret_val;
1359}
1360
1361} // namespace detail
1362
1396template <ControlFlowMode CFM, RecoveryMethod RCM>
1397ADOLC_API int
1398sparse_hess(short tag, int indep, int repeat, const double *basepoint, int *nnz,
1399 unsigned int **rind, unsigned int **cind, double **values) {
1400 using namespace detail;
1401 int ret_val = 0;
1402 if (repeat == 0)
1403 ret_val = buildHessPatternAndSeed<CFM, RCM>(tag, indep, basepoint, nnz);
1404 if (ret_val < 0) {
1405 printf(" ADOL-C error in sparse_hess() \n");
1406 return ret_val;
1407 }
1408 return computeSparseHess<RCM>(tag, indep, basepoint, nnz, rind, cind, values);
1409}
1410
1411/****************************************************************************/
1412
1413} // namespace ADOLC::Sparse
1414#endif // ADOLC_SPARSE_DRIVERS_H
ADOLC_API double *** myalloc3(size_t, size_t, size_t)
ADOLC_API void myfree2(double **)
ADOLC_API double * myalloc1(size_t)
ADOLC_API void myfree1(double *)
ADOLC_API void myfree3(double ***)
ADOLC_API double ** myalloc2(size_t, size_t)
#define ADOLC_API
Definition adolcexport.h:16
unsigned int coordinate_type
Definition sparsematrix.h:24
Owning sparse matrix container in coordinate-format.
Definition sparsematrix.h:81
size_t size() const
Get the number of stored nonzeros.
Definition sparsematrix.h:137
Owns one recorded function and the state required to evaluate it.
Definition valuetape.h:79
size_t numInds() const
Definition valuetape.h:366
void numSwitches(size_t num)
Definition valuetape.h:377
#define MINDEC(a, b)
Definition common.h:137
unsigned int uint
Definition common.h:39
uint32_t bitword_t
Definition common.h:37
ADOLC_API int int_forward_tight(short, int, int, int, const double *, const bitword_t *const *, double *, bitword_t **)
ADOLC_API int int_reverse_safe(short, int, int, int, const bitword_t *const *, bitword_t **)
ADOLC_API int hos_ov_reverse(short, int, int, int, int, const double *const *, double ***)
ADOLC_API int nonl_ind_forward_tight(short, int, int, const double *, uint **)
ADOLC_API int indopro_forward_absnormal(short, int, int, int, const double *, uint **)
ADOLC_API int nonl_ind_old_forward_tight(short, int, int, const double *, uint **)
ADOLC_API int indopro_forward_tight(short, int, int, const double *, uint **)
ADOLC_API int int_reverse_tight(short, int, int, int, const bitword_t *const *, bitword_t **)
ADOLC_API int fov_forward(short, int, int, int, const double *, const double *const *, double *, double **)
ADOLC_API int nonl_ind_forward_safe(short, int, int, const double *, uint **)
ADOLC_API int nonl_ind_old_forward_safe(short, int, int, const double *, uint **)
ADOLC_API int fov_reverse(short, int, int, int, const double *const *, double **)
ADOLC_API int zos_pl_forward(short, int, int, int, const double *, double *, double *)
ADOLC_API int int_forward_safe(short, int, int, int, const bitword_t *const *, bitword_t **)
BEGIN_C_DECLS ADOLC_API int zos_forward(short, int, int, int, const double *, double *)
ADOLC_API int hov_wk_forward(short, int, int, int, int, int, const double *, const double *const *const *, double *, double ***)
ADOLC_API int indopro_forward_safe(short, int, int, const double *, uint **)
ADOLC_API int fov_pl_reverse(short tag, int m, int n, int s, int nrow, const double *const *lagrange, const double *const *lagrangeSwitch, double **results, double **resultsSwitch)
Computes several vector-Jacobian product of the extended Jacobian of the abs-linearization.
void resetInput(std::span< uint * > &compressedRowStorage)
Resets all entries in the compressed row storage pointer array to nullptr.
Definition sparsedrivers.h:160
int computeSparseHess(short tag, int indep, const double *basepoint, int *nnz, unsigned int **rind, unsigned int **cind, double **values)
Compute sparse Hessian using precomputed seed/recovery info.
Definition sparsedrivers.h:1301
void prepareADCalls(short tapeId, const double *basepoint, BvpData< BPPD > &data)
Prepares reverse call using zos_forward.
Definition sparsedrivers.h:355
int bitVectorPropagation(short tapeId, int depen, int indep, const double *basepoint, std::span< uint * > &compressedRowStorage)
Main internal implementation for bit-vector propagation.
Definition sparsedrivers.h:416
void checkBVPInput(const double *basepoint)
Verifies input data consistency for bit-vector propagation.
Definition sparsedrivers.h:151
void createSeed(BvpData< BPPD > &data, size_t stripIdx, size_t end)
Creates a seed matrix segment by invoking setSeed() for each variable in the strip.
Definition sparsedrivers.h:229
void setSeed(BvpData< BPPD > &data, size_t idx, size_t currentStripWordIdx)
Sets a single bit in the seed matrix corresponding to a specific variable index.
Definition sparsedrivers.h:209
void extractCompressedRowStorage(int stripIdx, std::span< uint * > &compressedRowStorage, BvpData< BPPD > &data)
Converts Jacobian bit patterns to compressed row storage (CRS) format for one strip.
Definition sparsedrivers.h:300
void ADCalls(short tapeId, const double *basepoint, BvpData< BPPD > &data)
Executes the ADOL-C internal bit-vector propagation calls (forward or reverse).
Definition sparsedrivers.h:375
int computeSparseJac(short tag, int depen, int indep, const double *basepoint, SparseMatrix &sparseJac)
Compute sparse Jacobian using precomputed seed matrix and recovery information.
Definition sparsedrivers.h:888
int buildJacPatternAndSeed(short tag, int depen, int indep, const double *basepoint)
Allocates and computes pattern of jacobian and computes a seed to compute a sparse Jacobian.
Definition sparsedrivers.h:664
void resetOldSeed(BvpData< BPPD > &data, size_t dim2)
Sets all seed matrix entries to zero for reuse in the next strip-mined batch.
Definition sparsedrivers.h:175
int buildHessPatternAndSeed(short tag, int indep, const double *basepoint, int *nnz)
Build Hessian sparsity pattern and generate ColPack seed for recovery.
Definition sparsedrivers.h:1207
SparseANFBlock classifySparseANFBlock(CoordinateFormatTripled::Coordinates coords, int depen, int indep)
Definition sparsematrix.h:196
void recover(const ValueTape &tape, SparseMatrix &sparseJac)
Passes args to jacobian-recover method based on the template-args.
Definition sparsedrivers.h:810
void extract(size_t wordIdx, size_t stripIdx, size_t currentStripWordIdx, BvpData< BitPatternPropagationDirection::Forward > &data, std::span< uint * > &compressedRowStorage)
Extracts the sparsity pattern for one dependent variable (row) in forward bit-vector propagation mode...
void prepareSeedMatrix(size_t stripIdx, BvpData< BPPD > &data)
Builds a strip-mined partition of the seed matrix for a given batch.
Definition sparsedrivers.h:189
Definition adtl_indo.h:46
MemoryHandler
Selects how sparse coordinate buffers are provided.
Definition sparse_options.h:184
ADOLC_API void generate_seed_jac(int m, int n, const std::span< uint * > JP, double ***Seed, int *p)
Generate a seed matrix (coloring) for compressed Jacobian recovery.
Definition sparsedrivers.h:610
SparseMethod
Method used to determine the sparsity pattern.
Definition sparse_options.h:12
@ BitPattern
Bit-pattern propagation.
@ IndexDomains
Index-domain propagation.
ADOLC_API int sparse_jac(short tag, int depen, int indep, int repeat, const double *basepoint, SparseMatrix &sparseJac)
High-level API to compute a sparse Jacobian (single call or repeat).
Definition sparsedrivers.h:1008
ADOLC_API int sparse_hess(short tag, int indep, int repeat, const double *basepoint, int *nnz, unsigned int **rind, unsigned int **cind, double **values)
High-level API to compute a sparse Hessian.
Definition sparsedrivers.h:1398
ControlFlowMode
Control-flow handling mode for sparsity and dependence analysis.
Definition sparse_options.h:37
@ Tight
Tight (basepoint-dependent) control-flow handling.
@ OldSafe
Legacy safe control-flow handling.
@ OldTight
Legacy tight control-flow handling.
@ Safe
Safe (conservative) control-flow handling.
@ Indirect
Indirect (acyclic) recovery.
@ Direct
Direct (star) recovery.
BitPatternPropagationDirection
Direction used for bit-pattern propagation.
Definition sparse_options.h:86
@ Auto
Automatic selection of propagation direction.
@ Forward
Forward-mode bit-pattern propagation.
@ Reverse
Reverse-mode bit-pattern propagation.
ADOLC_API int jac_pat(short tag, int depen, int indep, const double *basepoint, std::span< uint * > &compressedRowStorage)
Compute Jacobian sparsity pattern using the selected sparse method.
Definition sparsedrivers.h:537
ADOLC_API int hess_pat(short tag, int indep, const double *basepoint, std::span< uint * > &compressedRowStorage)
Compute Hessian sparsity pattern (dispatch by control-flow mode).
Definition sparsedrivers.h:1123
void generateSeedHess(int dimIn, const std::span< uint * > HP, double ***Seed, int *p, const std::string &coloringVariant)
Generate a Hessian seed matrix using ColPack.
ADOLC_API void generate_seed_hess(int n, std::span< uint * > HP, double ***Seed, int *p)
Generate a seed matrix for compressed Hessian recovery.
Definition sparsedrivers.h:1161
CompressionMode
Compression orientation for sparse Jacobian recovery.
Definition sparse_options.h:120
@ Column
Column compression.
ADOLC_API int bit_vector_propagation(short tapeId, int depen, int indep, const double *basepoint, std::span< uint * > &compressedRowStorage)
Computes the sparsity pattern of a Jacobian using bit-vector propagation.
Definition sparsedrivers.h:479
#define PQ_STRIPMINE_MAX
Definition sparsedrivers.h:36
Tag type selecting sparse drivers for piecewise-linear abs-normal forms.
Definition sparse_options.h:172
Stores the abs-normal form in sparse format.
Definition sparsematrix.h:247
std::vector< double > z
Switching-variable values at the evaluation point.
Definition sparsematrix.h:268
void updateCz()
Compute cz = z - L|z| from the current data.
Definition sparsematrix.h:308
std::vector< double > y
Dependent values at the evaluation point.
Definition sparsematrix.h:266
void updateCy()
Compute cy = y - J|z| from the current data.
Definition sparsematrix.h:300
Internal data structure managing buffers and parameters for bit-vector propagation.
Definition sparsedrivers.h:60
BvpData & operator=(const BvpData &)=delete
std::vector< bitword_t * > seed_
Seed matrix partitions.
Definition sparsedrivers.h:73
int depen_
Number of dependent (output) variables.
Definition sparsedrivers.h:62
~BvpData()
Destructor — frees dynamically allocated memory for bit patterns.
Definition sparsedrivers.h:85
std::vector< bitword_t * > jacobianBitPattern_
Jacobian bit pattern partitions.
Definition sparsedrivers.h:75
int numStripmineBatches_
Number of batches needed to cover all variables.
Definition sparsedrivers.h:66
BvpData & operator=(BvpData &&)=delete
std::vector< unsigned char > indepWordHasNonzero_
Definition sparsedrivers.h:69
int rc_
Return code from ADOL-C drivers.
Definition sparsedrivers.h:61
BvpData(BvpData &&)=delete
std::vector< double > valuepoint_
Definition sparsedrivers.h:71
int bitsPerStrip_
Number of bits represented by one batch.
Definition sparsedrivers.h:65
int wordsPerBatch_
Number of bit words per batch.
Definition sparsedrivers.h:64
BvpData(const BvpData &)=delete
BvpData(int depen, int indep)
Constructs a bit-vector propagation data container.
Definition sparsedrivers.h:101
int indep_
Number of independent (input) variables.
Definition sparsedrivers.h:63
ADOLC_API ValueTape & findTape(short tapeId)
Returns a reference to a ValueTape by tapeId, or throws an error if not found.