public MyCompiledFunction(
     final ZonedDateTime earliestInvokation,
     final ZonedDateTime latestInvokation,
     final MultiCurveCalculationConfig impliedConfiguration,
     final YieldCurveDefinition impliedDefinition,
     final MultiCurveCalculationConfig originalConfiguration,
     final String originalCurveName) {
   super(earliestInvokation, latestInvokation);
   _impliedConfiguration = impliedConfiguration;
   _impliedDefinition = impliedDefinition;
   _originalConfiguration = originalConfiguration;
   _impliedCurveName = impliedDefinition.getName();
   _originalCurveName = originalCurveName;
   _currency = impliedDefinition.getCurrency();
   _interpolatorName = impliedDefinition.getInterpolatorName();
   _leftExtrapolatorName = impliedDefinition.getLeftExtrapolatorName();
   _rightExtrapolatorName = impliedDefinition.getRightExtrapolatorName();
 }
    @Override
    public Set<ComputedValue> execute(
        final FunctionExecutionContext executionContext,
        final FunctionInputs inputs,
        final ComputationTarget target,
        final Set<ValueRequirement> desiredValues)
        throws AsynchronousExecution {
      final Object originalCurveObject = inputs.getValue(YIELD_CURVE);
      if (originalCurveObject == null) {
        throw new OpenGammaRuntimeException("Could not get original curve");
      }
      ValueProperties resultCurveProperties = null;
      String absoluteToleranceName = null;
      String relativeToleranceName = null;
      String iterationsName = null;
      String decompositionName = null;
      String useFiniteDifferenceName = null;
      for (final ValueRequirement desiredValue : desiredValues) {
        if (desiredValue.getValueName().equals(YIELD_CURVE)) {
          absoluteToleranceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE);
          relativeToleranceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE);
          iterationsName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_MAX_ITERATIONS);
          decompositionName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_DECOMPOSITION);
          useFiniteDifferenceName =
              desiredValue.getConstraint(
                  MultiYieldCurvePropertiesAndDefaults.PROPERTY_USE_FINITE_DIFFERENCE);
          resultCurveProperties = desiredValue.getConstraints().copy().get();
          break;
        }
      }
      if (resultCurveProperties == null) {
        throw new OpenGammaRuntimeException("Could not get result curve properties");
      }
      final ValueProperties resultJacobianProperties = resultCurveProperties.withoutAny(CURVE);
      ZonedDateTime valuationDateTime =
          executionContext
              .getValuationTime()
              .atZone(executionContext.getValuationClock().getZone());
      final HolidaySource holidaySource =
          OpenGammaExecutionContext.getHolidaySource(executionContext);
      final ConventionSource conventionSource =
          OpenGammaExecutionContext.getConventionSource(executionContext);
      final Calendar calendar = CalendarUtils.getCalendar(holidaySource, _currency);
      final DepositConvention convention =
          conventionSource.getSingle(
              ExternalId.of(SCHEME_NAME, getConventionName(_currency, DEPOSIT)),
              DepositConvention.class);
      final int spotLag = convention.getSettlementDays();
      final ExternalId conventionSettlementRegion = convention.getRegionCalendar();
      ZonedDateTime spotDate;
      if (spotLag == 0 && conventionSettlementRegion == null) {
        spotDate = valuationDateTime;
      } else {
        spotDate = ScheduleCalculator.getAdjustedDate(valuationDateTime, spotLag, calendar);
        ;
      }
      final YieldCurveBundle curves = new YieldCurveBundle();
      final String fullYieldCurveName = _originalCurveName + "_" + _currency;
      curves.setCurve(fullYieldCurveName, (YieldAndDiscountCurve) originalCurveObject);
      final int n = _impliedDefinition.getStrips().size();
      final double[] t = new double[n];
      final double[] r = new double[n];
      int i = 0;
      final DayCount dayCount =
          DayCountFactory.INSTANCE.getDayCount(
              "Act/360"); // TODO: Get the convention from the curve.

      final String impliedDepositCurveName = _curveCalculationConfig + "_" + _currency.getCode();
      final List<InstrumentDerivative> derivatives = new ArrayList<>();

      for (final FixedIncomeStrip strip : _impliedDefinition.getStrips()) {
        final Tenor tenor = strip.getCurveNodePointTime();
        final ZonedDateTime paymentDate =
            ScheduleCalculator.getAdjustedDate(
                spotDate, tenor.getPeriod(), MOD_FOL, calendar, true);
        final double startTime = TimeCalculator.getTimeBetween(valuationDateTime, spotDate);
        final double endTime = TimeCalculator.getTimeBetween(valuationDateTime, paymentDate);
        final double accrualFactor = dayCount.getDayCountFraction(spotDate, paymentDate, calendar);
        final Cash cashFXCurve =
            new Cash(_currency, startTime, endTime, 1, 0, accrualFactor, fullYieldCurveName);
        final double parRate = METHOD_CASH.parRate(cashFXCurve, curves);
        final Cash cashDepositCurve =
            new Cash(_currency, startTime, endTime, 1, 0, accrualFactor, impliedDepositCurveName);
        derivatives.add(cashDepositCurve);
        t[i] = endTime;
        r[i++] = parRate;
      }
      final CombinedInterpolatorExtrapolator interpolator =
          CombinedInterpolatorExtrapolatorFactory.getInterpolator(
              _interpolatorName, _leftExtrapolatorName, _rightExtrapolatorName);
      final double absoluteTolerance = Double.parseDouble(absoluteToleranceName);
      final double relativeTolerance = Double.parseDouble(relativeToleranceName);
      final int iterations = Integer.parseInt(iterationsName);
      final Decomposition<?> decomposition =
          DecompositionFactory.getDecomposition(decompositionName);
      final boolean useFiniteDifference = Boolean.parseBoolean(useFiniteDifferenceName);
      final LinkedHashMap<String, double[]> curveNodes = new LinkedHashMap<>();
      final LinkedHashMap<String, Interpolator1D> interpolators = new LinkedHashMap<>();
      curveNodes.put(impliedDepositCurveName, t);
      interpolators.put(impliedDepositCurveName, interpolator);
      final FXMatrix fxMatrix = new FXMatrix();
      final YieldCurveBundle knownCurve = new YieldCurveBundle();
      final MultipleYieldCurveFinderDataBundle data =
          new MultipleYieldCurveFinderDataBundle(
              derivatives, r, knownCurve, curveNodes, interpolators, useFiniteDifference, fxMatrix);
      final NewtonVectorRootFinder rootFinder =
          new BroydenVectorRootFinder(
              absoluteTolerance, relativeTolerance, iterations, decomposition);
      final Function1D<DoubleMatrix1D, DoubleMatrix1D> curveCalculator =
          new MultipleYieldCurveFinderFunction(data, PAR_RATE_CALCULATOR);
      final Function1D<DoubleMatrix1D, DoubleMatrix2D> jacobianCalculator =
          new MultipleYieldCurveFinderJacobian(data, PAR_RATE_SENSITIVITY_CALCULATOR);
      final double[] fittedYields =
          rootFinder.getRoot(curveCalculator, jacobianCalculator, new DoubleMatrix1D(r)).getData();
      final DoubleMatrix2D jacobianMatrix =
          jacobianCalculator.evaluate(new DoubleMatrix1D(fittedYields));
      final YieldCurve impliedDepositCurve =
          new YieldCurve(
              impliedDepositCurveName,
              InterpolatedDoublesCurve.from(t, fittedYields, interpolator));
      final ValueSpecification curveSpec =
          new ValueSpecification(YIELD_CURVE, target.toSpecification(), resultCurveProperties);
      final ValueSpecification jacobianSpec =
          new ValueSpecification(
              YIELD_CURVE_JACOBIAN, target.toSpecification(), resultJacobianProperties);
      return Sets.newHashSet(
          new ComputedValue(curveSpec, impliedDepositCurve),
          new ComputedValue(jacobianSpec, jacobianMatrix));
    }
 @Override
 public CompiledFunctionDefinition compile(
     final FunctionCompilationContext context, final Instant atInstant) {
   final MultiCurveCalculationConfig impliedConfiguration =
       _multiCurveCalculationConfig.get(_curveCalculationConfig);
   if (impliedConfiguration == null) {
     throw new OpenGammaRuntimeException(
         "Multi-curve calculation called " + _curveCalculationConfig + " was null");
   }
   ComputationTarget target =
       context.getComputationTargetResolver().resolve(impliedConfiguration.getTarget());
   if (!(target.getValue() instanceof Currency)) {
     throw new OpenGammaRuntimeException(
         "Target of curve calculation configuration was not a currency");
   }
   final Currency impliedCurrency = (Currency) target.getValue();
   if (!IMPLIED_DEPOSIT.equals(impliedConfiguration.getCalculationMethod())) {
     throw new OpenGammaRuntimeException(
         "Curve calculation method was not "
             + IMPLIED_DEPOSIT
             + " for configuration called "
             + _curveCalculationConfig);
   }
   final String[] impliedCurveNames = impliedConfiguration.getYieldCurveNames();
   if (impliedCurveNames.length != 1) {
     throw new OpenGammaRuntimeException(
         "Can only handle configurations with a single implied curve");
   }
   final LinkedHashMap<String, String[]> originalConfigurationName =
       impliedConfiguration.getExogenousConfigData();
   if (originalConfigurationName == null || originalConfigurationName.size() != 1) {
     throw new OpenGammaRuntimeException("Need a configuration with one exogenous configuration");
   }
   final Map.Entry<String, String[]> entry =
       Iterables.getOnlyElement(originalConfigurationName.entrySet());
   final String[] originalCurveNames = entry.getValue();
   if (originalCurveNames.length != 1) {
     s_logger.warn("Found more than one exogenous configuration name; using only the first");
   }
   final MultiCurveCalculationConfig originalConfiguration =
       _multiCurveCalculationConfig.get(entry.getKey());
   if (originalConfiguration == null) {
     throw new OpenGammaRuntimeException(
         "Multi-curve calculation called " + entry.getKey() + " was null");
   }
   target = context.getComputationTargetResolver().resolve(originalConfiguration.getTarget());
   if (!(target.getValue() instanceof Currency)) {
     throw new OpenGammaRuntimeException(
         "Target of curve calculation configuration was not a currency");
   }
   final Currency originalCurrency = (Currency) target.getValue();
   if (!originalCurrency.equals(impliedCurrency)) {
     throw new OpenGammaRuntimeException(
         "Currency targets for configurations "
             + _curveCalculationConfig
             + " and "
             + entry.getKey()
             + " did not match");
   }
   final YieldCurveDefinition impliedDefinition =
       _yieldCurveDefinition.get(impliedCurveNames[0] + "_" + impliedCurrency.getCode());
   if (impliedDefinition == null) {
     throw new OpenGammaRuntimeException(
         "Could not get implied definition called "
             + impliedCurveNames[0]
             + "_"
             + impliedCurrency.getCode());
   }
   final Set<FixedIncomeStrip> strips = impliedDefinition.getStrips();
   for (final FixedIncomeStrip strip : strips) {
     if (strip.getInstrumentType() != StripInstrumentType.CASH) {
       throw new OpenGammaRuntimeException(
           "Can only handle yield curve definitions with CASH strips");
     }
   }
   final ZonedDateTime atZDT = ZonedDateTime.ofInstant(atInstant, ZoneOffset.UTC);
   return new MyCompiledFunction(
       atZDT.with(LocalTime.MIDNIGHT),
       atZDT.plusDays(1).with(LocalTime.MIDNIGHT).minusNanos(1000000),
       impliedConfiguration,
       impliedDefinition,
       originalConfiguration,
       originalCurveNames[0]);
 };