/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.view.cycle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Sets;
import com.opengamma.engine.function.FunctionParameters;
import com.opengamma.engine.marketdata.manipulator.DistinctMarketDataSelector;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.engine.view.compilation.CompiledViewCalculationConfiguration;
import com.opengamma.engine.view.compilation.CompiledViewDefinition;
import com.opengamma.engine.view.execution.ViewCycleExecutionOptions;
/**
* Determines which output value specifications have changed as a result of different execution option function parameters.
*/
public final class FunctionParametersDelta {
/**
* The "empty" delta instance, corresponding to no changes in function parameters.
*/
public static final FunctionParametersDelta EMPTY = new FunctionParametersDelta(null);
private final Collection<DistinctMarketDataSelector> _selectors;
private FunctionParametersDelta(final Collection<DistinctMarketDataSelector> selectors) {
_selectors = selectors;
}
/* package */Collection<DistinctMarketDataSelector> getSelectors() {
return _selectors;
}
/**
* Creates a delta of function parameterization between two cycle execution options.
*
* @param firstCycleOptions the options for the first cycle, not null
* @param secondCycleOptions the options for the second cycle, not null
* @return the delta, not null
*/
public static FunctionParametersDelta of(final ViewCycleExecutionOptions firstCycleOptions, final ViewCycleExecutionOptions secondCycleOptions) {
return of(firstCycleOptions.getFunctionParameters(), secondCycleOptions.getFunctionParameters());
}
/**
* Creates a delta of function parameterizations.
*
* @param firstCycleParameters the parameterization for the first cycle, not null
* @param secondCycleParameters the parameterization for the second cycle, not null
* @return the delta, not null
*/
public static FunctionParametersDelta of(final Map<DistinctMarketDataSelector, FunctionParameters> firstCycleParameters,
final Map<DistinctMarketDataSelector, FunctionParameters> secondCycleParameters) {
if (firstCycleParameters.isEmpty()) {
if (secondCycleParameters.isEmpty()) {
// No delta - no parameters
return EMPTY;
} else {
// Delta is anything defined in the second parameter set
return FunctionParametersDelta.of(secondCycleParameters.keySet());
}
} else {
if (secondCycleParameters.isEmpty()) {
// Delta is anything defined in the first parameter set
return FunctionParametersDelta.of(firstCycleParameters.keySet());
} else {
// Delta is the negative intersection of market data selectors, plus anything in the union with different parameters
final ArrayList<DistinctMarketDataSelector> delta = new ArrayList<DistinctMarketDataSelector>(firstCycleParameters.size() + secondCycleParameters.size());
int union = 0;
for (Map.Entry<DistinctMarketDataSelector, FunctionParameters> first : firstCycleParameters.entrySet()) {
final FunctionParameters secondValue = secondCycleParameters.get(first.getKey());
if (secondValue != null) {
// Intersection - include if parameters are different
if (first.getValue().equals(secondValue)) {
union++;
} else {
delta.add(first.getKey());
}
} else {
// Left negative intersection - include
delta.add(first.getKey());
}
}
if (union != secondCycleParameters.size()) {
// Include the right negative intersection
for (DistinctMarketDataSelector secondKey : secondCycleParameters.keySet()) {
if (!firstCycleParameters.containsKey(secondKey)) {
delta.add(secondKey);
}
}
}
if (delta.isEmpty()) {
return EMPTY;
} else {
return new FunctionParametersDelta(delta);
}
}
}
}
/* package */static FunctionParametersDelta of(final Collection<DistinctMarketDataSelector> selectors) {
return new FunctionParametersDelta(new ArrayList<DistinctMarketDataSelector>(selectors));
}
/**
* Returns the value specifications that are directly dirtied by this delta. The dependency graph must be used to determine any derived values that are also invalidated as a result of these.
*
* @param calcConfig the calculation configuration, not null
* @param firstCycle the compiled view definition from the first cycle, not null
* @param secondCycle the compiled view definition from the second cycle, not null
* @return the dirty specifications, not null
*/
public Set<ValueSpecification> getValueSpecifications(final String calcConfig, final CompiledViewDefinition firstCycle, final CompiledViewDefinition secondCycle) {
if (getSelectors() == null) {
// Nothing in the delta
return Collections.emptySet();
}
final CompiledViewCalculationConfiguration firstCycleConfig = firstCycle.getCompiledCalculationConfiguration(calcConfig);
if (firstCycleConfig == null) {
return Collections.emptySet();
}
final CompiledViewCalculationConfiguration secondCycleConfig = secondCycle.getCompiledCalculationConfiguration(calcConfig);
if (secondCycleConfig == null) {
return Collections.emptySet();
}
return getValueSpecifications(firstCycleConfig.getMarketDataSelections(), secondCycleConfig.getMarketDataSelections());
}
private Set<ValueSpecification> getValueSpecifications(final Map<DistinctMarketDataSelector, Set<ValueSpecification>> firstCycle,
final Map<DistinctMarketDataSelector, Set<ValueSpecification>> secondCycle) {
final Set<ValueSpecification> delta = Sets.newHashSetWithExpectedSize(getSelectors().size());
for (DistinctMarketDataSelector selector : getSelectors()) {
Set<ValueSpecification> specifications = firstCycle.get(selector);
if (specifications != null) {
// Specifications set on the first cycle might not be set on the second - mark dirty
delta.addAll(specifications);
}
specifications = secondCycle.get(selector);
if (specifications != null) {
// Specifications set on the second cycle might not have been set on the first - mark dirty
delta.addAll(specifications);
}
}
return delta;
}
}