Algoritmo inverso de Cuthill Mckee

El algoritmo Cuthill-Mckee se utiliza para reordenar una array cuadrada simétrica. Se basa en el algoritmo Breadth First Search de un gráfico, cuya array de adyacencia es la versión dispersa de la array cuadrada de entrada.
El ordenamiento se usa frecuentemente cuando se va a generar una array cuyas filas y columnas se numeran de acuerdo con la numeración de los Nodes. Mediante una renumeración adecuada de los Nodes, a menudo es posible producir una array con un ancho de banda mucho más pequeño . 

La versión dispersa de una array es una array en la que la mayoría de los elementos son cero.
El Algoritmo Cuthill-Mckee Inverso es el mismo que el algoritmo Cuthill-Mckee , la única diferencia es que los índices finales obtenidos usando el algoritmo Cuthill-Mckee están invertidos en el Algoritmo Cuthill-Mckee Inverso.

A continuación se muestran los pasos del algoritmo Reverse Cuthill-Mckee: 

  1. Instancia una cola vacía Q y una array vacía para el orden de permutación de los objetos R .
  2. S1: primero encontramos el objeto con grado mínimo cuyo índice aún no se ha agregado a R . Digamos que el objeto correspondiente a la p-ésima fila ha sido identificado como el objeto con un grado mínimo. Añadir p a R. _
  3. S2: como un índice se agrega a R , y se agregan todos los vecinos del objeto correspondiente en el índice, 
    en orden creciente de grado, a Q . Los vecinos son Nodes con valor distinto de cero entre los elementos no diagonales en la p-ésima fila.
  4. S3: extraiga el primer Node en Q , digamos C. Si C no se ha insertado en R , agréguelo a R , agregue a Q los vecinos de C en orden creciente de grado.
  5. S4: Si Q no está vacío, repita S3 .
  6. S5: Si Q está vacío, pero hay objetos en la array que no se han incluido en R , comience desde S1 , una vez más. (Esto podría suceder si hay gráficos disjuntos)
  7. S6: Termine este algoritmo una vez que todos los objetos estén incluidos en R .
  8. S7: Finalmente, invierta los índices en R , es decir ( swap(R[i], R[P-i+1]) ).

Grado: la definición de un grado no es constante, cambia según el conjunto de datos con el que esté trabajando. Para el ejemplo dado a continuación, el grado de un Node se define como la suma de elementos no diagonales en la fila correspondiente.

La definición generalizada del grado de un Node ‘A’ es el número de Nodes conectados a ‘A’. 

Ejemplo: 

Given a symmetric matrix:  
| 0.0    0.78    0.79    0.8     0.23  |
| 0.9    0.0     0.43    0.771   0.752 |
| 0.82   0.0     0.0     0.79    0.34  |
| 0.8    0.8     0.8     0.0     0.8   |
| 0.54   0.97    0.12    0.78    0.0   | 

Degree here is defined as sum of non-diagonal 
elements in the corresponding row.
Specification for a matrix is defined as, 
if the element of the matrix at i, j has a value 
less than 0.75 its made to 0 otherwise its made to 1.

Array después de la especificación

Degree of node 0 = 2.6
Degree of node 1 = 2.803
Degree of node 2 = 2.55
Degree of node 3 = 3.2
Degree of node 4 = 2.41

Permutation order of objects (R) : 0 2 1 3 4

El nuevo orden de permutación es simplemente el orden de los Nodes, es decir, convertir el Node ‘R[i]’ en el Node ‘i’. 
Por lo tanto, convierta el Node ‘R[0] = 0’, a 0; Node ‘R[1] = 2’, a 1; Node ‘R[2] = 1’, a 2; Node ‘R[3] = 3’, a 3; y Node ‘R[4] = 4’, a 4;
Tomemos un ejemplo más grande para entender el resultado del reordenamiento: 

Give a adjacency matrix : 

| 0   1   0   0   0   0   1   0   1   0 |
| 1   0   0   0   1   0   1   0   0   1 |
| 0   0   0   0   1   0   1   0   0   0 |
| 0   0   0   0   1   1   0   0   1   0 |
| 0   1   1   1   0   1   0   0   0   1 | 
| 0   0   0   1   1   0   0   0   0   0 |
| 1   1   1   0   0   0   0   0   0   0 |
| 0   0   0   0   0   0   0   0   1   1 |
| 1   0   0   1   0   0   0   1   0   0 |
| 0   1   0   0   1   0   0   1   0   0 | 

Degree of node 'A' is defined as number of 
nodes connected to 'A'

