org.jgrapht.alg.isomorphism.GraphOrdering Maven / Gradle / Ivy
The newest version!
/*
* (C) Copyright 2015-2023, by Fabian Späh and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* See the CONTRIBUTORS.md file distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the
* GNU Lesser General Public License v2.1 or later
* which is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
*
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
*/
package org.jgrapht.alg.isomorphism;
import org.jgrapht.*;
import org.jgrapht.alg.util.*;
import org.jgrapht.util.*;
import java.util.*;
/**
* This class represents the order on the graph vertices. There are also some helper-functions for
* receiving outgoing/incoming edges, etc.
*
* @param the type of the vertices
* @param the type of the edges
*/
final class GraphOrdering
{
private final Graph graph;
private final Map mapVertexToOrder;
private final List mapOrderToVertex;
private final int vertexCount;
private final int[][] outgoingEdges;
private final int[][] incomingEdges;
private final E[] edgeCache;
/**
* if caching is enabled, adjMatrix contains cached information on existing edges, valid values:
*
* - 0 - no cached value
* - 1 - edge exists
* - -1 - no edge exists
*
*/
private final byte[] adjMatrix;
private final boolean cacheEdges;
/**
* @param graph the graph to be ordered
* @param orderByDegree should the vertices be ordered by their degree. This speeds up the VF2
* algorithm.
* @param cacheEdges if true, the class creates a adjacency matrix and two arrays for incoming
* and outgoing edges for fast access.
*/
@SuppressWarnings("unchecked")
public GraphOrdering(Graph graph, boolean orderByDegree, boolean cacheEdges)
{
this.graph = graph;
this.cacheEdges = cacheEdges;
List vertexList = new ArrayList<>(graph.vertexSet());
if (orderByDegree) {
vertexList.sort(VertexDegreeComparator.of(graph));
}
vertexCount = vertexList.size();
mapVertexToOrder = new VertexToIntegerMapping<>(vertexList).getVertexMap();
mapOrderToVertex = vertexList;
if (cacheEdges) {
outgoingEdges = new int[vertexCount][];
incomingEdges = new int[vertexCount][];
edgeCache = (E[]) new Object[vertexCount * vertexCount];
adjMatrix = new byte[vertexCount * vertexCount];
} else {
outgoingEdges = null;
incomingEdges = null;
edgeCache = null;
adjMatrix = null;
}
}
/**
* @param graph the graph to be ordered
*/
public GraphOrdering(Graph graph)
{
this(graph, false, true);
}
/**
* @return returns the number of vertices in the graph.
*/
public int getVertexCount()
{
return this.vertexCount;
}
/**
* @param vertexNumber the number which identifies the vertex $v$ in this order.
*
* @return the identifying numbers of all vertices which are connected to $v$ by an edge
* outgoing from $v$.
*/
public int[] getOutEdges(int vertexNumber)
{
if (cacheEdges && (outgoingEdges[vertexNumber] != null)) {
return outgoingEdges[vertexNumber];
}
V v = getVertex(vertexNumber);
Set edgeSet = graph.outgoingEdgesOf(v);
int[] vertexArray = new int[edgeSet.size()];
int i = 0;
for (E edge : edgeSet) {
V source = graph.getEdgeSource(edge), target = graph.getEdgeTarget(edge);
vertexArray[i++] = mapVertexToOrder.get(source.equals(v) ? target : source);
}
if (cacheEdges) {
outgoingEdges[vertexNumber] = vertexArray;
}
return vertexArray;
}
/**
* @param vertexNumber the number which identifies the vertex $v$ in this order.
*
* @return the identifying numbers of all vertices which are connected to $v$ by an edge
* incoming to $v$.
*/
public int[] getInEdges(int vertexNumber)
{
if (cacheEdges && (incomingEdges[vertexNumber] != null)) {
return incomingEdges[vertexNumber];
}
V v = getVertex(vertexNumber);
Set edgeSet = graph.incomingEdgesOf(v);
int[] vertexArray = new int[edgeSet.size()];
int i = 0;
for (E edge : edgeSet) {
V source = graph.getEdgeSource(edge), target = graph.getEdgeTarget(edge);
vertexArray[i++] = mapVertexToOrder.get(source.equals(v) ? target : source);
}
if (cacheEdges) {
incomingEdges[vertexNumber] = vertexArray;
}
return vertexArray;
}
/**
* @param v1Number the number of the first vertex $v_1$
* @param v2Number the number of the second vertex $v_2$
*
* @return exists the edge from $v_1$ to $v_2$
*/
public boolean hasEdge(int v1Number, int v2Number)
{
int cacheIndex = 0;
if (cacheEdges) {
cacheIndex = v1Number * vertexCount + v2Number;
final byte cache = adjMatrix[cacheIndex];
if (cache != 0) {
return cache > 0;
} else {
// initialize both the adjacency matrix as well as the edge cache
final V v1 = getVertex(v1Number);
final V v2 = getVertex(v2Number);
final E edge = graph.getEdge(v1, v2);
if (edge == null) {
adjMatrix[cacheIndex] = (byte) -1;
return false;
} else {
adjMatrix[cacheIndex] = (byte) 1;
edgeCache[cacheIndex] = edge;
return true;
}
}
}
V v1 = getVertex(v1Number);
V v2 = getVertex(v2Number);
boolean containsEdge = graph.containsEdge(v1, v2);
return containsEdge;
}
/**
* be careful: there's no check against an invalid vertexNumber
*
* @param vertexNumber the number identifying the vertex $v$
*
* @return $v$
*/
public V getVertex(int vertexNumber)
{
return mapOrderToVertex.get(vertexNumber);
}
/**
* @param v1Number the number identifying the vertex $v_1$
* @param v2Number the number identifying the vertex $v_2$
*
* @return the edge from $v_1$ to $v_2$
*/
public E getEdge(int v1Number, int v2Number)
{
if (cacheEdges) {
final int cacheIndex = v1Number * vertexCount + v2Number;
final byte containsEdge = adjMatrix[cacheIndex];
if (containsEdge == 0) {
// edge cache has not been initialized yet for this element
hasEdge(v1Number, v2Number);
}
final E edge = edgeCache[cacheIndex];
return edge;
}
V v1 = getVertex(v1Number), v2 = getVertex(v2Number);
E edge = graph.getEdge(v1, v2);
return edge;
}
public int getVertexNumber(V v)
{
return mapVertexToOrder.get(v);
}
public int[] getEdgeNumbers(E e)
{
V v1 = graph.getEdgeSource(e), v2 = graph.getEdgeTarget(e);
int[] edge = new int[2];
edge[0] = mapVertexToOrder.get(v1);
edge[1] = mapVertexToOrder.get(v2);
return edge;
}
public Graph getGraph()
{
return graph;
}
}