diff --git a/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java b/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java index ee5ad9c9..365eb48c 100644 --- a/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java +++ b/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java @@ -1,22 +1,39 @@ package com.thealgorithms.divideandconquer; +// Java Program to Implement Binary Exponentiation (power in log n) + +/* + * Binary Exponentiation is a method to calculate a to the power of b. + * It is used to calculate a^n in O(log n) time. + * + * Reference: + * https://iq.opengenus.org/binary-exponentiation/ + */ + public class BinaryExponentiation { - public static void main(String args[]) { - System.out.println(calculatePower(2, 30)); - } - - // Function to calculate x^y - // Time Complexity: O(logn) + // recursive function to calculate a to the power of b public static long calculatePower(long x, long y) { if (y == 0) { return 1; } long val = calculatePower(x, y / 2); - val *= val; - if (y % 2 == 1) { - val *= x; + if (y % 2 == 0) { + return val * val; } - return val; + return val * val * x; + } + + // iterative function to calculate a to the power of b + long power(long N, long M) { + long power = N, sum = 1; + while (M > 0) { + if ((M & 1) == 1) { + sum *= power; + } + power = power * power; + M = M >> 1; + } + return sum; } } diff --git a/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java b/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java index 1ea4f1ae..7fe4fe18 100644 --- a/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java +++ b/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java @@ -1,10 +1,22 @@ package com.thealgorithms.divideandconquer; -// Java Program to Implement Strassen Algorithm -// Class Strassen matrix multiplication +// Java Program to Implement Strassen Algorithm for Matrix Multiplication + +/* + * Uses the divide and conquer approach to multiply two matrices. + * Time Complexity: O(n^2.8074) better than the O(n^3) of the standard matrix multiplication algorithm. + * Space Complexity: O(n^2) + * + * This Matrix multiplication can be performed only on square matrices + * where n is a power of 2. Order of both of the matrices are n × n. + * + * Reference: + * https://www.tutorialspoint.com/design_and_analysis_of_algorithms/design_and_analysis_of_algorithms_strassens_matrix_multiplication.htm#:~:text=Strassen's%20Matrix%20multiplication%20can%20be,matrices%20are%20n%20%C3%97%20n. + * https://www.geeksforgeeks.org/strassens-matrix-multiplication/ + */ + public class StrassenMatrixMultiplication { - // Method 1 // Function to multiply matrices public int[][] multiply(int[][] A, int[][] B) { int n = A.length; @@ -80,7 +92,6 @@ public class StrassenMatrixMultiplication { return R; } - // Method 2 // Function to subtract two matrices public int[][] sub(int[][] A, int[][] B) { int n = A.length; @@ -96,7 +107,6 @@ public class StrassenMatrixMultiplication { return C; } - // Method 3 // Function to add two matrices public int[][] add(int[][] A, int[][] B) { int n = A.length; @@ -112,9 +122,7 @@ public class StrassenMatrixMultiplication { return C; } - // Method 4 - // Function to split parent matrix - // into child matrices + // Function to split parent matrix into child matrices public void split(int[][] P, int[][] C, int iB, int jB) { for (int i1 = 0, i2 = iB; i1 < C.length; i1++, i2++) { for (int j1 = 0, j2 = jB; j1 < C.length; j1++, j2++) { @@ -123,9 +131,7 @@ public class StrassenMatrixMultiplication { } } - // Method 5 - // Function to join child matrices - // into (to) parent matrix + // Function to join child matrices into (to) parent matrix public void join(int[][] C, int[][] P, int iB, int jB) { for (int i1 = 0, i2 = iB; i1 < C.length; i1++, i2++) { for (int j1 = 0, j2 = jB; j1 < C.length; j1++, j2++) { @@ -134,49 +140,4 @@ public class StrassenMatrixMultiplication { } } - // Method 5 - // Main driver method - public static void main(String[] args) { - System.out.println( - "Strassen Multiplication Algorithm Implementation For Matrix Multiplication :\n" - ); - - StrassenMatrixMultiplication s = new StrassenMatrixMultiplication(); - - // Size of matrix - // Considering size as 4 in order to illustrate - int N = 4; - - // Matrix A - // Custom input to matrix - int[][] A = { - { 1, 2, 5, 4 }, - { 9, 3, 0, 6 }, - { 4, 6, 3, 1 }, - { 0, 2, 0, 6 }, - }; - - // Matrix B - // Custom input to matrix - int[][] B = { - { 1, 0, 4, 1 }, - { 1, 2, 0, 2 }, - { 0, 3, 1, 3 }, - { 1, 8, 1, 2 }, - }; - - // Matrix C computations - // Matrix C calling method to get Result - int[][] C = s.multiply(A, B); - - System.out.println("\nProduct of matrices A and B : "); - - // Print the output - for (int i = 0; i < N; i++) { - for (int j = 0; j < N; j++) { - System.out.print(C[i][j] + " "); - } - System.out.println(); - } - } } diff --git a/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java b/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java new file mode 100644 index 00000000..df9cce34 --- /dev/null +++ b/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java @@ -0,0 +1,39 @@ +package com.thealgorithms.divideandconquer; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class BinaryExponentiationTest { + + @Test + public void testCalculatePower() { + assertEquals(1, BinaryExponentiation.calculatePower(1, 10000000)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 100000000)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 1000000000)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 10000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 100000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 1000000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 10000000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 100000000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 1000000000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 10000000000000000L)); + assertEquals(1, BinaryExponentiation.calculatePower(1, 100000000000000000L)); + } + + @Test + public void testPower() { + assertEquals(1, new BinaryExponentiation().power(1, 10000000)); + assertEquals(1, new BinaryExponentiation().power(1, 100000000)); + assertEquals(1, new BinaryExponentiation().power(1, 1000000000)); + assertEquals(1, new BinaryExponentiation().power(1, 10000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 100000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 1000000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 10000000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 100000000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 1000000000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 10000000000000000L)); + assertEquals(1, new BinaryExponentiation().power(1, 100000000000000000L)); + } + +} diff --git a/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java b/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java new file mode 100644 index 00000000..adc6871b --- /dev/null +++ b/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java @@ -0,0 +1,42 @@ +package com.thealgorithms.divideandconquer; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class StrassenMatrixMultiplicationTest { + + StrassenMatrixMultiplication SMM = new StrassenMatrixMultiplication(); + + // Strassen Matrix Multiplication can only be allplied to matrices of size 2^n + // and has to be a Square Matrix + + @Test + public void StrassenMatrixMultiplicationTest2x2() { + int[][] A = { { 1, 2 }, { 3, 4 } }; + int[][] B = { { 5, 6 }, { 7, 8 } }; + int[][] expResult = { { 19, 22 }, { 43, 50 } }; + int[][] actResult = SMM.multiply(A, B); + assertArrayEquals(expResult, actResult); + } + + @Test + void StrassenMatrixMultiplicationTest4x4() { + int[][] A = { { 1, 2, 5, 4 }, { 9, 3, 0, 6 }, { 4, 6, 3, 1 }, { 0, 2, 0, 6 } }; + int[][] B = { { 1, 0, 4, 1 }, { 1, 2, 0, 2 }, { 0, 3, 1, 3 }, { 1, 8, 1, 2 } }; + int[][] expResult = { { 7, 51, 13, 28 }, { 18, 54, 42, 27 }, { 11, 29, 20, 27 }, { 8, 52, 6, 16 } }; + int[][] actResult = SMM.multiply(A, B); + assertArrayEquals(expResult, actResult); + } + + @Test + void StrassenMatrixMultiplicationTestNegetiveNumber4x4() { + int[][] A = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } }; + int[][] B = { { 1, -2, -3, 4 }, { 4, -3, -2, 1 }, { 5, -6, -7, 8 }, { 8, -7, -6, -5 } }; + int[][] expResult = { { 56, -54, -52, 10 }, { 128, -126, -124, 42 }, { 200, -198, -196, 74 }, + { 272, -270, -268, 106 } }; + int[][] actResult = SMM.multiply(A, B); + assertArrayEquals(expResult, actResult); + } + +} \ No newline at end of file