com.salesforce.jgrapht.generate.PruferTreeGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of AptSpringProcessor Show documentation
Show all versions of AptSpringProcessor Show documentation
This project contains the apt processor that implements all the checks enumerated in @Verify. It is a self contained, and
shaded jar.
The newest version!
/*
* (C) Copyright 2018-2018, by Alexandru Valeanu 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 com.salesforce.jgrapht.generate;
import com.salesforce.jgrapht.*;
import java.util.*;
/**
* Generates a random tree using Prüfer sequences.
*
*
* A Prüfer sequence of length $n$ is randomly generated and converted into the corresponding tree.
*
*
*
* This implementation is inspired by "X. Wang, L. Wang and Y. Wu, "An Optimal Algorithm for Prufer
* Codes," Journal of Software Engineering and Applications, Vol. 2 No. 2, 2009, pp. 111-115. doi:
* 10.4236/jsea.2009.22016." and has a running time of $O(n)$.
*
*
* @param the graph vertex type
* @param the graph edge type
*
* @author Alexandru Valeanu
*/
public class PruferTreeGenerator
implements
GraphGenerator
{
// number of vertices
private final int n;
// random number generator
private final Random rng;
// input Prufer sequence
private final int[] inputPruferSeq;
/**
* Construct a new PruferTreeGenerator from an input Prüfer sequence. Note that the size of the
* generated tree will be $l+2$ where $l$ is the length of the input sequence. The Prüfer
* sequence must contain integers between $0$ and $l+1$ (inclusive).
*
* Note: In this case, the same tree will be generated every time.
*
* @param pruferSequence the input Prüfer sequence
* @throws IllegalArgumentException if {@code n} is ≤ 0
* @throws IllegalArgumentException if {@code pruferSequence} is {@code null}
* @throws IllegalArgumentException if {@code pruferSequence} is invalid.
*/
public PruferTreeGenerator(int[] pruferSequence)
{
if (Objects.isNull(pruferSequence)) {
throw new IllegalArgumentException("pruferSequence cannot be null");
}
this.n = pruferSequence.length + 2;
this.rng = null;
this.inputPruferSeq = pruferSequence.clone();
if (n <= 0) {
throw new IllegalArgumentException("n must be greater than 0");
}
for (int i = 0; i < n - 2; i++) {
if (pruferSequence[i] < 0 || pruferSequence[i] >= n) {
throw new IllegalArgumentException("invalid pruferSequence");
}
}
}
/**
* Construct a new PruferTreeGenerator.
*
* @param n number of vertices to be generated
* @throws IllegalArgumentException if {@code n} is ≤ 0
*/
public PruferTreeGenerator(int n)
{
this(n, new Random());
}
/**
* Construct a new PruferTreeGenerator.
*
* @param n number of vertices to be generated
* @param seed seed for the random number generator
* @throws IllegalArgumentException if {@code n} is ≤ 0
*/
public PruferTreeGenerator(int n, long seed)
{
this(n, new Random(seed));
}
/**
* Construct a new PruferTreeGenerator
*
* @param n number of vertices to be generated
* @param rng the random number generator to use
* @throws IllegalArgumentException if {@code n} is ≤ 0
* @throws NullPointerException if {@code rng} is {@code null}
*/
public PruferTreeGenerator(int n, Random rng)
{
if (n <= 0) {
throw new IllegalArgumentException("n must be greater than 0");
}
this.n = n;
this.rng = Objects.requireNonNull(rng, "Random number generator cannot be null");
this.inputPruferSeq = null;
}
/**
* Generates a tree.
*
*
* Note: An exception will be thrown if the target graph is not empty (i.e. contains at least
* one vertex)
*
*
* @param target the target graph
* @param resultMap not used by this generator, can be null
* @throws NullPointerException if {@code target} is {@code null}
* @throws IllegalArgumentException if {@code target} is not undirected
* @throws IllegalArgumentException if {@code target} is not empty
*/
@Override
public void generateGraph(Graph target, Map resultMap)
{
GraphTests.requireUndirected(target);
if (!target.vertexSet().isEmpty()) {
throw new IllegalArgumentException("target graph is not empty");
}
List vertexList = new ArrayList<>(n);
// add vertices
for (int i = 0; i < n; i++) {
vertexList.add(target.addVertex());
}
// base case
if (n == 1) {
return;
}
// degree stores the remaining degree (plus one) for each node. The
// degree of a node in the decoded tree is one more than the number
// of times it appears in the code.
int[] degree = new int[n];
Arrays.fill(degree, 1);
int[] pruferSeq;
if (inputPruferSeq == null) {
pruferSeq = new int[n - 2];
for (int i = 0; i < n - 2; i++) {
pruferSeq[i] = rng.nextInt(n);
++degree[pruferSeq[i]];
}
} else {
pruferSeq = inputPruferSeq;
}
int index = -1;
for (int k = 0; k < n; k++) {
if (degree[k] == 1) {
index = k;
break;
}
}
assert index != -1;
int x = index;
// set of nodes without a parent
Set orphans = new HashSet<>(target.vertexSet());
for (int i = 0; i < n - 2; i++) {
int y = pruferSeq[i];
orphans.remove(vertexList.get(x));
target.addEdge(vertexList.get(x), vertexList.get(y));
--degree[y];
if (y < index && degree[y] == 1) {
x = y;
} else {
for (int k = index + 1; k < n; k++) {
if (degree[k] == 1) {
index = x = k;
break;
}
}
}
}
assert orphans.size() == 2;
Iterator iterator = orphans.iterator();
V u = iterator.next();
V v = iterator.next();
target.addEdge(u, v);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy