/** * 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); }