diff --git a/senkin_alexander_lab_6/README.md b/senkin_alexander_lab_6/README.md new file mode 100644 index 0000000..6b19dc3 --- /dev/null +++ b/senkin_alexander_lab_6/README.md @@ -0,0 +1,30 @@ +# Лабораторная работа №6 - Определение детерминанта матрицы с помощью параллельных вычислений + +Цель: реализовать нахождение детерминанта квадратной матрицы. + +Задача: в лабораторной работе требуется сделать два алгоритма: обычный и параллельный (задание со * - реализовать это в рамках одного алгоритма). В параллельном алгоритме предусмотреть ручное задание количества потоков (число потоков = 1 как раз и реализует задание со *), каждый из которых будет выполнять нахождение отдельной группы множителей. + +# Разработка приложения + +Было решено производить разработку приложения на языке Go, так как на нем удобно реализован механизм паралеллизма. +В рамках одного main файла реализованы две функции - параллельного и последовательного нахождения детерминанта матриц. Также реализована функция по запуску этих функций, и функция создания случайной матрицы. + +![img.png](img.png) + +# Запуск + +Запуск программы производится с помощью команды в командной строке go run {путь до исполняемого main.go файла} + +# Работа программы + +- Создание случайной матрицы: ![img_1.png](img_1.png) +- Метод для последовательного определения детерминанта матриц: ![img_2.png](img_2.png) +- Метод параллельного определения детерминанта матриц: ![img_3.png](img_3.png) ![img_4.png](img_4.png) +- Метод запуска тестов: ![img_5.png](img_5.png) +- Главный метод запуска программы main: ![img_6.png](img_6.png) +- Вывод на консоль и анализ результатов: ![img_7.png](img_7.png) +- Из-за выбранного мною метода поиска определения детерминанта - разложение по срокам, то при рассчитвании матриц больше размера 12x12 просиходит вылетание программы, то я провел тесты с размерами матриц 6x6, 8x8, 10x10. По результатам видим, что на Go параллельное определения детерминанта матриц проигрывает последовательному методу независимо от количества потоков, возможно это из-за не самого эффективного метода поиска определителя. + +# Видео + +Видео с разбором лабораторной работы - https://youtu.be/TdrMlgf1swg \ No newline at end of file diff --git a/senkin_alexander_lab_6/go.mod b/senkin_alexander_lab_6/go.mod new file mode 100644 index 0000000..23a20c8 --- /dev/null +++ b/senkin_alexander_lab_6/go.mod @@ -0,0 +1,3 @@ +module DAS_2023_1/senkin_alexander_lab_6 + +go 1.21.4 diff --git a/senkin_alexander_lab_6/img.png b/senkin_alexander_lab_6/img.png new file mode 100644 index 0000000..0791afd Binary files /dev/null and b/senkin_alexander_lab_6/img.png differ diff --git a/senkin_alexander_lab_6/img_1.png b/senkin_alexander_lab_6/img_1.png new file mode 100644 index 0000000..e0f4d8b Binary files /dev/null and b/senkin_alexander_lab_6/img_1.png differ diff --git a/senkin_alexander_lab_6/img_2.png b/senkin_alexander_lab_6/img_2.png new file mode 100644 index 0000000..dfc72a7 Binary files /dev/null and b/senkin_alexander_lab_6/img_2.png differ diff --git a/senkin_alexander_lab_6/img_3.png b/senkin_alexander_lab_6/img_3.png new file mode 100644 index 0000000..d39ae59 Binary files /dev/null and b/senkin_alexander_lab_6/img_3.png differ diff --git a/senkin_alexander_lab_6/img_4.png b/senkin_alexander_lab_6/img_4.png new file mode 100644 index 0000000..5bd992d Binary files /dev/null and b/senkin_alexander_lab_6/img_4.png differ diff --git a/senkin_alexander_lab_6/img_5.png b/senkin_alexander_lab_6/img_5.png new file mode 100644 index 0000000..2afcd9d Binary files /dev/null and b/senkin_alexander_lab_6/img_5.png differ diff --git a/senkin_alexander_lab_6/img_6.png b/senkin_alexander_lab_6/img_6.png new file mode 100644 index 0000000..7271264 Binary files /dev/null and b/senkin_alexander_lab_6/img_6.png differ diff --git a/senkin_alexander_lab_6/img_7.png b/senkin_alexander_lab_6/img_7.png new file mode 100644 index 0000000..9f65033 Binary files /dev/null and b/senkin_alexander_lab_6/img_7.png differ diff --git a/senkin_alexander_lab_6/main/main.go b/senkin_alexander_lab_6/main/main.go new file mode 100644 index 0000000..6e86958 --- /dev/null +++ b/senkin_alexander_lab_6/main/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "fmt" + "math/rand" + "sync" + "time" +) + +// SequentialDeterminant рассчитывает детерминант матрицы методом разложения по первой строке +func SequentialDeterminant(matrix [][]float64) float64 { + size := len(matrix) + // Базовый случай: если матрица 1x1, то детерминант равен единственному элементу + if size == 1 { + return matrix[0][0] + } + // Рекурсивно вычисляем детерминант матрицы + det := 0.0 + sign := 1.0 + for j := 0; j < size; j++ { + // Разложение по первой строке + submatrix := make([][]float64, size-1) + for i := range submatrix { + submatrix[i] = make([]float64, size-1) + } + for i := 1; i < size; i++ { + for k := 0; k < size; k++ { + if k < j { + submatrix[i-1][k] = matrix[i][k] + } else if k > j { + submatrix[i-1][k-1] = matrix[i][k] + } + } + } + // Рекурсивный вызов для подматрицы + det += sign * matrix[0][j] * SequentialDeterminant(submatrix) + // Меняем знак для следующей итерации + sign *= -1 + } + return det +} + +// ParallelDeterminant рассчитывает детерминант матрицы параллельно с использованием горутин +func ParallelDeterminant(matrix [][]float64, numWorkers int) float64 { + size := len(matrix) + // Базовый случай: если матрица 1x1, то детерминант равен единственному элементу + if size == 1 { + return matrix[0][0] + } + var wg sync.WaitGroup + resultChan := make(chan float64, numWorkers) + // Распределение работы между горутинами + for j := 0; j < size; j++ { + wg.Add(1) + go func(col int) { + defer wg.Done() + // Разложение по первой строке + submatrix := make([][]float64, size-1) + for i := range submatrix { + submatrix[i] = make([]float64, size-1) + } + for i := 1; i < size; i++ { + for k := 0; k < size; k++ { + if k < col { + submatrix[i-1][k] = matrix[i][k] + } else if k > col { + submatrix[i-1][k-1] = matrix[i][k] + } + } + } + // Рекурсивный вызов для подматрицы и отправка результата в канал + resultChan <- matrix[0][col] * ParallelDeterminant(submatrix, numWorkers) + }(j) + } + // Закрываем канал после завершения всех горутин + go func() { + wg.Wait() + close(resultChan) + }() + // Сбор результатов из канала и вычисление итогового детерминанта + det := 0.0 + sign := 1.0 + for result := range resultChan { + det += sign * result + sign *= -1 + } + return det +} + +func runTest(matrixSize, numProcesses int) { + matrix := generateRandomMatrix(matrixSize, matrixSize) + + startTime := time.Now() + _ = SequentialDeterminant(matrix) + sequentialTime := time.Since(startTime) + fmt.Printf("Sequential matrix Determinant took (%dx%d): %s\n", matrixSize, matrixSize, sequentialTime) + + startTime = time.Now() + _ = ParallelDeterminant(matrix, numProcesses) + parallelTime := time.Since(startTime) + fmt.Printf("Parallel matrix Determinant with %d threads took (%dx%d): %s\n", numProcesses, matrixSize, matrixSize, parallelTime) +} + +func generateRandomMatrix(rows, cols int) [][]float64 { + matrix := make([][]float64, rows) + for i := range matrix { + matrix[i] = make([]float64, cols) + for j := range matrix[i] { + matrix[i][j] = rand.Float64() + } + } + return matrix +} + +func main() { + // Пример использования функций + runTest(6, 2) + runTest(6, 4) + runTest(8, 2) + runTest(8, 4) + runTest(10, 2) + runTest(10, 4) +}