cdc.graphs.core.GraphPartialOrder Maven / Gradle / Ivy
package cdc.graphs.core;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import cdc.graphs.EdgeDirection;
import cdc.graphs.GraphAdapter;
import cdc.graphs.PartialOrderPosition;
import cdc.util.lang.Checks;
/**
* Utility related to graphs that define a partial order.
*
* This can also be applied to total orders.
*
* WARNING: by convention, {@code X -> Y} means {@code X > Y}.
*
* @author Damien Carbonne
*
* @param Node class
* @param Edge class
*/
public class GraphPartialOrder extends GraphBase {
private final GraphCycles cycles;
private final GraphTransitiveClosure closure;
private static final int NONE = 0;
private static final int ALL = 15;
private static final EdgeDirection GREATER_DIR = EdgeDirection.INGOING;
private static final EdgeDirection LESS_DIR = GREATER_DIR.opposite();
public GraphPartialOrder(GraphAdapter adapter) {
super(adapter);
this.cycles = new GraphCycles<>(adapter);
this.closure = new GraphTransitiveClosure<>(adapter);
}
/**
* @return {@code true} if the underlying graph defines a partial (or total) order.
*
*/
public boolean isPartialOrTotalOrder() {
return !cycles.containsCycles();
}
/**
* Returns the relative position of 2 nodes.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param left The left node.
* @param right The right node.
* @return The position of {@code left} relatively to {@code right}.
* @throws IllegalArgumentException When {@code left} or {@code right} don't belong to underlying graph.
*
*/
public PartialOrderPosition compare(N left,
N right) {
Checks.isTrue(adapter.containsNode(left), "Unknown left node {}", left);
Checks.isTrue(adapter.containsNode(right), "Unknown right node {}", right);
// FIXME There must exist a better solution
if (left.equals(right)) {
return PartialOrderPosition.EQUAL;
} else if (getAllGreaterOrEqualNodes(left).contains(right)) {
return PartialOrderPosition.LESS_THAN;
} else if (getAllLessOrEqualNodes(left).contains(right)) {
return PartialOrderPosition.GREATER_THAN;
} else {
return PartialOrderPosition.UNRELATED;
}
}
/**
* Returns the nodes that are directly connected to, and greater than, a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are directly connected to, and greater than, {@code node}.
*/
public Set getDirectGreaterThanNodes(N node) {
return getAdapter().getConnectedNodes(node, GREATER_DIR);
}
/**
* Returns the nodes that are directly connected to, and less than, a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are directly connected to, and less than, {@code node}.
*/
public Set getDirectLessThanNodes(N node) {
return getAdapter().getConnectedNodes(node, LESS_DIR);
}
/**
* Returns the nodes that are greater than a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are greater than {@code node}.
*/
public Set getAllGreaterThanNodes(N node) {
final Set set = getAllGreaterOrEqualNodes(node);
set.remove(node);
return set;
}
/**
* Returns the nodes that are less than a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are less than {@code node}.
*/
public Set getAllLessThanNodes(N node) {
final Set set = getAllLessOrEqualNodes(node);
set.remove(node);
return set;
}
/**
* Returns the nodes that are greater than, or equal to, a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are greater than, or equal to, {@code node}.
*/
public Set getAllGreaterOrEqualNodes(N node) {
return closure.computeTransitiveClosureNodes(node, GREATER_DIR);
}
/**
* Returns the nodes that are less than, or equal to, a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are less than, or equal to, {@code node}.
*/
public Set getAllLessOrEqualNodes(N node) {
return closure.computeTransitiveClosureNodes(node, LESS_DIR);
}
/**
* Returns the nodes that are related (equal, less than or greater than) to a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are related (equal, less than or greater than) to {@code node}.
*/
public Set getAllRelatedNodes(N node) {
return closure.computeTransitiveClosureNodes(node, null);
}
/**
* Returns the nodes that are not related to a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @return The nodes that are not related to {@code node}.
*/
public Set getAllUnrelatedNodes(N node) {
final Set set = new HashSet<>();
for (final N n : getAdapter().getNodes()) {
set.add(n);
}
set.remove(node);
set.removeAll(getAllGreaterThanNodes(node));
set.removeAll(getAllLessThanNodes(node));
return set;
}
/**
* Returns all the nodes that have a position relatively to a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @param position The relative position.
* @return All the nodes that have this {@code position} relatively to {@code node}.
*/
public Set getAllNodes(N node,
PartialOrderPosition position) {
Checks.isNotNull(node, "node");
Checks.isNotNull(position, "position");
final Set set;
if (position == PartialOrderPosition.EQUAL) {
set = new HashSet<>();
set.add(node);
} else if (position == PartialOrderPosition.GREATER_THAN) {
set = getAllGreaterThanNodes(node);
} else if (position == PartialOrderPosition.LESS_THAN) {
set = getAllLessThanNodes(node);
} else {
set = getAllUnrelatedNodes(node);
}
return set;
}
private static int toMask(PartialOrderPosition... positions) {
int mask = 0;
for (final PartialOrderPosition position : positions) {
if (position != null) {
mask |= 1 << position.ordinal();
}
}
return mask;
}
private static boolean isSet(int mask,
PartialOrderPosition position) {
return (mask & (1 << position.ordinal())) != 0;
}
/**
* Returns all the nodes that have one or many positions relatively to a node.
*
* WARNING: partial order of the underlying graph is not checked.
*
* @param node The node.
* @param positions The relative positions.
* @return All the nodes that have a position among {@code positions} relatively to {@code node}.
*/
public Set getAllNodes(N node,
PartialOrderPosition... positions) {
final int mask = toMask(positions);
if (mask == ALL) {
final Set set = new HashSet<>();
for (final N n : getAdapter().getNodes()) {
set.add(n);
}
return set;
} else if (mask == NONE) {
return Collections.emptySet();
} else {
final Set set = new HashSet<>();
if (isSet(mask, PartialOrderPosition.UNRELATED)) {
for (final N n : getAdapter().getNodes()) {
set.add(n);
}
if (!isSet(mask, PartialOrderPosition.EQUAL)) {
set.remove(node);
}
if (!isSet(mask, PartialOrderPosition.LESS_THAN)) {
set.removeAll(getAllLessThanNodes(node));
}
if (!isSet(mask, PartialOrderPosition.GREATER_THAN)) {
set.removeAll(getAllGreaterThanNodes(node));
}
} else {
if (isSet(mask, PartialOrderPosition.EQUAL)) {
set.add(node);
}
if (isSet(mask, PartialOrderPosition.LESS_THAN)) {
set.addAll(getAllLessThanNodes(node));
}
if (isSet(mask, PartialOrderPosition.GREATER_THAN)) {
set.addAll(getAllGreaterThanNodes(node));
}
}
return set;
}
}
}