106 lines
9.5 KiB
Markdown
106 lines
9.5 KiB
Markdown
|
||
## Лабораторная работа 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 |