src/main/java/marc/henrard/book/algorithmicdifferentiation/type/DoubleSad.java
public class DoubleSad {
  
  /** The value of the variable. */
  private final double value;
  /** The number of derivatives. */
  private final int nbDerivatives;
  /** The derivative of the variable with respect to all inputs. */
  private final double[] derivatives;
  
  /**
   * Constructor.
   * @param value The variable value.
   * @param derivatives The derivative of the variable with respect to all inputs.
   */
  public DoubleSad(double value, double[] derivatives) {
    this.value = value;
    this.derivatives = derivatives;
    nbDerivatives = derivatives.length;
  }
  
  /**
   * Create an array of augmented double suitable as a first step for the Standard AD.
   * The array is compose of one augmented double for each input. The i-th augmented double has the i-th input as
   * value and the derivatives are 0 except for the i-th one which is 1.
   * @param inputs The array of input values.
   * @return The array of augmented doubles.
   */
  static public DoubleSad[] init(double[] inputs) {
    int nbInputs = inputs.length;
    DoubleSad[] init = new DoubleSad[nbInputs];
    for(int loopi = 0; loopi < nbInputs; loopi++) {
      double[] initDot = new double[nbInputs];
      initDot[loopi] = 1.0d;
      init[loopi] =  new DoubleSad(inputs[loopi], initDot);
    }
    return init;
  }

  /**
   * Returns the value.
   * @return The value.
   */
  public double value() {
    return value;
  }

  /**
   * Returns the number of derivatives.
   * @return The number.
   */
  public int getNbDerivatives() {
    return nbDerivatives;
  }

  /**
   * Returns the array with the derivatives with respect to each input.
   * @return The derivatives.
   */
  public double[] derivatives() {
    return derivatives;
  }

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/tape/TapeEntryAad.java
public class TapeEntryAad {
  
  /** The operation type */
  private final OperationTypeAad operationType;
  /** The tape index of the first argument. */
  private final int indexArg1;
  /** The tape index of the second argument. Optional. If there is no second argument, the index is set to -1.*/
  private final int indexArg2;
  /** The value of the double. */
  private final double value;
  /** Extra value required for further processing. It can be a multiplication factor, an additive term 
   *  or an externally provided derivative. */
  private final double extraValue;
  /** The derivative of the final value with respect to the variable under consideration. 
   * Is populated only after the tape has been interpreted. */
  private double valueBar;
  
  /**
   * Constructor of a tape entry with two arguments and an extra value.
   * @param operationType  The AD type of operation
   * @param indexArg1 The tape index of the operation first argument.
   * @param indexArg2 The tape index of the operation second argument.
   * @param value The value of the result.
   * @param extraValue Extra value required in some cases for further processing.
   */
  public TapeEntryAad(
      OperationTypeAad operationType, 
      int indexArg1, 
      int indexArg2, 
      double value, 
      double extraValue) {
    this.operationType = operationType;
    this.indexArg1 = indexArg1;
    this.indexArg2 = indexArg2;
    this.value = value;
    this.extraValue = extraValue;
    valueBar = 0.0d;
  }
  
  /**
   * Constructor of a tape entry with two arguments.
   * @param operationType  The AD type of operation
   * @param indexArg1 The tape index of the operation first argument.
   * @param indexArg2 The tape index of the operation second argument.
   * @param value The value of the result.
   */
  public TapeEntryAad(
      OperationTypeAad operationType, 
      int indexArg1, 
      int indexArg2, 
      double value) {
    this.operationType = operationType;
    this.indexArg1 = indexArg1;
    this.indexArg2 = indexArg2;
    this.value = value;
    this.extraValue = 0.0d;
    valueBar = 0.0d;
  }

  /**
   * Constructor of a tape entry with one argument.
   * @param operationType  The AD type of operation
   * @param indexArg The tape index of the operation argument.
   * @param value The value of the result.
   */
  public TapeEntryAad(
      OperationTypeAad operationType, 
      int indexArg, 
      double value) {
    this.operationType = operationType;
    this.indexArg1 = indexArg;
    this.indexArg2 = -1;
    this.value = value;
    this.extraValue = 0.0d;
    valueBar = 0.0d;
  }

  /**
   * Constructor of a tape entry with no argument.
   * @param operationType  The AD type of operation
   * @param value The value of the result.
   */
  public TapeEntryAad(OperationTypeAad operationType, double value) {
    this.operationType = operationType;
    this.indexArg1 = -1;
    this.indexArg2 = -1;
    this.value = value;
    this.extraValue = 0.0d;
    valueBar = 0.0d;
  }
  
