using MPI; using System; using System.Diagnostics; class PolynomialMultiplication { static void Main(string[] args) { // mpiexec.exe -n 4 "Lab 7.exe" MPI.Environment.Run(ref args, communicator => { int rank = communicator.Rank; int size = communicator.Size; List poly1 = [3, 2, 1]; List poly2 = [1, 0, -1 ]; Console.WriteLine($"Rank: {rank}, Size: {size}"); if (rank == 0) { Console.WriteLine($"Polynomial 1: {string.Join(", ", poly1)}"); Console.WriteLine($"Polynomial 2: {string.Join(", ", poly2)}"); } communicator.Broadcast(ref poly1, 0); communicator.Broadcast(ref poly2, 0); if (rank == 0) Console.WriteLine("\nStarting Regular Multiplication..."); Stopwatch stopwatch = Stopwatch.StartNew(); List resultRegular = PerformRegularMultiplication(communicator, poly1, poly2); stopwatch.Stop(); if (rank == 0) { Console.WriteLine("Regular Multiplication Result: " + string.Join(", ", resultRegular)); Console.WriteLine($"Regular Multiplication Time: {stopwatch.Elapsed.TotalSeconds} seconds\n"); } if (rank == 0) Console.WriteLine("Starting Karatsuba Multiplication..."); stopwatch.Restart(); List resultKaratsuba = KaratsubaMain(communicator, poly1, poly2); stopwatch.Stop(); if (rank == 0) { Console.WriteLine("Karatsuba Multiplication Result: " + string.Join(", ", resultKaratsuba)); Console.WriteLine($"Karatsuba Multiplication Time: {stopwatch.Elapsed.TotalSeconds} seconds"); } }); } static List PerformRegularMultiplication(Intracommunicator communicator, List poly1, List poly2) { int rank = communicator.Rank; int size = communicator.Size; int resultSize = poly1.Count + poly2.Count - 1; int chunkSize = poly1.Count / size; int start = rank * chunkSize; int end = (rank == size - 1) ? poly1.Count : start + chunkSize; List localResult = []; localResult.AddRange(new int[resultSize]); for (int i = start; i < end; i++) { for (int j = 0; j < poly2.Count; j++) { localResult[i + j] += poly1[i] * poly2[j]; } } List finalResult = []; finalResult.AddRange(new int[resultSize]); for (int i = 0; i < resultSize; i++) { int localValue = localResult[i]; int reducedValue = communicator.Reduce(localValue, Operation.Add, 0); if (rank == 0) { finalResult[i] = reducedValue; } } return finalResult; } public static List AddPolynomials(List poly1, List poly2) { int maxLength = Math.Max(poly1.Count, poly2.Count); List result = new List(new int[maxLength]); for (int i = 0; i < maxLength; i++) { int coef1 = i < poly1.Count ? poly1[i] : 0; int coef2 = i < poly2.Count ? poly2[i] : 0; result[i] = coef1 + coef2; } return result; } public static List SubtractPolynomials(List poly1, List poly2) { int maxLength = Math.Max(poly1.Count, poly2.Count); List result = new List(new int[maxLength]); for (int i = 0; i < maxLength; i++) { int coef1 = i < poly1.Count ? poly1[i] : 0; int coef2 = i < poly2.Count ? poly2[i] : 0; result[i] = coef1 - coef2; } return result; } public static List Karatsuba(List poly1, List poly2) { int n = Math.Max(poly1.Count, poly2.Count); if (n == 1) { return new List { poly1[0] * poly2[0] }; } while (poly1.Count < n) poly1.Add(0); while (poly2.Count < n) poly2.Add(0); int half = n / 2; List low1 = poly1.GetRange(0, half); List high1 = poly1.GetRange(half, n - half); List low2 = poly2.GetRange(0, half); List high2 = poly2.GetRange(half, n - half); List z0 = Karatsuba(low1, low2); List z1 = Karatsuba(AddPolynomials(low1, high1), AddPolynomials(low2, high2)); List z2 = Karatsuba(high1, high2); List result = new List(new int[2 * n - 1]); for (int i = 0; i < z0.Count; i++) result[i] += z0[i]; List middle = SubtractPolynomials(SubtractPolynomials(z1, z0), z2); for (int i = 0; i < middle.Count; i++) result[i + half] += middle[i]; for (int i = 0; i < z2.Count; i++) result[i + 2 * half] += z2[i]; return result; } public static List KaratsubaMain(Intracommunicator communicator, List poly1, List poly2) { int rank = communicator.Rank; int size = communicator.Size; int n = Math.Max(poly1.Count, poly2.Count); List result = new List(new int[2 * n - 1]); if (rank == 0) { while (poly1.Count < n) poly1.Add(0); while (poly2.Count < n) poly2.Add(0); int half = n / 2; List low1 = poly1.GetRange(0, half); List high1 = poly1.GetRange(half, n - half); List low2 = poly2.GetRange(0, half); List high2 = poly2.GetRange(half, n - half); // Distribute tasks communicator.Send(low1, 1, 0); communicator.Send(low2, 1, 1); communicator.Send(AddPolynomials(low1, high1), 2, 0); communicator.Send(AddPolynomials(low2, high2), 2, 1); communicator.Send(high1, 3, 0); communicator.Send(high2, 3, 1); // Collect results List z0 = communicator.Receive>(1, 0); List z1 = communicator.Receive>(2, 0); List z2 = communicator.Receive>(3, 0); for (int i = 0; i < z0.Count; i++) result[i] += z0[i]; List middle = SubtractPolynomials(SubtractPolynomials(z1, z0), z2); for (int i = 0; i < middle.Count; i++) result[i + half] += middle[i]; for (int i = 0; i < z2.Count; i++) result[i + 2 * half] += z2[i]; } else { // Worker processes List poly1Part = communicator.Receive>(0, 0); List poly2Part = communicator.Receive>(0, 1); List resultWorker = Karatsuba(poly1Part, poly2Part); communicator.Send(resultWorker, 0, 0); } return result; } }