/** * recalculate interval if total number of partitions greater than maximum number of allowed * partitions * * @param low watermark value * @param high watermark value * @param partition interval * @param Maximum number of allowed partitions * @return calculated interval */ private long getInterval( long lowWatermarkValue, long highWatermarkValue, long partitionInterval, int maxIntervals) { if (lowWatermarkValue > highWatermarkValue) { LOG.info( "lowWatermarkValue: " + lowWatermarkValue + " is greater than highWatermarkValue: " + highWatermarkValue); return 0; } long outputInterval = partitionInterval; boolean longOverflow = false; long totalIntervals = Long.MAX_VALUE; try { totalIntervals = DoubleMath.roundToLong( (double) highWatermarkValue / partitionInterval - (double) lowWatermarkValue / partitionInterval, RoundingMode.CEILING); } catch (java.lang.ArithmeticException e) { longOverflow = true; } if (longOverflow || totalIntervals > maxIntervals) { outputInterval = DoubleMath.roundToLong( (double) highWatermarkValue / maxIntervals - (double) lowWatermarkValue / maxIntervals, RoundingMode.CEILING); } return outputInterval; }
private double getZOverChi(double rho, double z) { // Implementation comment: To avoid numerical instability (0/0) around ATM the first order // approximation is used. if (DoubleMath.fuzzyEquals(z, 0.0, SMALL_Z)) { return 1.0 - rho * z / 2.0; } double rhoStar = 1 - rho; if (DoubleMath.fuzzyEquals(rhoStar, 0.0, RHO_EPS)) { if (z < 1.0) { return -z / Math.log(1.0d - z); } else { throw new IllegalArgumentException("can't handle z>=1, rho=1"); } } double rhoHat = 1 + rho; if (DoubleMath.fuzzyEquals(rhoHat, 0.0, RHO_EPS_NEGATIVE)) { if (z > -1) { return z / Math.log(1 + z); } else if (z < -1) { if (rhoHat == 0) { return 0.0; } double chi = Math.log(rhoHat) - Math.log(-(1 + z) / rhoStar); return z / chi; } else { return 0.0; } } double arg; if (z < LARGE_NEG_Z) { arg = (rho * rho - 1) / 2 / z; // get rounding errors due to fine balanced cancellation for very large negative // z } else if (z > LARGE_POS_Z) { arg = 2 * (z - rho); } else { arg = (Math.sqrt(1 - 2 * rho * z + z * z) + z - rho); // Mathematically this cannot be less than zero, but you know what computers are like. if (arg <= 0.0) { return 0.0; } } double chi = Math.log(arg) - Math.log(rhoStar); return z / chi; }
@ScalarOperator(SATURATED_FLOOR_CAST) @SqlType(StandardTypes.INTEGER) public static long saturatedFloorCastToInteger(@SqlType(StandardTypes.DOUBLE) double value) { if (value <= MIN_INT_AS_DOUBLE) { return Integer.MIN_VALUE; } if (MAX_INT_AS_DOUBLE - value <= 1) { return Integer.MAX_VALUE; } return DoubleMath.roundToInt(value, FLOOR); }
@ScalarOperator(SATURATED_FLOOR_CAST) @SqlType(StandardTypes.BIGINT) public static long saturatedFloorCastToBigint(@SqlType(StandardTypes.DOUBLE) double value) { if (value <= MIN_LONG_AS_DOUBLE) { return Long.MIN_VALUE; } if (MAX_LONG_AS_DOUBLE_PLUS_ONE - value <= 1) { return Long.MAX_VALUE; } return DoubleMath.roundToLong(value, FLOOR); }
synchronized void startPublishingTimer() { if (state.get() == State.Closed) return; lifetimeCounter--; if (lifetimeCounter < 1) { logger.debug("[id={}] lifetime expired.", subscriptionId); setState(State.Closing); } else { long interval = DoubleMath.roundToLong(publishingInterval, RoundingMode.UP); subscriptionManager .getServer() .getScheduledExecutorService() .schedule(this::onPublishingTimer, interval, TimeUnit.MILLISECONDS); } }
private static Integer parseInteger(String value) { try { return Integer.valueOf(value); } catch (NumberFormatException nfeInteger) { try { Double result = parseDouble(value); if (DoubleMath.isMathematicalInteger(result)) { return result.intValue(); } } catch (NumberFormatException nfeDouble) { // Ignored } throw nfeInteger; } }
private void writeResultForGnuplot( AbstractMeter meter, String ds, String operation, int size, Collection<Double> values) throws IOException { String dirName = outputDir + "/" + meter.getName() + "/"; // Write data for *single* plot String fileName = ds + "_" + operation; String extension = plotExtension; Writer w = fileWriters.get(dirName + fileName + extension); if (w == null) { w = new Writer(dirName, fileName + extension); writeGnuplotHeaderSingle(w, dirName, fileName, operation, meter, ds); fileWriters.put(dirName + fileName + extension, w); } extension = rawExtension; w = fileWriters.get(dirName + fileName + extension); if (w == null) { w = new Writer(dirName, fileName + extension); fileWriters.put(dirName + fileName + extension, w); } double min = Collections.min(values); double max = Collections.max(values); double mean = DoubleMath.mean(values); w.writeln(" " + size + " " + mean + " " + min + " " + max); // Check for the aggregation file extension = plotExtension; String innerLastWrittenOp = lastWrittenOp.get(dirName + operation + extension); if (innerLastWrittenOp == null || !innerLastWrittenOp.equals(operation)) { w = fileWriters.get(dirName + aggregationFile); if (w == null) { w = new Writer(dirName, aggregationFile, true); fileWriters.put(dirName + aggregationFile, w); } w.writeln(operation + ";" + meter.getUnit() + ";" + fileName + rawExtension); } lastWrittenOp.put(dirName + operation + extension, operation); }
int determineHighestPossible(int currentMtn, int[] perceivedHighest, int heights[]) { // Any connection from peaks < currentMtn to peaks after int highestPossible = 1000000000; for (int mtn = 1; mtn < currentMtn; ++mtn) { int percievedMax = perceivedHighest[mtn - 1]; if (percievedMax <= currentMtn) continue; Line line = new Line( new Point(mtn, heights[mtn - 1]), new Point(percievedMax, heights[percievedMax - 1])); double cur = line.getPointGivenX(currentMtn).y(); int heightInt = DoubleMath.isMathematicalInteger(cur) ? (int) Math.floor(cur) - 1 : (int) Math.floor(cur); highestPossible = Math.min(heightInt, highestPossible); } return highestPossible; }
@Override public List<WorkUnit> pack(Map<String, List<WorkUnit>> workUnitsByTopic, int numContainers) { setWorkUnitEstSizes(workUnitsByTopic); List<WorkUnit> workUnits = Lists.newArrayList(); for (List<WorkUnit> workUnitsForTopic : workUnitsByTopic.values()) { // For each topic, merge all empty workunits into a single workunit, so that a single // empty task will be created instead of many. MultiWorkUnit zeroSizeWorkUnit = MultiWorkUnit.createEmpty(); for (WorkUnit workUnit : workUnitsForTopic) { if (DoubleMath.fuzzyEquals(getWorkUnitEstSize(workUnit), 0.0, EPS)) { addWorkUnitToMultiWorkUnit(workUnit, zeroSizeWorkUnit); } else { workUnit.setWatermarkInterval(getWatermarkIntervalFromWorkUnit(workUnit)); workUnits.add(workUnit); } } if (!zeroSizeWorkUnit.getWorkUnits().isEmpty()) { workUnits.add(squeezeMultiWorkUnit(zeroSizeWorkUnit)); } } return worstFitDecreasingBinPacking(workUnits, numContainers); }
public void test_cashFlowEquivalent() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ExpandedSwapLeg computed = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER); ExpandedSwapLeg computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG.expand(), PROVIDER); ExpandedSwapLeg computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentFixedLeg(FIXED_LEG.expand(), PROVIDER); assertEquals(computedFixedLeg.getPaymentEvents(), computed.getPaymentEvents().subList(0, 2)); assertEquals(computedIborLeg.getPaymentEvents(), computed.getPaymentEvents().subList(2, 6)); // expected payments from fixed leg NotionalExchange fixedPayment1 = NotionalExchange.of(PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC1)); NotionalExchange fixedPayment2 = NotionalExchange.of(PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC2)); // expected payments from ibor leg LocalDate fixingSTART1 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING1); double fixedYearFraction1 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART1, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART1)); double beta1 = (1d + fixedYearFraction1 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING1)) * PROVIDER.discountFactor(GBP, PAYMENT1) / PROVIDER.discountFactor(GBP, fixingSTART1); NotionalExchange iborPayment11 = NotionalExchange.of( fixingSTART1, CurrencyAmount.of(GBP, -NOTIONAL * beta1 * PAY_YC1 / fixedYearFraction1)); NotionalExchange iborPayment12 = NotionalExchange.of( PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC1 / fixedYearFraction1)); LocalDate fixingSTART2 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING2); double fixedYearFraction2 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART2, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART2)); double beta2 = (1d + fixedYearFraction2 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING2)) * PROVIDER.discountFactor(GBP, PAYMENT2) / PROVIDER.discountFactor(GBP, fixingSTART2); NotionalExchange iborPayment21 = NotionalExchange.of( fixingSTART2, CurrencyAmount.of(GBP, -NOTIONAL * beta2 * PAY_YC2 / fixedYearFraction2)); NotionalExchange iborPayment22 = NotionalExchange.of( PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC2 / fixedYearFraction2)); ExpandedSwapLeg expected = ExpandedSwapLeg.builder() .type(OTHER) .payReceive(RECEIVE) .paymentEvents( fixedPayment1, fixedPayment2, iborPayment11, iborPayment12, iborPayment21, iborPayment22) .build(); double eps = 1.0e-12; assertEquals(computed.getPaymentEvents().size(), expected.getPaymentEvents().size()); for (int i = 0; i < 6; ++i) { NotionalExchange payCmp = (NotionalExchange) computed.getPaymentEvents().get(i); NotionalExchange payExp = (NotionalExchange) expected.getPaymentEvents().get(i); assertEquals(payCmp.getCurrency(), payExp.getCurrency()); assertEquals(payCmp.getPaymentDate(), payExp.getPaymentDate()); assertTrue( DoubleMath.fuzzyEquals( payCmp.getPaymentAmount().getAmount(), payExp.getPaymentAmount().getAmount(), NOTIONAL * eps)); } }
/** * Erzeugt einen neuen Pixel an der Stelle (x,y). Die doubles werden entsprechend auf die * Integerpositionen des Pixels gerundet. * * @param x die x-Koordinate des Pixels * @param y die y-Koordinate des Pixels */ public Pixel(double x, double y) { this.x = DoubleMath.roundToInt(x, RoundingMode.HALF_DOWN); this.y = DoubleMath.roundToInt(y, RoundingMode.HALF_DOWN); }
/** * Computes the first and second order derivatives of the Black implied volatility in the SABR * model. * * <p>The first derivative values will be stored in the input array {@code volatilityD} The array * contains, [0] Derivative w.r.t the forward, [1] the derivative w.r.t the strike, [2] the * derivative w.r.t. to alpha, [3] the derivative w.r.t. to beta, [4] the derivative w.r.t. to * rho, and [5] the derivative w.r.t. to nu. Thus the length of the array should be 6. * * <p>The second derivative values will be stored in the input array {@code volatilityD2}. Only * the second order derivative with respect to the forward and strike are implemented. The array * contains [0][0] forward-forward; [0][1] forward-strike; [1][1] strike-strike. Thus the size * should be 2 x 2. * * <p>Around ATM, a first order expansion is used to due to some 0/0-type indetermination. The * second order derivative produced is poor around ATM. * * @param forward the forward value of the underlying * @param strike the strike value of the option * @param timeToExpiry the time to expiry of the option * @param data the SABR data. * @param volatilityD the array used to return the first order derivative * @param volatilityD2 the array of array used to return the second order derivative * @return the Black implied volatility */ @Override public double volatilityAdjoint2( double forward, double strike, double timeToExpiry, SabrFormulaData data, double[] volatilityD, double[][] volatilityD2) { double k = Math.max(strike, 0.000001); double alpha = data.getAlpha(); double beta = data.getBeta(); double rho = data.getRho(); double nu = data.getNu(); // Forward double h0 = (1 - beta) / 2; double h1 = forward * k; double h1h0 = Math.pow(h1, h0); double h12 = h1h0 * h1h0; double h2 = Math.log(forward / k); double h22 = h2 * h2; double h23 = h22 * h2; double h24 = h23 * h2; double f1 = h1h0 * (1 + h0 * h0 / 6.0 * (h22 + h0 * h0 / 20.0 * h24)); double f2 = nu / alpha * h1h0 * h2; double f3 = h0 * h0 / 6.0 * alpha * alpha / h12 + rho * beta * nu * alpha / 4.0 / h1h0 + (2 - 3 * rho * rho) / 24.0 * nu * nu; double sqrtf2 = Math.sqrt(1 - 2 * rho * f2 + f2 * f2); double f2x = 0.0; double x = 0.0, xp = 0, xpp = 0; if (DoubleMath.fuzzyEquals(f2, 0.0, SMALL_Z)) { f2x = 1.0 - 0.5 * f2 * rho; // small f2 expansion to f2^2 terms } else { if (DoubleMath.fuzzyEquals(rho, 1.0, RHO_EPS)) { x = f2 < 1.0 ? -Math.log(1.0 - f2) - 0.5 * Math.pow(f2 / (f2 - 1.0), 2) * (1.0 - rho) : Math.log(2.0 * f2 - 2.0) - Math.log(1.0 - rho); } else { x = Math.log((sqrtf2 + f2 - rho) / (1 - rho)); } xp = 1. / sqrtf2; xpp = (rho - f2) / Math.pow(sqrtf2, 3.0); f2x = f2 / x; } double sigma = Math.max(MIN_VOL, alpha / f1 * f2x * (1 + f3 * timeToExpiry)); // First level double h0Dbeta = -0.5; double sigmaDf1 = -sigma / f1; double sigmaDf2 = 0; if (DoubleMath.fuzzyEquals(f2, 0.0, SMALL_Z)) { sigmaDf2 = alpha / f1 * (1 + f3 * timeToExpiry) * -0.5 * rho; } else { sigmaDf2 = alpha / f1 * (1 + f3 * timeToExpiry) * (1.0 / x - f2 * xp / (x * x)); } double sigmaDf3 = alpha / f1 * f2x * timeToExpiry; double sigmaDf4 = f2x / f1 * (1 + f3 * timeToExpiry); double sigmaDx = -alpha / f1 * f2 / (x * x) * (1 + f3 * timeToExpiry); double[][] sigmaD2ff = new double[3][3]; sigmaD2ff[0][0] = -sigmaDf1 / f1 + sigma / (f1 * f1); // OK sigmaD2ff[0][1] = -sigmaDf2 / f1; sigmaD2ff[0][2] = -sigmaDf3 / f1; if (DoubleMath.fuzzyEquals(f2, 0.0, SMALL_Z)) { sigmaD2ff[1][2] = alpha / f1 * -0.5 * rho * timeToExpiry; } else { sigmaD2ff[1][1] = alpha / f1 * (1 + f3 * timeToExpiry) * (-2 * xp / (x * x) - f2 * xpp / (x * x) + 2 * f2 * xp * xp / (x * x * x)); sigmaD2ff[1][2] = alpha / f1 * timeToExpiry * (1.0 / x - f2 * xp / (x * x)); } sigmaD2ff[2][2] = 0.0; // double sigma = alpha / f1 * f2x * (1 + f3 * theta); // Second level double[] f1Dh = new double[3]; double[] f2Dh = new double[3]; double[] f3Dh = new double[3]; f1Dh[0] = h1h0 * (h0 * (h22 / 3.0 + h0 * h0 / 40.0 * h24)) + Math.log(h1) * f1; f1Dh[1] = h0 * f1 / h1; f1Dh[2] = h1h0 * (h0 * h0 / 6.0 * (2.0 * h2 + h0 * h0 / 5.0 * h23)); f2Dh[0] = Math.log(h1) * f2; f2Dh[1] = h0 * f2 / h1; f2Dh[2] = nu / alpha * h1h0; f3Dh[0] = h0 / 3.0 * alpha * alpha / h12 - 2 * h0 * h0 / 6.0 * alpha * alpha / h12 * Math.log(h1) - rho * beta * nu * alpha / 4.0 / h1h0 * Math.log(h1); f3Dh[1] = -2 * h0 * h0 / 6.0 * alpha * alpha / h12 * h0 / h1 - rho * beta * nu * alpha / 4.0 / h1h0 * h0 / h1; f3Dh[2] = 0.0; double[] f1Dp = new double[4]; // Derivative to sabr parameters double[] f2Dp = new double[4]; double[] f3Dp = new double[4]; double[] f4Dp = new double[4]; f1Dp[0] = 0.0; f1Dp[1] = f1Dh[0] * h0Dbeta; f1Dp[2] = 0.0; f1Dp[3] = 0.0; f2Dp[0] = -f2 / alpha; f2Dp[1] = f2Dh[0] * h0Dbeta; f2Dp[2] = 0.0; f2Dp[3] = h1h0 * h2 / alpha; f3Dp[0] = h0 * h0 / 3.0 * alpha / h12 + rho * beta * nu / 4.0 / h1h0; f3Dp[1] = rho * nu * alpha / 4.0 / h1h0 + f3Dh[0] * h0Dbeta; f3Dp[2] = beta * nu * alpha / 4.0 / h1h0 - rho / 4.0 * nu * nu; f3Dp[3] = rho * beta * alpha / 4.0 / h1h0 + (2 - 3 * rho * rho) / 12.0 * nu; f4Dp[0] = 1.0; f4Dp[1] = 0.0; f4Dp[2] = 0.0; f4Dp[3] = 0.0; double sigmaDh1 = sigmaDf1 * f1Dh[1] + sigmaDf2 * f2Dh[1] + sigmaDf3 * f3Dh[1]; double sigmaDh2 = sigmaDf1 * f1Dh[2] + sigmaDf2 * f2Dh[2] + sigmaDf3 * f3Dh[2]; double[][] f1D2hh = new double[2][2]; // No h0 double[][] f2D2hh = new double[2][2]; double[][] f3D2hh = new double[2][2]; f1D2hh[0][0] = h0 * (h0 - 1) * f1 / (h1 * h1); f1D2hh[0][1] = h0 * h1h0 / h1 * h0 * h0 / 6.0 * (2.0 * h2 + 4.0 * h0 * h0 / 20.0 * h23); f1D2hh[1][1] = h1h0 * (h0 * h0 / 6.0 * (2.0 + 12.0 * h0 * h0 / 20.0 * h2)); f2D2hh[0][0] = h0 * (h0 - 1) * f2 / (h1 * h1); f2D2hh[0][1] = nu / alpha * h0 * h1h0 / h1; f2D2hh[1][1] = 0.0; f3D2hh[0][0] = 2 * h0 * (2 * h0 + 1) * h0 * h0 / 6.0 * alpha * alpha / (h12 * h1 * h1) + h0 * (h0 + 1) * rho * beta * nu * alpha / 4.0 / (h1h0 * h1 * h1); f3D2hh[0][1] = 0.0; f3D2hh[1][1] = 0.0; double[][] sigmaD2hh = new double[2][2]; // No h0 for (int loopx = 0; loopx < 2; loopx++) { for (int loopy = loopx; loopy < 2; loopy++) { sigmaD2hh[loopx][loopy] = (sigmaD2ff[0][0] * f1Dh[loopy + 1] + sigmaD2ff[0][1] * f2Dh[loopy + 1] + sigmaD2ff[0][2] * f3Dh[loopy + 1]) * f1Dh[loopx + 1] + sigmaDf1 * f1D2hh[loopx][loopy] + (sigmaD2ff[0][1] * f1Dh[loopy + 1] + sigmaD2ff[1][1] * f2Dh[loopy + 1] + sigmaD2ff[1][2] * f3Dh[loopy + 1]) * f2Dh[loopx + 1] + sigmaDf2 * f2D2hh[loopx][loopy] + (sigmaD2ff[0][2] * f1Dh[loopy + 1] + sigmaD2ff[1][2] * f2Dh[loopy + 1] + sigmaD2ff[2][2] * f3Dh[loopy + 1]) * f3Dh[loopx + 1] + sigmaDf3 * f3D2hh[loopx][loopy]; } } // Third level double h1Df = k; double h1Dk = forward; double h1D2ff = 0.0; double h1D2kf = 1.0; double h1D2kk = 0.0; double h2Df = 1.0 / forward; double h2Dk = -1.0 / k; double h2D2ff = -1 / (forward * forward); double h2D2fk = 0.0; double h2D2kk = 1.0 / (k * k); volatilityD[0] = sigmaDh1 * h1Df + sigmaDh2 * h2Df; volatilityD[1] = sigmaDh1 * h1Dk + sigmaDh2 * h2Dk; volatilityD[2] = sigmaDf1 * f1Dp[0] + sigmaDf2 * f2Dp[0] + sigmaDf3 * f3Dp[0] + sigmaDf4 * f4Dp[0]; volatilityD[3] = sigmaDf1 * f1Dp[1] + sigmaDf2 * f2Dp[1] + sigmaDf3 * f3Dp[1] + sigmaDf4 * f4Dp[1]; if (DoubleMath.fuzzyEquals(f2, 0.0, SMALL_Z)) { volatilityD[4] = -0.5 * f2 + sigmaDf3 * f3Dp[2]; } else { double xDr; if (DoubleMath.fuzzyEquals(rho, 1.0, RHO_EPS)) { xDr = f2 > 1.0 ? 1.0 / (1.0 - rho) + (0.5 - f2) / (f2 - 1.0) / (f2 - 1.0) : 0.5 * Math.pow(f2 / (1.0 - f2), 2.0) + 0.25 * (f2 - 4.0) * Math.pow(f2 / (f2 - 1.0), 3) / (f2 - 1.0) * (1.0 - rho); if (Doubles.isFinite(xDr)) { volatilityD[4] = sigmaDf1 * f1Dp[2] + sigmaDx * xDr + sigmaDf3 * f3Dp[2] + sigmaDf4 * f4Dp[2]; } else { volatilityD[4] = Double.NEGATIVE_INFINITY; } } else { xDr = (-f2 / sqrtf2 - 1 + (sqrtf2 + f2 - rho) / (1 - rho)) / (sqrtf2 + f2 - rho); volatilityD[4] = sigmaDf1 * f1Dp[2] + sigmaDx * xDr + sigmaDf3 * f3Dp[2] + sigmaDf4 * f4Dp[2]; } } volatilityD[5] = sigmaDf1 * f1Dp[3] + sigmaDf2 * f2Dp[3] + sigmaDf3 * f3Dp[3] + sigmaDf4 * f4Dp[3]; volatilityD2[0][0] = (sigmaD2hh[0][0] * h1Df + sigmaD2hh[0][1] * h2Df) * h1Df + sigmaDh1 * h1D2ff + (sigmaD2hh[0][1] * h1Df + sigmaD2hh[1][1] * h2Df) * h2Df + sigmaDh2 * h2D2ff; volatilityD2[0][1] = (sigmaD2hh[0][0] * h1Dk + sigmaD2hh[0][1] * h2Dk) * h1Df + sigmaDh1 * h1D2kf + (sigmaD2hh[0][1] * h1Dk + sigmaD2hh[1][1] * h2Dk) * h2Df + sigmaDh2 * h2D2fk; volatilityD2[1][0] = volatilityD2[0][1]; volatilityD2[1][1] = (sigmaD2hh[0][0] * h1Dk + sigmaD2hh[0][1] * h2Dk) * h1Dk + sigmaDh1 * h1D2kk + (sigmaD2hh[0][1] * h1Dk + sigmaD2hh[1][1] * h2Dk) * h2Dk + sigmaDh2 * h2D2kk; return sigma; }
@Override public double factorialDouble(int n) { return DoubleMath.factorial(n); }
@Override public double volatility( double forward, double strike, double timeToExpiry, double alpha, double beta, double rho, double nu) { ArgChecker.isTrue(forward > 0.0, "forward must be greater than zero"); ArgChecker.isTrue(strike >= 0.0, "strike must be greater than zero"); ArgChecker.isTrue(timeToExpiry >= 0.0, "timeToExpiry must be greater than zero"); if (alpha == 0.0) { return 0.0; } double cutoff = forward * CUTOFF_MONEYNESS; double k; if (strike < cutoff) { Logger s_logger = LoggerFactory.getLogger(SabrHaganVolatilityFunctionProvider.class); s_logger.info( "Given strike of {} is less than cutoff at {}, therefore the strike is taken as {}", new Object[] {strike, cutoff, cutoff}); k = cutoff; } else { k = strike; } double vol, z, zOverChi; double beta1 = 1 - beta; if (DoubleMath.fuzzyEquals(forward, k, ATM_EPS)) { double f1 = Math.pow(forward, beta1); vol = alpha * (1 + timeToExpiry * (beta1 * beta1 * alpha * alpha / 24 / f1 / f1 + rho * alpha * beta * nu / 4 / f1 + nu * nu * (2 - 3 * rho * rho) / 24)) / f1; } else { if (DoubleMath.fuzzyEquals(beta, 0, BETA_EPS)) { double ln = Math.log(forward / k); z = nu * Math.sqrt(forward * k) * ln / alpha; zOverChi = getZOverChi(rho, z); vol = alpha * ln * zOverChi * (1 + timeToExpiry * (alpha * alpha / forward / k + nu * nu * (2 - 3 * rho * rho)) / 24) / (forward - k); } else if (DoubleMath.fuzzyEquals(beta, 1, BETA_EPS)) { double ln = Math.log(forward / k); z = nu * ln / alpha; zOverChi = getZOverChi(rho, z); vol = alpha * zOverChi * (1 + timeToExpiry * (rho * alpha * nu / 4 + nu * nu * (2 - 3 * rho * rho) / 24)); } else { double ln = Math.log(forward / k); double f1 = Math.pow(forward * k, beta1); double f1Sqrt = Math.sqrt(f1); double lnBetaSq = Math.pow(beta1 * ln, 2); z = nu * f1Sqrt * ln / alpha; zOverChi = getZOverChi(rho, z); double first = alpha / (f1Sqrt * (1 + lnBetaSq / 24 + lnBetaSq * lnBetaSq / 1920)); double second = zOverChi; double third = 1 + timeToExpiry * (beta1 * beta1 * alpha * alpha / 24 / f1 + rho * nu * beta * alpha / 4 / f1Sqrt + nu * nu * (2 - 3 * rho * rho) / 24); vol = first * second * third; } } // There is nothing to prevent the nu * nu * (2 - 3 * rho * rho) / 24 to be large negative, and // hence the volatility negative return Math.max(MIN_VOL, vol); }
@Override public ExperimentResults compute(Builder builder, Set<SimArgs> inputs) { final IdMap<MASConfiguration> configMap = new IdMap<>("c", MASConfiguration.class); final IdMap<ScenarioProvider> scenarioMap = new IdMap<>("s", ScenarioProvider.class); final IdMap<ObjectiveFunction> objFuncMap = new IdMap<>("o", ObjectiveFunction.class); final List<ResultListener> listeners = newArrayList(builder.resultListeners); @SuppressWarnings({"rawtypes", "unchecked"}) final IdMap<PostProcessor<?>> ppMap = new IdMap("p", PostProcessor.class); final Map<String, Scenario> scenariosMap = newLinkedHashMap(); // create tasks final List<SimulationTask> tasks = newArrayList(); constructTasks(inputs, tasks, configMap, scenarioMap, objFuncMap, ppMap, scenariosMap); // this sorts tasks using this chain: scenario, configuration, objective // function, postprocessor, seed Collections.sort(tasks); // determine size of batches final int numBatches = Math.min(tasks.size(), builder.numBatches); final int batchSize = DoubleMath.roundToInt(tasks.size() / (double) numBatches, RoundingMode.CEILING); final Map<Task<?>, JPPFJob> taskJobMap = newLinkedHashMap(); final ResultsCollector res = new ResultsCollector(tasks.size(), scenariosMap, taskJobMap, listeners); final List<JPPFJob> jobs = newArrayList(); for (int i = 0; i < numBatches; i++) { final JPPFJob job = new JPPFJob(new MemoryMapDataProvider(), res); job.setName(Joiner.on("").join(JOB_NAME, " ", i + 1, "/", numBatches)); jobs.add(job); for (final SimulationTask t : tasks.subList(i * batchSize, (i + 1) * batchSize)) { try { final MASConfiguration config = configMap.getValue(t.getConfigurationId()); final ScenarioProvider scenario = scenarioMap.getValue(t.getScenarioId()); final ObjectiveFunction objFunc = objFuncMap.getValue(t.getObjectiveFunctionId()); job.getDataProvider() .setParameter(t.getPostProcessorId(), ppMap.getValue(t.getPostProcessorId())); job.getDataProvider().setParameter(t.getConfigurationId(), config); job.getDataProvider().setParameter(t.getScenarioId(), scenario); job.getDataProvider().setParameter(t.getObjectiveFunctionId(), objFunc); job.add(t); } catch (final JPPFException e) { throw new IllegalStateException(e); } taskJobMap.put(t, job); } } for (final ResultListener l : listeners) { l.startComputing(tasks.size()); } checkState(!getJPPFClient().isClosed()); try { for (final JPPFJob job : jobs) { getJPPFClient().submitJob(job); } } catch (final Exception e) { throw new IllegalStateException(e); } res.awaitResults(); for (final ResultListener l : listeners) { l.doneComputing(); } return ExperimentResults.create(builder, res.buildResults()); }
public double findMinPerim(int leftIndex, int rightIndex, List<PointInt> listPointsSortedY) { int numberOfPoints = rightIndex - leftIndex + 1; Preconditions.checkArgument(listPointsSortedY.size() == numberOfPoints); if (numberOfPoints < 3) { return Double.MAX_VALUE; } int leftHalfEndIndex = leftIndex + numberOfPoints / 2 - 1; int rightHalfStartIndex = leftHalfEndIndex + 1; Preconditions.checkState(rightHalfStartIndex <= rightIndex); double min = Double.MAX_VALUE; /* * In order to avoid having to do another sort by y, (taking n log n), we just split using the sortedY list */ List<PointInt> leftList = new ArrayList<>(leftHalfEndIndex - leftIndex + 1); List<PointInt> rightList = new ArrayList<>(rightIndex - rightHalfStartIndex + 1); // We must compare x and y because though we are partitioning by a vertical line, we must also // be able to partition if all points have the same x // Because the partition is strictly less and due to rounding error from longs, // we use this as the division point PointInt midPoint = list.get(rightHalfStartIndex); for (PointInt pl : listPointsSortedY) { // Verify the points are still between left and right index Preconditions.checkState(list.get(leftIndex).getX() <= pl.getX()); Preconditions.checkState(list.get(rightIndex).getX() >= pl.getX()); if (compX.compare(pl, midPoint) < 0) { leftList.add(pl); } else { rightList.add(pl); } } Preconditions.checkState(leftList.size() == numberOfPoints / 2); Preconditions.checkState(leftList.size() > 0); Preconditions.checkState(rightList.size() > 0); Preconditions.checkState(leftHalfEndIndex != rightIndex); Preconditions.checkState(rightHalfStartIndex != leftIndex); Preconditions.checkState(numberOfPoints == leftList.size() + rightList.size()); // Divide double minLeft = findMinPerim(leftIndex, leftHalfEndIndex, leftList); double minRight = findMinPerim(rightHalfStartIndex, rightIndex, rightList); min = Math.min(minLeft, minRight); /* * For the combine, we make a box. * Left bound is min / 2 from vertical line, right bound is min / 2. * * Reason being that any triangle covering the vertical line and with a * point greater than min / 2 would have a perimeter > min. */ int boxMargin = DoubleMath.roundToInt( (min > Double.MAX_VALUE / 2 ? Integer.MAX_VALUE : min) / 2d, RoundingMode.UP); Preconditions.checkState(min > Integer.MAX_VALUE || boxMargin < min); Preconditions.checkState(min > Integer.MAX_VALUE || boxMargin * 2 >= min); List<PointInt> boxPoints = new ArrayList<>(); int startBox = 0; for (int i = 0; i < listPointsSortedY.size(); ++i) { PointInt point = listPointsSortedY.get(i); if (Math.abs(point.getX() - midPoint.getX()) > boxMargin) { continue; } // Calculate start of the box to consider. Should be at most // boxMargin away from currenty point. End of box is the last point added while (startBox < boxPoints.size() && point.getY() - boxPoints.get(startBox).getY() > boxMargin) { startBox++; } /** * To explain this, the box goes from -minP / 2 to + minP / 2 from the dividing vertical line. * Its height is also minP / 2. * * <p>Because we have the minimum with respect to the left and right sides, all triangles to * the left and right have max perimiter <= minP. * * <p>The only way to cram 16 points is to have 2 points on each corner and in the middle * * <p>PP-------PP--------PP * * <p>PP PP * * <p>PP-------PP--------PP * * <p>The perim of any triangle is >= minP. Any other point would be a triangle of perim < * minP. */ Preconditions.checkState(boxPoints.size() - startBox <= 16); // Consider all points in box (can be proved <= 16...Similar to most 6 for closest 2 points // algorithm for (int bi = startBox; bi < boxPoints.size(); ++bi) { for (int j = bi + 1; j < boxPoints.size(); ++j) { double perim = point.distance(boxPoints.get(bi)) + point.distance(boxPoints.get(j)) + boxPoints.get(bi).distance(boxPoints.get(j)); min = Math.min(min, perim); } } boxPoints.add(point); } return min; }
/** * Computes the implied volatility in the SABR model and its derivatives. * * <p>The derivatives are stored in an array with: * * <ul> * <li>[0] derivative with respect to the forward * <li>[1] derivative with respect to the strike * <li>[2] derivative with respect to the alpha * <li>[3] derivative with respect to the beta * <li>[4] derivative with respect to the rho * <li>[5] derivative with respect to the nu * </ul> * * @param forward the forward value of the underlying * @param strike the strike value of the option * @param timeToExpiry the time to expiry of the option * @param alpha the SABR alpha value * @param beta the SABR beta value * @param rho the SABR rho value * @param nu the SABR nu value * @return the volatility and associated derivatives */ @Override public ValueDerivatives volatilityAdjoint( double forward, double strike, double timeToExpiry, double alpha, double beta, double rho, double nu) { ArgChecker.isTrue(forward > 0.0, "forward must be greater than zero"); ArgChecker.isTrue(strike >= 0.0, "strike must be greater than zero"); ArgChecker.isTrue(timeToExpiry >= 0.0, "timeToExpiry must be greater than zero"); double cutoff = forward * CUTOFF_MONEYNESS; double k = strike; if (k < cutoff) { Logger s_logger = LoggerFactory.getLogger(SabrHaganVolatilityFunctionProvider.class); s_logger.info( "Given strike of {} is less than cutoff at {}, therefore the strike is taken as {}", new Object[] {k, cutoff, cutoff}); k = cutoff; } double betaStar = 1 - beta; double rhoStar = 1.0 - rho; if (alpha == 0.0) { double alphaBar; if (DoubleMath.fuzzyEquals(forward, k, ATM_EPS)) { // TODO should this is relative alphaBar = (1 + (2 - 3 * rho * rho) * nu * nu / 24 * timeToExpiry) / Math.pow(forward, betaStar); } else { // for non-atm options the alpha sensitivity at alpha = 0 is infinite. Returning this will // most likely break calibrations, // so we return an arbitrary large number alphaBar = 1e7; } return ValueDerivatives.of(0d, DoubleArray.of(0, 0, alphaBar, 0, 0, 0)); } // Implementation note: Forward sweep. double sfK = Math.pow(forward * k, betaStar / 2); double lnrfK = Math.log(forward / k); double z = nu / alpha * sfK * lnrfK; double rzxz; double xz = 0; if (DoubleMath.fuzzyEquals(z, 0.0, SMALL_Z)) { rzxz = 1.0 - 0.5 * z * rho; // small z expansion to z^2 terms } else { if (DoubleMath.fuzzyEquals(rhoStar, 0.0, RHO_EPS)) { if (z < 1.0) { xz = -Math.log(1.0d - z); rzxz = z / xz; } else { throw new IllegalArgumentException("can't handle z>=1, rho=1"); } } else { double arg; if (z < LARGE_NEG_Z) { arg = (rho * rho - 1) / 2 / z; // get rounding errors due to fine balanced cancellation for very large // negative z } else if (z > LARGE_POS_Z) { arg = 2 * (z - rho); } else { arg = (Math.sqrt(1 - 2 * rho * z + z * z) + z - rho); } if (arg <= 0.0) { // Mathematically this cannot be less than zero, but you know what computers // are like. rzxz = 0.0; } else { xz = Math.log(arg / (1 - rho)); rzxz = z / xz; } } } double sf1 = sfK * (1 + betaStar * betaStar / 24 * (lnrfK * lnrfK) + Math.pow(betaStar, 4) / 1920 * Math.pow(lnrfK, 4)); double sf2 = (1 + (Math.pow(betaStar * alpha / sfK, 2) / 24 + (rho * beta * nu * alpha) / (4 * sfK) + (2 - 3 * rho * rho) * nu * nu / 24) * timeToExpiry); double volatility = Math.max(MIN_VOL, alpha / sf1 * rzxz * sf2); // Implementation note: Backward sweep. double vBar = 1; double sf2Bar = alpha / sf1 * rzxz * vBar; double sf1Bar = -alpha / (sf1 * sf1) * rzxz * sf2 * vBar; double rzxzBar = alpha / sf1 * sf2 * vBar; double zBar; double xzBar = 0.0; if (DoubleMath.fuzzyEquals(z, 0.0, SMALL_Z)) { zBar = -rho / 2 * rzxzBar; } else { if (DoubleMath.fuzzyEquals(rhoStar, 0.0, RHO_EPS)) { if (z < 1.0) { xzBar = -z / (xz * xz) * rzxzBar; zBar = 1.0d / xz * rzxzBar + 1.0d / (1.0d - z) * xzBar; } else { throw new IllegalArgumentException("can't handle z>=1, rho=1"); } } else { if (z < LARGE_NEG_Z) { zBar = 1 / xz * rzxzBar + xzBar / (xz * xz) * rzxzBar; } else if (z > LARGE_POS_Z) { zBar = 1 / xz * rzxzBar - xzBar / (xz * xz) * rzxzBar; } else { xzBar = -z / (xz * xz) * rzxzBar; zBar = 1 / xz * rzxzBar + 1 / ((Math.sqrt(1 - 2 * rho * z + z * z) + z - rho)) * (0.5 * Math.pow(1 - 2 * rho * z + z * z, -0.5) * (-2 * rho + 2 * z) + 1) * xzBar; } } } double lnrfKBar = sfK * (betaStar * betaStar / 12 * lnrfK + Math.pow(betaStar, 4) / 1920 * 4 * Math.pow(lnrfK, 3)) * sf1Bar + nu / alpha * sfK * zBar; double sfKBar = nu / alpha * lnrfK * zBar + sf1 / sfK * sf1Bar - (Math.pow(betaStar * alpha, 2) / Math.pow(sfK, 3) / 12 + (rho * beta * nu * alpha) / 4 / (sfK * sfK)) * timeToExpiry * sf2Bar; double strikeBar = -1 / k * lnrfKBar + betaStar * sfK / (2 * k) * sfKBar; double forwardBar = 1 / forward * lnrfKBar + betaStar * sfK / (2 * forward) * sfKBar; double nuBar = 1 / alpha * sfK * lnrfK * zBar + ((rho * beta * alpha) / (4 * sfK) + (2 - 3 * rho * rho) * nu / 12) * timeToExpiry * sf2Bar; double rhoBar; if (Math.abs(forward - k) < ATM_EPS) { rhoBar = -z / 2 * rzxzBar; } else { if (DoubleMath.fuzzyEquals(rhoStar, 0.0, RHO_EPS)) { if (z >= 1) { if (rhoStar == 0.0) { rhoBar = Double .NEGATIVE_INFINITY; // the derivative at rho = 1 is infinite - this sets it to // some arbitrary large number } else { rhoBar = xzBar * (1.0 / rhoStar + (0.5 - z) / (z - 1.0) / (z - 1.0)); } } else { rhoBar = (0.5 * Math.pow(z / (1 - z), 2) + 0.25 * (z - 4.0) * Math.pow(z / (1.0 - z), 3) / (1.0 - z) * rhoStar) * xzBar; } } else { rhoBar = (1 / (Math.sqrt(1 - 2 * rho * z + z * z) + z - rho) * (-Math.pow(1 - 2 * rho * z + z * z, -0.5) * z - 1) + 1 / rhoStar) * xzBar; } } rhoBar += ((beta * nu * alpha) / (4 * sfK) - rho * nu * nu / 4) * timeToExpiry * sf2Bar; double alphaBar = -nu / (alpha * alpha) * sfK * lnrfK * zBar + ((betaStar * alpha / sfK) * (betaStar / sfK) / 12 + (rho * beta * nu) / (4 * sfK)) * timeToExpiry * sf2Bar + 1 / sf1 * rzxz * sf2 * vBar; double betaBar = -0.5 * Math.log(forward * k) * sfK * sfKBar - sfK * (betaStar / 12 * (lnrfK * lnrfK) + Math.pow(betaStar, 3) / 480 * Math.pow(lnrfK, 4)) * sf1Bar + (-betaStar * alpha * alpha / sfK / sfK / 12 + rho * nu * alpha / 4 / sfK) * timeToExpiry * sf2Bar; return ValueDerivatives.of( volatility, DoubleArray.of(forwardBar, strikeBar, alphaBar, betaBar, rhoBar, nuBar)); }