alexandrov_dmitrii_lab_6 is ready #72
109
alexandrov_dmitrii_lab_6/matrix.py
Normal file
109
alexandrov_dmitrii_lab_6/matrix.py
Normal file
@ -0,0 +1,109 @@
|
||||
import numpy as np
|
||||
import time
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
|
||||
benchmark = {}
|
||||
matrix = []
|
||||
# int переполняется
|
||||
det = 0.0
|
||||
|
||||
|
||||
# ручной метод - от размера матриц ~15 и выше может случайно винду
|
||||
def get_determinant_usr_implementation(input_m):
|
||||
if input_m.size == 4:
|
||||
return input_m[0, 0] * input_m[1, 1] - input_m[0, 1] * input_m[1, 0]
|
||||
r_det = [0] * input_m.size
|
||||
for i in range(input_m.shape[0]):
|
||||
r_det[i] = input_m[0, i]
|
||||
if r_det[i] != 0:
|
||||
if i % 2 == 1:
|
||||
r_det[i] = r_det[i] * -1
|
||||
r_det[i] = r_det[i] * get_determinant_usr_implementation(
|
||||
np.delete(np.delete(input_m, 0, axis=0), i, axis=1))
|
||||
return sum(r_det)
|
||||
|
||||
|
||||
def get_determinant_component_usr_implementation(input_m, col):
|
||||
r_det = float(input_m[0, col])
|
||||
if r_det == 0:
|
||||
return r_det
|
||||
if col % 2 == 1:
|
||||
r_det = r_det * -1
|
||||
return r_det * get_determinant_usr_implementation(np.delete(np.delete(input_m, 0, axis=0), col, axis=1))
|
||||
|
||||
|
||||
def get_determinant_component(input_m, col):
|
||||
r_det = float(input_m[0, col])
|
||||
if r_det == 0:
|
||||
return r_det
|
||||
if col % 2 == 1:
|
||||
r_det = r_det * -1
|
||||
return r_det * np.linalg.det(np.delete(np.delete(input_m, 0, axis=0), col, axis=1))
|
||||
|
||||
|
||||
def calculate_determinant_parallel(size, proc_num):
|
||||
global matrix
|
||||
global det
|
||||
|
||||
if proc_num > 61:
|
||||
proc_num = 61
|
||||
|
||||
matrix = np.random.randint(10, size=(size, size))
|
||||
start_time = time.time()
|
||||
with ProcessPoolExecutor(max_workers=proc_num) as executor:
|
||||
if size <= 10:
|
||||
components = [executor.submit(get_determinant_component_usr_implementation, matrix, i) for i in range(size)]
|
||||
else:
|
||||
components = [executor.submit(get_determinant_component, matrix, i) for i in range(size)]
|
||||
res = [fut.result() for fut in components]
|
||||
|
||||
det = sum(res)
|
||||
return time.time() - start_time
|
||||
|
||||
|
||||
def do_research():
|
||||
benchmark['size=2, proc_num=1: '] = calculate_determinant_parallel(2, 1)
|
||||
benchmark['size=5, proc_num=1: '] = calculate_determinant_parallel(5, 1)
|
||||
benchmark['size=10, proc_num=1: '] = calculate_determinant_parallel(10, 1)
|
||||
benchmark['size=2, proc_num=10: '] = calculate_determinant_parallel(2, 10)
|
||||
benchmark['size=5, proc_num=10: '] = calculate_determinant_parallel(5, 10)
|
||||
benchmark['size=10, proc_num=10: '] = calculate_determinant_parallel(10, 10)
|
||||
benchmark['size=2, proc_num=100: '] = calculate_determinant_parallel(2, 100)
|
||||
benchmark['size=5, proc_num=100: '] = calculate_determinant_parallel(5, 100)
|
||||
benchmark['size=10, proc_num=100: '] = calculate_determinant_parallel(10, 100)
|
||||
print(benchmark)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
do_research()
|
||||
|
||||
|
||||
def get_results(size, proc_num):
|
||||
global matrix
|
||||
global det
|
||||
|
||||
res = "time: "
|
||||
res = res + str(calculate_determinant_parallel(size, proc_num))
|
||||
|
||||
res = res + "<br/>"
|
||||
for i in range(size):
|
||||
res = res + "<p>"
|
||||
for a in range(size):
|
||||
res = res + str(matrix[i][a]) + ", "
|
||||
res = res + "</p>"
|
||||
res = res + "<br/><p>" + str(det) + "</p>"
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def get_benchmark():
|
||||
global benchmark
|
||||
|
||||
if len(benchmark) == 0:
|
||||
do_research()
|
||||
|
||||
res = ''
|
||||
for key, val in benchmark.items():
|
||||
res = res + "<p>" + key + str(val) + "</p>"
|
||||
|
||||
return res
|
42
alexandrov_dmitrii_lab_6/readme.md
Normal file
42
alexandrov_dmitrii_lab_6/readme.md
Normal file
@ -0,0 +1,42 @@
|
||||
## Задание
|
||||
Создать программу, производящую поиск детерминанта больших квадратных матриц.
|
||||
|
||||
## Выполнение
|
||||
Программа состоит из модуля-сервиса service и модуля для вычислений matrix.
|
||||
В модуле для вычислений реализовано:
|
||||
* метод get_determinant_usr_implementation. "Вручную" ищет детерминант переданной матрицы.
|
||||
* метод get_determinant_component_usr_implementation. Ищет минорный детерминант, используя "ручной" метод, для реализации распараллеливания.
|
||||
* метод get_determinant_component. Ищет минорный детерминант, используя библиотечный метод для поиска детерминантов миноров, для распараллеливания.
|
||||
* метод calculate_determinant_parallel. Генерирует случайные матрицы заданного размера и производит параллельные вычисления предыдущими методами в зависимости от размера (если размер больше 10 использовать ручной метод лучше не надо, можно случайно компьютер).
|
||||
* метод прогона эксперимента с заполнением данных результатами. Методы интерфейса доступа.
|
||||
|
||||
Способ вычисления: в методе do_multiplication_parallel матрица B транспонируется, создаётся объект ProcessPoolExecutor с переданным количеством процессов, который их создаёт и распределяет по ним вычисление минорных детерминантов первой строки для последующего сложения, в зависимости от размера матрицы используется get_determinant_component_usr_implementation или get_determinant_component.
|
||||
Если передать методу число 1 в качестве количества процессов, то соответственно вычисление произойдёт в одном потоке.
|
||||
|
||||
## Результаты
|
||||
Был создан Flask сервис, позволяющий получать детерминанты случайных квадратных матриц.
|
||||
Возможно задать размер и количество процессов.
|
||||
|
||||
Дополнительно возможно провести эксперимент и получить результаты умножения матриц размера 2, 5 и 10 одним, десятью и ста процессами.
|
||||
Для создания бенчмарка был сокращён размер матриц, поскольку:
|
||||
* ручной метод не может в обозримом будущем посчитать матрицу размером больше 15-20.
|
||||
* библиотечный метод считает детерминант за секунду-две без заметных изменений от увеличения количества процессов обработки. анализировать результаты не получится (разве что заключить, что метод не нуждается в распараллеливании).
|
||||
|
||||
Поскольку распараллеливание основано на процессах, а в системе имеется 6 ядер (+2 виртуальных), то максимальное увеличение производительности будет достигнуто при выборе такого количества процессов.
|
||||
Более 61 потока урезается до 61 из-за системных ограничений.
|
||||
|
||||
Как видно из бенчмарка:
|
||||
* в случае больших размеров скорость максимальна при выборе 100 (61) процессов, можно заключить, что алгоритм "ручной" алгоритм хорошо реагирует на распараллеливание.
|
||||
* в случае 100 процессов из-за издержек создания процессов малые матрицы обрабатываются на порядок дольше, нежели одним процессом.
|
||||
* в случае 100 процессов благодаря распараллеливанию скорость обработки матрицы размером 10 оказалась в 5 раз выше скорости обработки одним процессом.
|
||||
|
||||
Результаты:
|
||||
![matrix5x5](screens/5x5.png)
|
||||
|
||||
![matrix30x30](screens/30x30.png)
|
||||
|
||||
Бенчмарк:
|
||||
![bench](screens/bench.png)
|
||||
|
||||
## Ссылка на видео
|
||||
https://drive.google.com/file/d/1kxMccJDCQsVK1qcrsiQKDXUuDzPQ1Lsc/view?usp=drive_link
|
BIN
alexandrov_dmitrii_lab_6/screens/30x30.png
Normal file
BIN
alexandrov_dmitrii_lab_6/screens/30x30.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
BIN
alexandrov_dmitrii_lab_6/screens/5x5.png
Normal file
BIN
alexandrov_dmitrii_lab_6/screens/5x5.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
alexandrov_dmitrii_lab_6/screens/bench.png
Normal file
BIN
alexandrov_dmitrii_lab_6/screens/bench.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
35
alexandrov_dmitrii_lab_6/service.py
Normal file
35
alexandrov_dmitrii_lab_6/service.py
Normal file
@ -0,0 +1,35 @@
|
||||
from flask import Flask, redirect, request, render_template
|
||||
import matrix
|
||||
|
||||
app = Flask(__name__, template_folder='')
|
||||
|
||||
results = ''
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
global results
|
||||
return render_template("template.html", results_html=results)
|
||||
|
||||
|
||||
@app.route('/do')
|
||||
def do():
|
||||
global results
|
||||
|
||||
data = request.args
|
||||
results = matrix.get_results(int(data['size']), int(data['proc_num']))
|
||||
|
||||
return redirect("/")
|
||||
|
||||
|
||||
@app.route('/benchmark')
|
||||
def benchmark():
|
||||
global results
|
||||
|
||||
results = matrix.get_benchmark()
|
||||
|
||||
return redirect("/")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=8082)
|
18
alexandrov_dmitrii_lab_6/template.html
Normal file
18
alexandrov_dmitrii_lab_6/template.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Matrix</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="http://127.0.0.1:8082/do">
|
||||
<input type="number" id="size" name="size" value="5">
|
||||
<input type="number" id="proc_num" name="proc_num" value="1">
|
||||
<input align="center" type="submit" value="Выполнить"/>
|
||||
</form>
|
||||
<form action="http://127.0.0.1:8082/benchmark">
|
||||
<input align="center" type="submit" value="Вывести бенчмарк"/>
|
||||
</form>
|
||||
{{results_html|safe}}
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user