  /**
   * Constructor of a tape entry with one argument and an extra value.
   * @param operationType  The AD type of operation
   * @param indexArg The tape index of the operation argument.
   * @param value The value of the result.
   * @param extraValue Extra value required in some cases for further processing.
   */
  public TapeEntryAad(
      OperationTypeAad operationType, 
      int indexArg, 
      double value, 
      double extraValue) {
    this.operationType = operationType;
    this.indexArg1 = indexArg;
    this.indexArg2 = -1;
    this.value = value;
    this.extraValue = extraValue;
    valueBar = 0.0d;
  }

  /**
   * Returns the operation type.
   * @return The operation type.
   */
  public OperationTypeAad getOperationType() {
    return operationType;
  }

  /**
   * Returns the tape index of the first argument.
   * @return The index.
   */
  public int getIndexArg1() {
    return indexArg1;
  }

  /**
   * Returns the tape index of the second argument.
   * @return The index.
   */
  public int getIndexArg2() {
    return indexArg2;
  }

  /**
   * Returns the entry value.
   * @return The value.
   */
  public double getValue() {
    return value;
  }

  /**
   * Returns the derivative of the output with respect to the value, also called value bar.
   * The variable is populated only when the tape has been interpreted, see {@link TapeUtils#interpret}.
   * @return The derivative.
   */
  public double getValueBar() {
    return valueBar;
  }

  /**
   * Adds a given value to the valueBar argument. The entry is modified by this method.
   * @param valueBar Return the total.
   */
  public void addValueBar(double valueBar) {
    this.valueBar += valueBar;
  }

  /**
   * Returns the extra value required for further processing. 
   * It can be a multiplication factor, an additive term or an externally provided derivative.
   * @return The extra value.
   */
  public double getExtraValue() {
    return extraValue;
  }
  
  @Override
  public String toString() {
    String s = "TapeEntry: " + operationType + ", " + indexArg1 + ", " + indexArg2 + ": " + 
      value + ", " + extraValue + ", " + valueBar;
    return s;
  }
  
  
}
src/main/java/marc/henrard/book/algorithmicdifferentiation/type/DoubleDerivatives.java
public class DoubleDerivatives {
  
  /** The value of the variable. */
  private final double value;
  /** The derivatives of the value with respect to inputs. */
  private final double[] derivatives;
  
  /**
   * Constructor from the value and the derivatives.
   * @param value The variable value.
   * @param derivatives The variable derivatives.
   */
  public DoubleDerivatives(double value, double[] derivatives) {
    this.value = value;
    this.derivatives = derivatives;
  }

  /** 
   * The variable value.
   * @return The value.
   */
  public double value() {
    return value;
  }

  /**
   * The variable derivatives.
   * @return The derivatives.
   */
  public double[] derivatives() {
    return derivatives;
  }

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/tape/TapeAad.java
public class TapeAad {
  
  /** The initial capacity of the list holding the tape. */
  private final static int INITIAL_CAPACITY = 250;
  /** The list holding each entry in the tape.*/
  private final List<TapeEntryAad> tapeList;
  /** The current size of the tape. */
  private int size;
  
  /**
   * Construct an empty list with a default initial capacity.
   */
  public TapeAad() {
    this.tapeList = new ArrayList<TapeEntryAad>(INITIAL_CAPACITY);
    size = 0;
  }
  
  /**
   * Returns the current size of the tape.
   * @return The size.
   */
  public int size() {
    return size;
  }
  
  /**
   * Retrieve an entry in the tape by its index.
   * @param index The entry index.
   * @return The entry.
   */
  public TapeEntryAad getEntry(int index) {
    return tapeList.get(index);
  }

  /**
   * Add an entry in the tape and returns the index of the new entry.
   * @param entry The entry to add on the tape.
   * @return The index of the new entry.
   */
  public int addEntry(TapeEntryAad entry) {
    tapeList.add(entry);
    size++;
    return size - 1;
  }

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/utils/FiniteDifferenceSchemes.java
public enum FiniteDifferenceSchemes {
  
  /** Forward difference: $\frac{f(a+\epsilon)-f(a)}{\epsilon}$ */
  FORWARD,
  /** Backward difference: $\frac{f(a+\epsilon)-f(a)}{\epsilon}$ */
  BACKWARD,
  /** Symmetrical difference: $\frac{f(a+\epsilon)-f(a-\epsilon)}{2\epsilon}$ */
  SYMMETRICAL,
  /** Fourth order: $\frac{-f(a+2\epsilon)+8f(a+\epsilon)-8F(a-\epsilon) + f(a-2\epsilon)}{12\epsilon}$ */
  FOURTH_ORDER

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/finance/formula/BlackFormula2.java
public class BlackFormula2 {

