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

net.sf.gluebooster.java.booster.basic.math.graph.GraphSequenceClusterer Maven / Gradle / Ivy

package net.sf.gluebooster.java.booster.basic.math.graph;

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

import org.apache.commons.collections4.Transformer;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.UndirectedGraph;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.Callable;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.CallableAbstraction;
import net.sf.gluebooster.java.booster.essentials.meta.objects.DisplayConfiguration;

/**
 * Finds sequences within graphs.
 * 
 * A sequence is a subgraph (with at least two vertices) with only at most two
 * vertices that are connected with the rest of the graph. One of the vertices
 * must have only at most one edge to the rest of the graph.
 * 
 * A sequence is for example A-B-C-D
 * 
 * @author CBauer
 *
 * @param 
 * @param 
 */
public class GraphSequenceClusterer extends CallableAbstraction, Set>> implements
		Transformer, Set>> {

	/**
	 * Should the debug mode with more logging be enabled.
	 */
	private boolean debugMode = false;

	/**
	 * @return the sequences
	 */
	@Override
	public Set> transform(UndirectedGraph graph) {

		if (debugMode) {
			JungGraphBoostUtils.displayShapes(new DisplayConfiguration(
					"graph to transform", (Graph) graph));
		}

		HashSet> result = new HashSet>();

		Set usedVertices = new HashSet();

		for (V vertex : graph.getVertices()) {
			int degree = graph.degree(vertex);
			if ((!usedVertices.contains(vertex)) && degree <= 2) {
				// startpoint of the sequence
				Set sequence = new HashSet();
				if (degree == 0) {
					// nothing to do
					// end
				} else {
					continueSequence(sequence, usedVertices, graph, vertex,
							false);
					// the sequence size may be 1 if all other vertices are
					// alredy used.
					// ignore such sequences
					if (sequence.size() > 1) {
						result.add(sequence);
					}
				}
			}
		}

		return result;
	}

	/**
	 * Continues finding the remainder of the sequence.
	 * 
	 * @param sequence
	 *            the result sequence
	 * @param usedVertices
	 *            the vertices already inspected
	 * @param graph
	 *            the graph which is to be inspected
	 * @param nextVertexOfSequence
	 *            the next vertex that is to be inspected
	 * @param alreadyOneNodeWithMoreThan2Neighbours
	 *            is there already one node with more than 2 neighbours.
	 */
	private  void continueSequence(Set sequence, Set usedVertices,
			UndirectedGraph graph, V nextVertexOfSequence,
			boolean alreadyOneNodeWithMoreThan2Neighbours) {
		if (!usedVertices.contains(nextVertexOfSequence)) {
			Collection neighbours = graph.getNeighbors(nextVertexOfSequence);
			int neighboursSize = neighbours.size();

			// a node of the sequence either has max 2 neighbours, or it is an
			// end of the sequence
			// one end is allowed in the sequence

			if ((neighboursSize <= 2 || !alreadyOneNodeWithMoreThan2Neighbours)) {

				HashSet usedNeighbours = new HashSet(neighbours);
				usedNeighbours.retainAll(usedVertices);
				// the nodes of the sequence, that are already used

				usedVertices.add(nextVertexOfSequence);

				if (usedNeighbours.size() > 1) {
					// there is a circle, don't use that node
					return;
				}

				sequence.add(nextVertexOfSequence);

				if (neighboursSize > 2) {
					alreadyOneNodeWithMoreThan2Neighbours = true;
				} else {
					for (V neighbour : neighbours) {
						continueSequence(sequence, usedVertices, graph,
								neighbour,
								alreadyOneNodeWithMoreThan2Neighbours);
					}
				}
			}
		}
	}

	/**
	 * Orders a sequence.
	 * 
	 * @param sequence
	 *            the elements must form a sequence a-b-c-d-e...
	 * @param graph
	 *            the inspected graph
	 * @param hashCodeOfVerticesMayHaveChanged
	 *            if the hash code has changed some more work is to do.
	 * @return the ordered sequence
	 */
	public List order(Collection sequence, Graph graph,
			boolean hashCodeOfVerticesMayHaveChanged) {

		if (graph == null) {
			throw new IllegalStateException("graph must not be null");
		}

		if (hashCodeOfVerticesMayHaveChanged) {
			// create a new graph with working hash codes
			graph = JungGraphBoostUtils.createUndirectedGraph(graph);
		}

		ArrayList result = new ArrayList(sequence.size());

		// the nodes that have not yet been added to the result
		HashSet unused = new HashSet(sequence);
		if (!sequence.isEmpty()) {
			V current = unused.iterator().next();
			// successors
			while (current != null) {
				result.add(current);
				unused.remove(current);
				Collection neighbours = graph.getNeighbors(current);
				if (neighbours == null) {
					throw new IllegalStateException(
							"current node not found in graph. Maybe the hash code of the node changed");
				}
				current = null;
				for (V neighbour : neighbours) {
					if (unused.contains(neighbour)) {
						// continue with the neighbour
						current = neighbour;
						break;
					}
				}
			}

			// predecessors
			current = result.get(0);
			while (current != null) {
				// do not in set the current here, because it is alredy in the
				// list
				Collection neighbours = graph.getNeighbors(current);
				current = null;
				for (V neighbour : neighbours) {
					if (unused.contains(neighbour)) {
						result.add(0, neighbour);
						unused.remove(neighbour);
						// continue with the neighbour
						current = neighbour;
						break;
					}
				}

			}

		}

		return result;
	}

	public boolean isDebugMode() {
		return debugMode;
	}

	public void setDebugMode(boolean debugMode) {
		this.debugMode = debugMode;
	}

	@Override
	protected Set> callImpl(UndirectedGraph... parameters) throws Exception {

		return transform(parameters[0]);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy