الگوریتم‌های ضرب ماتریس
ضرب ماتریس یکی از اعمال پایه در بسیاری از الگوریتم‌های آنالیز عددی محسوب می‌شود به همین دلیل در راستای بهبود زمان آن تلاش‌های بسیاری انجام شده‌است. کاربردهای ضرب ماتریس در بسیاری از زمینه‌های مختلف همچون علم محاسبه و بازشناخت الگو و حتی زمینه‌های به ظاهر بی‌ربط مانند شمردن تعداد گشت‌ها در یک گراف دیده می‌شود. الگوریتم‌های بسیاری برای این‌کار روی سیستم‌های رایانش موازی طراحی شده‌است که در آن چند هسته به صورت همزمان و موازی عملیات را انجام می‌دهند.
اگر از تعریف ضرب ماتریس به صورت مستقیم استفاده کنیم برای ضرب دو ماتریس زمان طول خواهد کشید که به صورت می‌توانیم نمایش دهیم. الگوریتم‌هایی با زمان اجرای بهتری برای این‌کار ارائه شده‌اند. برای مثال در دههٔ ۱۹۶۰ استراسن در این زمینه الگوریتم‌هایی ارائه داد اما به‌طور کلی هنوز نمی‌دانیم بهترین الگوریتم برای این کار چیست. (در واقع پیچیدگی زمانی آن مشخص نیست)
طبق تعریف ضرب ماتریس می‌توانیم یک الگوریتم برای این کار ارائه دهیم. به ازای ماتریس formula_1 که یک ماتریس formula_2 است و ماتریس formula_3 که یک ماتریس formula_4 است می‌خواهیم ماتریس formula_5 که ماتریسی formula_6 است را محسابه کنیم. طبق تعریف ضرب ماتریس formula_7 بنابراین به ازای هر دوتایی formula_8 می‌توانیم با formula_9 مقدار formula_10 را محاسبه کنیم. یعنی در کل الگوریتمی با زمان اجرای formula_11 خواهیم داشت. اگر فرض کنیم هر سه ماتریس formula_12 هستند آنگاه الگوریتم formula_13 خواهد بود.
در الگوریتم بالا ترتیب حلقه‌ها را می‌توانیم جابه‌جا کنیم. اگر چه این جابه‌جایی در مدت زمان اجرای الگوریتم تأثیری نخواهد داشت اما این ترتیب در بحث‌های مربوط به دسترسی حافظه (access pattern) و مسائل مربوط به استفاده از حافظه نهان پردازنده مهم است. مثلاً اینکه ماتریس‌ها به ترتیب سطری یا ستونی (یا ترکیبی از این دو) ذخیره شوند در زمان حافظهٔ نهان پردازنده تأثیر گذار خواهد بود.
حتی اگر حالت بهینه را در نظر بگیریم که حافظهٔ کش شرکت پذیر کامل با formula_14 سطر حافظهٔ formula_15 بیتی باشد و ماتریس‌های formula_16 و formula_17 به صورت سطری ذخیره شده‌باشند، این الگوریتم بهینه نخواهد بود. هنگامی که formula_18 از آنجایی که ماتریس‌ها به صورت سطری ذخیره شده‌اند هر پیمایش حلقهٔ داخلی در الگوریتم (یک پیمایش روی سطر ماتریس اول و ستون ماتریس دوم) یک خطای کش به هنگام دسترسی به خانه‌ی‌های ماتریس دوم به همراه خواهد داشت؛ و این به این معناست که الگوریتم در بدترین حالت حاوی formula_19 خطای کش خواهد بود. امروزه -یعنی از سال ۲۰۱۰- خطای کش‌ها به نسبت اعمال پردازنده تأثیر بیشتری روی زمان اجرا می‌گذارند بنابراین بهتر است با روشی این خطای کش‌ها را کاهش دهیم.
برای حل این مشکل ماتریس‌ها را به بلوک‌هایی از اردر formula_20 تایی تقسیم می‌کنیم. با اینکار کل یک زیرجدول در حافظهٔ کش قرار می‌گیرد و این بلوک‌ها در هم ضرب می‌شوند. ضرب هر بلوکی هیچ خطای کشی به همراه نخواهد داشت. تعداد خطاهای کش در این مدل برابر formula_21 خواهدبود. مخرج formula_22 باعث می‌شود در پردازنده‌های جدید خطاهای کش در زمان اجرا تأثیر گذار نشوند و صرفاً تحلیل زمانی الگوریتم تأثیر گذار باشد.
حال سعی می‌کنیم روشی تقسیم و حل برای ضرب ماتریس‌ها ارائه دهیم. ابتدا فرض کنید ماتریس‌هایمان formula_12 هستند. در این روش مطابق زیر ماتریس‌ها را به چهار بلوک تقسیم می‌کنیم که اندازهٔ آن‌ها تقریباً برابرند.
اگر ماتریس‌های‌مان اندازه‌شان توانی از دو باشد (یعنی ماتریسی با ابعاد formula_25 ) می‌توانیم این الگوریتم را به کار بگیریم. به صورت زیر دو ماتریس را در هم ضرب می‌کنیم.
این الگوریتم شامل ۸ ضرب ماتریس‌های کوچکتر formula_27 خواهد بود که به‌صورت بازگشتی محاسبه می‌شود و پایهٔ آن ضرب اسکالر formula_28 است. همچنین جمع کردن ماتریس‌ها به صورتی که در بالا گفته‌شده formula_29 طول خواهد کشید.
توجه کنید اگر ماتریس ما ابعادش توانی از ۲ نبود باز هم می‌توانیم این الگوریتم را به کار ببریم. کافیست با اضافه کردن سطرهایی تمام صفر و ستون‌هایی تمام صفر به پایین و راست ماتریس ابعادش را توانی از دو کنیم. با اضافه کردن آن‌ها اندازهٔ ماتریس حداکثر ۴ برابر خواهد شد (تعداد ستون‌ها و سطرها هر کدام ۲ برابر خواهند شد) بنابراین تفاوتی در تحلیل زمانی ایجاد نمی‌شود به‌علاوه افزودن سطر و ستون تمام صفر تأثیری در حاصل‌ضرب نخواهدگذاشت.
با توجه به مطالب گفته‌شده برای تحلیل زمانی آن می‌توانیم رابطهٔ زیر را بنویسیم:
بر طبق قضیه‌ی اصلی می‌توانیم این الگوریتم را تحلیل زمانی کنیم. می‌دانیم formula_32 بنابراین formula_33 خواهد بود.
در نتیجه این الگوریتم با الگوریتم ابتدایی‌ای که بررسی کردیم تفاوتی از نظر زمانی ندارد.
این الگوریتم در عمل برای ماتریس‌های غیر مربعی سریع‌تر عمل می‌کند. کافیست به جای تقسیم کردن هر دو ماتریس به چهار تکه یکی از ماتریس‌ها را به دو تکهٔ برابر (یا تقریباً برابر) با تقسیم کردن سطرها یا ستون‌ها تقسیم کنیم. در زیر می‌توانید الگوریتم چنین کاری را ببینید:
الگوریتم گفته‌شده در این بخش تقسیم‌بندی را تا جایی می‌تواند ادامه دهد که کل ماتریس در حافظهٔ کش جا شوند و بنابراین از نظر تعداد خطاهای کش مانند روش تقسیم‌بندی بلوکی عمل می‌کند. با این تفاوت که در آن الگوریتم خود پیاده‌سازی الگوریتم با توجه به اندازهٔ کش پردازندهٔ هدف انجام می‌شود (پارامتر formula_37 ای را باید در خود متن الگوریتم تعیین کنیم) در حالیکه این الگوریتم برای کش‌های پویا با اندازه‌های مختلف بهینه‌تر عمل خواهد کرد.
تعداد خطاهای کش در این الگوریتم با formula_14 خط حافظهٔ کش که هر خط formula_15 بیت دارد به صورت زیر خواهد بود:
الگوریتم‌هایی وجود دارند که زمان اجرای بهتری از الگوریتم‌های فوق دارند. اولین الگوریتم کشف شده که اینگونه بود الگوریتم استراسن بود که در سال ۱۹۶۹ توسط وولکر استراسن (Volker Strassen) کشف شد. این الگوریتم به «الگوریتم سریع ضرب ماتریس» نیز معروف است. این الگوریتم بر مبنای ضرب دو ماتریس formula_42 با ۷ عملیات ضرب است که در عوض تعداد بیشتری جمع و عملیات ریاضی این‌چنینی لازم دارد. با استفاده از این ایده به‌صورت بازگشتی الگوریتمی از formula_43 به ما می‌دهد. این الگوریتم پیچیده‌است و ضرایب ثابت آن در تحلیل زمانی به اندازه‌ای زیاد است که تنها برای ماتریس‌های بزرگ کارامدتر از الگوریتم‌های قبلی عمل خواهد کرد.
سریعترین الگوریتم با formula_44 الگوریتمی است که از تعمیم الگوریتم کوپراسمیت–وینوگارد به‌دست آمده و از نظر زمانی formula_45 می‌باشد. این الگوریتم توسط François Le Gall کشف شد و به قدری ضرایب زیادی دارد و سربار الگوریتم بالاست که تنها برای ماتریس‌های بسیار بزرگی که هم‌اکنون در علوم کامپیوتر کاربردی ندارند، کارامد خواهد بود.
با توجه به این‌که باید حداقل روی همهٔ اعضای دو ماتریس formula_12 پیمایش انجام بشود کران‌پایین formula_47 برای الگوریتم‌های ضرب ماتریس وجود دارد. راز (Raz) ثابت کرد که کران پایین formula_48 نیز برای هر الگوریتم ضرب ماتریس نیز وجود دارد.
همچنین الگوریتم الگوریتم فریوالد یک الگوریتم احتمالی و مونت کارلو است که در formula_49 چک می‌کند که آیا ضرب دو ماتریس formula_50 برابر formula_51 هست یا نه.