  /** The normal distribution implementation. */
  private static final NormalDistribution NORMAL = new NormalDistribution(0.0d, 1.0d);

  /**
   * Returns the option price computed by the Black-Scholes formula.
   * @param forward The forward price/rate.
   * @param volatility The log-normal volatility of the model.
   * @param numeraire The numeraire.
   * @param strike The strike price/rate.
   * @param expiry The time to expiry.
   * @param isCall The call (true) / put (false) flag.
   * @return The price.
   * @throws MathException 
   */
  public static double price(
      double forward, 
      double volatility, 
      double numeraire,
      double strike, 
      double expiry, 
      boolean isCall) {
    double periodVolatility = volatility * Math.sqrt(expiry);
    double dPlus = Math.log(forward / strike) / periodVolatility + 0.5d * periodVolatility;
    double dMinus = dPlus - periodVolatility;
    double omega = isCall ? 1.0d : -1.0d;
    double nPlus = NORMAL.cumulativeProbability(omega * dPlus);
    double nMinus = NORMAL.cumulativeProbability(omega * dMinus);
    double price = numeraire * omega * (forward * nPlus - strike * nMinus);
    return price;
  }

  /**
   * Returns the option price for the Black-Scholes formula and its derivatives with respect to 
   * [0] forward, [1] volatility, [2] numeraire, [3] strike, and [4] expiry.
   * The derivatives are computed by Standard Algorithmic Differentiation.
   * @param forward The forward price/rate.
   * @param volatility The log-normal volatility of the model.
   * @param numeraire The numeraire.
   * @param strike The strike price/rate.
   * @param expiry The time to expiry.
   * @param isCall The call (true) / put (false) flag.
   * @return The price and derivatives.
   * @throws MathException 
   */
  public static DoubleDerivatives price_Sad(
      double forward, 
      double volatility, 
      double numeraire,
      double strike, 
      double expiry, 
      boolean isCall) {
    // Forward sweep - function
    double omega = isCall ? 1.0d : -1.0d;
    double periodVolatility = volatility * Math.sqrt(expiry);
    double dPlus = Math.log(forward / strike) / periodVolatility + 0.5d * periodVolatility;
    double dMinus = dPlus - periodVolatility;
    double nPlus = NORMAL.cumulativeProbability(omega * dPlus);
    double nMinus = NORMAL.cumulativeProbability(omega * dMinus);
    double price = numeraire * omega * (forward * nPlus - strike * nMinus);
    // Forward sweep - derivatives
    int nbInputs = 5;
    double[] inputDot = new double[nbInputs];
    for (int loopinput = 0; loopinput < nbInputs; loopinput++) {
      inputDot[loopinput] = 1.0d;
    }
    double[] periodVolatilityDot = new double[nbInputs];
    periodVolatilityDot[1] = Math.sqrt(expiry) * inputDot[1];
    periodVolatilityDot[4] = volatility * 0.5d / Math.sqrt(expiry) * inputDot[4];
    double[] dPlusDot = new double[nbInputs];
    for (int loopinput = 0; loopinput < nbInputs; loopinput++) {
      dPlusDot[loopinput] = (Math.log(forward / strike) * -1.0d / (periodVolatility * periodVolatility) + 0.5d)
          * periodVolatilityDot[loopinput];
    }
    dPlusDot[0] += 1.0d / (periodVolatility * forward) * inputDot[0];
    dPlusDot[3] += -1.0d / (periodVolatility * forward) * inputDot[3];
    double[] dMinusDot = new double[nbInputs];
    for (int loopinput = 0; loopinput < nbInputs; loopinput++) {
      dMinusDot[loopinput] = dPlusDot[loopinput] - periodVolatilityDot[loopinput];
    }
    double[] nPlusDot = new double[nbInputs];
    double nPdfpPlus = NORMAL.density(omega * dPlus);
    for (int loopinput = 0; loopinput < nbInputs; loopinput++) {
      nPlusDot[loopinput] = nPdfpPlus * omega * dPlusDot[loopinput];
    }
    double[] nMinusDot = new double[nbInputs];
    double nPdfdMinus = NORMAL.density(omega * dMinus);
    for (int loopinput = 0; loopinput < nbInputs; loopinput++) {
      nMinusDot[loopinput] = nPdfdMinus * omega * dMinusDot[loopinput];
    }
    double[] priceDot = new double[nbInputs];
    for (int loopinput = 0; loopinput < nbInputs; loopinput++) {
      priceDot[loopinput] = numeraire * omega * forward * nPlusDot[loopinput]
          - numeraire * omega * strike * nMinusDot[loopinput];
    }
    priceDot[0] += numeraire * omega * nPlus * inputDot[0];
    priceDot[2] += omega * (forward * nPlus - strike * nMinus) * inputDot[2];
    priceDot[3] += -numeraire * omega * nMinus * inputDot[3];
    return new DoubleDerivatives(price, priceDot);
  }

  /**
   * Returns the option price for the Black-Scholes formula and its derivatives with respect to 
   * [0] forward, [1] volatility, [2] numeraire, [3] strike, and [4] expiry.
   * The derivatives are computed by automatic Standard Algorithmic Differentiation.
   * <p>
   * The mathematical library underlying the automatic AD is 
   *  <a href="https://dst.lbl.gov/ACSSoftware/colt/index.html">Colt</a> 
   * @param forward The forward price/rate.
   * @param volatility The log-normal volatility of the model.
   * @param numeraire The numeraire.
   * @param strike The strike price/rate.
   * @param expiry The time to expiry.
   * @param isCall The call (true) / put (false) flag.
   * @return The price and derivatives.
   * @throws MathException 
   */
  public static DoubleSad price_Sad_Automatic(
      double forward, 
      double volatility, 
      double numeraire,
      double strike, 
      double expiry, 
      boolean isCall) {
    int nbInputs = 5;
    double[] input = new double[nbInputs];
    input[0] = forward;
    input[1] = volatility;
    input[2] = numeraire;
    input[3] = strike;
    input[4] = expiry;
    DoubleSad[] inputSad = DoubleSad.init(input);
    double omega = isCall ? 1.0d : -1.0d;
    DoubleSad periodVolatility = MathSad.multipliedBy(inputSad[1], MathSad.sqrt(inputSad[4]));
    DoubleSad dPlus = MathSad.plus(
        MathSad.dividedBy(MathSad.log(MathSad.dividedBy(inputSad[0], inputSad[3])), periodVolatility), 
        MathSad.multipliedBy(periodVolatility, 0.5d));
    DoubleSad dMinus = MathSad.minus(dPlus, periodVolatility);
    DoubleSad nPlus = MathSad.normalCdf(MathSad.multipliedBy(dPlus, omega));
    DoubleSad nMinus = MathSad.normalCdf(MathSad.multipliedBy(dMinus, omega));
    DoubleSad price = MathSad.multipliedBy(MathSad.multipliedBy(inputSad[2], omega), 
        MathSad.minus(MathSad.multipliedBy(inputSad[0], nPlus), MathSad.multipliedBy(inputSad[3], nMinus)));
    return price;
  }

  /**
   * Returns the option price for the Black-Scholes formula and its derivatives with respect to 
   * [0] forward, [1] volatility, [2] numeraire, [3] strike, and [4] expiry.
   * The derivatives are computed by Adjoint Algorithmic Differentiation.
   * @param forward The forward price/rate.
   * @param volatility The log-normal volatility of the model.
   * @param numeraire The numeraire.
   * @param strike The strike price/rate.
   * @param expiry The time to expiry.
   * @param isCall The call (true) / put (false) flag.
   * @return The price and derivatives.
   * @throws MathException 
   */
  public static DoubleDerivatives price_Aad(
      double forward, 
      double volatility, 
      double numeraire,
      double strike, 
      double expiry, 
      boolean isCall) {
    // Forward sweep - function
    double omega = isCall ? 1.0d : -1.0d;
    double periodVolatility = volatility * Math.sqrt(expiry);
    double dPlus = Math.log(forward / strike) / periodVolatility + 0.5d * periodVolatility;
    double dMinus = dPlus - periodVolatility;
    double nPlus = NORMAL.cumulativeProbability(omega * dPlus);
    double nMinus = NORMAL.cumulativeProbability(omega * dMinus);
    double price = numeraire * omega * (forward * nPlus - strike * nMinus);
    // Backward sweep - derivatives
    double priceBar = 1.0;
    double nMinusBar = numeraire * omega * -strike * priceBar;
    double nPlusBar = numeraire * omega * forward * priceBar;
    double dMinusBar = NORMAL.density(omega * dMinus) * omega * nMinusBar;
    double dPlusBar = 1.0d * dMinusBar + NORMAL.density(omega * dPlus) * omega * nPlusBar;
    // Note: dPlusBar is always 0; it is the optimal exercise boundary.
    double periodVolatilityBar = -1.0d * dMinusBar +
        (-Math.log(forward / strike) / (periodVolatility * periodVolatility) + 0.5d) * dPlusBar;
    double[] inputBar = new double[5]; // forward, volatility, numeraire, strike, expiry
    inputBar[4] = volatility * 0.5 / Math.sqrt(expiry) * periodVolatilityBar;
    inputBar[3] = -1.0d / strike / periodVolatility * dPlusBar + numeraire * omega * -nMinus * priceBar;
    inputBar[2] = omega * (forward * nPlus - strike * nMinus) * priceBar;
    inputBar[1] = Math.sqrt(expiry) * periodVolatilityBar;
    inputBar[0] = 1.0d / forward / periodVolatility * dPlusBar + numeraire * omega * nPlus * priceBar;
    return new DoubleDerivatives(price, inputBar);
  }

  /**
   * Returns the option price for the Black-Scholes formula and its derivatives with respect to 
   * [0] forward, [1] volatility, [2] numeraire, [3] strike, and [4] expiry.
   * The derivatives are computed by Adjoint Algorithmic Differentiation.
   * The formula is optimized to reduce computation time by using domain specific knowledge.
   * @param forward The forward price/rate.
   * @param volatility The log-normal volatility of the model.
   * @param numeraire The numeraire.
   * @param strike The strike price/rate.
   * @param expiry The time to expiry.
   * @param isCall The call (true) / put (false) flag.
   * @return The price and derivatives.
   * @throws MathException 
   */
  public static DoubleDerivatives price_Aad_Optimized(
      double forward, 
      double volatility, 
      double numeraire,
      double strike, 
      double expiry, 
      boolean isCall) {
    // Forward sweep - function
    double omega = isCall ? 1.0d : -1.0d;
    double sqrtExpiry = Math.sqrt(expiry);
    double periodVolatility = volatility * sqrtExpiry;
    double dPlus = Math.log(forward / strike) / periodVolatility + 0.5d * periodVolatility;
    double dMinus = dPlus - periodVolatility;
    double nPlus = NORMAL.cumulativeProbability(omega * dPlus);
    double nMinus = NORMAL.cumulativeProbability(omega * dMinus);
    double price = numeraire * omega * (forward * nPlus - strike * nMinus);
    // Backward sweep - derivatives
    double priceBar = 1.0;
    double nMinusBar = numeraire * omega * -strike * priceBar;
    double dMinusBar = NORMAL.density(omega * dMinus) * omega * nMinusBar;
    double periodVolatilityBar = -1.0d * dMinusBar;
    double[] inputBar = new double[5]; // forward, volatility, numeraire, strike, expiry
    inputBar[4] = volatility * 0.5 / sqrtExpiry * periodVolatilityBar;
    inputBar[3] = numeraire * omega * -nMinus * priceBar;
    inputBar[2] = omega * (forward * nPlus - strike * nMinus) * priceBar;
    inputBar[1] = sqrtExpiry * periodVolatilityBar;
    inputBar[0] = numeraire * omega * nPlus * priceBar;
    return new DoubleDerivatives(price, inputBar);
  }

  /**
   * Returns the option price for the Black-Scholes formula as a {@link DoubleAad}.
   * The method also update the tape of type {@link TapeAad} which can be use to compute derivatives
   * by automatic AD.
   * @param forward The forward price/rate.
   * @param volatility The log-normal volatility of the model.
   * @param numeraire The numeraire.
   * @param strike The strike price/rate.
   * @param expiry The time to expiry.
   * @param isCall The call (true) / put (false) flag.
   * @return The price and derivatives.
   * @throws MathException 
   */
  public static DoubleAad price_Aad_Automatic(
      DoubleAad forward, 
      DoubleAad volatility, 
      DoubleAad numeraire,
      DoubleAad strike, 
      DoubleAad expiry, 
      boolean isCall, 
      TapeAad tape) {
    double omega = isCall ? 1.0d : -1.0d;
    DoubleAad periodVolatility = MathAad.multipliedBy(volatility, MathAad.sqrt(expiry, tape), tape);
    DoubleAad dPlus = MathAad.plus(MathAad.dividedBy(MathAad.log(MathAad.dividedBy(forward, strike, tape), tape), 
        periodVolatility, tape), MathAad.multipliedBy(periodVolatility, 0.5d, tape), tape);
    DoubleAad dMinus = MathAad.minus(dPlus, periodVolatility, tape);
    DoubleAad nPlus = MathAad.normalCdf(MathAad.multipliedBy(dPlus, omega, tape), tape);
    DoubleAad nMinus = MathAad.normalCdf(MathAad.multipliedBy(dMinus, omega, tape), tape);
    DoubleAad price = MathAad.multipliedBy(MathAad.multipliedBy(numeraire, omega, tape), 
        MathAad.minus(MathAad.multipliedBy(forward, nPlus, tape), MathAad.multipliedBy(strike, nMinus, tape), tape), tape);
    return price;
  }
  
}
src/main/java/marc/henrard/book/algorithmicdifferentiation/type/OperationTypeAad.java
public enum OperationTypeAad {
  
  /** Input with respect to which the derivatives are computed. */
  INPUT,
  /** Used for manual code providing AD results in a Automatic AD setting. */
  MANUAL,
  /** Addition of two AAD doubles. */
  ADDITION,
  /** Addition of one AAD doubles with a constant double. */
  ADDITION1,
  /** Subtraction of two AAD doubles. */
  SUBTRACTION,
  /** Multiplication of two AAD doubles. */
  MULTIPLICATION,
  /** Multiplication of one AAD double with a constant double. */
  MULTIPLICATION1,
  /** Division of two AAD doubles. */
  DIVISION,
  /** Sine of a AAD double. */
  SIN,
  /** Cosine of a AAD double. */
  COS, 
  /** Exponential of a AAD double. */
  EXP,
  /** Logarithm of a AAD double. */
  LOG,
  /** Square root of a AAD double. */
  SQRT,
  /** Power of a AAD double by another AAD double. */
  POW,
  /** Power of a AAD double with a standard double. */
  POW1,
  /** Normal cumulative density function of a AAD double. */
  NORMALCDF

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/tape/TapeUtils.java
public class TapeUtils {
  
  /** The normal distribution implementation. */
  private static final Normal NORMAL = new Normal(0.0d, 1.0d, null);
  
  /**
   * Interpret a tape. 
   * <p>
   * The exact description of the interpretation can be found in the book
   * M. Henrard, Algorithmic Differentiation in Finance Explained, to appear. Section 4.2.
   * @param tape The tape.
   * @return The derivatives with respect to the input as recorded in the tape.
   */
  public static double[] interpret(TapeAad tape) {
    int nbEntries = tape.size();
    tape.getEntry(nbEntries-1).addValueBar(1.0d);
    List<Double> derivativesList = new ArrayList<Double>();
    for(int loope = nbEntries-1; loope>=0; loope--  ) {
      TapeEntryAad entry = tape.getEntry(loope);
      switch (entry.getOperationType()) {
        case INPUT:
          derivativesList.add(entry.getValueBar());
          break;
        case MANUAL:
          tape.getEntry(entry.getIndexArg1()).addValueBar(entry.getExtraValue() * entry.getValueBar());
          if(entry.getIndexArg2() != -1) {
            tape.getEntry(entry.getIndexArg2()).addValueBar(entry.getValueBar());
          }
          break;
        case ADDITION: // Addition of two AAD doubles.
          tape.getEntry(entry.getIndexArg1()).addValueBar(entry.getValueBar());
          tape.getEntry(entry.getIndexArg2()).addValueBar(entry.getValueBar());
          break;
        case ADDITION1: // Addition with a simple double.
          tape.getEntry(entry.getIndexArg1()).addValueBar(entry.getValueBar());
          break;
        case SUBTRACTION:
          tape.getEntry(entry.getIndexArg1()).addValueBar(entry.getValueBar());
          tape.getEntry(entry.getIndexArg2()).addValueBar(-entry.getValueBar());
          break;
        case MULTIPLICATION: // Multiplication of two AAD doubles.
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              tape.getEntry(entry.getIndexArg2()).getValue() * entry.getValueBar());
          tape.getEntry(entry.getIndexArg2()).addValueBar(
              tape.getEntry(entry.getIndexArg1()).getValue() * entry.getValueBar());
          break;
        case MULTIPLICATION1: // Multiplication by a simple double.
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              entry.getExtraValue() * entry.getValueBar());
          break;
        case DIVISION:
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              entry.getValueBar() / tape.getEntry(entry.getIndexArg2()).getValue());
          tape.getEntry(entry.getIndexArg2()).addValueBar(
              -tape.getEntry(entry.getIndexArg1()).getValue() /
              (tape.getEntry(entry.getIndexArg2()).getValue() 
                  * tape.getEntry(entry.getIndexArg2()).getValue() ) *
              entry.getValueBar());
          break;
        case SIN:
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              Math.cos(tape.getEntry(entry.getIndexArg1()).getValue()) * entry.getValueBar());
          break;
        case COS:
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              - Math.sin(tape.getEntry(entry.getIndexArg1()).getValue()) * entry.getValueBar());
          break;
        case EXP:
          tape.getEntry(entry.getIndexArg1()).addValueBar(entry.getValue() * entry.getValueBar());
          break;
        case LOG:
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              entry.getValueBar() / tape.getEntry(entry.getIndexArg1()).getValue());
          break;
        case SQRT:
          tape.getEntry(entry.getIndexArg1()).addValueBar(0.5 / entry.getValue() * entry.getValueBar());
          break;
        case POW:
          double x = tape.getEntry(entry.getIndexArg1()).getValue(); // x^y
          double y = tape.getEntry(entry.getIndexArg2()).getValue();
          tape.getEntry(entry.getIndexArg1()).addValueBar(y * entry.getValue() / x * entry.getValueBar());
          tape.getEntry(entry.getIndexArg2()).addValueBar(entry.getValue() * Math.log(x) * entry.getValueBar());
          break;
        case POW1:
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              entry.getExtraValue() * entry.getValue() / tape.getEntry(entry.getIndexArg1()).getValue() * 
              entry.getValueBar());
          break;
        case NORMALCDF:
          tape.getEntry(entry.getIndexArg1()).addValueBar(
              NORMAL.pdf(tape.getEntry(entry.getIndexArg1()).getValue()) * entry.getValueBar());
          break;
        default:
          break;
      }
    }
    int nbDerivatives = derivativesList.size();
    double[] derivatives = new double[nbDerivatives];
    for (int loopd = 0; loopd < nbDerivatives; loopd++) {
      derivatives[loopd] = derivativesList.get(nbDerivatives - 1 - loopd);
    }
    return derivatives;
  }
  
  /**
   * Extract the derivative of the final value with respect to the inputs in a {@link TapeAad}.
   * @param tape The tape.
   * @return The derivatives.
   */
  public static double[] extractDerivatives(TapeAad tape) {
    int nbEntries = tape.size();
    List<Double> derivativesList = new ArrayList<Double>();
    for (int loope = 0; loope < nbEntries; loope++) {
      TapeEntryAad entry = tape.getEntry(loope);
      if (entry.getOperationType() == OperationTypeAad.INPUT) {
        derivativesList.add(entry.getValueBar());
      }
    }
    int nbDerivatives = derivativesList.size();
    double[] derivatives = new double[nbDerivatives];
    for (int loopd = 0; loopd < nbDerivatives; loopd++) {
      derivatives[loopd] = derivativesList.get(loopd);
    }
    return derivatives;
  }

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/type/DoubleAad.java
public class DoubleAad {
  
