CoDiPack  2.3.0
A Code Differentiation Package
SciComp TU Kaiserslautern
Loading...
Searching...
No Matches
Example 25 - Tape Writers

Goal: Write a tape to storage in a binary, text, graphical or math format.

Prerequisite: Tutorial 2 - Reverse mode AD

Function:

template<typename Real>
Real func(const std::vector<Real>& x) {
return x[0] * x[1] * x[0];
}

Generate Tape

template<typename Real>
void generateTape(std::string const& fileName) {
using Tape = typename Real::Tape;
using Identifier = typename Real::Identifier;
std::vector<Identifier> x_id;
std::vector<Identifier> y_id;
// Step 1: Do a normal recording
std::vector<Real> x = {4.0, 3.0};
Tape& tape = Real::getTape();
tape.setActive();
tape.registerInput(x[0]);
tape.registerInput(x[1]);
Real y = func(x);
tape.registerOutput(y);
// Step 2: Record the inputs and outputs in std::vectors
x_id.push_back(x[0].getIdentifier());
x_id.push_back(x[1].getIdentifier());
y_id.push_back(y.getIdentifier());
tape.setPassive();
// Step 3: Write the tape to storage. Select between a text, binary or graphical file type. For primal value tapes, a
// math representation can also be selected.
// Text format
tape.writeTape(codi::createWriter<Real>(fileName + "_text.txt", x_id, y_id, codi::FileType::Text));
// Graphical format
tape.writeTape(codi::createWriter<Real>(fileName + "_graph.dot", x_id, y_id, codi::FileType::Graph));
// The tape can be still be evaluated as before
y.setGradient(1.0);
tape.evaluate();
std::cout << fileName << ":" << std::endl;
std::cout << "df/dx[0](4.0) = " << x[0].getGradient() << std::endl;
std::cout << "df/dx[1](3.0) = " << x[1].getGradient() << std::endl << std::endl;
tape.reset();
}

Full code:

#include <codi.hpp>
#include <iostream>
template<typename Real>
Real func(const std::vector<Real>& x) {
return x[0] * x[1] * x[0];
}
template<typename Real>
void generateTape(std::string const& fileName) {
using Tape = typename Real::Tape;
using Identifier = typename Real::Identifier;
std::vector<Identifier> x_id;
std::vector<Identifier> y_id;
// Step 1: Do a normal recording
std::vector<Real> x = {4.0, 3.0};
Tape& tape = Real::getTape();
tape.setActive();
tape.registerInput(x[0]);
tape.registerInput(x[1]);
Real y = func(x);
tape.registerOutput(y);
// Step 2: Record the inputs and outputs in std::vectors
x_id.push_back(x[0].getIdentifier());
x_id.push_back(x[1].getIdentifier());
y_id.push_back(y.getIdentifier());
tape.setPassive();
// Step 3: Write the tape to storage. Select between a text, binary or graphical file type. For primal value tapes, a
// math representation can also be selected.
// Text format
tape.writeTape(codi::createWriter<Real>(fileName + "_text.txt", x_id, y_id, codi::FileType::Text));
// Graphical format
tape.writeTape(codi::createWriter<Real>(fileName + "_graph.dot", x_id, y_id, codi::FileType::Graph));
// The tape can be still be evaluated as before
y.setGradient(1.0);
tape.evaluate();
std::cout << fileName << ":" << std::endl;
std::cout << "df/dx[0](4.0) = " << x[0].getGradient() << std::endl;
std::cout << "df/dx[1](3.0) = " << x[1].getGradient() << std::endl << std::endl;
tape.reset();
}
int main(int nargs, char** args) {
// Example with two different tape types
generateTape<codi::RealReverse>("jacobian_linear");
generateTape<codi::RealReversePrimalIndex>("primal_reuse");
return 0;
}

The tape writers are used to store a tape. The writers can create a binary or text file which can later be used in a new context to restore a tape. The writers can also create a graphical (for both Jacobian and primal value tapes) or a math representation of the tape (only for primal value tapes). These formats are useful for visualization and debugging.