Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Сравнение алгоритмов умножения квадратных матри...docx
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
82.87 Кб
Скачать

Список использованной литературы

  1. Умножение матрицы на матрицу [электронный ресурс] // http://vm.psati.ru/online-math-sem-1/page-1-1-02-03.html

  2. Алгоритм Штрассена [электронный ресурс] // http://ru.wikipedia.org/wiki/Алгоритм_Штрассена

Приложения

Приложение 1. Замеры времени, размерности 100 – 1200

Таблица 1. Зависимость времени (мс.) работы алгоритмов от размерностей матриц.

Размерность

Классический

Штрассена

Штрассена (ускоренный)

100

16

15

28

110

0

16

19

120

0

15

18

130

16

62

103

140

0

78

104

150

15

63

104

160

16

62

105

170

16

62

104

180

15

78

104

190

31

63

104

200

32

78

135

210

46

63

134

220

47

63

136

230

47

62

135

240

62

62

137

250

62

78

135

260

62

500

593

270

94

483

593

280

94

483

594

290

109

499

594

300

110

499

594

310

141

483

593

320

140

499

594

330

171

484

724

340

172

499

727

350

187

500

724

360

218

484

726

370

234

484

726

380

265

515

729

Размерность

Классический

Штрассена

Штрассена (ускоренный)

390

281

483

900

400

297

499

898

410

328

483

900

420

328

499

903

430

374

500

900

440

406

484

900

450

437

499

968

460

515

484

970

470

546

500

969

480

562

499

970

490

608

500

991

500

640

484

969

510

733

500

969

520

702

3447

3474

530

795

3479

3476

540

796

3588

3476

550

843

3463

3473

560

936

3478

3477

570

1014

3447

3477

580

1279

3463

4048

590

1061

3494

4050

600

1295

3463

4052

610

1264

3479

4055

620

1326

3494

4055

630

1404

3463

4056

640

1482

3494

4057

650

1560

3463

4812

660

1653

3510

4818

670

1669

3557

4819

680

2917

3557

4818

690

2200

3494

4802

700

2043

3510

4816

710

2216

3494

5107

720

2371

3557

5106

Размерность

Классический

Штрассена

Штрассена (ускоренный)

730

2450

3478

5115

740

2652

3494

5093

750

2668

3525

5109

760

2823

3495

5129

770

3042

3494

6030

780

3151

3526

6037

790

3244

3510

6050

800

3354

3479

6035

810

3791

3619

6034

820

3837

3619

6033

830

3915

3541

6020

840

4150

3572

6352

850

4509

3728

6345

860

4493

3713

6389

870

4883

3651

6366

880

5242

3681

6391

890

5366

3666

6391

900

5460

3588

6755

910

5382

3510

6786

920

6396

3588

6770

930

5944

3494

6771

940

6427

3541

6864

950

6630

3635

6755

960

7083

3650

6801

970

7566

3759

6927

980

7691

3728

6910

990

7246

3660

6973

1000

8296

3668

6911

1010

9904

3700

6942

1020

11770

3568

6926

1030

10717

25295

21606

1040

10537

25711

21622

1050

10004

25370

21591

1060

9767

25676

21700

Размерность

Классический

Штрассена

Штрассена (ускоренный)

1070

9218

25728

21575

1080

10634

25563

21622

1090

13240

25570

24149

1100

10651

25338

24289

1110

11423

25544

24258

1120

11050

25470

24227

1130

11312

25926

24259

1140

12468

25730

24134

1150

13514

25861

24602

1160

12926

25828

28064

1170

12748

25880

27846

1180

13746

25946

28127

1190

14537

26174

27862

1200

14902

26082

27752

Приложение 2. Замеры времени, размерности 500 – 4500

Таблица 2. Зависимость времени (мс.) работы алгоритмов от размерностей матриц.

Размерность

Классический

Штрассена

Штрассена (ускоренный)

500

546

485

967

1000

6956

3485

6878

1500

24704

24607

36009

2000

63220

24672

