208 lines
6.9 KiB
C#
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;
|
|
}
|
|
|
|
} |