Output : 
Permutation order of objects (R) : 
7 8 9 3 5 1 0 4 6 2

Ahora convierta el Node ‘R[i]’ en el Node ‘i’ 
Entonces el gráfico se convierte en: 
 

El resultado de la reordenación se puede ver en la array de adyacencia de los dos gráficos: 
 

Original Matrix

array original

Array reordenada RCM

Desde aquí podemos ver claramente cómo el algoritmo de Cuthill-Mckee ayuda a reordenar una array cuadrada en una array no distribuida.

A continuación se muestra la implementación del algoritmo anterior. Tomando la definición general de grado. 

C++

// C++ program for Implementation of
// Reverse Cuthill Mckee Algorithm
 
#include <bits/stdc++.h>
using namespace std;
 
vector<double> globalDegree;
 
int findIndex(vector<pair<int, double> > a, int x)
{
    for (int i = 0; i < a.size(); i++)
        if (a[i].first == x)
            return i;
    return -1;
}
 
bool compareDegree(int i, int j)
{
    return ::globalDegree[i] < ::globalDegree[j];
}
 
template <typename T>
ostream& operator<<(ostream& out, vector<T> const& v)
{
    for (int i = 0; i < v.size(); i++)
        out << v[i] << ' ';
    return out;
}
 
class ReorderingSSM {
private:
    vector<vector<double> > _matrix;
 
public:
    // Constructor and Destructor
    ReorderingSSM(vector<vector<double> > m)
    {
        _matrix = m;
    }
 
    ReorderingSSM() {}
    ~ReorderingSSM() {}
 
    // class methods
 
    // Function to generate degree of all the nodes
    vector<double> degreeGenerator()
    {
 
        vector<double> degrees;
 
        for (int i = 0; i < _matrix.size(); i++) {
            double count = 0;
            for (int j = 0; j < _matrix[0].size(); j++) {
                count += _matrix[i][j];
            }
 
            degrees.push_back(count);
        }
 
        return degrees;
    }
 
    // Implementation of Cuthill-Mckee algorithm
    vector<int> CuthillMckee()
    {
        vector<double> degrees = degreeGenerator();
 
        ::globalDegree = degrees;
 
        queue<int> Q;
        vector<int> R;
        vector<pair<int, double> > notVisited;
 
        for (int i = 0; i < degrees.size(); i++)
            notVisited.push_back(make_pair(i, degrees[i]));
 
        // Vector notVisited helps in running BFS
        // even when there are dijoind graphs
        while (notVisited.size()) {
 
            int minNodeIndex = 0;
 
            for (int i = 0; i < notVisited.size(); i++)
                if (notVisited[i].second < notVisited[minNodeIndex].second)
                    minNodeIndex = i;
 
            Q.push(notVisited[minNodeIndex].first);
 
            notVisited.erase(notVisited.begin()
                                    + findIndex(notVisited,
                                                notVisited[Q.front()].first));
 
            // Simple BFS
            while (!Q.empty()) {
 
                vector<int> toSort;
 
                for (int i = 0; i < _matrix[0].size(); i++) {
                    if (i != Q.front() && _matrix[Q.front()][i] == 1
                        && findIndex(notVisited, i) != -1) {
                        toSort.push_back(i);
                        notVisited.erase(notVisited.begin()
                                           + findIndex(notVisited, i));
                    }
                }
 
                sort(toSort.begin(), toSort.end(), compareDegree);
 
                for (int i = 0; i < toSort.size(); i++)
                    Q.push(toSort[i]);
 
                R.push_back(Q.front());
                Q.pop();
            }
        }
 
        return R;
    }
 
    // Implementation of reverse Cuthill-Mckee algorithm
    vector<int> ReverseCuthillMckee()
    {
 
        vector<int> 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[cuthill.size() - 1 - i];
            cuthill[cuthill.size() - 1 - i] = cuthill[i];
            cuthill[i] = j;
        }
 
        return cuthill;
    }
};
 
// Driver Code
int main()
{
    int num_rows = 10;
 
    vector<vector<double> > matrix;
 
    for (int i = 0; i < num_rows; i++) {
        vector<double> datai;
 
        for (int j = 0; j < num_rows; j++)
            datai.push_back(0.0);
 
        matrix.push_back(datai);
    }
 
    // This is the test graph,
    // check out the above graph photo
    matrix[0] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0 };
    matrix[1] = { 1, 0, 0, 0, 1, 0, 1, 0, 0, 1 };
    matrix[2] = { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 };
    matrix[3] = { 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 };
    matrix[4] = { 0, 1, 1, 1, 0, 1, 0, 0, 0, 1 };
    matrix[5] = { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 };
    matrix[6] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
    matrix[7] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
    matrix[8] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 0 };
    matrix[9] = { 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 };
 
    ReorderingSSM m(matrix);
 
    vector<int> r = m.ReverseCuthillMckee();
 
    cout << "Permutation order of objects: " << r << endl;
 
    return 0;
}