48852

2500

136142

191030

212285

3000

258350

196074

273624

3500

518202

193112

341890

4000

873557

195904

392076

4500

1359373

1482270

1324115

Приложение 3. Листинг

Класс Matrix

//---------------------------------------------------------------------------

#ifndef MatrixH

#define MatrixH

#pragma once

#include <ComCtrls.hpp>

#include <Windows.h>

#include <Math.h>

template <typename T>

class Matrix{

private:

int n;

T ** a;

int notZeroColumns; // количество ненулевых столбцов

int notZeroLines;

static Matrix<T> ** decomposeMatrix( Matrix<T> * const m );

Matrix<T> * buildMatrix( Matrix<T> ** const m );

static int isNormalSize( Matrix<T> * const m );

Matrix<T> * getNormalized(int nextPow);

Matrix<T> * __fastcall sp( Matrix<T> * const a, Matrix<T> * const b); // shtrassenProduct

bool inline isNull();

public:

Matrix< T >(int n, bool autoSet = true);

Matrix< T >* __fastcall classicProduct (Matrix< T > *m);

Matrix< T >* shtrassenProduct (Matrix< T > *m);

Matrix< T >* operator - (Matrix< T > * op);

Matrix< T >* operator + (Matrix< T > * op);

~Matrix< T >();

};

//---------------------------------------------------------------------------

template <typename T>

Matrix< T >::Matrix(int n, bool autoSet){

this->n = n;

a = new T*[ n ];

for (int i = 0; i < n; i ++){

a[ i ] = new T[ n ];

}

short p = RAND_MAX;

if ( autoSet ){

for (int i = 0; i < n; i ++)

for (int j = 0; j < n; j ++)

a[ i ][ j ] = (T)rand() ;

notZeroColumns = n;

notZeroLines = n;

} else {

notZeroColumns = 0;

notZeroLines = 0;

}

}

template <typename T>

Matrix< T >::~Matrix(){

for (int i = 0; i < n; i ++ )

delete[] a[i];

delete[] a;

}

template <typename T>

bool inline Matrix< T >::isNull(){

return ! (notZeroColumns && notZeroLines);

}

template <typename T>

Matrix< T >* __fastcall Matrix< T >::classicProduct(Matrix< T > *m){

Matrix *res = new Matrix(n, false);

T Aij = 0;

for (int i = 0; i < n; i ++){

for (int j = 0; j < n; j ++){

for (int t = 0; t < n; t ++)

Aij += (T)(a[ i ][ t ] * m->a[ t ][ j ]);

res->a[ i ][ j ] = Aij;

Aij = 0;

}

}

return res;

}

template <typename T>

Matrix< T >* Matrix< T >::shtrassenProduct(Matrix< T > *m){

// подготовка и запуск рекурсии

Matrix<T> * res = NULL,

* normalizedMatrixA = NULL,

* normalizedMatrixB = NULL;

if( int nextPow = isNormalSize( m )){

normalizedMatrixA = this->getNormalized( nextPow );

normalizedMatrixB = m->getNormalized( nextPow ); // подгон размера под степень двойки

} else {

normalizedMatrixA = this;

normalizedMatrixB = m;

}

res = sp( normalizedMatrixA, normalizedMatrixB);

// достаточно проверить "нормальность" одной из матриц

if( normalizedMatrixB != m ){

delete normalizedMatrixA; delete normalizedMatrixB; // удаляем порождённые матрицы

}

return res;

}

template <typename T>

Matrix<T> * __fastcall Matrix< T >::sp( Matrix<T> * const ma, Matrix<T> * const mb){

// только матрицы размера степени 2 !!!

Matrix<T> * res = NULL;

// выявление нулевой матрицы

if( ma->isNull() || mb->isNull() )

return new Matrix< T >( ma->n , false );

if(ma->n <= int (2 << 5)){

return ma->classicProduct(mb);

}

else {

Matrix<T> ** A = decomposeMatrix( ma ),

* A11 = A[0], * A12 = A[1],

* A21 = A[2], * A22 = A[3],

** B = decomposeMatrix( mb ),

* B11 = B[0], * B12 = B[1],

* B21 = B[2], * B22 = B[3],

* C11, * C12,* C21,* C22; // части результирующей матрицы

Matrix<T> * P1, * P2, * P3, * P4, // промежуточные вычисления

* P5, * P6, * P7, * sumBuf1, * sumBuf2;

sumBuf1 = *A11 + A22; sumBuf2 = *B11 + B22;

P1 = sp( sumBuf1, sumBuf2);

delete sumBuf1; delete sumBuf2;

sumBuf1 = *A21 + A22;

P2 = sp( sumBuf1, B11);

delete sumBuf1;

sumBuf1 = *B12 - B22;

P3 = sp( A11, sumBuf1);

delete sumBuf1;

sumBuf1 = *B21 - B11;

P4 = sp( A22, sumBuf1);

delete sumBuf1;

sumBuf1 = *A11 + A12;

P5 = sp( sumBuf1, B22);

delete sumBuf1;

sumBuf1 = *A21 - A11; sumBuf2 = *B11 + B12;

P6 = sp( sumBuf1, sumBuf2);

delete sumBuf1; delete sumBuf2;

delete A11; delete B11; delete B12;

sumBuf1 = *A12 - A22; sumBuf2 = *B21 + B22;

P7 = sp( sumBuf1, sumBuf2);

delete sumBuf1; delete sumBuf2;

delete A22; delete B22; delete A21; delete B21; delete A12;

delete[] A; delete[] B;

//------------------------------------------------------------------------------

sumBuf1 = *P1 + P4; sumBuf2 = *P5 + P7;

C11 = *sumBuf1 - sumBuf2;

delete sumBuf1; delete sumBuf2;

delete P7;

C12 = *P3 + P5;

delete P5;

C21 = *P2 + P4;

delete P4;

sumBuf1 = *P1 - P2; sumBuf2 = *P3 + P6;

C22 = *sumBuf1 + sumBuf2;

delete sumBuf1; delete sumBuf2;

delete P1; delete P2; delete P3; delete P6;

Matrix<T> * C[4] = {C11, C12, C21, C22};

res = buildMatrix( C );

delete C11; delete C12; delete C21; delete C22;

}

return res;

}

template <typename T>

Matrix<T> ** Matrix<T>::decomposeMatrix( Matrix<T> * const m ){

int size = m->n / 2, max = m->n,

dc = m->notZeroColumns - size,

firstPathCol = dc > 0 ? size : m->notZeroColumns,

scondPathCol = dc > 0 ? dc : 0, // количество ненулевых столбцов в матрицых 1 4 четверити

dl = m->notZeroLines - size,

firstPathLin = dl > 0 ? size : m->notZeroLines,

scondPathLin = dl > 0 ? dl : 0;

Matrix<T> ** res = new Matrix<T> * [4],

* A11 = new Matrix<T>( size, false ),

* A12 = new Matrix<T>( size, false ),

* A21 = new Matrix<T>( size, false ),

* A22 = new Matrix<T>( size, false );

res[0] = A11; res[1] = A12; res[2] = A21; res[3] = A22;

A11->notZeroColumns = firstPathCol; A11->notZeroLines = firstPathLin;

A12->notZeroColumns = scondPathCol; A12->notZeroLines = firstPathLin;

A21->notZeroColumns = firstPathCol; A21->notZeroLines = scondPathLin;

A22->notZeroColumns = scondPathCol; A22->notZeroLines = scondPathLin;

// выборка А11

for (int i = 0; i < size; i ++)

for ( int j = 0; j < size; j ++)

A11->a[i][j] = m->a[i][j];

// выборка А12

for (int i = 0; i < size && scondPathCol; i ++) // не копируем нули

for (int j = size; j < max; j ++)

A12->a[i][j - size] = m->a[i][j];

// выборка А21

for (int i = size; i < max && scondPathLin; i ++)

for (int j = 0; j < size; j ++)

A21->a[i - size][j] = m->a[i][j];

// выборка А22

for (int i = size; i < max && scondPathCol && scondPathLin; i ++)

for (int j = size; j < max; j ++)

A22->a[i - size][j - size] = m->a[i][j];

return res;

}

template <typename T>

Matrix<T> * Matrix<T>::buildMatrix( Matrix<T> ** const m ){

Matrix<T> * A11 = m[0], * A12 = m[1], * A21 = m[2], * A22 = m[3];

int halth = A11->n, size = A11->n * 2, i = 0, j = 0;

Matrix<T> * result = new Matrix<T>( size, false );

for ( i; i < halth; i ++)

for ( j; j < halth; j ++)

result->a[i][j] = A11->a[i][j];

for ( i = 0; i < halth; i ++)

for ( j = halth; j < size; j ++)

result->a[i][j] = A12->a[i][j - halth];

for ( i = halth; i < size; i ++)

for ( j = 0; j < halth; j ++)

result->a[i][j] = A21->a[i - halth][j];

for ( i = halth; i < size; i ++)

for ( j = halth; j < size; j ++)

result->a[i][j] = A22->a[i - halth][j - halth];

result->notZeroColumns = size;

result->notZeroLines = size;

return result;

}

template <typename T>

Matrix<T> * Matrix< T >::getNormalized( int nextPow ){

// считаем что исходная матрица меньше

Matrix<T> * res = new Matrix<T>(nextPow, false);

for (int i = 0; i < n; i ++)

for (int j = 0; j < n; j ++)

res->a[i][j] = a[i][j];

res->notZeroColumns = n; res->notZeroLines = n;

return res;

}

template <typename T>

int Matrix< T >::isNormalSize( Matrix<T> * const m ){

// возвращать 0 когда степень 2ки

int power = 2;

while( power < m->n )

power <<= 1;

return m->n & power ? 0 : power;

}

template <typename T>

Matrix< T >* Matrix<T>::operator - (Matrix< T > * op){

Matrix<T> *res = new Matrix<T>(n, false);

for (int i = 0; i < n; i ++)

for (int j = 0; j < n; j ++)

res->a[i][j] = T(a[i][j] - op->a[i][j]);

res->notZeroColumns = notZeroColumns > op->notZeroColumns ?

notZeroColumns : op->notZeroColumns;

res->notZeroLines = notZeroLines > op->notZeroLines ?

notZeroLines : op->notZeroLines;

return res;

}

template <typename T>

Matrix< T >* Matrix<T>::operator + (Matrix< T > * op){

Matrix<T> *res = new Matrix<T>(n, false);

for (int i = 0; i < n; i ++)

for (int j = 0; j < n; j ++)

res->a[i][j] = T (a[i][j] + op->a[i][j]);

res->notZeroColumns = notZeroColumns > op->notZeroColumns ?

notZeroColumns : op->notZeroColumns;

res->notZeroLines = notZeroLines > op->notZeroLines ?

notZeroLines : op->notZeroLines;

return res;

}

#endif

Оболочка для тестирования

//---------------------------------------------------------------------------

#ifndef MainFormH

#define MainFormH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ComCtrls.hpp>

#include <ExtCtrls.hpp>

#include <Grids.hpp>

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published: // IDE-managed Components

TButton *Start;

TStringGrid *Results;

TGroupBox *GroupBox1;

TGroupBox *GroupBox2;

TRichEdit *Output;

TGroupBox *GroupBox3;

TLabel *Label3;

TEdit *StartSize;

TLabel *Label4;

TEdit *EndSize;

TLabel *Label5;

TEdit *StepBySize;

TLabel *Label6;

TEdit *NumberExperements;

TCheckBox *LogCheckBox;

void __fastcall StartClick(TObject *Sender);

private:

void __fastcall doExperementCicle( short experementCircleNumber, short experementCount, short matrixSize,

TTime & classicTime, TTime & strassenTime);

public: // User declarations

__fastcall TForm1(TComponent* Owner);

void prepareOutput();

};

//---------------------------------------------------------------------------

extern PACKAGE TForm1 *Form1;

//---------------------------------------------------------------------------

#endif

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "MainForm.h"

#include "Matrix.h"

#include <iostream>

using namespace std;

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

#define TYPE short

#define LOG_FILE_NAME_PREFIX "logs/LOG "

#define LOG_FILE_EXTENSION ".txt"

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

Results->Cells[0][0] = "Алгоритм";

}

//---------------------------------------------------------------------------

void prepareTable(TStringGrid * table, int experementCount){

AnsiString * str;

for ( int i = 0; i < experementCount; i ++){

table->ColCount += 1;

str = new AnsiString();

str->printf("Тест №%i",i + 1);

table->Cells[i + 1][0] = *str;

delete str;

}

}

void __fastcall TForm1::doExperementCicle( short experementCircleNumber, short experementCount, short matrixSize,

TTime & classicTime, TTime & strassenTime){

Matrix<TYPE> m( matrixSize, true ), m1( matrixSize, true ), *m2; // рабочие матрицы

AnsiString *str; // для вывода

unsigned short hour, min, sec, msec; // время для вывода

TTime t1, t2, dt, // время работы

*classicTimes = new TTime[experementCount], // для вычисления среднего времени работы алгоритмов

*shtrassenTimes = new TTime[experementCount];

Results->RowCount += 2;

int classicLineNumber = 2 * experementCircleNumber + 1;

for ( int i = 0; i < experementCount; i ++){

str = new AnsiString("Клас.");

str->cat_printf("(n=%i)", matrixSize);

Results->Cells[0][classicLineNumber] = str->c_str();

delete str;

str = new AnsiString("Штрас.");

str->cat_printf("(n=%i)", matrixSize);

Results->Cells[0][classicLineNumber + 1] = str->c_str();

delete str;

// запуск теста классического алгоритма

str = new AnsiString();

str->printf("Серия %i. Тест %i Классического алгоритма с n=%i начат...",

experementCircleNumber + 1, i + 1, matrixSize);

Output->Lines->Add(*str);

SendMessage(Output->Handle, EM_LINESCROLL, 0, MAKEWORD(SB_LINEDOWN, 0));

//Update();

delete str;

t1 = Time();

m2 = m.classicProduct( &m1 );

t2 = Time();

dt = t2 - t1;

classicTimes[ i ] = dt;

DecodeTime(dt, hour, min, sec, msec);

str = new AnsiString();

str->printf("%im: %is: %ims", min, sec, msec );

Results->Cells[i + 1][classicLineNumber] = *str;

delete str;

delete m2;

// запуск теста алгоритма Штрассена

str = new AnsiString();

str->printf("Серия %i. Тест %i алгоритма Штрассена с n=%i начат...",

experementCircleNumber + 1, i + 1, matrixSize);

Output->Lines->Add(*str);

delete str;

SendMessage(Output->Handle, EM_LINESCROLL, 0, MAKEWORD(SB_LINEDOWN, 0));

//Update();

t1 = Time();

m2 = m.shtrassenProduct( &m1 );

t2 = Time();

dt = t2 - t1;

shtrassenTimes[ i ] = dt;

DecodeTime(dt, hour, min, sec, msec);

str = new AnsiString();

str->printf("%im: %is: %ims", min, sec, msec );

Results->Cells[i + 1][classicLineNumber + 1] = *str;

delete str;

delete m2;

Repaint();

}

// подсчёт среднего времени

t1 = 0; t2 = 0;

for (int i = 0; i < experementCount; i ++){

t1 += classicTimes[ i ];

t2 += shtrassenTimes[ i ];

}

delete[] classicTimes; delete[] shtrassenTimes;

t1 = t1.operator double() / experementCount;

t2 = t2.operator double() / experementCount;

classicTime = t1; strassenTime = t2;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::StartClick(TObject *Sender)

{

int currentMatrixSize = 0,

maxMatrixSize = 0,

stepBy = 0,

numberExperements = 0;

try {

currentMatrixSize = StartSize->Text.ToInt();

maxMatrixSize = EndSize->Text.ToInt();

stepBy = StepBySize->Text.ToInt();

numberExperements = NumberExperements->Text.ToInt();

}

catch (...) {

ShowMessage("Необходимо вводить только целочисленные значения.");

}

if ( currentMatrixSize > 0 && numberExperements > 0){

prepareOutput();

prepareTable( Results, numberExperements );

AnsiString *str;

// ведение лога

TDateTime dt = TTime::CurrentDateTime();

str = new AnsiString( LOG_FILE_NAME_PREFIX );

str->cat_printf( "%s", dt.FormatString("dd-mm-yyyy (hhч nnм ssс)") );

str->cat_printf( LOG_FILE_EXTENSION );

FILE *file;

file = this->LogCheckBox->Checked ?

fopen(str->c_str(), "w") : NULL;

delete str;

if( file ){

AnsiString text( "Испытания от: " ),

line( "---------------------------------------------------------------------------------------------------");

text.cat_printf("%s\n", dt.DateTimeString());

text.cat_printf("%s\n", line);

text.cat_printf("%s\n\n", "Входные параметры испытаний:");

text.cat_printf("%s %i\n", "Начальный размер матриц:" , currentMatrixSize);

text.cat_printf("%s %i\n", "Максимальный размер матриц:" , maxMatrixSize);

text.cat_printf("%s %i\n", "Шаг увеличения размера матриц:" , stepBy);

text.cat_printf("%s %i\n", "Количество повторений одного опыта:" , numberExperements);

text.cat_printf("%s\n\n", line);

text.cat_printf("%s\n", "n - размерность матриц");

text.cat_printf("%s\n", "ВК - время работы классического алгоритма (в миллисекундах)");

text.cat_printf("%s\n\n", "ВШ - время работы алгоритма Штрассена (в миллисекундах)");

text.cat_printf("%s\n", "n\tВК\tВШ");

fwrite(text.c_str(), text.Length(), 1, file);

}

unsigned short hour, min, sec, msec;

TTime t1, t2;

short experementCicleNumber = 0;

do{

this->doExperementCicle(experementCicleNumber ++ , numberExperements, currentMatrixSize, t1, t2);

// для лога

unsigned int classicTime, shtrassenTime;

Output->Lines->Add("Подведение итогов:");

str = new AnsiString();

DecodeTime(t1, hour, min, sec, msec);

classicTime = min * 60000 + sec * 1000 + msec;

str->printf(

"среднее время работы классического алгоритма при n=%i : %im, %is, %ims", currentMatrixSize, min, sec, msec);

Output->Lines->Add(*str);

str->Delete(0, str->Length());

DecodeTime(t2, hour, min, sec, msec);

shtrassenTime = min * 60000 + sec * 1000 + msec;

str->printf (

"среднее время работы алгоритма Штрассена при n=%i : %im, %is, %ims", currentMatrixSize, min, sec, msec);

Output->Lines->Add(*str);

delete str;

// ведение лога

if( file ){

str = new AnsiString();

str->printf ("%i\t%i\t%i\n", currentMatrixSize, classicTime, shtrassenTime);

fwrite(str->c_str(), str->Length(), 1, file);

delete str;

}

currentMatrixSize += stepBy;

} while( currentMatrixSize <= maxMatrixSize );

// ведение лога

if( file ) fclose( file );

ShowMessage("Работа окончена");

}

}

void TForm1::prepareOutput(){

int count = Results->ColCount;

if( count > 1 )

for ( ; count > 1; count -- )

Results->Cols[count - 1]->Clear();

Results->ColCount = 1;

Results->RowCount = 1;

Output->Lines->Clear();

}

//---------------------------------------------------------------------------

1 Погружение в рекурсию происходит до тех пор, пока размерность сомножителей не станет равной двум.

29