Files
School/Anul 3/Semestrul 1/Parallel and Distributed Programming/Lab 7/Program.cs
T
2025-02-06 20:33:26 +02:00

208 lines
6.9 KiB
C#

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<int> poly1 = [3, 2, 1];
List<int> 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<int> 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<int> 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<int> PerformRegularMultiplication(Intracommunicator communicator, List<int> poly1, List<int> 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<int> 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<int> finalResult = [];
finalResult.AddRange(new int[resultSize]);
for (int i = 0; i < resultSize; i++)
{
int localValue = localResult[i];
int reducedValue = communicator.Reduce(localValue, Operation<int>.Add, 0);
if (rank == 0)
{
finalResult[i] = reducedValue;
}
}
return finalResult;
}
public static List<int> AddPolynomials(List<int> poly1, List<int> poly2)
{
int maxLength = Math.Max(poly1.Count, poly2.Count);
List<int> result = new List<int>(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<int> SubtractPolynomials(List<int> poly1, List<int> poly2)
{
int maxLength = Math.Max(poly1.Count, poly2.Count);
List<int> result = new List<int>(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<int> Karatsuba(List<int> poly1, List<int> poly2)
{
int n = Math.Max(poly1.Count, poly2.Count);
if (n == 1)
{
return new List<int> { poly1[0] * poly2[0] };
}
while (poly1.Count < n) poly1.Add(0);
while (poly2.Count < n) poly2.Add(0);
int half = n / 2;
List<int> low1 = poly1.GetRange(0, half);
List<int> high1 = poly1.GetRange(half, n - half);
List<int> low2 = poly2.GetRange(0, half);
List<int> high2 = poly2.GetRange(half, n - half);
List<int> z0 = Karatsuba(low1, low2);
List<int> z1 = Karatsuba(AddPolynomials(low1, high1), AddPolynomials(low2, high2));
List<int> z2 = Karatsuba(high1, high2);
List<int> result = new List<int>(new int[2 * n - 1]);
for (int i = 0; i < z0.Count; i++) result[i] += z0[i];
List<int> 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<int> KaratsubaMain(Intracommunicator communicator, List<int> poly1, List<int> poly2)
{
int rank = communicator.Rank;
int size = communicator.Size;
int n = Math.Max(poly1.Count, poly2.Count);
List<int> result = new List<int>(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<int> low1 = poly1.GetRange(0, half);
List<int> high1 = poly1.GetRange(half, n - half);
List<int> low2 = poly2.GetRange(0, half);
List<int> 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<int> z0 = communicator.Receive<List<int>>(1, 0);
List<int> z1 = communicator.Receive<List<int>>(2, 0);
List<int> z2 = communicator.Receive<List<int>>(3, 0);
for (int i = 0; i < z0.Count; i++) result[i] += z0[i];
List<int> 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<int> poly1Part = communicator.Receive<List<int>>(0, 0);
List<int> poly2Part = communicator.Receive<List<int>>(0, 1);
List<int> resultWorker = Karatsuba(poly1Part, poly2Part);
communicator.Send(resultWorker, 0, 0);
}
return result;
}
}