/* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
package org.jgrapht.experimental.alg.color;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.experimental.alg.*;
public class GreedyColoring<V, E>
extends IntArrayGraphAlgorithm<V, E>
implements ApproximationAlgorithm<Integer, V>
{
public static final int BEST_ORDER = 0;
public static final int NATURAL_ORDER = 1;
public static final int SMALLEST_DEGREE_LAST_ORDER = 2;
public static final int LARGEST_SATURATION_FIRST_ORDER = 3;
private int _order = BEST_ORDER;
/**
* @param g
*/
public GreedyColoring(final Graph<V, E> g)
{
this(g, BEST_ORDER);
}
/**
* @param g
*/
public GreedyColoring(final Graph<V, E> g, final int method)
{
super(g);
_order = method;
}
int color(int [] order)
{
final int [] color = new int[_neighbors.length];
int maxColor = 1;
BitSet usedColors = new BitSet(_neighbors.length);
for (int i = 0; i < _neighbors.length; i++) {
final int v = (order == null) ? i : order[i];
usedColors.clear();
for (int j = 0; j < _neighbors[v].length; j++) {
final int nb = _neighbors[v][j];
if (color[nb] > 0) {
usedColors.set(color[nb]);
}
}
color[v] = usedColors.nextClearBit(1);
if (color[v] > maxColor) {
maxColor = color[v];
}
}
return maxColor;
}
int [] smallestDegreeLastOrder()
{
final int [] order = new int[_neighbors.length];
final int [] degree = new int[_neighbors.length];
final List<List<Integer>> buckets =
new ArrayList<List<Integer>>(_neighbors.length);
int index = _neighbors.length - 1;
for (int i = 0; i < _neighbors.length; i++) {
buckets.add(new ArrayList<Integer>());
degree[i] = _neighbors[i].length;
}
for (int i = 0; i < _neighbors.length; i++) {
buckets.get(degree[i]).add(i);
}
for (int i = 0; i < _neighbors.length; i++) {
while (buckets.get(i).size() > 0) {
final int s = buckets.get(i).size() - 1;
final int vertex = (Integer) buckets.get(i).get(s);
buckets.get(i).remove(s);
degree[vertex] = -1;
order[index--] = vertex;
for (int j = 0; j < _neighbors[vertex].length; j++) {
final int nb = _neighbors[vertex][j];
if (degree[nb] >= 0) {
buckets.get(degree[nb]).remove(new Integer(nb));
degree[nb]--;
buckets.get(degree[nb]).add(nb);
if (degree[nb] < i) {
i = degree[nb];
}
}
}
}
}
return order;
}
int [] largestSaturationFirstOrder()
{
final int [] satur = new int[_neighbors.length];
final int [] buckets = new int[_neighbors.length];
final int [] cumBucketSize = new int[_neighbors.length];
final int [] bucketIndex = new int[_neighbors.length];
int index = 0;
int maxSat = 0;
for (int i = 0; i < _neighbors.length; i++) {
buckets[i] = i;
bucketIndex[i] = i;
}
cumBucketSize[0] = _neighbors.length;
while (index < _neighbors.length) {
while (
(maxSat > 0)
&& (cumBucketSize[maxSat] == cumBucketSize[maxSat - 1]))
{
cumBucketSize[maxSat--] = 0;
}
final int v = buckets[cumBucketSize[maxSat] - 1];
cumBucketSize[maxSat]--;
satur[v] = -1;
index++;
for (int j = 0; j < _neighbors[v].length; j++) {
final int nb = (int) _neighbors[v][j];
final int bi = bucketIndex[nb];
if (satur[nb] >= 0) {
if (bi != (cumBucketSize[satur[nb]] - 1)) {
buckets[bi] = buckets[cumBucketSize[satur[nb]] - 1];
buckets[cumBucketSize[satur[nb]] - 1] = nb;
bucketIndex[nb] = cumBucketSize[satur[nb]] - 1;
bucketIndex[buckets[bi]] = bi;
}
cumBucketSize[satur[nb]]--;
satur[nb]++;
if (cumBucketSize[satur[nb]] == 0) {
cumBucketSize[satur[nb]] =
cumBucketSize[satur[nb] - 1] + 1;
}
if (satur[nb] > maxSat) {
maxSat = satur[nb];
}
}
}
}
Collections.reverse(Arrays.asList(buckets));
return buckets;
}
public Integer getLowerBound(Map<V, Object> optionalData)
{
return 0;
}
public Integer getUpperBound(Map<V, Object> optionalData)
{
switch (_order) {
case BEST_ORDER:
return Math.min(
Math.min(color(null), color(smallestDegreeLastOrder())),
color(largestSaturationFirstOrder()));
case NATURAL_ORDER:
return color(null);
case SMALLEST_DEGREE_LAST_ORDER:
return color(smallestDegreeLastOrder());
case LARGEST_SATURATION_FIRST_ORDER:
return color(largestSaturationFirstOrder());
}
return _neighbors.length;
}
public boolean isExact()
{
return false;
}
}
// End GreedyColoring.java