  /** The value of the variable. */
  private final double value;
  /** The index of the variable in the tape. */
  private final int tapeIndex;
  
  /**
   * Constructor.
   * @param value The double value.
   * @param tapeIndex The index of the double in the AAD tape.
   */
  public DoubleAad(double value, int tapeIndex) {
    this.value = value;
    this.tapeIndex = tapeIndex;
  }

  /**
   * Returns the value of the Double.
   * @return The value.
   */
  public double value() {
    return value;
  }

  /** 
   * Returns the tape index.
   * @return The index.
   */
  public int tapeIndex() {
    return tapeIndex;
  }
  
  /**
   * Returns a new DoubleAad with the value and add an entry in the tape with that value and 
   * operation type INPUT.
   * @param value The input value
   * @param tape The tape.
   * @return The input DoubleAad.
   */
  public static DoubleAad input(double value, TapeAad tape){
    return new DoubleAad(value, tape.addEntry(new TapeEntryAad(OperationTypeAad.INPUT, value)));
  }

}
src/main/java/marc/henrard/book/algorithmicdifferentiation/utils/FiniteDifferenceFirstOrder.java
public class FiniteDifferenceFirstOrder {
  
  /**
   * Compute the first order differentiation of function by finite difference. 
   * The underlying function take a double[] as input and output a Double.
   * @param function The function to differentiate.
   * @param x The value at which the derivative should be computed. 
   * @param epsilon The finite difference shift.
   * @param scheme The finite difference scheme.
   * @return The derivative.
   */
  public static double[] differentiate(Function<double[], Double> function, double[] x,
      double epsilon, FiniteDifferenceSchemes scheme) {
    int nbX = x.length;
    double[] derivative = new double[nbX];
    switch (scheme) {
      case FORWARD: {
        Double y0 = function.apply(x);
        for (int loopx = 0; loopx < nbX; loopx++) {
          double[] xShifted = x.clone();
          xShifted[loopx] += epsilon;
          derivative[loopx] = (function.apply(xShifted) - y0)/epsilon;
        }
        return derivative;
      }
      case BACKWARD: {
        Double y0 = function.apply(x);
        for(int loopx = 0; loopx < nbX; loopx++) {
          double[] xShifted = x.clone();
          xShifted[loopx] -= epsilon;
          derivative[loopx] = (y0 - function.apply(xShifted))/epsilon;
        }
        return derivative;
      }
      case SYMMETRICAL: {
        for(int loopx = 0; loopx < nbX; loopx++) {
          double[] xShiftedP = x.clone();
          double[] xShiftedM = x.clone();
          xShiftedP[loopx] += epsilon;
          xShiftedM[loopx] -= epsilon;
          derivative[loopx] = (function.apply(xShiftedP) - function.apply(xShiftedM)) / (2 * epsilon);
        }
        return derivative;
      }
      case FOURTH_ORDER: {
        for(int loopx = 0; loopx < nbX; loopx++) {
          double[] xShiftedP1 = x.clone();
          double[] xShiftedM1 = x.clone();
          double[] xShiftedP2 = x.clone();
          double[] xShiftedM2 = x.clone();
          xShiftedP1[loopx] += epsilon;
          xShiftedP2[loopx] += 2 * epsilon;
          xShiftedM1[loopx] -= epsilon;
          xShiftedM2[loopx] -= 2 * epsilon;
          derivative[loopx] = (-function.apply(xShiftedP2) + 8 * function.apply(xShiftedP1)
              - 8 * function.apply(xShiftedM1) + function.apply(xShiftedM2)) / (12 * epsilon);
        }
        return derivative;
      }
      default:
        throw new IllegalArgumentException(
            "Finite difference scheme should be FORWARD, BACKWARD, SYMMETRICAL or FOURTH_ORDER");
    }
  }

}


