CoDiPack  2.2.0
A Code Differentiation Package
SciComp TU Kaiserslautern
Loading...
Searching...
No Matches
matrixMatrixMultiplication.hpp
1/*
2 * CoDiPack, a Code Differentiation Package
3 *
4 * Copyright (C) 2015-2024 Chair for Scientific Computing (SciComp), University of Kaiserslautern-Landau
5 * Homepage: http://scicomp.rptu.de
6 * Contact: Prof. Nicolas R. Gauger (codi@scicomp.uni-kl.de)
7 *
8 * Lead developers: Max Sagebaum, Johannes Blühdorn (SciComp, University of Kaiserslautern-Landau)
9 *
10 * This file is part of CoDiPack (http://scicomp.rptu.de/software/codi).
11 *
12 * CoDiPack is free software: you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * CoDiPack is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty
19 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * See the GNU General Public License for more details.
22 * You should have received a copy of the GNU
23 * General Public License along with CoDiPack.
24 * If not, see <http://www.gnu.org/licenses/>.
25 *
26 * For other licensing options please contact us.
27 *
28 * Authors:
29 * - SciComp, University of Kaiserslautern-Landau:
30 * - Max Sagebaum
31 * - Johannes Blühdorn
32 * - Former members:
33 * - Tim Albring
34 */
35#pragma once
36
37#include <codi/config.h>
38
39#include <codi/misc/macros.hpp>
40#include <codi/tools/lowlevelFunctions/eigenWrappers.hpp>
41#include <codi/tools/lowlevelFunctions/generationHelperCoDiPack.hpp>
42#include <codi/tools/lowlevelFunctions/lowLevelFunctionCreationUtilities.hpp>
43
45namespace codi {
47 template<Eigen::StorageOptions eigenStore, typename Type>
52 using Tape = typename Type::Tape;
53
56
58 CODI_INLINE static void forward(Tape* tape, codi::ByteDataView& dataStore, AdjointVectorAccess adjoints) {
59 codi::TemporaryMemory& allocator = tape->getTemporaryMemory();
60 codiAssert(allocator.isEmpty()); // No memory should be allocated. We would free it at the end.
62
63 // Traits for arguments.
64 using Trait_A = typename LLFH::ActiveStoreTrait<Type*>;
65 using Trait_B = typename LLFH::ActiveStoreTrait<Type*>;
66 using Trait_R = typename LLFH::ActiveStoreTrait<Type*>;
67 using Trait_n = typename LLFH::PassiveStoreTrait<int, uint8_t>;
68 using Trait_k = typename LLFH::PassiveStoreTrait<int, uint8_t>;
69 using Trait_m = typename LLFH::PassiveStoreTrait<int, uint8_t>;
70
71 // Declare variables.
72 typename LLFH::ActivityStoreType activityStore = {};
73 typename Trait_A::ArgumentStore A_store = {};
74 typename Trait_B::ArgumentStore B_store = {};
75 typename Trait_R::ArgumentStore R_store = {};
76 typename Trait_n::Store n = {};
77 typename Trait_k::Store k = {};
78 typename Trait_m::Store m = {};
79
80 bool active_A = false;
81 bool active_B = false;
82
83 // Restore data.
84 LLFH::restoreActivity(&dataStore, activityStore);
85 active_A = LLFH::getActivity(activityStore, 0);
86 active_B = LLFH::getActivity(activityStore, 1);
87 Trait_n::restore(&dataStore, allocator, 1, true, n);
88 Trait_k::restore(&dataStore, allocator, 1, true, k);
89 Trait_m::restore(&dataStore, allocator, 1, true, m);
90 Trait_A::restore(&dataStore, allocator, n * k, LLFH::createRestoreActions(true, false, active_A, active_B),
91 A_store);
92 Trait_B::restore(&dataStore, allocator, k * m, LLFH::createRestoreActions(true, false, active_B, active_A),
93 B_store);
94 Trait_R::restore(&dataStore, allocator, n * m, LLFH::createRestoreActions(false, true, false, true), R_store);
95
96 if (Tape::HasPrimalValues) {
97 // Get primal values for inputs.
98 if (active_A && active_B) {
99 Trait_A::getPrimalsFromVector(adjoints, n * k, A_store.identifierIn(), A_store.primal());
100 }
101 if (active_B && active_A) {
102 Trait_B::getPrimalsFromVector(adjoints, k * m, B_store.identifierIn(), B_store.primal());
103 }
104 }
105
106 for (size_t curDim = 0; curDim < adjoints->getVectorSize(); curDim += 1) {
107 // Get input gradients.
108 if (active_A) {
109 Trait_A::getGradients(adjoints, n * k, false, A_store.identifierIn(), A_store.gradientIn(), curDim);
110 }
111 if (active_B) {
112 Trait_B::getGradients(adjoints, k * m, false, B_store.identifierIn(), B_store.gradientIn(), curDim);
113 }
114 if (Tape::HasPrimalValues && 0 == curDim) {
115 if (!Tape::LinearIndexHandling) {
116 // Update old primal values.
117 Trait_R::getPrimalsFromVector(adjoints, n * m, R_store.identifierOut(), R_store.oldPrimal());
118 }
119
120 // Set new primal values.
121 Trait_R::setPrimalsIntoVector(adjoints, n * m, R_store.identifierOut(), R_store.primal());
122 }
123
124 // Evaluate forward mode.
125 callForward(A_store.primal(), active_A, A_store.gradientIn(), B_store.primal(), active_B,
126 B_store.gradientIn(), R_store.primal(), R_store.gradientOut(), n, k, m);
127
128 Trait_R::setGradients(adjoints, n * m, false, R_store.identifierOut(), R_store.gradientOut(), curDim);
129 }
130
131 allocator.free();
132 }
133
135 CODI_INLINE static void callForward(typename codi::ActiveArgumentStoreTraits<Type*>::Real const* A, bool active_A,
137 typename codi::ActiveArgumentStoreTraits<Type*>::Real const* B, bool active_B,
144 codi::CODI_UNUSED(A, active_A, A_d_in, B, active_B, B_d_in, R, R_d_out, n, k, m);
145 if (active_A) {
146 mapEigen<eigenStore>(R_d_out, n, m) += mapEigen<eigenStore>(A_d_in, n, k) * mapEigen<eigenStore>(B, k, m);
147 }
148 if (active_B) {
149 mapEigen<eigenStore>(R_d_out, n, m) += mapEigen<eigenStore>(A, n, k) * mapEigen<eigenStore>(B_d_in, k, m);
150 }
151 mapEigen<eigenStore>(R, n, m) = mapEigen<eigenStore>(A, n, k) * mapEigen<eigenStore>(B, k, m);
152 }
153
155 CODI_INLINE static void reverse(Tape* tape, codi::ByteDataView& dataStore, AdjointVectorAccess adjoints) {
156 codi::TemporaryMemory& allocator = tape->getTemporaryMemory();
157 codiAssert(allocator.isEmpty()); // No memory should be allocated. We would free it at the end.
159
160 // Traits for arguments.
161 using Trait_A = typename LLFH::ActiveStoreTrait<Type*>;
162 using Trait_B = typename LLFH::ActiveStoreTrait<Type*>;
163 using Trait_R = typename LLFH::ActiveStoreTrait<Type*>;
164 using Trait_n = typename LLFH::PassiveStoreTrait<int, uint8_t>;
165 using Trait_k = typename LLFH::PassiveStoreTrait<int, uint8_t>;
166 using Trait_m = typename LLFH::PassiveStoreTrait<int, uint8_t>;
167
168 // Declare variables.
169 typename LLFH::ActivityStoreType activityStore = {};
170 typename Trait_A::ArgumentStore A_store = {};
171 typename Trait_B::ArgumentStore B_store = {};
172 typename Trait_R::ArgumentStore R_store = {};
173 typename Trait_n::Store n = {};
174 typename Trait_k::Store k = {};
175 typename Trait_m::Store m = {};
176
177 bool active_A = false;
178 bool active_B = false;
179
180 // Restore data.
181 LLFH::restoreActivity(&dataStore, activityStore);
182 active_A = LLFH::getActivity(activityStore, 0);
183 active_B = LLFH::getActivity(activityStore, 1);
184 Trait_n::restore(&dataStore, allocator, 1, true, n);
185 Trait_k::restore(&dataStore, allocator, 1, true, k);
186 Trait_m::restore(&dataStore, allocator, 1, true, m);
187 Trait_A::restore(&dataStore, allocator, n * k, LLFH::createRestoreActions(true, false, active_A, active_B),
188 A_store);
189 Trait_B::restore(&dataStore, allocator, k * m, LLFH::createRestoreActions(true, false, active_B, active_A),
190 B_store);
191 Trait_R::restore(&dataStore, allocator, n * m, LLFH::createRestoreActions(false, true, false, true), R_store);
192
193 if (Tape::HasPrimalValues) {
194 if (!Tape::LinearIndexHandling) {
195 // Restore old primal values from outputs.
196 Trait_R::setPrimalsIntoVector(adjoints, n * m, R_store.identifierOut(), R_store.oldPrimal());
197 }
198
199 // Get primal values for inputs.
200 if (active_A && active_B) {
201 Trait_A::getPrimalsFromVector(adjoints, n * k, A_store.identifierIn(), A_store.primal());
202 }
203 if (active_B && active_A) {
204 Trait_B::getPrimalsFromVector(adjoints, k * m, B_store.identifierIn(), B_store.primal());
205 }
206 }
207
208 for (size_t curDim = 0; curDim < adjoints->getVectorSize(); curDim += 1) {
209 // Get output gradients.
210 Trait_R::getGradients(adjoints, n * m, true, R_store.identifierOut(), R_store.gradientOut(), curDim);
211
212 // Evaluate reverse mode.
213 callReverse(A_store.primal(), active_A, A_store.gradientIn(), B_store.primal(), active_B,
214 B_store.gradientIn(), R_store.primal(), R_store.gradientOut(), n, k, m);
215
216 if (active_A) {
217 Trait_A::setGradients(adjoints, n * k, true, A_store.identifierIn(), A_store.gradientIn(), curDim);
218 }
219 if (active_B) {
220 Trait_B::setGradients(adjoints, k * m, true, B_store.identifierIn(), B_store.gradientIn(), curDim);
221 }
222 }
223
224 allocator.free();
225 }
226
228 CODI_INLINE static void callReverse(typename codi::ActiveArgumentStoreTraits<Type*>::Real const* A, bool active_A,
230 typename codi::ActiveArgumentStoreTraits<Type*>::Real const* B, bool active_B,
237 codi::CODI_UNUSED(A, active_A, A_b_in, B, active_B, B_b_in, R, R_b_out, n, k, m);
238 if (active_A) {
239 mapEigen<eigenStore>(A_b_in, n, k) =
240 mapEigen<eigenStore>(R_b_out, n, m) * mapEigen<eigenStore>(B, k, m).transpose();
241 }
242 if (active_B) {
243 mapEigen<eigenStore>(B_b_in, k, m) =
244 mapEigen<eigenStore>(A, n, k).transpose() * mapEigen<eigenStore>(R_b_out, n, m);
245 }
246 }
247
249 CODI_INLINE static void del(Tape* tape, codi::ByteDataView& dataStore) {
250 codi::TemporaryMemory& allocator = tape->getTemporaryMemory();
251 codiAssert(allocator.isEmpty()); // No memory should be allocated. We would free it at the end.
253
254 // Traits for arguments.
255 using Trait_A = typename LLFH::ActiveStoreTrait<Type*>;
256 using Trait_B = typename LLFH::ActiveStoreTrait<Type*>;
257 using Trait_R = typename LLFH::ActiveStoreTrait<Type*>;
258 using Trait_n = typename LLFH::PassiveStoreTrait<int, uint8_t>;
259 using Trait_k = typename LLFH::PassiveStoreTrait<int, uint8_t>;
260 using Trait_m = typename LLFH::PassiveStoreTrait<int, uint8_t>;
261
262 // Declare variables.
263 typename LLFH::ActivityStoreType activityStore = {};
264 typename Trait_A::ArgumentStore A_store = {};
265 typename Trait_B::ArgumentStore B_store = {};
266 typename Trait_R::ArgumentStore R_store = {};
267 typename Trait_n::Store n = {};
268 typename Trait_k::Store k = {};
269 typename Trait_m::Store m = {};
270
271 bool active_A = false;
272 bool active_B = false;
273
274 // Restore data.
275 LLFH::restoreActivity(&dataStore, activityStore);
276 active_A = LLFH::getActivity(activityStore, 0);
277 active_B = LLFH::getActivity(activityStore, 1);
278 Trait_n::restore(&dataStore, allocator, 1, true, n);
279 Trait_k::restore(&dataStore, allocator, 1, true, k);
280 Trait_m::restore(&dataStore, allocator, 1, true, m);
281 Trait_A::restore(&dataStore, allocator, n * k, LLFH::createRestoreActions(true, false, active_A, active_B),
282 A_store);
283 Trait_B::restore(&dataStore, allocator, k * m, LLFH::createRestoreActions(true, false, active_B, active_A),
284 B_store);
285 Trait_R::restore(&dataStore, allocator, n * m, LLFH::createRestoreActions(false, true, false, true), R_store);
286
287 allocator.free();
288 }
289
291 CODI_INLINE static void evalAndStore(Type const* A, Type const* B, Type* R, int n, int k, int m) {
292 Tape& tape = Type::getTape();
293 codi::TemporaryMemory& allocator = tape.getTemporaryMemory();
295
296 // Traits for arguments.
297 using Trait_A = typename LLFH::ActiveStoreTrait<Type*>;
298 using Trait_B = typename LLFH::ActiveStoreTrait<Type*>;
299 using Trait_R = typename LLFH::ActiveStoreTrait<Type*>;
300 using Trait_n = typename LLFH::PassiveStoreTrait<int, uint8_t>;
301 using Trait_k = typename LLFH::PassiveStoreTrait<int, uint8_t>;
302 using Trait_m = typename LLFH::PassiveStoreTrait<int, uint8_t>;
303
304 // Declare variables.
305 typename LLFH::ActivityStoreType activityStore = {};
306 typename Trait_A::ArgumentStore A_store = {};
307 typename Trait_B::ArgumentStore B_store = {};
308 typename Trait_R::ArgumentStore R_store = {};
309
310 // Detect activity.
311 bool active_A = Trait_A::isActive(A, n * k);
312 bool active_B = Trait_B::isActive(B, k * m);
313 bool active = active_A | active_B;
314
315 if (active) {
316 // Store function.
318
319 // Count data size.
320 size_t dataSize = LLFH::countActivitySize();
321 dataSize += Trait_n::countSize(n, 1, true);
322 dataSize += Trait_k::countSize(k, 1, true);
323 dataSize += Trait_m::countSize(m, 1, true);
324 dataSize += Trait_A::countSize(A, n * k, LLFH::createStoreActions(active, true, false, active_A, active_B));
325 dataSize += Trait_B::countSize(B, k * m, LLFH::createStoreActions(active, true, false, active_B, active_A));
326 dataSize += Trait_R::countSize(R, n * m, LLFH::createStoreActions(active, false, true, false, true));
327
328 // Reserve data.
329 codi::ByteDataView dataStore = {};
330 tape.pushLowLevelFunction(ID, dataSize, dataStore);
331
332 // Store data.
333 LLFH::setActivity(activityStore, 0, active_A);
334 LLFH::setActivity(activityStore, 1, active_B);
335 LLFH::storeActivity(&dataStore, activityStore);
336 Trait_n::store(&dataStore, allocator, n, 1, true);
337 Trait_k::store(&dataStore, allocator, k, 1, true);
338 Trait_m::store(&dataStore, allocator, m, 1, true);
339 Trait_A::store(&dataStore, allocator, A, n * k,
340 LLFH::createStoreActions(active, true, false, active_A, active_B), A_store);
341 Trait_B::store(&dataStore, allocator, B, k * m,
342 LLFH::createStoreActions(active, true, false, active_B, active_A), B_store);
343 Trait_R::store(&dataStore, allocator, R, n * m, LLFH::createStoreActions(active, false, true, false, true),
344 R_store);
345 } else {
346 // Prepare passive evaluation.
347 Trait_A::store(nullptr, allocator, A, n * k,
348 LLFH::createStoreActions(active, true, false, active_A, active_B), A_store);
349 Trait_B::store(nullptr, allocator, B, k * m,
350 LLFH::createStoreActions(active, true, false, active_B, active_A), B_store);
351 Trait_R::store(nullptr, allocator, R, n * m, LLFH::createStoreActions(active, false, true, false, true),
352 R_store);
353 }
354
355 callPrimal(active, A_store.primal(), active_A, A_store.identifierIn(), B_store.primal(), active_B,
356 B_store.identifierIn(), R_store.primal(), R_store.identifierOut(), n, k, m);
357
358 Trait_R::setExternalFunctionOutput(active, R, n * m, R_store.identifierOut(), R_store.primal(),
359 R_store.oldPrimal());
360
361 allocator.free();
362 }
363
365 CODI_INLINE static void callPrimal(bool active, typename codi::ActiveArgumentStoreTraits<Type*>::Real const* A,
366 bool active_A,
368 typename codi::ActiveArgumentStoreTraits<Type*>::Real const* B, bool active_B,
372 int k, int m) {
373 codi::CODI_UNUSED(active, A, active_A, A_i_in, B, active_B, B_i_in, R, R_i_out, n, k, m);
374 mapEigen<eigenStore>(R, n, m) = mapEigen<eigenStore>(A, n, k) * mapEigen<eigenStore>(B, k, m);
375
376 // User defined activity update.
377 if (active) {
378 mapEigen<eigenStore>(R_i_out, n, m).setZero();
379 if (active_A) {
380 mapEigen<eigenStore>(R_i_out, n, m).colwise() += mapEigen<eigenStore>(A_i_in, n, k).rowwise().any();
381 }
382 if (active_B) {
383 mapEigen<eigenStore>(R_i_out, n, m).rowwise() += mapEigen<eigenStore>(B_i_in, k, m).colwise().any();
384 }
385 }
386 }
387
392 ID = Type::getTape().registerLowLevelFunction(Entry(reverse, forward, nullptr, del));
393 }
394 }
395 };
396
397 template<Eigen::StorageOptions eigenStore, typename Type>
400
409 template<Eigen::StorageOptions eigenStore, typename Type>
410 void matrixMatrixMultiplication(Type const* A, Type const* B, Type* R, int n, int k, int m) {
412 }
413
420 template<typename Type>
421 void matrixMatrixMultiplicationRowMajor(Type const* A, Type const* B, Type* R, int n, int k, int m) {
422 matrixMatrixMultiplication<Eigen::StorageOptions::RowMajor>(A, B, R, n, k, m);
423 }
430 template<typename Type>
431 void matrixMatrixMultiplicationColMajor(Type const* A, Type const* B, Type* R, int n, int k, int m) {
432 matrixMatrixMultiplication<Eigen::StorageOptions::ColMajor>(A, B, R, n, k, m);
433 }
434}
#define CODI_INLINE
See codi::Config::ForcedInlines.
Definition config.h:457
#define codiAssert(x)
See codi::Config::EnableAssert.
Definition config.h:432
uint16_t LowLevelFunctionToken
Token type for low level functions in the tapes.
Definition config.h:108
size_t constexpr LowLevelFunctionTokenInvalid
Invalid low level function token.
Definition config.h:114
CoDiPack - Code Differentiation Package.
Definition codi.hpp:90
void matrixMatrixMultiplicationRowMajor(Type const *A, Type const *B, Type *R, int n, int k, int m)
Definition matrixMatrixMultiplication.hpp:421
void CODI_UNUSED(Args const &...)
Disable unused warnings for an arbitrary number of arguments.
Definition macros.hpp:46
void matrixMatrixMultiplication(Type const *A, Type const *B, Type *R, int n, int k, int m)
Definition matrixMatrixMultiplication.hpp:410
void matrixMatrixMultiplicationColMajor(Type const *A, Type const *B, Type *R, int n, int k, int m)
Definition matrixMatrixMultiplication.hpp:431
double Real
The type with no CoDiPack values.
Definition activeArgumentStoreTraits.hpp:207
int Identifier
The type for holding the identifiers.
Definition activeArgumentStoreTraits.hpp:208
Real Gradient
The type that can represent the gradient values.
Definition activeArgumentStoreTraits.hpp:209
Definition byteDataView.hpp:51
Low level function generation for matrixMatrixMultiplication.
Definition matrixMatrixMultiplication.hpp:48
static CODI_INLINE void callPrimal(bool active, typename codi::ActiveArgumentStoreTraits< Type * >::Real const *A, bool active_A, typename codi::ActiveArgumentStoreTraits< Type * >::Identifier const *A_i_in, typename codi::ActiveArgumentStoreTraits< Type * >::Real const *B, bool active_B, typename codi::ActiveArgumentStoreTraits< Type * >::Identifier const *B_i_in, typename codi::ActiveArgumentStoreTraits< Type * >::Real *R, typename codi::ActiveArgumentStoreTraits< Type * >::Identifier *R_i_out, int n, int k, int m)
Primal computation function.
Definition matrixMatrixMultiplication.hpp:365
static codi::Config::LowLevelFunctionToken ID
Id for this function.
Definition matrixMatrixMultiplication.hpp:55
static CODI_INLINE void callReverse(typename codi::ActiveArgumentStoreTraits< Type * >::Real const *A, bool active_A, typename codi::ActiveArgumentStoreTraits< Type * >::Gradient *A_b_in, typename codi::ActiveArgumentStoreTraits< Type * >::Real const *B, bool active_B, typename codi::ActiveArgumentStoreTraits< Type * >::Gradient *B_b_in, typename codi::ActiveArgumentStoreTraits< Type * >::Real *R, typename codi::ActiveArgumentStoreTraits< Type * >::Gradient *R_b_out, typename codi::PassiveArgumentStoreTraits< int, uint8_t >::Store n, typename codi::PassiveArgumentStoreTraits< int, uint8_t >::Store k, typename codi::PassiveArgumentStoreTraits< int, uint8_t >::Store m)
Reverse function for derivative evaluation.
Definition matrixMatrixMultiplication.hpp:228
static CODI_INLINE void reverse(Tape *tape, codi::ByteDataView &dataStore, AdjointVectorAccess adjoints)
Function for reverse interpretation.
Definition matrixMatrixMultiplication.hpp:155
static CODI_INLINE void evalAndStore(Type const *A, Type const *B, Type *R, int n, int k, int m)
Store on tape.
Definition matrixMatrixMultiplication.hpp:291
static CODI_INLINE void del(Tape *tape, codi::ByteDataView &dataStore)
Function for deletion of contents.
Definition matrixMatrixMultiplication.hpp:249
static CODI_INLINE void callForward(typename codi::ActiveArgumentStoreTraits< Type * >::Real const *A, bool active_A, typename codi::ActiveArgumentStoreTraits< Type * >::Gradient *A_d_in, typename codi::ActiveArgumentStoreTraits< Type * >::Real const *B, bool active_B, typename codi::ActiveArgumentStoreTraits< Type * >::Gradient *B_d_in, typename codi::ActiveArgumentStoreTraits< Type * >::Real *R, typename codi::ActiveArgumentStoreTraits< Type * >::Gradient *R_d_out, typename codi::PassiveArgumentStoreTraits< int, uint8_t >::Store n, typename codi::PassiveArgumentStoreTraits< int, uint8_t >::Store k, typename codi::PassiveArgumentStoreTraits< int, uint8_t >::Store m)
Forward function for derivative evaluation.
Definition matrixMatrixMultiplication.hpp:135
static CODI_INLINE void forward(Tape *tape, codi::ByteDataView &dataStore, AdjointVectorAccess adjoints)
Function for forward interpretation.
Definition matrixMatrixMultiplication.hpp:58
static CODI_INLINE void registerOnTape()
Register function on tape.
Definition matrixMatrixMultiplication.hpp:389
typename Type::Tape Tape
Abbreviation for tape.
Definition matrixMatrixMultiplication.hpp:52
Helper structure for storing low level functions and their arguments on a tape.
Definition lowLevelFunctionCreationUtilities.hpp:128
Low level function entry on the tape. See LowLevelFunctionTapeInterface for details.
Definition lowLevelFunctionEntry.hpp:67
T Store
Type for the variable declaration for restoring the data.
Definition passiveArgumentStoreTraits.hpp:61
Allocator for temporary used memory.
Definition temporaryMemory.hpp:54
bool isEmpty()
Returns true if no data is currently allocated.
Definition temporaryMemory.hpp:71
void free()
Free all allocated memory. No destructors are called. Stored pointers and resources need to be deallo...
Definition temporaryMemory.hpp:110
Unified access to the adjoint vector and primal vector in a tape evaluation.
Definition vectorAccessInterface.hpp:91
virtual size_t getVectorSize() const =0
Vector size in the current tape evaluation.