diff --git a/alexandrov_dmitrii_lab_6/matrix.py b/alexandrov_dmitrii_lab_6/matrix.py new file mode 100644 index 0000000..9629fe5 --- /dev/null +++ b/alexandrov_dmitrii_lab_6/matrix.py @@ -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 + "
" + for i in range(size): + res = res + "

" + for a in range(size): + res = res + str(matrix[i][a]) + ", " + res = res + "

" + res = res + "

" + str(det) + "

" + + return res + + +def get_benchmark(): + global benchmark + + if len(benchmark) == 0: + do_research() + + res = '' + for key, val in benchmark.items(): + res = res + "

" + key + str(val) + "

" + + return res diff --git a/alexandrov_dmitrii_lab_6/readme.md b/alexandrov_dmitrii_lab_6/readme.md new file mode 100644 index 0000000..00f13a9 --- /dev/null +++ b/alexandrov_dmitrii_lab_6/readme.md @@ -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 \ No newline at end of file diff --git a/alexandrov_dmitrii_lab_6/screens/30x30.png b/alexandrov_dmitrii_lab_6/screens/30x30.png new file mode 100644 index 0000000..b9ba606 Binary files /dev/null and b/alexandrov_dmitrii_lab_6/screens/30x30.png differ diff --git a/alexandrov_dmitrii_lab_6/screens/5x5.png b/alexandrov_dmitrii_lab_6/screens/5x5.png new file mode 100644 index 0000000..155e2f0 Binary files /dev/null and b/alexandrov_dmitrii_lab_6/screens/5x5.png differ diff --git a/alexandrov_dmitrii_lab_6/screens/bench.png b/alexandrov_dmitrii_lab_6/screens/bench.png new file mode 100644 index 0000000..0b756e8 Binary files /dev/null and b/alexandrov_dmitrii_lab_6/screens/bench.png differ diff --git a/alexandrov_dmitrii_lab_6/service.py b/alexandrov_dmitrii_lab_6/service.py new file mode 100644 index 0000000..3b1f5bd --- /dev/null +++ b/alexandrov_dmitrii_lab_6/service.py @@ -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) diff --git a/alexandrov_dmitrii_lab_6/template.html b/alexandrov_dmitrii_lab_6/template.html new file mode 100644 index 0000000..c999367 --- /dev/null +++ b/alexandrov_dmitrii_lab_6/template.html @@ -0,0 +1,18 @@ + + + + + Matrix + + +
+ + + +
+
+ +
+ {{results_html|safe}} + + \ No newline at end of file