Question: import static org.testng.AssertJUnit.assertEquals;
import java.util.function.Function;
import marc.henrard.book.algorithmicdifferentiation.finance.formula.BlackFormula2;
import marc.henrard.book.algorithmicdifferentiation.tape.TapeAad;
import marc.henrard.book.algorithmicdifferentiation.tape.TapeEntryAad;
import marc.henrard.book.algorithmicdifferentiation.tape.TapeUtils;
import marc.henrard.book.algorithmicdifferentiation.type.DoubleAad;
import marc.henrard.book.algorithmicdifferentiation.type.DoubleDerivatives;
import marc.henrard.book.algorithmicdifferentiation.type.DoubleSad;
import marc.henrard.book.algorithmicdifferentiation.type.OperationTypeAad;
import marc.henrard.book.algorithmicdifferentiation.utils.FiniteDifferenceFirstOrder;
import marc.henrard.book.algorithmicdifferentiation.utils.FiniteDifferenceSchemes;
import org.testng.annotations.Test;
import org.testng.internal.junit.ArrayAsserts;
/**
 * Copyright (C) 2014 - present by Marc Henrard
 */
package marc.henrard.book.algorithmicdifferentiation.finance.formula;





/**
 * Tests {@link BlackFormula2} and its Algorithmic Differentiation implementations.
 * <p>
 * The mathematical library underlying is 
 * <a href="http://commons.apache.org/proper/commons-math/">Apache Commons Mathematics Library</a>
 */
public class BlackFormula2Test {
  
  // Forward / volatility / Numeraire / Strike / Expiry
  static private final double[][] DATA = { {1.0, 0.50, 1.0, 1.0, 1.0}, {0.05, 0.20, 0.90, 0.04, 2.0}, 
    {100.0, 0.15, 0.75, 111.1, 5.0}, {0.0010, 0.99, 0.99, 0.0015, 1.25}, {1234.0, 0.25, 0.99, 1432.0, 10.0} };
  static private final int NB_TESTS = DATA.length;
  static private final double EPSILON = 1.0E-6;
  static private final double TOLERANCE_PRICE = 1.0E-10;
  static private final double TOLERANCE_DELTA = 1.0E-6;
  
  /** Tests the implementation of the AD by comparison to finite difference. 
   * @throws MathException */
  @Test
  public void derivativesCorrectness() {
    boolean[] callPut = {true, false };
    for (int looptest = 0; looptest < NB_TESTS; looptest++) {
      for (int looppc = 0; looppc < 2; looppc++) {
        double[] d3Call = FiniteDifferenceFirstOrder.differentiate(callPut[looppc] ? new blackCall() : new blackPut(), 
Answer:             DATA[looptest], EPSILON, FiniteDifferenceSchemes.FOURTH_ORDER);