docs: public static Map<String, double[]> getLogSwaprateDerivative(TimeDiscretizationInterface liborPeriodDiscretization, ForwardCurveInterface forwardCurveInterface, double[] swapTenor) {
  		double swapStart    = swapTenor[0];
  		double swapEnd      = swapTenor[swapTenor.length-1];
  
  		// Get the indices of the swap start and end on the forward rate tenor
  		int swapStartIndex  = liborPeriodDiscretization.getTimeIndex(swapStart);
  		int swapEndIndex    = liborPeriodDiscretization.getTimeIndex(swapEnd);
  
  		// Precalculate forward rates and discount factors. Note: the swap contains swapEndIndex-swapStartIndex forward rates
  		double[] forwardRates       = new double[swapEndIndex-swapStartIndex+1];
  		double[] discountFactors    = new double[swapEndIndex-swapStartIndex+1];
  
  		// Calculate discount factor at swap start
  		discountFactors[0] = 1.0;
  		for(int liborPeriodIndex = 0; liborPeriodIndex < swapStartIndex; liborPeriodIndex++) {
  			double libor = forwardCurveInterface.getForward(null, liborPeriodDiscretization.getTime(liborPeriodIndex));
  			double liborPeriodLength = liborPeriodDiscretization.getTimeStep(liborPeriodIndex);
  			discountFactors[0] /= 1 + libor * liborPeriodLength;
  		}
  
  		// Calculate discount factors for swap period ends (used for swap annuity)
  		for(int liborPeriodIndex = swapStartIndex; liborPeriodIndex < swapEndIndex; liborPeriodIndex++) {
  			double libor = forwardCurveInterface.getForward(null, liborPeriodDiscretization.getTime(liborPeriodIndex));
  			double liborPeriodLength = liborPeriodDiscretization.getTimeStep(liborPeriodIndex);
  
  			forwardRates[liborPeriodIndex-swapStartIndex]       = libor;
  			discountFactors[liborPeriodIndex-swapStartIndex+1]  = discountFactors[liborPeriodIndex-swapStartIndex] / (1 + libor * liborPeriodLength);
  		}
  
  		// Precalculate swap annuities
  		double[]    swapAnnuities   = new double[swapTenor.length-1];
  		double      swapAnnuity     = 0.0;
  		for(int swapPeriodIndex = swapTenor.length-2; swapPeriodIndex >= 0; swapPeriodIndex--) {
  			int periodEndIndex = liborPeriodDiscretization.getTimeIndex(swapTenor[swapPeriodIndex+1]);
  			swapAnnuity += discountFactors[periodEndIndex-swapStartIndex] * (swapTenor[swapPeriodIndex+1]-swapTenor[swapPeriodIndex]);
  			swapAnnuities[swapPeriodIndex] = swapAnnuity;
  		}
  
  
  		// Precalculate weights: The formula is take from ISBN 0470047224
  		double longForwardRate = discountFactors[swapEndIndex-swapStartIndex] / ( discountFactors[0] - discountFactors[swapEndIndex-swapStartIndex]);
  
  		double[] swapCovarianceWeights = new double[swapEndIndex-swapStartIndex];
  
  		int swapPeriodIndex = 0;
  		for(int liborPeriodIndex = swapStartIndex; liborPeriodIndex < swapEndIndex; liborPeriodIndex++) {
  			if(liborPeriodDiscretization.getTime(liborPeriodIndex) >= swapTenor[swapPeriodIndex+1]) {
  				swapPeriodIndex++;
  			}
  
  			swapCovarianceWeights[liborPeriodIndex-swapStartIndex] = (longForwardRate + swapAnnuities[swapPeriodIndex] / swapAnnuity) * (1.0 - discountFactors[liborPeriodIndex-swapStartIndex+1] / discountFactors[liborPeriodIndex-swapStartIndex]);
  		}
  
  		// Return results
  		Map<String, double[]> results = new HashMap<String, double[]>();
  		results.put("values",			swapCovarianceWeights);
  		results.put("discountFactors",	discountFactors);
  		results.put("swapAnnuities",	swapAnnuities);
  
  		return results;
  	}