Implementando el Algoritmo de Strassen en Java

El algoritmo de Strassen se usa para la multiplicación de arrays cuadradas, es decir, el orden de las arrays debe ser (N x N). El Algoritmo de Strassen se basa en la técnica de divide y vencerás . En términos más simples, se utiliza para la multiplicación de arrays. El método de multiplicación de arrays de Strassen es un algoritmo típico de divide y vencerás. Sin embargo, volvamos a lo que hay detrás del enfoque divide y vencerás e impleméntalo considerando una ilustración como la siguiente. Por ejemplo: Sean A y B dos arrays, entonces la array resultante C tal que 

Array C = Array A * Array B

Considere por ahora que el cálculo matemático de arrays es que se puede concluir por qué entra en juego la implementación de las arrays de Strassen. Supongamos que dos arrays se operan para ser multiplicadas, entonces el enfoque habría sido

  1. Tome la entrada de dos arrays.
  2. Compruebe la compatibilidad de la multiplicación de arrays, que es válida solo y solo si el número de filas de la primera array es igual al número de columnas de la segunda array.
  3. Multiplique la array y asigne la multiplicación de dos arrays a otra array conocida como array resultante.
  4. Imprime la array resultante.

En el enfoque anterior, se trazan dos supuestos que muestran por qué surge la necesidad del algoritmo de Strassen.

  • En primer lugar, la complejidad temporal del algoritmo es O(n 3 ), que es demasiado alta.
  • En segundo lugar, la multiplicación de más de dos arrays no solo aumentará la confusión y la complejidad del programa, sino que también aumentará la complejidad del tiempo en consecuencia.

Objetivo:

Volker Strassen es un nombre que publicó su algoritmo para demostrar que la complejidad temporal O(n 3 ) de la multiplicación general de arrays no era óptima. Así se publicó la multiplicación de strings de arrays de Strassen y se redujo la complejidad del tiempo. Este algoritmo es más rápido que la multiplicación de arrays estándar y es útil cuando se calculan numerosas multiplicaciones de arrays grandes en el mundo cotidiano.

Algoritmo de Strassen para la multiplicación de arrays

Paso 1: Tome tres arrays para suponer A, B, C donde C es la array resultante y A y B son arrays que se multiplicarán utilizando el método de Strassen.

Paso 2: divida la array A, B, C en cuatro arrays (n/2) × (n/2) y tome la primera parte de cada una como se muestra a continuación

Paso 3: Use las fórmulas a continuación para resolver la parte 1 de la array

M1:=(A1+A3)×(B1+B2)
M2:=(A2+A4)×(B3+B4)
M3:=(A1−A4)×(B1+A4)
M4:=A1×(B2−B4)
M5:=(A3+A4)×(B1)
M6:=(A1+A2)×(B4)
M7:=A4×(B3−B1)

Then,

P:=M2+M3−M6−M7
Q:=M4+M6
R:=M5+M7
S:=M1−M3−M4−M5

Paso 4: después de resolver la primera parte, calcule la segunda, la tercera y la cuarta, y además del resultado final, se genera una array multiplicada como resultado, como se muestra en la imagen de arriba.

Paso 5: Imprime la array resultante.

Implementación: 

Ejemplo

Java

// Java Program to Implement Strassen Algorithm
 
// Class Strassen matrix multiplication
public class GFG {
 
    // Method 1
    // Function to multiply matrices
    public int[][] multiply(int[][] A, int[][] B)
    {
        // Order of matrix
        int n = A.length;
 
        // Creating a 2D square matrix with size n
        // n is input from the user
        int[][] R = new int[n][n];
 
        // Base case
        // If there is only single element
        if (n == 1)
 
            // Returning the simple multiplication of
            // two elements in matrices
            R[0][0] = A[0][0] * B[0][0];
 
        // Matrix
        else {
            // Step 1: Dividing Matrix into parts
            // by storing sub-parts to variables
            int[][] A11 = new int[n / 2][n / 2];
            int[][] A12 = new int[n / 2][n / 2];
            int[][] A21 = new int[n / 2][n / 2];
            int[][] A22 = new int[n / 2][n / 2];
            int[][] B11 = new int[n / 2][n / 2];
            int[][] B12 = new int[n / 2][n / 2];
            int[][] B21 = new int[n / 2][n / 2];
            int[][] B22 = new int[n / 2][n / 2];
 
            // Step 2: Dividing matrix A into 4 halves
            split(A, A11, 0, 0);
            split(A, A12, 0, n / 2);
            split(A, A21, n / 2, 0);
            split(A, A22, n / 2, n / 2);
 
            // Step 2: Dividing matrix B into 4 halves
            split(B, B11, 0, 0);
            split(B, B12, 0, n / 2);
            split(B, B21, n / 2, 0);
            split(B, B22, n / 2, n / 2);
 
            // Using Formulas as described in algorithm
 
            // M1:=(A1+A3)×(B1+B2)
            int[][] M1
                = multiply(add(A11, A22), add(B11, B22));
           
            // M2:=(A2+A4)×(B3+B4)
            int[][] M2 = multiply(add(A21, A22), B11);
           
            // M3:=(A1−A4)×(B1+A4)
            int[][] M3 = multiply(A11, sub(B12, B22));
           
            // M4:=A1×(B2−B4)
            int[][] M4 = multiply(A22, sub(B21, B11));
           
            // M5:=(A3+A4)×(B1)
            int[][] M5 = multiply(add(A11, A12), B22);
           
            // M6:=(A1+A2)×(B4)
            int[][] M6
                = multiply(sub(A21, A11), add(B11, B12));
           
            // M7:=A4×(B3−B1)
            int[][] M7
                = multiply(sub(A12, A22), add(B21, B22));
 
            // P:=M2+M3−M6−M7
            int[][] C11 = add(sub(add(M1, M4), M5), M7);
           
            // Q:=M4+M6
            int[][] C12 = add(M3, M5);
           
            // R:=M5+M7
            int[][] C21 = add(M2, M4);
           
            // S:=M1−M3−M4−M5
            int[][] C22 = add(sub(add(M1, M3), M2), M6);
 
            // Step 3: Join 4 halves into one result matrix
            join(C11, R, 0, 0);
            join(C12, R, 0, n / 2);
            join(C21, R, n / 2, 0);
            join(C22, R, n / 2, n / 2);
        }
 
        // Step 4: Return result
        return R;
    }
 
    // Method 2
    // Function to subtract two matrices
    public int[][] sub(int[][] A, int[][] B)
    {
        //
        int n = A.length;
 
        //
        int[][] C = new int[n][n];
 
        // Iterating over elements of 2D matrix
        // using nested for loops
 
        // Outer loop for rows
        for (int i = 0; i < n; i++)
 
            // Inner loop for columns
            for (int j = 0; j < n; j++)
 
                // Subtracting corresponding elements
                // from matrices
                C[i][j] = A[i][j] - B[i][j];
 
        // Returning the resultant matrix
        return C;
    }
 
    // Method 3
    // Function to add two matrices
    public int[][] add(int[][] A, int[][] B)
    {
 
        //
        int n = A.length;
 
        // Creating a 2D square matrix
        int[][] C = new int[n][n];
 
        // Iterating over elements of 2D matrix
        // using nested for loops
 
        // Outer loop for rows
        for (int i = 0; i < n; i++)
 
            // Inner loop for columns
            for (int j = 0; j < n; j++)
 
                // Adding corresponding elements
                // of matrices
                C[i][j] = A[i][j] + B[i][j];
 
        // Returning the resultant matrix
        return C;
    }
 
    // Method 4
    // Function to split parent matrix
    // into child matrices
    public void split(int[][] P, int[][] C, int iB, int jB)
    {
        // Iterating over elements of 2D matrix
        // using nested for loops
 
        // Outer loop for rows
        for (int i1 = 0, i2 = iB; i1 < C.length; i1++, i2++)
 
            // Inner loop for columns
            for (int j1 = 0, j2 = jB; j1 < C.length;
                 j1++, j2++)
 
                C[i1][j1] = P[i2][j2];
    }
 
    // Method 5
    // Function to join child matrices
    // into (to) parent matrix
    public void join(int[][] C, int[][] P, int iB, int jB)
 
    {
        // Iterating over elements of 2D matrix
        // using nested for loops
 
        // Outer loop for rows
        for (int i1 = 0, i2 = iB; i1 < C.length; i1++, i2++)
 
            // Inner loop for columns
            for (int j1 = 0, j2 = jB; j1 < C.length;
                 j1++, j2++)
 
                P[i2][j2] = C[i1][j1];
    }
 
    // Method 5
    // Main driver method
    public static void main(String[] args)
    {
        // Display message
        System.out.println(
            "Strassen Multiplication Algorithm Implementation For Matrix Multiplication :\n");
 
        // Create an object of Strassen class
        // in he main function
        GFG s = new GFG();
 
        // Size of matrix
        // Considering size as 4 in order to illustrate
        int N = 4;
 
        // Matrix A
        // Custom input to matrix
        int[][] A = { { 1, 2, 3, 4 },
                      { 4, 3, 0, 1 },
                      { 5, 6, 1, 1 },
                      { 0, 2, 5, 6 } };
 
        // Matrix B
        // Custom input to matrix
        int[][] B = { { 1, 0, 5, 1 },
                      { 1, 2, 0, 2 },
                      { 0, 3, 2, 3 },
                      { 1, 2, 1, 2 } };
 
        // Matrix C computations
 
        // Matrix C calling method to get Result
        int[][] C = s.multiply(A, B);
 
        // Display message
        System.out.println(
            "\nProduct of matrices A and  B : ");
 
        // Iterating over elements of 2D matrix
        // using nested for loops
 
        // Outer loop for rows
        for (int i = 0; i < N; i++) {
            // Inner loop for columns
            for (int j = 0; j < N; j++)
 
                // Printing elements of resultant matrix
                // with whitespaces in between
                System.out.print(C[i][j] + " ");
 
            // New line once the all elements
            // are printed for specific row
            System.out.println();
        }
    }
}
Producción

Strassen Multiplication Algorithm Implementation For Matrix Multiplication :


Product of arrays A and  B : 
7 21 15 22 
8 8 21 12 
12 17 28 22 
8 31 16 31 

 Complejidad temporal del método de Strassen

Por análisis, la función de complejidad temporal se puede escribir como: 

T(N) = 7T(N/2) +  O(N2)

Resolviendo esto usando el Teorema Maestro obtenemos: 

T(n)=O(nlog7)

Por lo tanto, el tiempo Complejidad del algoritmo de Strassen para la multiplicación de arrays se deriva como: 

O(nlog7) = O (n2.81)

O(n 3 ) Vs O(n 2.81)

Publicación traducida automáticamente

Artículo escrito por jagroopofficial 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 *