return res;
}
//non-stochastic vol limit
if (_omega == 0.0 || mod(multiply(_omega / _kappa, u, add(I, u))) < 1e-6) {
final ComplexNumber z = multiply(u, add(I, u));
// //TODO calculate the omega -> 0 sensitivity without resorting to this hack
// HestonCharacteristicExponent ceTemp = this.withOmega(1.1e-6 * _kappa / mod(z));
// ComplexNumber[] temp = ceTemp.getCharacteristicExponentAdjoint(u, t);
final double var;
if (_kappa * t < 1e-6) {
var = _vol0 * t + (_vol0 - _theta) * _kappa * t * t / 2;
res[1] = multiply(-0.5 * (_vol0 - _theta) * t * t / 2, z);
res[2] = multiply(_kappa * t * t / 4, z);
res[3] = multiply(-0.5 * (t + _kappa * t * t / 2), z);
res[4] = ZERO; //TODO this is wrong
res[5] = ZERO;
} else {
final double expKappaT = Math.exp(-_kappa * t);
var = _theta * t + (_vol0 - _theta) * (1 - expKappaT) / _kappa;
res[1] = multiply(-0.5 * (_vol0 - _theta) * (expKappaT * (1 + t * _kappa) - 1) / _kappa / _kappa, z);
res[2] = multiply(-0.5 * (t - (1 - expKappaT) / _kappa), z);
res[3] = multiply(-0.5 * (1 - expKappaT) / _kappa, z);
res[4] = ZERO; //TODO this is wrong
res[5] = ZERO;
}
res[0] = multiply(-var / 2, z);
return res;
}
final double oneOverOmega2 = 1 / _omega / _omega;
final double w0 = _kappa * _theta * oneOverOmega2;
final ComplexNumber w1 = multiply(u, new ComplexNumber(0, _rho * _omega)); //w1
final ComplexNumber w2 = subtract(w1, _kappa); //w2
final ComplexNumber w3 = square(w2); //w3
final ComplexNumber w4 = multiply(u, new ComplexNumber(0, _omega * _omega));
final ComplexNumber w5 = square(multiply(u, _omega));
final ComplexNumber w6 = add(w3, w4, w5);
final ComplexNumber w7 = sqrt(w6);
final ComplexNumber w8 = subtract(w7, w2);
final ComplexNumber w9 = multiply(-1.0, add(w7, w2));
final ComplexNumber w10 = divide(w8, w9);
final ComplexNumber w11 = multiply(t, w9);
final ComplexNumber w12 = exp(multiply(w7, -t));
final ComplexNumber w13 = divide(subtract(w10, w12), subtract(w10, 1));
final ComplexNumber w14 = log(w13);
final ComplexNumber w15 = divide(subtract(1, w12), subtract(w10, w12));
final ComplexNumber w16 = multiply(w0, subtract(w11, multiply(2, w14)));
final ComplexNumber w17 = multiply(oneOverOmega2, w8, w15);
final ComplexNumber w18 = add(w16, multiply(_vol0, w17));
res[0] = w18; //value of CE
//backwards sweep
final ComplexNumber wBar16 = new ComplexNumber(1.0);
final ComplexNumber wBar17 = new ComplexNumber(_vol0);
final ComplexNumber wBar15 = multiply(oneOverOmega2, wBar17, w8);
final ComplexNumber wBar14 = multiply(-2 * w0, wBar16);
final ComplexNumber wBar13 = divide(wBar14, w13);
final ComplexNumber wBar12a = multiply(wBar15, divide(subtract(1, w10), square(subtract(w10, w12))));
final ComplexNumber wBar12b = multiply(wBar13, divide(1.0, subtract(1.0, w10)));
final ComplexNumber wBar12 = add(wBar12a, wBar12b);
final ComplexNumber wBar11 = multiply(w0, wBar16);
final ComplexNumber wBar10a = multiply(wBar15, divide(w15, subtract(w12, w10)));
final ComplexNumber wBar10b = multiply(wBar13, divide(subtract(w12, 1.0), square(subtract(w10, 1.0))));
final ComplexNumber wBar10 = add(wBar10a, wBar10b);
final ComplexNumber wBar9a = multiply(t, wBar11);
final ComplexNumber wBar9b = multiply(-1.0, wBar10, divide(w10, w9));
final ComplexNumber wBar9 = add(wBar9a, wBar9b);
final ComplexNumber wBar8a = multiply(oneOverOmega2, wBar17, w15);
final ComplexNumber wBar8b = divide(wBar10, w9);
final ComplexNumber wBar8 = add(wBar8a, wBar8b);
final ComplexNumber wBar7 = subtract(add(multiply(wBar12, multiply(-t, w12)), wBar8), wBar9);
final ComplexNumber wBar6 = multiply(wBar7, divide(0.5, w7));
final ComplexNumber wBar5 = wBar6;
final ComplexNumber wBar4 = wBar6;
final ComplexNumber wBar3 = wBar6;
final ComplexNumber wBar2 = subtract(multiply(wBar3, multiply(2.0, w2)), add(wBar8, wBar9));
final ComplexNumber wBar1 = wBar2;
final ComplexNumber wBar0 = multiply(wBar16, subtract(w11, multiply(2, w14)));
res[1] = subtract(multiply(wBar0, _theta / _omega / _omega), wBar2); //kappaBar
res[2] = multiply(wBar0, _kappa / _omega / _omega); //thetaBar
res[3] = w17; //vol0
final ComplexNumber omegaBar1 = multiply(-2 / _omega, w17, wBar17);
final ComplexNumber omegaBar2 = multiply(-2.0 * w0 / _omega, wBar0);
final ComplexNumber omegaBar3 = multiply(1 / _omega, w1, wBar1);
final ComplexNumber omegaBar4 = multiply(2 / _omega, w4, wBar4);
final ComplexNumber omegaBar5 = multiply(2 / _omega, w5, wBar5);
res[4] = add(omegaBar1, omegaBar2, omegaBar3, omegaBar4, omegaBar5);
res[5] = multiply(_omega, u, I, wBar1);
return res;