diff --git a/zhimolostnova_anna_lab_6/README.md b/zhimolostnova_anna_lab_6/README.md new file mode 100644 index 0000000..791a859 --- /dev/null +++ b/zhimolostnova_anna_lab_6/README.md @@ -0,0 +1,87 @@ +# Отчет по лабораторной работе №5 + +## Описание задачи + +Данная работа нацелена на изучение эффективности параллельных вычислений при нахождении детерминанта +квадратной матрицы. Были реализованы два алгоритма: + +1. **Последовательный алгоритм**: рекурсивное вычисление детерминанта методом разложения по строкам. +2. **Параллельный алгоритм**: вычисление детерминанта с использованием многопоточности, + где различные миноры матрицы вычисляются в отдельных потоках. + +Целью эксперимента было сравнение времени выполнения последовательного и параллельного алгоритмов для +матриц разного размера и с разным количеством потоков. + +## Структура проекта + +Проект состоит из двух файлов с реализацией алгоритмов: + +- regular.go (в папке alg) — рекурсивное вычисление детерминанта методом разложения по строкам. +- parallel.go (в папке alg) — вычисление детерминанта с использованием многопоточности, + где различные миноры матрицы вычисляются в отдельных потоках. +- matrix.go (в папке util) — вспомогательные функции для матриц. +- run.go - запуск бенчмарков. + +## Результаты + +### Последовательный алгоритм + +![img.png](images%2Fimg.png) + +| Размер матрицы | Время выполнения | +|----------------|------------------| +| 7x7 | 525.1µs | +| 8x8 | 5.8494ms | +| 9x9 | 35.3115ms | + +### Параллельный алгоритм + +![img_1.png](images%2Fimg_1.png) + +| Размер матрицы | Количество потоков | Время выполнения | +|----------------|--------------------|------------------| +| 7x7 | 2 | 2ms | +| 7x7 | 4 | 2.0009ms | +| 7x7 | 6 | 1.0002ms | +| 7x7 | 8 | 1.9989ms | +| 8x8 | 2 | 5.0014ms | +| 8x8 | 4 | 21.5145ms | +| 8x8 | 6 | 16.3851ms | +| 8x8 | 8 | 17.9676ms | +| 9x9 | 2 | 65.099ms | +| 9x9 | 4 | 115.9553ms | +| 9x9 | 6 | 161.408ms | +| 9x9 | 8 | 117.4747ms | + +## Анализ полученных данных + +1. **Последовательный алгоритм**: + + Последовательный алгоритм показал ожидаемую тенденцию: с увеличением размера матрицы, время выполнения + увеличивается экспоненциально. Это связано с тем, что сложность рекурсивного алгоритма вычисления + детерминанта составляет O(n!), где n — размер матрицы. Даже небольшое увеличение размера матрицы + приводит к значительному росту времени вычислений. +2. **Параллельный алгоритм**: + + **Матрицы 7x7**: + - Время параллельного алгоритма оказалось больше, чем последовательного. + Это связано с тем, что накладные расходы на создание потоков, синхронизацию данных и распределение + задач превышают выгоду от параллельного выполнения для небольших задач. Матрица 7x7 слишком мала, + чтобы эффективно распределить вычисления между потоками, поэтому многопоточность не дает прироста в + производительности. + + **Матрицы 8x8**: + - Параллельное вычисление снова оказалось медленнее последовательного. Время выполнения с увеличением + количества потоков увеличивалось вплоть до 4 потоков, что демонстрирует отрицательный эффект от + создания избыточного числа потоков для задач такого размера. Наибольшее ускорение удалось достичь с 2 и 6 потоками, + но даже в этом случае результат (5.0014 и 16.3851 ms) был хуже и менее стабильным последовательного (5.8494 ms). + + **Матрицы 9x9**: + - Здесь также наблюдается значительное замедление при увеличении количества потоков. Время с 8 потоками + составило 117.4747 ms, что все равно больше времени последовательного алгоритма (35.3115 ms). Это связано с тем, + что при увеличении числа потоков на задаче, где каждая операция по вычислению минора требует больших + вычислительных затрат, накладные расходы на управление потоками могут стать слишком велики. + +## Демонстрационное видео + +Видеозапись доступна по адресу: [https://vk.com/video193898050_456240874](https://vk.com/video193898050_456240874) \ No newline at end of file diff --git a/zhimolostnova_anna_lab_6/alg/parallel.go b/zhimolostnova_anna_lab_6/alg/parallel.go new file mode 100644 index 0000000..1987928 --- /dev/null +++ b/zhimolostnova_anna_lab_6/alg/parallel.go @@ -0,0 +1,47 @@ +package alg + +import ( + "sync" + "zhimolostnova_anna_lab_6/util" +) + +func DeterminantParallel(matrix [][]float64, workers int) float64 { + size := len(matrix) + + if size == 1 { + return matrix[0][0] + } + + if size == 2 { + return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0] + } + + det := 0.0 + wg := sync.WaitGroup{} + mu := sync.Mutex{} + chunks := size / workers + if chunks == 0 { + chunks = 1 + } + for j := 0; j < size; j += chunks { + wg.Add(1) + go func(jStart int) { + defer wg.Done() + localDet := 0.0 + for jj := jStart; jj < jStart+chunks && jj < size; jj++ { + subMatrix := util.GetMinor(matrix, jj) + sign := 1 + if jj%2 != 0 { + sign = -1 + } + localDet += float64(sign) * matrix[0][jj] * DeterminantParallel(subMatrix, workers) + } + mu.Lock() + det += localDet + mu.Unlock() + }(j) + } + + wg.Wait() + return det +} diff --git a/zhimolostnova_anna_lab_6/alg/regular.go b/zhimolostnova_anna_lab_6/alg/regular.go new file mode 100644 index 0000000..eec7134 --- /dev/null +++ b/zhimolostnova_anna_lab_6/alg/regular.go @@ -0,0 +1,30 @@ +package alg + +import ( + "zhimolostnova_anna_lab_6/util" +) + +// Determinant Функция для вычисления детерминанта матрицы +func Determinant(matrix [][]float64) float64 { + size := len(matrix) + + if size == 1 { + return matrix[0][0] + } + + if size == 2 { + return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0] + } + + // Рекурсивное вычисление детерминанта по разложению по первой строке + det := 0.0 + for j := 0; j < size; j++ { + subMatrix := util.GetMinor(matrix, j) + sign := 1 + if j%2 != 0 { + sign = -1 + } + det += float64(sign) * matrix[0][j] * Determinant(subMatrix) + } + return det +} diff --git a/zhimolostnova_anna_lab_6/images/img.png b/zhimolostnova_anna_lab_6/images/img.png new file mode 100644 index 0000000..e3ac208 Binary files /dev/null and b/zhimolostnova_anna_lab_6/images/img.png differ diff --git a/zhimolostnova_anna_lab_6/images/img_1.png b/zhimolostnova_anna_lab_6/images/img_1.png new file mode 100644 index 0000000..0be77ae Binary files /dev/null and b/zhimolostnova_anna_lab_6/images/img_1.png differ diff --git a/zhimolostnova_anna_lab_6/run.go b/zhimolostnova_anna_lab_6/run.go new file mode 100644 index 0000000..fcc1604 --- /dev/null +++ b/zhimolostnova_anna_lab_6/run.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "strconv" + "time" + "zhimolostnova_anna_lab_6/alg" + "zhimolostnova_anna_lab_6/util" +) + +// Функция для бенчмарка последовательного вычисления детерминанта +func benchmarkDeterminantSequential(sizes []int) { + for _, size := range sizes { + matrix := util.GenerateMatrix(size) + + start := time.Now() + _ = alg.Determinant(matrix) + elapsed := time.Since(start) + + fmt.Printf("Sequential determinant of matrix %sx%s took %s\n", strconv.Itoa(size), strconv.Itoa(size), elapsed) + } +} + +// Функция для бенчмарка параллельного вычисления детерминанта +func benchmarkDeterminantParallel(sizes []int, threadsList []int) { + for _, size := range sizes { + for _, threads := range threadsList { + matrix := util.GenerateMatrix(size) + + start := time.Now() + _ = alg.DeterminantParallel(matrix, threads) + elapsed := time.Since(start) + + fmt.Printf("Parallel determinant of matrix %sx%s with %d threads took %s\n", strconv.Itoa(size), strconv.Itoa(size), threads, elapsed) + } + } +} + +func main() { + // Список размерностей матриц + sizes := []int{7, 8, 9} + + // Список количества потоков для тестирования + threadsList := []int{2, 4, 6, 8} + + // Запуск бенчмарков + fmt.Println("Sequential Benchmark:") + benchmarkDeterminantSequential(sizes) + + fmt.Println("\nParallel Benchmark:") + benchmarkDeterminantParallel(sizes, threadsList) +} diff --git a/zhimolostnova_anna_lab_6/util/matrix.go b/zhimolostnova_anna_lab_6/util/matrix.go new file mode 100644 index 0000000..b9430c7 --- /dev/null +++ b/zhimolostnova_anna_lab_6/util/matrix.go @@ -0,0 +1,36 @@ +package util + +import "math/rand" + +// GetMinor Получение минора матрицы +func GetMinor(matrix [][]float64, col int) [][]float64 { + size := len(matrix) + minor := make([][]float64, size-1) + for i := range minor { + minor[i] = make([]float64, size-1) + } + + for i := 1; i < size; i++ { + subCol := 0 + for j := 0; j < size; j++ { + if j == col { + continue + } + minor[i-1][subCol] = matrix[i][j] + subCol++ + } + } + return minor +} + +// GenerateMatrix Генерация случайной матрицы размера size x size +func GenerateMatrix(size int) [][]float64 { + matrix := make([][]float64, size) + for i := range matrix { + matrix[i] = make([]float64, size) + for j := range matrix[i] { + matrix[i][j] = float64(rand.Intn(6)) + } + } + return matrix +}