All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.biopax.paxtools.query.algorithm.CycleBreaker Maven / Gradle / Ivy

Go to download

BioPAX graph-theoretic querying - for finding paths between molecules, or identifying molecules that are reachable through specific paths, using the BioPAX pathway data model.

There is a newer version: 6.0.0
Show newest version
package org.biopax.paxtools.query.algorithm;

import org.biopax.paxtools.query.model.Edge;
import org.biopax.paxtools.query.model.GraphObject;
import org.biopax.paxtools.query.model.Node;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

/**
 * When an algorithm searches for a paths between multiple source nodes, or from a source to a
 * target node (source and targets may overlap), sometimes there comes paths from and to the same
 * node, i.e cycles. When we want to avoid these cases this class can be used to remove those
 * cycles in the result set.
 *
 * @author Ozgun Babur
 */
public class CycleBreaker extends BFS
{
	/**
	 * The result set to search for cycles.
	 */
	Set result;

	/**
	 * Source and (if exists) target nodes.
	 */
	Set ST;

	/**
	 * Constructor with the objects in the result, source and target nodes, and search limit.
	 * @param result Result set to search in
	 * @param ST Source and target nodes
	 * @param limit Search limit
	 */
	public CycleBreaker(Set result, Set ST, int limit)
	{
		this.result = result;
		this.ST = ST;
		this.limit = limit;
	}

	/**
	 * Run the algorithm.
	 */
	public void breakCycles()
	{
		for (GraphObject go : new ArrayList(result))
		{
			if (go instanceof Node)
			{
				Node node = (Node) go;

				for (Edge edge : node.getDownstream())
				{
					if (result.contains(edge) && !isSafe(node, edge))
					{
						result.remove(edge);
					}
				}
			}
		}
	}

	/**
	 * Checks whether an edge is on an unwanted cycle.
	 * @param node Node that the edge is bound
	 * @param edge The edge to check
	 * @return True if no cycle is detected, false otherwise
	 */
	public boolean isSafe(Node node, Edge edge)
	{
		initMaps();

		setColor(node, BLACK);
		setLabel(node, 0);
		setLabel(edge, 0);

		labelEquivRecursive(node, UPWARD, 0, false, false);
		labelEquivRecursive(node, DOWNWARD, 0, false, false);

		// Initialize dist and color of source set

		Node neigh = edge.getTargetNode();

		if (getColor(neigh) != WHITE) return false;

		setColor(neigh, GRAY);
		setLabel(neigh, 0);

		queue.add(neigh);

		labelEquivRecursive(neigh, UPWARD, 0, true, false);
		labelEquivRecursive(neigh, DOWNWARD, 0, true, false);

		// Process the queue

		while (!queue.isEmpty())
		{
			Node current = queue.remove(0);

			if (ST.contains(current)) return true;
			
			boolean safe = processNode2(current);

			if (safe) return true;

			// Current node is processed
			setColor(current, BLACK);
		}

		return false;
	}

	/**
	 * Continue the search from the node. 2 is added because a name clash in the parent class.
	 * @param current The node to traverse
	 * @return False if a cycle is detected
	 */
	protected boolean processNode2(Node current)
	{
		return processEdges(current, current.getDownstream()) ||
			processEdges(current, current.getUpstream());
	}

	/**
	 * Continue evaluating the next edge.
	 * @param current Current node
	 * @param edges The edge to evaluate
	 * @return False if a cycle is detected
	 */
	private boolean processEdges(Node current, Collection edges)
	{
		for (Edge edge : edges)
		{
			if (!result.contains(edge)) continue;
			
			// Label the edge considering direction of traversal and type of current node

			setLabel(edge, getLabel(current));

			// Get the other end of the edge
			Node neigh = edge.getSourceNode() == current ?
				edge.getTargetNode() : edge.getSourceNode();

			// Process the neighbor if not processed or not in queue

			if (getColor(neigh) == WHITE)
			{
				// Label the neighbor according to the search direction and node type

				if (neigh.isBreadthNode())
				{
					setLabel(neigh, getLabel(current) + 1);
				}
				else
				{
					setLabel(neigh, getLabel(edge));
				}

				// Check if we need to stop traversing the neighbor, enqueue otherwise

				if (getLabel(neigh) == limit || isEquivalentInTheSet(neigh, ST))
				{
					return true;
				}

				setColor(neigh, GRAY);

				// Enqueue the node according to its type

				if (neigh.isBreadthNode())
				{
					queue.addLast(neigh);
				}
				else
				{
					// Non-breadth nodes are added in front of the queue
					queue.addFirst(neigh);
				}

				labelEquivRecursive(neigh, UPWARD, getLabel(neigh), true, !neigh.isBreadthNode());
				labelEquivRecursive(neigh, DOWNWARD, getLabel(neigh), true, !neigh.isBreadthNode());
			}
		}
		return false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy