classycle.graph.PathsFinder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of classycle Show documentation
Show all versions of classycle Show documentation
dependency analysis for specs2
The newest version!
/*
* Copyright (c) 2003-2008, Franz-Josef Elmer, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package classycle.graph;
import java.util.HashSet;
/**
* Class searching for all (or only the shortest) paths between classes
* of a start set and classes of a final set.
*
* @author Franz-Josef Elmer
*/
public class PathsFinder
{
private final VertexCondition _startSetCondition;
private final VertexCondition _finalSetCondition;
private final boolean _shortestPathsOnly;
private final boolean _directPathsOnly;
/**
* Creates an instance for the specified vertex conditions.
* @param startSetCondition Condition defining the start set.
* @param finalSetCondition Condition defining the final set.
* @param shortestPathsOnly if true
only the shortest
* paths are returned.
*/
public PathsFinder(VertexCondition startSetCondition,
VertexCondition finalSetCondition,
boolean shortestPathsOnly)
{
this(startSetCondition, finalSetCondition, shortestPathsOnly, false);
}
/**
* Creates an instance for the specified vertex conditions.
* @param startSetCondition Condition defining the start set.
* @param finalSetCondition Condition defining the final set.
* @param shortestPathsOnly if true
only the shortest
* paths are returned.
* @param directPathsOnly if true
only paths of length 1
* are returned.
*/
public PathsFinder(VertexCondition startSetCondition,
VertexCondition finalSetCondition,
boolean shortestPathsOnly,
boolean directPathsOnly)
{
_startSetCondition = startSetCondition;
_finalSetCondition = finalSetCondition;
_shortestPathsOnly = shortestPathsOnly;
_directPathsOnly = directPathsOnly;
}
public VertexCondition getFinalSetCondition()
{
return _finalSetCondition;
}
public boolean isShortestPathsOnly()
{
return _shortestPathsOnly;
}
public VertexCondition getStartSetCondition()
{
return _startSetCondition;
}
/**
* Finds all paths from the specified start vertices to the vertices
* fullfilling the specified condition.
* @param graph Complete graph.
* @return All vertices including start and end vertices defining the
* subgraph with all paths.
*/
public AtomicVertex[] findPaths(AtomicVertex[] graph)
{
prepareGraph(graph);
HashSet pathVertices = new HashSet();
HashSet currentPath = new HashSet();
for (int i = 0; i < graph.length; i++)
{
AtomicVertex vertex = graph[i];
if (_startSetCondition.isFulfilled(vertex))
{
if (_directPathsOnly)
{
findDirectPaths(vertex, pathVertices);
} else
{
prepareIfFinal(vertex);
int pathLength = calculateShortestPath(vertex, currentPath);
if (pathLength < Integer.MAX_VALUE)
{
vertex.setOrder(pathLength);
followPaths(vertex, pathVertices);
}
}
}
}
return (AtomicVertex[]) pathVertices.toArray(
new AtomicVertex[pathVertices.size()]);
}
private void findDirectPaths(AtomicVertex vertex, HashSet pathVertices)
{
if (_finalSetCondition.isFulfilled(vertex))
{
pathVertices.add(vertex);
} else
{
for (int i = 0, n = vertex.getNumberOfOutgoingArcs(); i < n; i++)
{
Vertex headVertex = vertex.getHeadVertex(i);
if (_finalSetCondition.isFulfilled(headVertex))
{
pathVertices.add(vertex);
pathVertices.add(headVertex);
}
}
}
}
private void prepareGraph(AtomicVertex[] graph)
{
for (int i = 0; i < graph.length; i++)
{
AtomicVertex vertex = graph[i];
prepareVertex(vertex);
for (int j = 0, n = vertex.getNumberOfOutgoingArcs(); j < n; j++)
{
prepareVertex((AtomicVertex) vertex.getHeadVertex(j));
}
}
}
private void prepareVertex(AtomicVertex vertex)
{
vertex.reset();
vertex.setOrder(Integer.MAX_VALUE);
if (_startSetCondition.isFulfilled(vertex))
{
vertex.visit();
}
}
private int calculateShortestPath(AtomicVertex vertex, HashSet currentPath)
{
currentPath.add(vertex);
int shortestPath = Integer.MAX_VALUE;
for (int i = 0, n = vertex.getNumberOfOutgoingArcs(); i < n; i++)
{
AtomicVertex nextVertex = (AtomicVertex) vertex.getHeadVertex(i);
prepareIfFinal(nextVertex);
int pathLength = _startSetCondition.isFulfilled(nextVertex)
? Integer.MAX_VALUE : nextVertex.getOrder();
if (!currentPath.contains(nextVertex) && !nextVertex.isVisited())
{
pathLength = calculateShortestPath(nextVertex, currentPath);
nextVertex.setOrder(pathLength);
nextVertex.visit();
}
shortestPath = Math.min(shortestPath, pathLength);
}
currentPath.remove(vertex);
if (shortestPath < Integer.MAX_VALUE)
{
shortestPath++;
}
return shortestPath;
}
private void prepareIfFinal(AtomicVertex vertex)
{
if (_finalSetCondition.isFulfilled(vertex))
{
vertex.visit();
vertex.setOrder(0);
}
}
private void followPaths(AtomicVertex vertex, HashSet pathVertices)
{
pathVertices.add(vertex);
int shortestPathLength = vertex.getOrder() - 1;
for (int i = 0, n = vertex.getNumberOfOutgoingArcs(); i < n; i++)
{
AtomicVertex nextVertex = (AtomicVertex) vertex.getHeadVertex(i);
int pathLength = nextVertex.getOrder();
if (pathLength < Integer.MAX_VALUE && !pathVertices.contains(nextVertex))
{
if (!_shortestPathsOnly || pathLength == shortestPathLength)
{
pathVertices.add(nextVertex);
if (pathLength > 0)
{
followPaths(nextVertex, pathVertices);
}
}
}
}
}
// private int search(AtomicVertex vertex, HashSet currentPath,
// HashSet pathVertices)
// {
// currentPath.add(vertex);
// boolean found = false;
// int shortestPath = Integer.MAX_VALUE;
// for (int i = 0, n = vertex.getNumberOfOutgoingArcs(); i < n; i++)
// {
// AtomicVertex nextVertex = (AtomicVertex) vertex.getHeadVertex(i);
// int pathLength = nextVertex.getOrder();
// if (!nextVertex.isVisited() && !currentPath.contains(nextVertex))
// {
// pathLength = search(nextVertex, currentPath, pathVertices);
// nextVertex.setOrder(pathLength);
// nextVertex.visit();
// }
// shortestPath = Math.min(shortestPath, pathLength);
// }
// for (int i = 0, n = vertex.getNumberOfOutgoingArcs(); i < n; i++)
// {
// AtomicVertex nextVertex = (AtomicVertex) vertex.getHeadVertex(i);
// int pathLength = nextVertex.getOrder();
// if (pathLength < Integer.MAX_VALUE)
// {
// if (!_shortestPathsOnly || pathLength == shortestPath)
// {
// pathVertices.add(nextVertex);
// }
// }
// }
// currentPath.remove(vertex);
// if (shortestPath < Integer.MAX_VALUE)
// {
// shortestPath++;
// }
// return shortestPath;
// }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy