我注意到维度从 1 到 2047 的矩阵的计算时间超过 6 秒
从 2048 开始,它们从 44 +- 秒开始。时间如此跳跃的原因可能是什么?
对于 2047 矩阵,RAM 升至 279 MB;对于 2048,RAM 升至 1042 MB
同时,有足够的RAM,她很难只数数
using System.Diagnostics;
using System.Text;
class Program
{
static void Main(string[] args)
{
int m = 0, n = 0;
while (true)
{
Stopwatch stopwatch = new Stopwatch();
InputDate(ref m, "строк m");
InputDate(ref n, "колонок n");
int[][] matrix1 = GenerateMatrix(m, n);
int[][] matrix2 = GenerateMatrix(m, n);
int nn = GetNewDimension(ref m, ref n);
int[][] aN = Addition2SquareMatrix(matrix1, nn, m, n);
int[][] bN = Addition2SquareMatrix(matrix2, nn, m, n);
stopwatch.Start();
int[][] temp = MultiStrassen(aN, bN, nn);
stopwatch.Stop();
//OutputMatrix(matrix1);
//OutputMatrix(matrix2);
//OutputMatrix(GetSubmatrix(temp, m, n));
Console.WriteLine("\n" + stopwatch.Elapsed);
Console.ReadKey();
}
}
/// <summary>
/// Ввод количество строк и столбцов
/// </summary>
/// <param name="number">запись числа в переменную</param>
/// <param name="txt">передаваемый текст</param>
static void InputDate(ref int number, string txt)
{
do
{
Console.Write($"Введите число {txt}: ");
number = int.Parse(Console.ReadLine());
}
while (number <= 0);
}
/// <summary>
/// получаем новую степень матрицы
/// </summary>
/// <param name="m">строка</param>
/// <param name="n">столбец</param>
/// <returns>возвращаем степень матрицы</returns>
static int GetNewDimension(ref int m, ref int n) => 1 << (int)(Math.Log2(Math.Max(m, n))+1);
/// <summary>
/// Преобразуем матрицу к виду 2^n путём добавление дополнительных строк
/// </summary>
/// <param name="a">передаваемый массив</param>
/// <param name="nn">наша новая степень матрицы (размерность)</param>
/// <param name="m">количество строк</param>
/// <param name="n">количество столбцов</param>
/// <returns>возвращаем обновленную матрицу</returns>
static int[][] Addition2SquareMatrix(int[][] a, int nn, int m, int n)
{
int[][] result = new int[nn][];
for (int i = 0; i < nn; i++)
{
result[i] = new int[nn];
if (i < m)
{
for (int j = 0; j < n; j++)
{
result[i][j] = a[i][j];
}
}
}
return result;
}
/// <summary>
/// Алгоритм Штрассена
/// </summary>
/// <param name="a">1 матрица</param>
/// <param name="b">2 матрица</param>
/// <param name="n">размерность матрицы</param>
/// <returns>возвращаем результат</returns>
static int[][] MultiStrassen(int[][] a, int[][] b, int n)
{
if (n <= 64)
{
return Multiply(a, b);
}
n = n >> 1;
int[][] a11 = new int[n][];
int[][] a12 = new int[n][];
int[][] a21 = new int[n][];
int[][] a22 = new int[n][];
int[][] b11 = new int[n][];
int[][] b12 = new int[n][];
int[][] b21 = new int[n][];
int[][] b22 = new int[n][];
for (int i = 0; i < n; i++)
{
a11[i] = new int[n];
a12[i] = new int[n];
a21[i] = new int[n];
a22[i] = new int[n];
b11[i] = new int[n];
b12[i] = new int[n];
b21[i] = new int[n];
b22[i] = new int[n];
}
SplitMatrix(a, a11, a12, a21, a22);
SplitMatrix(b, b11, b12, b21, b22);
int[][] p1 = MultiStrassen(Summation(a11, a22), Summation(b11, b22), n);
int[][] p2 = MultiStrassen(Summation(a21, a22), b11, n);
int[][] p3 = MultiStrassen(a11, Subtraction(b12, b22), n);
int[][] p4 = MultiStrassen(a22, Subtraction(b21, b11), n);
int[][] p5 = MultiStrassen(Summation(a11, a12), b22, n);
int[][] p6 = MultiStrassen(Subtraction(a21, a11), Summation(b11, b12), n);
int[][] p7 = MultiStrassen(Subtraction(a12, a22), Summation(b21, b22), n);
int[][] c11 = Summation(Summation(p1, p4), Subtraction(p7, p5));
int[][] c12 = Summation(p3, p5);
int[][] c21 = Summation(p2, p4);
int[][] c22 = Summation(Subtraction(p1, p2), Summation(p3, p6));
return CollectMatrix(c11, c12, c21, c22);
}
/// <summary>
/// Разделение на матрицу на под матрицы
/// </summary>
/// <param name="a">исходная матрица</param>
/// <param name="a11">матрицы а11</param>
/// <param name="a12">матрица а12</param>
/// <param name="a21">матрица а21</param>
/// <param name="a22">матрица а22</param>
static void SplitMatrix(int[][] a, int[][] a11, int[][] a12, int[][] a21, int[][] a22)
{
int n = a.Length >> 1;
for (int i = 0; i < n; i++)
{
Array.Copy(a[i], 0, a11[i], 0, n);
Array.Copy(a[i], n, a12[i], 0, n);
Array.Copy(a[i + n], 0, a21[i], 0, n);
Array.Copy(a[i + n], n, a22[i], 0, n);
}
}
/// <summary>
/// Объединение подматриц в одну матрицу
/// </summary>
/// <param name="a11"></param>
/// <param name="a12"></param>
/// <param name="a21"></param>
/// <param name="a22"></param>
/// <returns>возвращаем объединённую матрицу</returns>
static int[][] CollectMatrix(int[][] a11, int[][] a12, int[][] a21, int[][] a22)
{
int n = a11.Length;
var b = (n << 1);
int[][] a = new int[b][];
for (int i = 0; i < b; i++)
{
a[i] = new int[b];
}
for (int i = 0; i < n; i++)
{
Array.Copy(a11[i], 0, a[i], 0, n);
Array.Copy(a12[i], 0, a[i], n, n);
Array.Copy(a21[i], 0, a[i + n], 0, n);
Array.Copy(a22[i], 0, a[i + n], n, n);
}
return a;
}
/// <summary>
/// Разность между матрицами
/// </summary>
/// <param name="a">матрица 1</param>
/// <param name="b">матрица 2</param>
/// <returns>результат разности матриц</returns>
static int[][] Subtraction(int[][] a, int[][] b)
{
int n = a.Length;
int m = a[0].Length;
int[][] c = new int[n][];
for (int i = 0; i < n; i++)
{
c[i] = new int[m];
for (int j = 0; j < m; j++)
{
c[i][j] = a[i][j] - b[i][j];
}
}
return c;
}
/// <summary>
/// Умножение матриц
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns>результат умножения </returns>
static int[][] Multiply(int[][] a, int[][] b)
{
int rowsA = a.Length;
int columnsB = b[0].Length;
int columnsA_rowsB = a[0].Length;
int[][] c = new int[rowsA][];
for (int i = 0; i < rowsA; i++)
{
c[i] = new int[columnsB];
for (int j = 0; j < columnsB; j++)
{
int sum = 0;
for (int k = 0; k < columnsA_rowsB; k++)
{
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return c;
}
/// <summary>
/// Суммирование матриц
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
static int[][] Summation(int[][] a, int[][] b)
{
int n = a.Length;
int m = a[0].Length;
int[][] c = new int[n][];
for (int i = 0; i < n; i++)
{
c[i] = new int[m];
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
c[i][j] = a[i][j] + b[i][j];
}
}
return c;
}
/// <summary>
/// Убирает лишние строки матриц
/// </summary>
/// <param name="a"></param>
/// <param name="n"></param>
/// <param name="m"></param>
/// <returns>возвращаем матрицу</returns>
static int[][] GetSubmatrix(int[][] a, int n, int m)
{
int[][] result = new int[n][];
for (int i = 0; i < n; i++)
{
result[i] = new int[m];
Array.Copy(a[i], 0, result[i], 0, m);
}
return result;
}
/// <summary>
/// Генерация произвольного размера матрицы
/// </summary>
/// <param name="m">количество строк</param>
/// <param name="n">количество столбцов</param>
/// <returns>возврощаем матрицу</returns>
static int[][] GenerateMatrix(int m, int n)
{
Random rand = new Random();
int[][] matrix = new int[m][];
for (int i = 0; i < m; i++)
{
matrix[i] = new int[n];
for (int j = 0; j < n; j++)
{
matrix[i][j] = rand.Next(1, 100);
}
}
return matrix;
}
/// <summary>
/// Вывод на экран матриц
/// </summary>
/// <param name="matrix"></param>
static void OutputMatrix(int[][] matrix)
{
var sb = new StringBuilder();
foreach (int[] row in matrix)
{
foreach (int element in row)
{
sb.Append(element);
sb.Append(' ');
}
sb.Length--;
sb.AppendLine();
}
Console.WriteLine($"\n" + sb);
}
}



