ending
This commit is contained in:
@@ -31,54 +31,31 @@ python matrix.py
|
||||
|
||||
```
|
||||
matrix.py # Основной файл с реализацией алгоритмов
|
||||
README.md # Документация проекта
|
||||
README.md # Документация проекта
|
||||
```
|
||||
|
||||
## 4. Результаты тестирования
|
||||
|
||||
### Матрицы 100×100
|
||||
На всех тестах одинаковый результат:
|
||||
Детерминант при использовании множества потоков(процессов) высчитывается дольше чем при использовании строго 1 потока (главного). Это происходит из-за необходимости тратить время на выделение потоков(процессов), а также необходимости объединять результаты
|
||||
|
||||
#### Результат:
|
||||
# Сводная таблица результатов
|
||||
|
||||
| Алгоритм | Время (сек) | Ускорение |
|
||||
|----------|-------------|-----------|
|
||||
| Последовательный (LU) | 0.01-0.03 | 1.00x |
|
||||
| Параллельный (2 процесса) | 2.5-3.5 | 0.01x |
|
||||
| Параллельный (4 процесса) | 1.8-2.8 | 0.01x |
|
||||
| Параллельный (8 процессов) | 1.5-2.5 | 0.01x |
|
||||
| Размер | Потоки | Время (сек) | Ускорение |
|
||||
|--------|---------|-------------|-----------|
|
||||
| 100 | 1 | 0.0100 | 1.00 |
|
||||
| 100 | 2 | 0.3408 | 0.03 |
|
||||
| 100 | 4 | 0.3861 | 0.03 |
|
||||
| 100 | 12 | 0.5920 | 0.02 |
|
||||
| 300 | 1 | 0.0783 | 1.00 |
|
||||
| 300 | 2 | 1.0641 | 0.07 |
|
||||
| 300 | 4 | 1.2565 | 0.06 |
|
||||
| 300 | 12 | 2.1755 | 0.04 |
|
||||
| 500 | 1 | 0.2195 | 1.00 |
|
||||
| 500 | 2 | 3.0588 | 0.07 |
|
||||
| 500 | 4 | 3.0725 | 0.07 |
|
||||
| 500 | 12 | 4.7439 | 0.05 |
|
||||
|
||||
#### Вывод:
|
||||
На матрицах 100×100 параллелизм **крайне неэффективен**. Overhead от создания процессов (2-3 сек) во много раз превышает время самих вычислений (0.01-0.03 сек). Последовательный LU-алгоритм работает мгновенно и является оптимальным выбором.
|
||||
## 5. Видео
|
||||
|
||||
### Матрицы 300×300
|
||||
|
||||
#### Результат:
|
||||
|
||||
| Алгоритм | Время (сек) | Ускорение |
|
||||
|----------|-------------|-----------|
|
||||
| Последовательный (LU) | 0.15-0.25 | 1.00x |
|
||||
| Параллельный (2 процесса) | 45-55 | 0.004x ❌ |
|
||||
| Параллельный (4 процесса) | 25-35 | 0.007x ❌ |
|
||||
| Параллельный (8 процессов) | 15-20 | 0.01x ❌ |
|
||||
|
||||
#### Вывод:
|
||||
Даже на матрицах 300×300 параллелизм через разложение по строке остается **неэффективным**. LU-разложение работает за доли секунды, в то время как параллельное разложение требует десятков секунд на вычисление 300 миноров размером 299×299.
|
||||
|
||||
### Матрицы 500×500
|
||||
|
||||
#### Результат:
|
||||
|
||||
| Алгоритм | Время (сек) | Ускорение | Детерминант |
|
||||
|----------|-------------|-----------|-------------|
|
||||
| Последовательный (LU) | 0.5-0.8 | 1.00x | ~10¹⁰⁰⁰ |
|
||||
| Параллельный (2 процесса) | 180-220 | 0.003x ❌ | ~10¹⁰⁰⁰ |
|
||||
| Параллельный (4 процесса) | 100-130 | 0.006x ❌ | ~10¹⁰⁰⁰ |
|
||||
| Параллельный (8 процессов) | 60-80 | 0.009x ❌ | ~10¹⁰⁰⁰ |
|
||||
|
||||
#### Вывод:
|
||||
На больших матрицах 500×500 ситуация **не улучшается**. LU-разложение остается самым эффективным (менее 1 секунды), в то время как параллельное разложение по строке требует минут работы.
|
||||
|
||||
|
||||
## 13. Видео
|
||||
|
||||
ВидеоСсылка на видео работы алгоритма: [Rutube](https://rutube.ru/video/private/d4dc5613005afbbe601862d54b248d36/?p=De8RTMImQZQtab3avfH2Zg)
|
||||
ВидеоСсылка на видео работы алгоритма: [Rutube](https://rutube.ru/video/private/b655cb0028629067f79920162bf3b199/?p=l5uLlZQUmoEgv6RSAm4cVA)
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import numpy as np
|
||||
import multiprocessing as mp
|
||||
import time
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
def sequential_determinant(matrix):
|
||||
n = matrix.shape[0]
|
||||
@@ -79,27 +76,70 @@ def parallel_determinant(matrix, num_processes = None):
|
||||
num_processes = mp.cpu_count()
|
||||
|
||||
n = matrix.shape[0]
|
||||
|
||||
|
||||
if n < 100 or num_processes == 1:
|
||||
return sequential_determinant(matrix)
|
||||
|
||||
A = matrix.astype(np.float64).copy()
|
||||
sign = 1
|
||||
|
||||
with mp.Pool(num_processes) as pool:
|
||||
for i in range(n):
|
||||
max_row = i
|
||||
max_val = abs(A[i, i])
|
||||
|
||||
for k in range(i + 1, n):
|
||||
if abs(A[k, i]) > max_val:
|
||||
max_row = k
|
||||
max_val = abs(A[k, i])
|
||||
|
||||
if max_row != i:
|
||||
A[[i, max_row]] = A[[max_row, i]]
|
||||
sign *= -1
|
||||
|
||||
if abs(A[i, i]) < 1e-15:
|
||||
return 0.0, -np.inf
|
||||
|
||||
rows_to_update = list(range(i + 1, n))
|
||||
|
||||
if len(rows_to_update) >= num_processes * 2:
|
||||
tasks = []
|
||||
for k in rows_to_update:
|
||||
tasks.append((A[k].copy(), A[i].copy(), A[k, i], A[i, i], i))
|
||||
|
||||
updated_rows = pool.map(_update_row_worker, tasks)
|
||||
|
||||
for idx, k in enumerate(rows_to_update):
|
||||
A[k] = updated_rows[idx]
|
||||
else:
|
||||
for k in rows_to_update:
|
||||
factor = A[k, i] / A[i, i]
|
||||
A[k, i:] -= factor * A[i, i:]
|
||||
|
||||
log_abs_det = 0.0
|
||||
for i in range(n):
|
||||
if A[i, i] < 0:
|
||||
sign *= -1
|
||||
log_abs_det += np.log(abs(A[i, i]))
|
||||
|
||||
return sign, log_abs_det
|
||||
|
||||
|
||||
def _update_row_worker(args):
|
||||
row_k, row_i, a_ki, a_ii, i = args
|
||||
|
||||
import os
|
||||
old_threads = os.environ.get('OMP_NUM_THREADS', None)
|
||||
os.environ['OMP_NUM_THREADS'] = str(num_processes)
|
||||
os.environ['MKL_NUM_THREADS'] = str(num_processes)
|
||||
os.environ['NUMEXPR_NUM_THREADS'] = str(num_processes)
|
||||
os.environ['OMP_NUM_THREADS'] = '1'
|
||||
os.environ['MKL_NUM_THREADS'] = '1'
|
||||
|
||||
result = sequential_determinant(matrix)
|
||||
|
||||
if old_threads:
|
||||
os.environ['OMP_NUM_THREADS'] = old_threads
|
||||
else:
|
||||
os.environ.pop('OMP_NUM_THREADS', None)
|
||||
factor = a_ki / a_ii
|
||||
|
||||
return result
|
||||
row_k[i:] -= factor * row_i[i:]
|
||||
|
||||
return row_k
|
||||
|
||||
|
||||
def generate_stable_matrix(size: int, scale: float = 1.0) -> np.ndarray:
|
||||
def generate_stable_matrix(size, scale = 1.0) -> np.ndarray:
|
||||
np.random.seed(13)
|
||||
|
||||
random_matrix = np.random.randn(size, size)
|
||||
@@ -150,10 +190,6 @@ def benchmark(sizes, thread_counts):
|
||||
print(f" Детерминант: {det_seq:.6e}")
|
||||
print(f" Sign: {sign_seq}, Log|det|: {logdet_seq:.6f}")
|
||||
|
||||
if logdet_numpy is not None:
|
||||
log_error = abs(logdet_seq - logdet_numpy)
|
||||
print(f" Ошибка Log|det|: {log_error:.10f}")
|
||||
|
||||
results.append({
|
||||
'size': size,
|
||||
'threads': 1,
|
||||
@@ -174,18 +210,12 @@ def benchmark(sizes, thread_counts):
|
||||
det_par = to_float(sign_par, logdet_par)
|
||||
|
||||
speedup = seq_time / par_time if par_time > 0 else 0
|
||||
efficiency = speedup / num_threads * 100
|
||||
|
||||
print(f"Параллельный алгоритм ({num_threads} потоков):")
|
||||
print(f" Время: {par_time:.4f} сек")
|
||||
print(f" Детерминант: {det_par:.6e}")
|
||||
print(f" Ускорение: {speedup:.2f}x")
|
||||
print(f" Эффективность: {efficiency:.1f}%")
|
||||
|
||||
if logdet_numpy is not None:
|
||||
log_error = abs(logdet_par - logdet_numpy)
|
||||
print(f" Ошибка Log|det|: {log_error:.10f}")
|
||||
|
||||
|
||||
results.append({
|
||||
'size': size,
|
||||
'threads': num_threads,
|
||||
@@ -210,26 +240,8 @@ if __name__ == "__main__":
|
||||
print("СВОДНАЯ ТАБЛИЦА РЕЗУЛЬТАТОВ")
|
||||
print("=" * 80)
|
||||
print()
|
||||
print(f"{'Размер':<10} {'Потоки':<10} {'Время (сек)':<15} {'Ускорение':<12} {'Эффективность'}")
|
||||
print(f"{'Размер':<10} {'Потоки':<10} {'Время (сек)':<15} {'Ускорение':<12}")
|
||||
print("-" * 80)
|
||||
|
||||
for r in results:
|
||||
efficiency = (r['speedup'] / r['threads'] * 100) if r['threads'] > 1 else 100
|
||||
print(f"{r['size']:<10} {r['threads']:<10} {r['time']:<15.4f} {r['speedup']:<12.2f} {efficiency:>6.1f}%")
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print("АНАЛИЗ ПРОИЗВОДИТЕЛЬНОСТИ")
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
for size in sizes:
|
||||
size_results = [r for r in results if r['size'] == size]
|
||||
if len(size_results) > 1:
|
||||
seq_time = size_results[0]['time']
|
||||
best_parallel = min(size_results[1:], key=lambda x: x['time'])
|
||||
|
||||
print(f"Матрица {size}x{size}:")
|
||||
print(f" Последовательное время: {seq_time:.4f} сек")
|
||||
print(f" Лучшее параллельное: {best_parallel['time']:.4f} сек ({best_parallel['threads']} потоков)")
|
||||
print(f" Максимальное ускорение: {best_parallel['speedup']:.2f}x")
|
||||
print()
|
||||
print(f"{r['size']:<10} {r['threads']:<10} {r['time']:<15.4f} {r['speedup']:<12.2f}")
|
||||
|
||||
Reference in New Issue
Block a user