DAS_2023_1/arutunyan_dmitry_lab_6/README.md

106 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Лабораторная работа 6. Вариант 4.
### Задание
Реализовать нахождение детерминанта квадратной матрицы.
- Создать алгоритм параллельного нахождения детерминанта квадратной матрицы,
- Предусмотреть задание потоков вручную, для работы параллельного алгоритма нахождения определителя как обычного.
### Как запустить
Для запуска программы необходимо с помощью командной строки в корневой директории файлов прокета прописать:
```
python main.py
```
Результат работы программы будет выведен в консоль.
### Используемые технологии
- Библиотека `numpy`, используемая для обработки массивов данных и вычислений.
- Библиотека `concurrent.futures`- высокоуровневый интерфейс для выполнения параллельных и асинхронных задач.
- `ThreadPoolExecutor` - класс пула потоков для выполнения задач в нескольких потоках. Он использует пул потоков, чтобы автоматически управлять созданием и выполнением потоков, что обеспечивает простой способ распараллеливания задач. Метод `submit()` позволяет отправлять задачи в пул потоков, и возвращает объект `Future`, который представляет результат выполнения задачи.
- Библиотека `time`, используемая для измерения времени работы программы.
- Библиотека `psutil`, используемая для отслеживания нагрузки на процессор и количества загруженной оперативной памяти.
### Описание работы
#### Распараллеливание задачи нахождения определителя
Воспользуемся правилом нахождения определителя с помощью миноров матрицы:
- Определитель матрицы равен сумме произведений элементов строки (столбца) на соответствующие алгебраические дополнения.
```
|a1, a2, a3| |b2, b3| |b1, b3| |b1, b2|
|b1, b2, b3| = (+)a1 x |c2, c3| + (-)a2 x |c1, c3| + (+)a3 x |c1, c2|
|c1, c2, c3|
```
Таким образом, мы можем выбрать 1ю строку матрицы и параллельно вычислить определитель каждого минора матрицы, умножив его на соответсвующий элемент.
#### Разработка программы
Для начала создадим функцию вычисления детерминанта минора матрицы с его умножением на соответсвующий элемент строки:
```python
def calculate_determinant(args):
matrix, i = args
multiplier = matrix[0][i]
if i % 2 != 0:
multiplier *= -1
matrix = np.delete(matrix, 0, axis=0)
submatrix = np.delete(matrix, i, axis=1)
return np.linalg.det(submatrix) * multiplier
```
Если элемент находится на нечётной позиции в строке, то, по правилу, знак множителя меняется на противоположный.
Теперь перейдём к алгоритму параллельного вычисления детерминанта матрицы. Создадим пул потоков с помощью класса `concurrent.futures.ThreadPoolExecutor`, в который будем передавать желаемое количество потоков:
```python
with concurrent.futures.ThreadPoolExecutor(max_workers=n) as executor:
results = []
start_time = time.time()
for i in range(n):
results.append(executor.submit(calculate_determinant, args=(matrix, i)))
result = np.sum([res.result() for res in results])
end_time = time.time()
```
В пул потоков в качестве аргументов мы передаём последовательно матрицу и номер столбца элемента-множителя, а в качестве их обработчика указываем ранее созданный метод `calculate_determinant`. Массив определителей миноров, умноженных на соответсвующие множители суммируется методом `sum` и записывается в результат.
> **Note**
>
> Поскольку определение детерминанта матрицы распараллеливается по 1му порядку миноров, задавать значение кол-ва потоков больше числа элементов строки-множителя (1й строки матрицы) не имеет значения. По сути, самым оптимальным решением будет являться состояние, когда каждый поток ищет определитель определённого минора, составленного по определённому элементу строки матрицы.
Создадим тестовый метод и проверим работу калькулятора вычисления определителя на грамотность:
```python
mx = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
return parallel_determinant(mx, parallel)
```
Результат вычислений: `0`
Алгоритм работает верно.
#### Замеры параметров
Бенчмарки в данной лабораторной работе задаются аналогично предыдущей. Прогоним все бенчмарки и сравним измеряемые показатели при максимальной многопоточности (кол-во потоков = кол-ву эл-тов 1й строки матрицы) и монопоточности.
Результаты (параллельный - слева, обычный - справа):
```
50 * 50
_________________________________________________________________
Время выполнения: 0.0129.. сек. | Время выполнения: 0.0010.. сек.
Загрузка ЦП: 5.4% | Загрузка ЦП: 4.8%
Использование ОЗУ: 71.6% | Использование ОЗУ: 71.7%
75 * 75
_________________________________________________________________
Время выполнения: 0.0220.. сек. | Время выполнения: 0.0.. сек.
Загрузка ЦП: 5.7% | Загрузка ЦП: 1.2%
Использование ОЗУ: 71.1% | Использование ОЗУ: 71.0%
125 * 125
_________________________________________________________________
Время выполнения: 0.5048.. сек. | Время выполнения: 0.0070.. сек.
Загрузка ЦП: 5.6% | Загрузка ЦП: 2.5%
Использование ОЗУ: 71.2% | Использование ОЗУ: 71.7%
```
### Вывод
По результатам замеров видно, что при любых размерностях матрицы, монопоточное вычисление определителя происходит эффективнее как по времени, так и по ресурс-затратности. По загруженности ЦП можно убедиться, что многопоточное определение детерминанта матрицы работает корректно, тк загрузка процессора при использовании нескольких потоков всегда выше, чем при использовании монопоточности.
Таким образом, применение парралельных вычислений при решении данной задачи показали себя не учшим образом. Связанно это может быть с оптимальностью алгоритма вычисления определителя функции `det` библиотеки `numpy`, с недостаточной оптимальностью алгоритма распараллеливания вычисления (находится минор только последующего порядка, а не рассчитывается до 1го в связи с рекурсивностью выбранного метода определения детерминанта) или с недостаточно большой размерностью матрицы (оперативной памяти данной машины хватает на вычисления определителя матрицы, максимальной размерностью 125х125)
### Видео
https://youtu.be/ayDhflcf7PM