ضرب ماتریسهای خلوت
هر سطر را فقط با جملههای ناصفرش نگه میدارد و فقط ضربهای ناصفر را انجام میدهد؛ برای ماتریسهای خلوت خیلی کمتر از n³ ضرب.
در ماتریس خلوت بیشتر ضربهای A[i][k]·B[k][j] صفرند و انجامشان بیفایده است. اگر هر سطر را فقط با جملههای ناصفرش نگه داریم:
- زمان:
O(rows + the number of non-zero products) - حافظه:
O(non-zeros) - هوروویتز–ساهنی، فصل ۲
دو ماتریس ۴×۴ که بیشتر خانههایشان صفر است؛ بهجای ۶۴ ضرب فقط ۵ ضرب لازم است.
def sparse_multiply(A, B):if len(A[0]) != len(B):return None# Row lists: for each row, only its non-zero (column, value) pairs.a_rows = [[(j, v) for j, v in enumerate(row) if v != 0] for row in A]b_rows = [[(j, v) for j, v in enumerate(row) if v != 0] for row in B]C = []products = 0for i in range(len(A)):acc = {}for k, a in a_rows[i]:for j, b in b_rows[k]:acc[j] = acc.get(j, 0) + a * bproducts = products + 1C.append(sorted((j, v) for j, v in acc.items() if v != 0))return products
شروع اجرا
products—
a_rows
جدول هنوز خالی است.
b_rows
جدول هنوز خالی است.
C
جدول هنوز خالی است.
متغیرهای محلی
نارنجی = در همین گام عوض شد
A list
[1, 0, 0, 2][0, 0, 3, 0][0, 0, 0, 0][4, 0, 0, 0]
B list
[0, 5, 0, 0][0, 0, 0, 0][6, 0, 0, 7][0, 0, 8, 0]
Call stack
- sparse_multiply()خط 1
گام ۱ از ۴۷
توضیح
ایده
در ماتریس خلوت بیشتر ضربهای A[i][k]·B[k][j] صفرند و انجامشان بیفایده است. اگر هر سطر را فقط با جملههای ناصفرش نگه داریم:
- برای سطر
iازA، هر جملهی ناصفرA[i][k]را در جملههای ناصفر سطرkازBضرب کن و درacc[j]جمع کن. accسطرiحاصل است؛ صفرها کنار گذاشته میشوند.
هزینه
تعداد ضربها دقیقاً تعداد جفتهای ناصفر (A[i][k], B[k][j]) است، که برای ماتریسهای خلوت خیلی کمتر از n³ است. کتاب هوروویتز همین کار را روی سهتاییها و با ترانهادهی B انجام میدهد؛ ایده یکی است.
در trace به چه چیزی نگاه کنی
- جدولهای
a_rowsوb_rowsفهرست جملههای ناصفر هر سطرند وCحاصل به همان شکل.productsتعداد ضربهای انجامشده است.