alluxio.collections.DirectedAcyclicGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alluxio-core-common Show documentation
Show all versions of alluxio-core-common Show documentation
Common utilities shared in Alluxio core modules
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.collections;
import com.google.common.base.Preconditions;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
/**
* A Directed Acyclic Graph (DAG).
*
* @param the payload of each node
*/
@NotThreadSafe
public class DirectedAcyclicGraph {
private final List> mRoots;
private final Map> mIndex;
/**
* A Directed Acyclic Graph (DAG).
*/
public DirectedAcyclicGraph() {
mRoots = new ArrayList<>();
mIndex = new HashMap<>();
}
/**
* Adds a node to the DAG, that takes the given payload and depends on the specified parents.
*
* @param payload the payload
* @param parents the parents of the created node
*/
public void add(T payload, List parents) {
// This checks the payload doesn't exist in the graph, and therefore prevents cycles.
Preconditions.checkState(!contains(payload), "the payload already exists in the DAG");
// construct the new node
DirectedAcyclicGraphNode newNode = new DirectedAcyclicGraphNode<>(payload);
mIndex.put(payload, newNode);
if (parents.isEmpty()) {
// add to root
mRoots.add(newNode);
} else {
// find parent nodes
for (T parent : parents) {
Preconditions.checkState(contains(parent),
"the parent payload " + parent + " does not exist in the DAG");
DirectedAcyclicGraphNode parentNode = mIndex.get(parent);
parentNode.addChild(newNode);
newNode.addParent(parentNode);
}
}
}
/**
* Deletes a leaf DAG node that carries the given payload.
*
* @param payload the payload of the node to delete
*/
public void deleteLeaf(T payload) {
Preconditions.checkState(contains(payload), "the node does not exist");
DirectedAcyclicGraphNode node = mIndex.get(payload);
Preconditions.checkState(node.getChildren().isEmpty(), "the node is not a leaf");
// delete from parent
for (DirectedAcyclicGraphNode parent : node.getParents()) {
parent.removeChild(node);
}
// remove from index
mIndex.remove(payload);
if (node.getParents().isEmpty()) {
mRoots.remove(node);
}
}
/**
* Checks if a node with the given payload is in the DAG.
*
* @param payload the payload of the node to check
* @return true if there a node in the DAG contains the given value as payload, false otherwise
*/
public boolean contains(T payload) {
return mIndex.containsKey(payload);
}
/**
* Gets the payloads for the children of the given node.
*
* @param payload the payload of the parent node
* @return the children's payloads, an empty list if the given payload doesn't exist in the DAG
*/
public List getChildren(T payload) {
List children = new ArrayList<>();
if (!mIndex.containsKey(payload)) {
return children;
}
DirectedAcyclicGraphNode node = mIndex.get(payload);
for (DirectedAcyclicGraphNode child : node.getChildren()) {
children.add(child.getPayload());
}
return children;
}
/**
* Gets the payloads for the given nodes parents.
*
* @param payload the payload of the children node
* @return the parents' payloads, an empty list if the given payload doesn't exist in the DAG
*/
public List getParents(T payload) {
List parents = new ArrayList<>();
if (!mIndex.containsKey(payload)) {
return parents;
}
DirectedAcyclicGraphNode node = mIndex.get(payload);
for (DirectedAcyclicGraphNode parent : node.getParents()) {
parents.add(parent.getPayload());
}
return parents;
}
/**
* Checks if a given payload is in a root of the DAG.
*
* @param payload the payload to check for root
* @return true if the payload is in the root of the DAG, false otherwise
*/
public boolean isRoot(T payload) {
if (!contains(payload)) {
return false;
}
return mRoots.contains(mIndex.get(payload));
}
/**
* Gets the payloads of all the root nodes of the DAG.
*
* @return all the root payloads
*/
public List getRoots() {
List roots = new ArrayList<>();
for (DirectedAcyclicGraphNode root : mRoots) {
roots.add(root.getPayload());
}
return roots;
}
/**
* Sorts a given set of payloads topologically based on the DAG. This method requires all the
* payloads to be in the DAG.
*
* @param payloads the set of input payloads
* @return the payloads after topological sort
*/
public List sortTopologically(Set payloads) {
List result = new ArrayList<>();
Set input = new HashSet<>(payloads);
Deque> toVisit = new ArrayDeque<>(mRoots);
while (!toVisit.isEmpty()) {
DirectedAcyclicGraphNode visit = toVisit.removeFirst();
T payload = visit.getPayload();
if (input.remove(payload)) {
result.add(visit.getPayload());
}
toVisit.addAll(visit.getChildren());
}
Preconditions.checkState(input.isEmpty(), "Not all the given payloads are in the DAG: ",
input);
return result;
}
/**
* Gets all payloads of the DAG in the topological order.
*
* @return the payloads of all the nodes in topological order
*/
public List getAllInTopologicalOrder() {
return sortTopologically(mIndex.keySet());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy