public Set<ValueRequirement> getRequirements(
      final FunctionCompilationContext context,
      final ComputationTarget target,
      final ValueRequirement desiredValue) {
    Set<ValueRequirement> superReqs = super.getRequirements(context, target, desiredValue);
    if (superReqs == null) {
      return null;
    }

    // Test constraints are provided, else set to ""
    final ValueProperties constraints = desiredValue.getConstraints();
    ValueProperties.Builder scenarioDefaults = null;

    final Set<String> priceShiftSet = constraints.getValues(s_priceShift);
    if (priceShiftSet == null || priceShiftSet.isEmpty()) {
      scenarioDefaults = constraints.copy().withoutAny(s_priceShift).with(s_priceShift, "");
    }
    final Set<String> priceShiftTypeSet = constraints.getValues(s_priceShiftType);
    if (priceShiftTypeSet == null || priceShiftTypeSet.isEmpty()) {
      if (scenarioDefaults == null) {
        scenarioDefaults =
            constraints
                .copy()
                .withoutAny(s_priceShiftType)
                .with(s_priceShiftType, "Multiplicative");
      } else {
        scenarioDefaults =
            scenarioDefaults.withoutAny(s_priceShiftType).with(s_priceShiftType, "Multiplicative");
      }
    }
    final Set<String> volShiftSet = constraints.getValues(s_volShift);
    if (volShiftSet == null || volShiftSet.isEmpty()) {
      if (scenarioDefaults == null) {
        scenarioDefaults = constraints.copy().withoutAny(s_volShift).with(s_volShift, "");
      } else {
        scenarioDefaults = scenarioDefaults.withoutAny(s_volShift).with(s_volShift, "");
      }
    }
    final Set<String> volShiftSetType = constraints.getValues(s_volShiftType);
    if (volShiftSetType == null || volShiftSetType.isEmpty()) {
      if (scenarioDefaults == null) {
        scenarioDefaults =
            constraints.copy().withoutAny(s_volShiftType).with(s_volShiftType, "Multiplicative");
      } else {
        scenarioDefaults =
            scenarioDefaults.withoutAny(s_volShiftType).with(s_volShiftType, "Multiplicative");
      }
    }

    // If defaults have been added, this adds additional copy of the Function into dep graph with
    // the adjusted constraints
    if (scenarioDefaults != null) {
      return Collections.singleton(
          new ValueRequirement(
              getValueRequirementName(), target.toSpecification(), scenarioDefaults.get()));
    } else { // Scenarios are defined, so we're satisfied
      return superReqs;
    }
  }
 private ValueSpecification getSpec(final ValueProperties props) {
   final Builder realProps = props.copy().with(ValuePropertyNames.FUNCTION, "SomeFunc");
   final ValueSpecification spec =
       new ValueSpecification(
           "X", ComputationTargetSpecification.of(Currency.USD), realProps.get());
   return spec;
 }
 @Override
 public Set<ValueRequirement> getRequirements(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final ValueRequirement desiredValue) {
   final ValueProperties constraints = desiredValue.getConstraints();
   Set<String> values = constraints.getValues(VALUE_PROPERTY_NAME);
   final String inputValue;
   if ((values == null) || values.isEmpty()) {
     inputValue = DEFAULT_VALUE_NAME;
   } else if (values.size() == 1) {
     inputValue = values.iterator().next();
   } else {
     return null;
   }
   // Propogate the desired value constraints onto the requirements, removing those specific to
   // this function and adding a unit homogeneity clause
   final ValueProperties.Builder requirementConstraintsBuilder =
       constraints.copy().withoutAny(VALUE_PROPERTY_NAME);
   for (String unit : UnitProperties.unitPropertyNames()) {
     values = constraints.getValues(unit);
     if (values == null) {
       // Unit was not specified on the output, but we specify it on the inputs so we can check
       // homogeneity to ensure the division is valid
       requirementConstraintsBuilder.withOptional(unit);
     }
   }
   // Request value on the value and parent
   final ValueProperties requirementConstraints = requirementConstraintsBuilder.get();
   return ImmutableSet.of(
       new ValueRequirement(inputValue, getValueTarget(target), requirementConstraints),
       new ValueRequirement(inputValue, getParentTarget(target), requirementConstraints));
 }
 private void assertEqualOrdered(
     final ValueProperties expected,
     final MockPropertyPreservingFunction func,
     final Collection<ValueSpecification> specses) {
   final ValueProperties resultProperties = func.getResultProperties(specses);
   final ValueProperties filteredResult =
       resultProperties.copy().withoutAny(ValuePropertyNames.FUNCTION).get();
   assertEquals(expected, filteredResult);
 }
 @Override
 public Set<ValueSpecification> getResults(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final Map<ValueSpecification, ValueRequirement> inputs) {
   ValueSpecification inputValue = null;
   ValueSpecification inputParent = null;
   final UniqueId value = target.getUniqueId();
   for (ValueSpecification input : inputs.keySet()) {
     if (value.equals(input.getTargetSpecification().getUniqueId())) {
       assert inputValue == null;
       inputValue = input;
     } else {
       assert inputParent == null;
       inputParent = input;
     }
   }
   final ValueProperties rawResultProperties =
       inputValue.getProperties().intersect(inputParent.getProperties());
   final ValueProperties.Builder resultPropertiesBuilder = rawResultProperties.copy();
   for (String unit : UnitProperties.unitPropertyNames()) {
     final Set<String> valueUnits = inputValue.getProperties().getValues(unit);
     final Set<String> parentUnits = inputParent.getProperties().getValues(unit);
     if (valueUnits != null) {
       if (parentUnits != null) {
         if (rawResultProperties.getValues(unit) != null) {
           // The operation is a division, so there are no units on the result
           resultPropertiesBuilder.withoutAny(unit);
         } else {
           // No common intersection between parent and value properties for this unit
           return null;
         }
       } else {
         // Parent did not include the same units as the value
         return null;
       }
     } else {
       if (parentUnits != null) {
         // Value did not include the same units as the parent
         return null;
       }
     }
   }
   resultPropertiesBuilder
       .withoutAny(VALUE_PROPERTY_NAME)
       .with(VALUE_PROPERTY_NAME, inputValue.getValueName());
   resultPropertiesBuilder
       .withoutAny(ValuePropertyNames.FUNCTION)
       .with(ValuePropertyNames.FUNCTION, getUniqueId());
   return Collections.singleton(
       new ValueSpecification(
           ValueRequirementNames.WEIGHT, target.toSpecification(), resultPropertiesBuilder.get()));
 }
 @Override
 public Set<ComputedValue> execute(
     final FunctionExecutionContext context,
     final FunctionInputs inputs,
     final ComputationTarget target,
     final Set<ValueRequirement> desiredValues)
     throws AsynchronousExecution {
   final MultipleCurrencyParameterSensitivity sensitivities =
       (MultipleCurrencyParameterSensitivity) inputs.getValue(BLOCK_CURVE_SENSITIVITIES);
   final ValueRequirement desiredValue = desiredValues.iterator().next();
   final ValueProperties properties = desiredValue.getConstraints();
   final String desiredCurveName = desiredValue.getConstraint(CURVE);
   final Map<Pair<String, Currency>, DoubleMatrix1D> entries = sensitivities.getSensitivities();
   final Set<ComputedValue> results = new HashSet<>();
   for (final Map.Entry<Pair<String, Currency>, DoubleMatrix1D> entry : entries.entrySet()) {
     final String curveName = entry.getKey().getFirst();
     if (desiredCurveName.equals(curveName)) {
       final ValueProperties curveSpecificProperties =
           properties.copy().withoutAny(CURVE).with(CURVE, curveName).get();
       final CurveDefinition curveDefinition =
           (CurveDefinition)
               inputs.getValue(
                   new ValueRequirement(
                       CURVE_DEFINITION,
                       ComputationTargetSpecification.NULL,
                       ValueProperties.builder().with(CURVE, curveName).get()));
       final DoubleLabelledMatrix1D ycns =
           MultiCurveUtils.getLabelledMatrix(entry.getValue(), curveDefinition);
       final ValueSpecification spec =
           new ValueSpecification(
               YIELD_CURVE_NODE_SENSITIVITIES, target.toSpecification(), curveSpecificProperties);
       results.add(new ComputedValue(spec, ycns));
       return results;
     }
   }
   s_logger.info(
       "Could not get sensitivities to " + desiredCurveName + " for " + target.getName());
   return Collections.emptySet();
 }
 @Override
 public Set<ValueRequirement> getRequirements(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final ValueRequirement desiredValue) {
   final ValueProperties constraints = desiredValue.getConstraints();
   final Set<String> payCurveNames = constraints.getValues(ValuePropertyNames.PAY_CURVE);
   if (payCurveNames == null || payCurveNames.size() != 1) {
     return null;
   }
   final Set<String> payCurveCalculationConfigs =
       constraints.getValues(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG);
   if (payCurveCalculationConfigs == null || payCurveCalculationConfigs.size() != 1) {
     return null;
   }
   final Set<String> receiveCurveNames = constraints.getValues(ValuePropertyNames.RECEIVE_CURVE);
   if (receiveCurveNames == null || receiveCurveNames.size() != 1) {
     return null;
   }
   final Set<String> receiveCurveCalculationConfigs =
       constraints.getValues(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG);
   if (receiveCurveCalculationConfigs == null || receiveCurveCalculationConfigs.size() != 1) {
     return null;
   }
   final Set<String> calculationMethods =
       constraints.getValues(ValuePropertyNames.CALCULATION_METHOD);
   if (calculationMethods == null || calculationMethods.size() != 1) {
     final ValueProperties newConstraints =
         constraints
             .copy()
             .withoutAny(ValuePropertyNames.CALCULATION_METHOD)
             .with(
                 ValuePropertyNames.CALCULATION_METHOD,
                 CalculationPropertyNamesAndValues.DISCOUNTING)
             .get();
     return Collections.singleton(
         new ValueRequirement(
             ValueRequirementNames.PNL_SERIES, target.toSpecification(), newConstraints));
   }
   final Set<ValueRequirement> requirements = new HashSet<>();
   final String calculationMethod = Iterables.getOnlyElement(calculationMethods);
   final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
   if (CalculationPropertyNamesAndValues.DISCOUNTING.equals(calculationMethod)) {
     requirements.add(
         new ValueRequirement(
             ValueRequirementNames.FX_CURRENCY_EXPOSURE,
             ComputationTargetSpecification.of(target.getPosition().getSecurity()),
             ValueProperties.builder()
                 .with(
                     ValuePropertyNames.CALCULATION_METHOD,
                     CalculationPropertyNamesAndValues.DISCOUNTING)
                 .with(ValuePropertyNames.PAY_CURVE, payCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG,
                     payCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.RECEIVE_CURVE, receiveCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG,
                     receiveCurveCalculationConfigs.iterator().next())
                 .get()));
   } else if (CalculationPropertyNamesAndValues.FORWARD_POINTS.equals(calculationMethod)) {
     final Set<String> forwardCurveNames =
         constraints.getValues(ValuePropertyNames.FORWARD_CURVE_NAME);
     if (forwardCurveNames == null || forwardCurveNames.size() != 1) {
       return null;
     }
     final String forwardCurveName = Iterables.getOnlyElement(forwardCurveNames);
     requirements.add(
         new ValueRequirement(
             ValueRequirementNames.FX_CURRENCY_EXPOSURE,
             ComputationTargetSpecification.of(target.getPosition().getSecurity()),
             ValueProperties.builder()
                 .with(
                     ValuePropertyNames.CALCULATION_METHOD,
                     CalculationPropertyNamesAndValues.FORWARD_POINTS)
                 .with(ValuePropertyNames.PAY_CURVE, payCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG,
                     payCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.RECEIVE_CURVE, receiveCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG,
                     receiveCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.FORWARD_CURVE_NAME, forwardCurveName)
                 .get()));
   } else {
     return null;
   }
   final Set<String> resultCurrencies = constraints.getValues(CURRENCY);
   final Currency payCurrency = security.accept(ForexVisitors.getPayCurrencyVisitor());
   final Currency receiveCurrency = security.accept(ForexVisitors.getReceiveCurrencyVisitor());
   final String resultCurrency;
   final CurrencyPair baseQuotePair =
       _currencyPairs.getCurrencyPair(payCurrency, receiveCurrency);
   final Currency baseCurrency = baseQuotePair.getBase();
   final Currency nonBaseCurrency = baseQuotePair.getCounter();
   if (resultCurrencies != null && resultCurrencies.size() == 1) {
     final Currency ccy = Currency.of(Iterables.getOnlyElement(resultCurrencies));
     if (!(ccy.equals(payCurrency) || ccy.equals(receiveCurrency))) {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(baseCurrency, ccy)));
       resultCurrency = ccy.getCode();
     } else if (ccy.equals(nonBaseCurrency)) {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(nonBaseCurrency, baseCurrency)));
       resultCurrency = nonBaseCurrency.getCode();
     } else {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(baseCurrency, nonBaseCurrency)));
       resultCurrency = baseCurrency.getCode();
     }
   } else {
     resultCurrency = baseCurrency.getCode();
   }
   final ValueProperties fxSpotConstraints =
       desiredValue
           .getConstraints()
           .copy()
           .withoutAny(ValuePropertyNames.PAY_CURVE)
           .withoutAny(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG)
           .withoutAny(ValuePropertyNames.RECEIVE_CURVE)
           .withoutAny(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG)
           .withoutAny(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS)
           .withoutAny(ValuePropertyNames.CURVE_CURRENCY)
           .withoutAny(ValuePropertyNames.CALCULATION_METHOD)
           .withoutAny(ValuePropertyNames.FORWARD_CURVE_NAME)
           .with(CURRENCY, resultCurrency)
           .withOptional(CURRENCY)
           .get();
   final ComputationTargetSpecification fxSpotReturnSeriesSpec =
       ComputationTargetType.UNORDERED_CURRENCY_PAIR.specification(
           UnorderedCurrencyPair.of(payCurrency, receiveCurrency));
   requirements.add(
       new ValueRequirement(
           ValueRequirementNames.RETURN_SERIES, fxSpotReturnSeriesSpec, fxSpotConstraints));
   return requirements;
 }