Tape¶
Overview¶
-
template <typename T>
class Tape¶ Tape data type to record operations for adjoint computations, using the underlying scalar type T (which may in turn be an active type for higher-order derivative calculations).
Typical usage:
Tape<double> tape; // initialize independent variables AReal<double> x1 = 1.2, x2 = 12.1; // register independents with the tape tape.registerInput(x1); tape.registerInput(x2); // start recording derivatives on tape tape.newRecording(); AReal<double> y = sin(x1) + x1*x2; // register output and set adjoint values tape.registerOutput(y); derivative(y) = 1.0; // compute the adjoints of the independent variables tape.computeAdjoints(); // output/use results std::cout << "y = " << value(y) << "\n" << "dy/dx1 = " << derivative(x1) << "\n" << "dy/dx2 = " << derivative(x2) << "\n";
For usability, it is recommended to use the type definitions in AD Mode Interface instead of declaring this tape type directly.
Members¶
Types¶
- type size_type¶
Type for sizes
- type slot_type¶
Type used to represent a slot of a specific active variable
- type position_type¶
Type to represent a position in the tape (same as slot_type)
- typedef CheckpointCallback<tape_type> *callback_type¶
The callback type used for checkpoints
Construct, Destruct, and Assign¶
A tape can be created and moved, but it is not copyable.
- explicit Tape(bool activate = true)¶
Constructs a new tape, and activates it if needed.
If
active
istrue
, a global thread-local pointer is set to this constructed instance, resulting all operations and instantiations of active data types that follow to get automatically associated with this tape instance.- Throws:¶
TapeAlreadyActive
– if activate is true and another tape is already active for the current thread
- ~Tape()¶
Destructor.
Recording Control¶
- void activate()¶
Sets a global thread-local pointer to this tape instance, resulting all
registerInput
calls and operations of active data types depending on such inputs to get associated with this tape instance.- Throws:¶
TapeAlreadyActive
– if another tape is already active for the current thread
- void deactivate()¶
Resets the global thread-local pointer to NULL, hence deactivating this tape.
- bool isActive() const¶
Check if the current instance is the currently active tape.
- Returns:¶
true
if the this instance is active
- static Tape *getActive()¶
Get a pointer to the currently active tape.
Note that this is a thread-local pointer - calling this function in different threads gives different results.
- Returns:¶
Pointer to the currently-active thread-local tape - or
nullptr
- void registerInput(active_type &inp)¶
Register the given variable with the tape and start recording dependents of it. A call to this function or its overloads is required in order to calculate adjoints.
-
template <typename Inner>
void registerInputs(std::vector<Inner> &v)¶ Convenience function to register all variables in a vector as an input.
-
template <typename It>
void registerInputs(It first, It last)¶ Convenience iterator interface to register variables in a range with the tape.
- void registerInput(std::complex<active_type> &inp)¶
Register a complex-valued input.
- void registerOutput(active_type &inp)¶
Register the given variable as an output with the tape. A call to this function or its overloads is required in order to allow seeding derivatives (adjoints).
-
template <typename Inner>
void registerOutputs(std::vector<Inner> &v)¶ Convenience function to register all variables in a vector as an input.
-
template <typename It>
void registerOutputs(It first, It last)¶ Convenience iterator interface to register variables in a range with the tape.
- void registerOutput(std::complex<active_type> &inp)¶
Register a complex-valued output.
- void newRecording()¶
Start recording derivatives.
This function should be called after the independent variables are initialized and registered, as the
computeAdjoints()
method will roll back the adjoints until the point wherenewRecording()
was called.
- void computeAdjoints()¶
Propagates adjoints by interpreting the operations on the tape.
This function should be called after the output derivatives (adjoints) have been initialized to a non-zero value.
After this call, the derivatives of the independent variables are set and can be obtained.
- Throws:¶
DerivativesNotInitialized
– If called without setting any derivative first. Gives strong exception safety guarantee - tape state unchanged in case of exception.
- position_type getPosition()¶
Returns the current position in the tape as an opaque integer (its value is internal and should not be relied upon in client code). This posiiton can later be used in the methods
clearDerivativesAfter
,resetTo
, andcomputeAdjointsTo
.
- void clearDerivativesAfter(position_type pos)¶
Clears all derivatives after the given position in the tape (resets them to zero). Derivatives before this point keep their value, meaning that further calls to
computeAdjoints
will potentially increment these adjoints further.
- void resetTo(position_type pos)¶
Resets the tape back to the given position. All statements recorded after this point will be discarded.
Warning
If variables registered after the given postion (are dependent variables computed after this position) are used again after a call to
resetTo
, the behaviour is undefined, as their slot in the tape is no longer valid.
- void computeAdjointsTo(position_type pos)¶
Like
computeAdjoints
, but stops rolling back the adjoints at the given position in the tape.
- void clearAll()¶
Clears the stored tape info and brings it back to its initial state.
While this clears the content, it leaves allocated memory untouched. This may be a performance gain compared to repeated construction/destruction of tapes of the same time, for example in a path-wise AD Monte-Carlo.
Derivatives¶
- T &derivative(slot_type s)¶
Get a reference to the derivative associated with the slot
s
.- Parameters:¶
- Throws:¶
OutOfRange
– if the given slot is not associated with a stored derivative. (Only thrown in debug mode, otherwise the behaviour is undefined in this case) Gives strong exception safety guarantee - tape state unchanged in case of exception.
- const T &derivative(slot_type s) const¶
Get a const reference to the derivative associated with the slot
s
.- Parameters:¶
- Throws:¶
OutOfRange
– if the given slot is not associated with a stored derivative. (Only thrown in debug mode, otherwise the behaviour is undefined in this case) Gives strong exception safety guarantee - tape state unchanged in case of exception.
- T getDerivative(slot_type s) const¶
Get the value of the derivative associated with the slot
s
.- Parameters:¶
- Throws:¶
OutOfRange
– if the given slot is not associated with a stored derivative. (Only thrown in debug mode, otherwise the behaviour is undefined in this case) Gives strong exception safety guarantee - tape state unchanged in case of exception.
- void setDerivative(slot_type s, const T &v)¶
Set the value of the derivative associated with the slot
s
.- Parameters:¶
- Throws:¶
OutOfRange
– if the given slot is not associated with a stored derivative. (Only thrown in debug mode, otherwise the behaviour is undefined in this case) Gives strong exception safety guarantee - tape state unchanged in case of exception.
- void clearDerivatives()¶
Resets all stored derivatives to 0 (but leaving the recorded data in place). This can be used to calculate derivatives w.r.t. multiple outputs, as the same tape can be rolled back multiple times.
Status¶
- void printStatus() const¶
Prints the number of recorded operations, statements, and registered variables to stdout.
- std::size_t getMemory() const¶
Returns the memory in bytes that is occupied by the tape.
- Returns:¶
Memory in bytes
Checkpointing¶
- void insertCallback(callback_type cb)¶
Insert a checkpoint callback into the tape.
During computing adjoints (
computeAdjoints()
), this callback is called when the tape reaches the current position, allowing users to implement their own adjoint computation.Note that the parameter is provided by pointer, but the tape does not take ownership. It is the responsibility of the user to free the memory for the callback object. Alternatively, the Checkpoint Callback Memory Management API can be used to have the tape destroy the callbacks automatically.
- Parameters:¶
- callback_type cb¶
Pointer to a
CheckpointCallback
instance.
- T getAndResetOutputAdjoint(slot_type slot)¶
Obtains and resets the output adjoint to 0
This function should be called by
CheckpointCallback<TapeType>::computeAdjoints()
to get the current value of the adjoint. It also resets its adjoint to 0 on the tape to allow re-use of that variable.- Parameters:¶
- Returns:¶
The value of the variable’s derivative (i.e. its adjoint)
- Throws:¶
OutOfRange
– If the given slot is not associated with a stored derivative. (Only thrown in debug mode, otherwise the behaviour is undefined) Gives strong exception safety guarantee - tape state unchanged in case of exception.
- void incrementAdjoint(slot_type slot, const T &x)¶
Increments the adjoint of the given slot by the value x.
This function should be called at the end of a
CheckpointCallback<TapeType>::computeAdjoints()
implementation, to update the input adjoints with the computed adjoint increments.- Parameters:¶
- Throws:¶
OutOfRange
– If the given slot is not associated with a stored derivative. (Only thrown in debug mode, otherwise the behaviour is undefined) Gives strong exception safety guarantee - tape state unchanged in case of exception.
- void newNestedRecording()¶
Starts a new nested recording that can be rolled-back on its own. It must be ended with
endNestedRecording()
.It is intended for use within a
CheckpointCallback<TapeType>::computeAdjoints()
implementation, when from a checkpoint, the adjoints are computed using XAD in a nested recording.To avoid forgetting the call to
endNestedRecording()
, consider using the RAII classScopedNestedRecording
.
- void endNestedRecording()¶
Ends a nested recording.
Checkpoint Callback Memory Management¶
- void pushCallback(callback_type cb)¶
Let this tape handle the de-allocation of the given callback.
When the tape is destructed, it also destructs all callbacks that have been registered using this function.
Use this if checkpoints are created in a stateless function to avoid having to track and destroy checkpoint callbacks manually.
- Parameters:¶
- callback_type cb¶
Pointer to a dynamically-allocated checkpoint callback
- callback_type getLastCallback()¶
Obtains the last
CheckpointCallback
object that has been pushed withpushCallback()
.This can be useful if multiple subsequent checkpoints can be added to the same checkpoint callback object.
- Returns:¶
Pointer to the last callback object that has been pushed.
- Throws:¶
OutOfRange
– if the callback stack is empty Gives strong exception safety guarantee - tape state unchanged in case of exception.
- size_type getNumCallbacks() const¶
Gets the number of callback objects that have been pushed by
pushCallback()
- Returns:¶
Number of callback objects registered
- bool haveCallbacks() const¶
Checks if there have been any checkpoint callbacks registered by
pushCallback()
- Returns:¶
true
if there is at least one pushed callback object.
- void popCallback()¶
Removes the callback object that has been last pushed by
pushCallback()
- Throws:¶
OutOfRange
– if the stack of callbacks is empty Gives strong exception safety guarantee - tape state unchanged in case of exception.
Nested Tape¶
-
template <typename TapeType>
class ScopedNestedRecording¶ Convenience RAII class to ensure that a call to
Tape<T>::newNestedRecording()
is always followed by the correspondingTape<T>::endNestedRecording()
.It should be constructed on the stack. On creation it starts a nested recording on the corresponding tape, and on destruction it ends the nested recording. This is useful for checkpoint callbacks, i.e. within the implementation of
CheckpointCallback<TapeType>::computeAdjoints()
.- ScopedNestedRecording(TapeType *t)¶
Start a new nested recording on the given tape and track it with this object.
- ~ScopedNestedRecording()¶
Ends the nested recording with the associated tape
- void computeAdjoints()¶
Computes adjoints within the nested recording