diff --git a/aleikin_artem_lab_6/DerminantMatrix/DerminantMatrix.csproj b/aleikin_artem_lab_6/DerminantMatrix/DerminantMatrix.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/aleikin_artem_lab_6/DerminantMatrix/DerminantMatrix.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/aleikin_artem_lab_6/DerminantMatrix/DerminantMatrix.sln b/aleikin_artem_lab_6/DerminantMatrix/DerminantMatrix.sln new file mode 100644 index 0000000..05dbea5 --- /dev/null +++ b/aleikin_artem_lab_6/DerminantMatrix/DerminantMatrix.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35312.102 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DerminantMatrix", "DerminantMatrix.csproj", "{40E2A332-5A1C-46A7-AFA9-833E4922AD08}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {40E2A332-5A1C-46A7-AFA9-833E4922AD08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40E2A332-5A1C-46A7-AFA9-833E4922AD08}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40E2A332-5A1C-46A7-AFA9-833E4922AD08}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40E2A332-5A1C-46A7-AFA9-833E4922AD08}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DF40653A-B248-4AC9-8203-1F8E8EA9423F} + EndGlobalSection +EndGlobal diff --git a/aleikin_artem_lab_6/DerminantMatrix/Program.cs b/aleikin_artem_lab_6/DerminantMatrix/Program.cs new file mode 100644 index 0000000..ad9388f --- /dev/null +++ b/aleikin_artem_lab_6/DerminantMatrix/Program.cs @@ -0,0 +1,118 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; + +class Program +{ + static void Main(string[] args) + { + int[] sizes = { 10, 11, 12 }; + + int maxThreads = 20; + + foreach (var size in sizes) + { + Console.WriteLine($"\nРазмер матрицы: {size}x{size}"); + + // Генерация матрицы + var matrix = GenerateMatrix(size); + + // Последовательное нахождение детерминанта + var stopwatch = Stopwatch.StartNew(); + var detSequential = DeterminantSequential(matrix); + stopwatch.Stop(); + long timeSequential = stopwatch.ElapsedMilliseconds; + Console.WriteLine($"Последовательное вычисление: {timeSequential} мс, детерминант = {detSequential}"); + + // Параллельное нахождение детерминанта + Console.WriteLine("Параллельное вычисление (время выполнения для каждого количества потоков):"); + for (int threads = 1; threads <= maxThreads; threads++) + { + stopwatch.Restart(); + var detParallel = DeterminantParallel(matrix, threads); + stopwatch.Stop(); + long timeParallel = stopwatch.ElapsedMilliseconds; + Console.WriteLine($"Потоков: {threads} — {timeParallel} мс"); + } + } + } + + // Генерация квадратной матрицы размером size x size + static double[,] GenerateMatrix(int size) + { + var random = new Random(); + var matrix = new double[size, size]; + for (int i = 0; i < size; i++) + for (int j = 0; j < size; j++) + matrix[i, j] = random.Next(-10, 10); + return matrix; + } + + // Последовательное вычисление детерминанта + static double DeterminantSequential(double[,] matrix) + { + int size = matrix.GetLength(0); + if (size == 1) + return matrix[0, 0]; + + if (size == 2) + return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]; + + double determinant = 0; + for (int col = 0; col < size; col++) + { + determinant += Math.Pow(-1, col) * matrix[0, col] * DeterminantSequential(Minor(matrix, 0, col)); + } + return determinant; + } + + // Параллельное вычисление детерминанта + static double DeterminantParallel(double[,] matrix, int threadCount) + { + int size = matrix.GetLength(0); + if (size == 1) + return matrix[0, 0]; + + if (size == 2) + return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]; + + double determinant = 0; + object lockObject = new object(); + + Parallel.For(0, size, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, col => + { + double minorDeterminant = DeterminantSequential(Minor(matrix, 0, col)); + double term = Math.Pow(-1, col) * matrix[0, col] * minorDeterminant; + + lock (lockObject) + { + determinant += term; + } + }); + + return determinant; + } + + // Создание минора для матрицы + static double[,] Minor(double[,] matrix, int row, int col) + { + int size = matrix.GetLength(0); + var minor = new double[size - 1, size - 1]; + + for (int i = 0, minorRow = 0; i < size; i++) + { + if (i == row) continue; + + for (int j = 0, minorCol = 0; j < size; j++) + { + if (j == col) continue; + + minor[minorRow, minorCol] = matrix[i, j]; + minorCol++; + } + minorRow++; + } + + return minor; + } +} diff --git a/aleikin_artem_lab_6/Images/Отчет1.png b/aleikin_artem_lab_6/Images/Отчет1.png new file mode 100644 index 0000000..fd387bc Binary files /dev/null and b/aleikin_artem_lab_6/Images/Отчет1.png differ diff --git a/aleikin_artem_lab_6/readme.md b/aleikin_artem_lab_6/readme.md new file mode 100644 index 0000000..853d244 --- /dev/null +++ b/aleikin_artem_lab_6/readme.md @@ -0,0 +1,95 @@ +# Лабораторная работа 6 - Параллельный поиск значения детерминанта матрицы +## ПИбд-42 || Алейкин Артем + +### Описание +В данной лабораторной работе мы занимались написанием многопоточного вычислителя детерминанта больших матриц. + +### Объяснения +Последовательный алгоритм: +Нахождение детерминанта реализовано рекурсивно через формулу разложения по строке матрицы. +Метод DeterminantSequential вычисляет детерминант через разложение по первой строке и вызов минора. + +``` +static double DeterminantSequential(double[,] matrix) +{ + int size = matrix.GetLength(0); + if (size == 1) + return matrix[0, 0]; + + if (size == 2) + return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]; + + double determinant = 0; + for (int col = 0; col < size; col++) + { + determinant += Math.Pow(-1, col) * matrix[0, col] * DeterminantSequential(Minor(matrix, 0, col)); + } + return determinant; +} +``` + +Параллельный алгоритм: +Каждую итерацию разложения по строке матрицы можно выполнять в отдельном потоке. +DeterminantParallel использует Parallel.For для запуска потоков. + +``` +static double DeterminantParallel(double[,] matrix, int threadCount) +{ + int size = matrix.GetLength(0); + if (size == 1) + return matrix[0, 0]; + + if (size == 2) + return matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]; + + double determinant = 0; + object lockObject = new object(); + + Parallel.For(0, size, new ParallelOptions { MaxDegreeOfParallelism = threadCount }, col => + { + double minorDeterminant = DeterminantSequential(Minor(matrix, 0, col)); + double term = Math.Pow(-1, col) * matrix[0, col] * minorDeterminant; + + lock (lockObject) + { + determinant += term; + } + }); + + return determinant; +} +``` + +Миноры: +Метод Minor создает подматрицу, исключая заданные строку и столбец. + +``` +static double[,] Minor(double[,] matrix, int row, int col) +{ + int size = matrix.GetLength(0); + var minor = new double[size - 1, size - 1]; + + for (int i = 0, minorRow = 0; i < size; i++) + { + if (i == row) continue; + + for (int j = 0, minorCol = 0; j < size; j++) + { + if (j == col) continue; + + minor[minorRow, minorCol] = matrix[i, j]; + minorCol++; + } + minorRow++; + } + + return minor; +} +``` + +В результате мы получаем следующие значения: +![Вычисление детерминанта матриц](./Images/Отчет1.png) + +Результаты аналогичны с предыдущей лабораторной работой, многопоточный подход позволяет кратно выигрывать время, но и ресурсы на организацию работы всех потоков тоже существенны. + +Видео демонстрации работы: https://vk.com/video248424990_456239613?list=ln-tyTv9vKdAOzQyPm5Y3 \ No newline at end of file