Python3

# C++ program for Implementation of
# Reverse Cuthill Mckee Algorithm
from collections import deque as Queue
 
globalDegree = []
 
 
def findIndex(a, x):
    for i in range(len(a)):
        if a[i][0] == x:
            return i
    return -1
 
 
class ReorderingSSM:
    __matrix = []
    # Constructor and Destructor
    def __init__(self, m):
        self.__matrix = m
 
    # class methods
 
    # Function to generate degree of all the nodes
    def degreeGenerator(self):
 
        degrees = []
 
        for i in range(len(self.__matrix)):
            count = 0
            for j in range(len(self.__matrix[0])):
                count += self.__matrix[i][j]
 
            degrees.append(count)
 
        return degrees
 
    # Implementation of Cuthill-Mckee algorithm
    def CuthillMckee(self):
        global globalDegree
        degrees = self.degreeGenerator()
 
        globalDegree = degrees
 
        Q = Queue()
        R = []
        notVisited = []
 
        for i in range(len(degrees)):
            notVisited.append((i, degrees[i]))
 
        # Vector notVisited helps in running BFS
        # even when there are dijoind graphs
        while len(notVisited):
 
            minNodeIndex = 0
 
            for i in range(len(notVisited)):
                if notVisited[i][1] < notVisited[minNodeIndex][1]:
                    minNodeIndex = i
 
            Q.append(notVisited[minNodeIndex][0])
 
            notVisited.pop(findIndex(notVisited, notVisited[Q[0]][0]))
 
            # Simple BFS
            while Q:
 
                toSort = []
 
                for i in range(len(self.__matrix[0])):
                    if (
                        i != Q[0]
                        and self.__matrix[Q[0]][i] == 1
                        and findIndex(notVisited, i) != -1
                    ):
                        toSort.append(i)
                        notVisited.pop(findIndex(notVisited, i))
 
                toSort.sort(key=lambda x: globalDegree[x])
 
                for i in range(len(toSort)):
                    Q.append(toSort[i])
 
                R.append(Q[0])
                Q.popleft()
 
        return R
 
    # Implementation of reverse Cuthill-Mckee algorithm
    def ReverseCuthillMckee(self):
 
        cuthill = self.CuthillMckee()
 
        n = len(cuthill)
 
        if n % 2 == 0:
            n -= 1
 
        n = n // 2
 
        for i in range(n + 1):
            j = cuthill[len(cuthill) - 1 - i]
            cuthill[len(cuthill) - 1 - i] = cuthill[i]
            cuthill[i] = j
 
        return cuthill
 
 
# Driver Code
if __name__ == "__main__":
    num_rows = 10
 
    matrix = [[0.0] * num_rows for _ in range(num_rows)]
 
    # This is the test graph,
    # check out the above graph photo
    matrix[0] = [0, 1, 0, 0, 0, 0, 1, 0, 1, 0]
    matrix[1] = [1, 0, 0, 0, 1, 0, 1, 0, 0, 1]
    matrix[2] = [0, 0, 0, 0, 1, 0, 1, 0, 0, 0]
    matrix[3] = [0, 0, 0, 0, 1, 1, 0, 0, 1, 0]
    matrix[4] = [0, 1, 1, 1, 0, 1, 0, 0, 0, 1]
    matrix[5] = [0, 0, 0, 1, 1, 0, 0, 0, 0, 0]
    matrix[6] = [1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
    matrix[7] = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1]
    matrix[8] = [1, 0, 0, 1, 0, 0, 0, 1, 0, 0]
    matrix[9] = [0, 1, 0, 0, 1, 0, 0, 1, 0, 0]
 
    m = ReorderingSSM(matrix)
 
    r = m.ReverseCuthillMckee()
 
    print("Permutation order of objects:", r)
Producción

Permutation order of objects: 7 8 9 3 5 1 0 4 6 2 

Referencia : https://en.wikipedia.org/wiki/Cuthill%E2%80%93McKee_algorithm
 

Publicación traducida automáticamente

Artículo escrito por Ronak_Doshi y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *