/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.depgraph;
import it.unimi.dsi.fastutil.Hash.Strategy;
import java.util.Map;
import com.opengamma.core.security.Security;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.depgraph.impl.DependencyNodeImpl;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.util.PublicAPI;
/**
* A single node in a {@link DependencyGraph}. A node represents the need to execute a particular function at runtime to produce certain outputs.
* <p>
* A node consists of a computation target (e.g. a {@link Security}), a function to operate on that target, input values for the function, and output values generated by the function. Relationships
* with other nodes - either input or dependent - indicate how input values are produced and how output values are to be used.
* <p>
* A node instance only holds references to nodes that produce its input values. Any given node, and the sub-graph required to produce its outputs, may then be present in multiple graphs. Node
* instances are immutable and thread-safe.
*/
@PublicAPI
public interface DependencyNode {
/**
* Hashing strategy for using arbitrary implementations in a hash map.
* <p>
* Two nodes, {@code a} and {@code b} are deep-equal if they:
* <ul>
* <li>Apply the same function;
* <li>Act on the same target specification;
* <li>Produce the same set of output values;
* <li>Consume the same set of input values; and
* <li>The node producing an input for {@code a} is deep-equal to the node producing the equal input for {@code b}
* </ul>
* <p>
* Note that comparing two nodes in this way can be an expensive operation for large/deep graphs, especially if used as part of a general graph comparison. This should be used for debugging/testing
* only.
*/
Strategy<DependencyNode> HASHING_STRATEGY = new Strategy<DependencyNode>() {
@Override
public int hashCode(final DependencyNode o) {
int hc = ((DependencyNodeFunction.HASHING_STRATEGY.hashCode(o.getFunction()) * 31) + o.getTarget().hashCode()) * 31;
int count = o.getOutputCount();
for (int i = 0; i < count; i++) {
hc += o.getOutputValue(i).hashCode();
}
hc *= 31;
count = o.getInputCount();
for (int i = 0; i < count; i++) {
hc += o.getInputValue(i).hashCode();
hc += hashCode(o.getInputNode(i));
}
return hc;
}
@Override
public boolean equals(final DependencyNode a, final DependencyNode b) {
if (a == b) {
return true;
}
if ((a == null) || (b == null)) {
return false;
}
if (!DependencyNodeFunction.HASHING_STRATEGY.equals(a.getFunction(), b.getFunction())) {
return false;
}
if (!a.getTarget().equals(b.getTarget())) {
return false;
}
if (a.getOutputCount() != b.getOutputCount()) {
return false;
}
if (a.getInputCount() != b.getInputCount()) {
return false;
}
if (!DependencyNodeImpl.getOutputValues(a).equals(DependencyNodeImpl.getOutputValues(b))) {
return false;
}
final Map<ValueSpecification, DependencyNode> aInputs = DependencyNodeImpl.getInputs(a);
final Map<ValueSpecification, DependencyNode> bInputs = DependencyNodeImpl.getInputs(b);
for (Map.Entry<ValueSpecification, DependencyNode> aInput : aInputs.entrySet()) {
if (!equals(bInputs.get(aInput.getKey()), aInput.getValue())) {
return false;
}
}
return true;
}
};
/**
* Returns the function at this node
*
* @return the function information, not null
*/
DependencyNodeFunction getFunction();
/**
* Returns the target specification of this node.
*
* @return the target specification, not null
*/
ComputationTargetSpecification getTarget();
/**
* Returns the number of inputs this node consumes.
*
* @return the number of inputs
*/
int getInputCount();
/**
* Returns a value specification label from one of the input edges to this node.
*
* @param index the edge index, between 0 (inclusive) and {@link #getInputCount} (exclusive).
* @return the input value specification, not null
* @throws ArrayIndexOutOfBoundsException if the index is invalid
*/
ValueSpecification getInputValue(int index);
/**
* Returns the node producing an input to this node.
*
* @param index the edge index, between 0 (inclusive) and {@link #getInputCount} (exclusive).
* @return the input node, not null
* @throws ArrayIndexOutOfBoundsException if the index is invalid
*/
DependencyNode getInputNode(int index);
/**
* Returns the index of the input edge for the given value specification, if it is consumed by this node.
*
* @param value the value specification to test for, not null
* @return the index of the edge, between 0 (inclusive) and {@link #getInputCount} (exclusive) if found, or -1 if the value is not consumed by this node
*/
int findInputValue(ValueSpecification value);
/**
* Returns the number of outputs this node produces.
*
* @return the number of outputs
*/
int getOutputCount();
/**
* Returns an output value specification produced by this node.
*
* @param index the output index, between 0 (inclusive) and {@link #getOutputCount} (exclusive).
* @return the output value specification, not null
* @throws ArrayIndexOutOfBoundsException if the index is invalid
*/
ValueSpecification getOutputValue(int index);
/**
* Tests whether the node produces the given output value.
*
* @param value the value specification to test for, not null
* @return true if the value is produced, false otherwise
*/
boolean hasOutputValue(ValueSpecification value);
}