import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.stream.Collectors;
public class ReorderingSSM {
private List<List<Double>> matrix;
public ReorderingSSM(List<List<Double>> m) {
matrix = m;
}
public ReorderingSSM() {
}
// Function to generate degree of all the nodes
private List<Double> DegreeGenerator() {
List<Double> degrees = new ArrayList<>();
for (int i = 0; i < matrix.size(); i++) {
double count = 0;
for (int j = 0; j < matrix.get(0).size(); j++) {
count += matrix.get(i).get(j);
}
degrees.add(count);
}
return degrees;
}
// Implementation of Cuthill-Mckee algorithm
private List<Integer> CuthillMckee() {
List<Double> degrees = DegreeGenerator();
List<Double> globalDegree = new ArrayList<>(degrees);
Queue<Integer> Q = new LinkedList<>();
List<Integer> R = new ArrayList<>();
List<Pair<Integer, Double>> notVisited = new ArrayList<>();
for (int i = 0; i < degrees.size(); i++)
notVisited.add(new Pair<>(i, degrees.get(i)));
// Vector notVisited helps in running BFS
// even when there are disjoint graphs
while (!notVisited.isEmpty()) {
int minNodeIndex = 0;
for (int i = 0; i < notVisited.size(); i++) {
if (notVisited.get(i).getValue() < notVisited.get(minNodeIndex).getValue())
minNodeIndex = i;
}
Q.add(notVisited.get(minNodeIndex).getKey());
notVisited.remove(FindIndex(notVisited, notVisited.get(Q.peek()).getKey()));
// Simple BFS
while (!Q.isEmpty()) {
List<Integer> toSort = new ArrayList<>();
for (int i = 0; i < matrix.get(0).size(); i++) {
if (i != Q.peek() && matrix.get(Q.peek()).get(i) == 1
&& FindIndex(notVisited, i) != -1) {
toSort.add(i);
notVisited.remove(FindIndex(notVisited, i));
}
}
toSort.sort(Comparator.comparingDouble(globalDegree::get));
Q.addAll(toSort);
R.add(Q.peek());
Q.poll();
}
}
return R;
}
// Implementation of reverse Cuthill-Mckee algorithm
private List<Integer> ReverseCuthillMckee() {
List<Integer> cuthill = CuthillMckee();
int n = cuthill.size();
if (n % 2 == 0)
n -= 1;
n = n / 2;
for (int i = 0; i <= n; i++) {
int j = cuthill.get(cuthill.size() - 1 - i);
cuthill.set(cuthill.size() - 1 - i, cuthill.get(i));
cuthill.set(i, j);
}
return cuthill;
}
// Helper function to find index of an element in a list of pairs
private int FindIndex(List<Pair<Integer, Double>> a, int x) {
for (int i = 0; i < a.size(); i++) {
if (a.get(i).getKey() == x)
return i;
}
return -1;
}
// Helper function to print a list
private <T> void PrintList(List<T> list) {
System.out.println(list.stream().map(Object::toString).collect(Collectors.joining(" ")));
}
// Driver Code
public static void main(String[] args) {
int num_rows = 10;
List<List<Double>> matrix = new ArrayList<>();
for (int i = 0; i < num_rows; i++) {
List<Double> datai = new ArrayList<>();
for (int j = 0; j < num_rows; j++)
datai.add(0.0);
matrix.add(datai);
}
// This is the test graph,
// check out the above graph photo
matrix.set(0, List.of(0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0));
matrix.set(1, List.of(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0));
matrix.set(2, List.of(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0));
matrix.set(3, List.of(0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0));
matrix.set(4, List.of(0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0));
matrix.set(5, List.of(0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0));
matrix.set(6, List.of(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
matrix.set(7, List.of(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0));
matrix.set(8, List.of(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0));
matrix.set(9, List.of(0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0));
ReorderingSSM m = new ReorderingSSM(matrix);
List<Integer> r = m.ReverseCuthillMckee();
System.out.println("Permutation order of objects: ");
m.PrintList(r);
}
}
class Pair<K, V> {
private final K key;
private final V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}