diff --git a/ResultMatrix.h b/ResultMatrix.h new file mode 100644 index 0000000..386a0ca --- /dev/null +++ b/ResultMatrix.h @@ -0,0 +1,112 @@ +#pragma once +class ResultMatrix +{ +private: + int *data;//Чистые данные + + int block_quantity;//Кол-во блоков + int block_width;//Ширина блока в элементах + int block_capacity;//Кол-во элементов в блоке + int matrix_width;//Ширина матрицы в элементах + int matrix_capacity;//Кол-во элементов в матрице + int width_matrix_in_blocks;//Ширина матрицы в блоках + + //Получение индекса первого элемента конкретного блока + int getFirstElementBlock(int row, int column); + //Получение индекса элемента уже внутри блока относительно глобальной нумерации в матрице + int getElementBlock(int row, int column); + +public: + + ResultMatrix(int matrix_width, int block_width);//Конструктор результирующей матрицы + ~ResultMatrix();//Деструктор результирующей матрицы + + int getValue(int row, int column);//Получение элемента из матрицы + int *getBlock(int blockY, int blockX);//Получение блока + + int getWidthMatrixInBlocks();//Получение ширины матрицы в блоках + int getBlockCount();//Получение кол-ва блоков + int getBlockWidth();//Получение ширины одного блока + void zerofication();//Зануление всех элементов матрицы + void printMatrix(); +}; + + +int ResultMatrix::getValue(int row, int column) +{ + return data[getElementBlock(row, column)]; +} + +int* ResultMatrix::getBlock(int blockY, int blockX) +{ + int* block = data + getFirstElementBlock(blockY, blockX); + return block; +} + +int ResultMatrix::getBlockCount() +{ + return block_quantity; +} + +int ResultMatrix::getBlockWidth() +{ + return block_width; +} + +int ResultMatrix::getWidthMatrixInBlocks() +{ + return width_matrix_in_blocks; +} + +void ResultMatrix::zerofication() +{ + for (int i = 0; i < matrix_capacity; i++) + data[i] = 0; +} + +int ResultMatrix::getFirstElementBlock(int blockY, int blockX) +{ + int block_number = blockX * width_matrix_in_blocks + blockY; + return block_number * block_capacity; +} + +int ResultMatrix::getElementBlock(int row, int column) +{ + // Элементы внутри блока хранятся по столбцам + int element_number = (row % block_width) * block_width + (column % block_width); + + int blockY = row / block_width; + int blockX = column / block_width; + + int memory_shift = getFirstElementBlock(blockY, blockX); + return memory_shift + element_number; +} + +ResultMatrix::ResultMatrix(int matrix_width, int block_width) +{ + this->block_width = block_width; + this->matrix_width = matrix_width; + + width_matrix_in_blocks = matrix_width / block_width; + + block_quantity = (width_matrix_in_blocks) * (width_matrix_in_blocks); + block_capacity = block_width * block_width; + + matrix_capacity = block_quantity * block_capacity; + data = new int[matrix_capacity]; +} + +ResultMatrix::~ResultMatrix() { + delete[] data; +} + +void ResultMatrix::printMatrix() { + { + for (int i = 0;i < matrix_width;++i) { + for (int j = 0;j < matrix_width;++j) + std::cout << getValue(i, j) << " "; + std::cout << std::endl; + } + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/SymmetrMatrix.h b/SymmetrMatrix.h new file mode 100644 index 0000000..70c0e26 --- /dev/null +++ b/SymmetrMatrix.h @@ -0,0 +1,186 @@ +#pragma once +#include +#include +#include + +class SymmetrMatrix +{ +private: + int *data;//Чистые данные + int block_quantity;//Кол-во блоков + int block_width;//Ширина блока в элементах + int block_capacity;//Кол-во элементов в блоке + int matrix_width;//Ширина матрицы в элементах + int matrix_capacity;//Кол-во элементов в матрице + int width_matrix_in_blocks;//Ширина матрицы в блоках + + //Получение индекса первого элемента конкретного блока + int getFirstElementBlock(int row, int column); + //Получение индекса элемента уже внутри блока относительно глобальной нумерации в матрице + int getElementBlock(int row, int column); + //Зануление всех элементов матрицы + void zerofication(); + +public: + //Конструктор симметричной матрицы + SymmetrMatrix(int matrix_width, int block_width); + //Деструктор симметричной матрицы + ~SymmetrMatrix(); + + int getValue(int row, int column);//Получение элемента из матрицы + void setValue(int row, int column, int value);//Установка значения конкретного элемента матрицы + int *getBlock(int blockY, int blockX);//Получение блока + void readMatrixFromFile(std::string filePath);//Чтение матрицы из файла + void printMatrix();//Вывод матрицы на печать + void generateMatrix(int min_val, int max_val); + + int*tmp; +}; + +int SymmetrMatrix::getFirstElementBlock(int blockY, int blockX) +{ + // По строчкам + int block_number = blockY * width_matrix_in_blocks - ((2.0 + (double)blockY - 1) / 2.0)*(double)blockY + blockX; + return block_number * block_capacity; +} + +int SymmetrMatrix::getElementBlock(int row, int column) +{ + int element_number = (row%block_width) * block_width + (column%block_width); + + int blockX = column / block_width; + int blockY = row / block_width; + + int memory_shift = getFirstElementBlock(blockY, blockX); + return element_number + memory_shift; +} + +void SymmetrMatrix::zerofication() +{ + for (int i = 0; i < matrix_capacity; i++) + data[i] = 0; +} + +SymmetrMatrix::SymmetrMatrix(int matrix_width, int block_width) +{ + this->block_width = block_width; + this->matrix_width = matrix_width; + + width_matrix_in_blocks = matrix_width / block_width; + + block_quantity = width_matrix_in_blocks * width_matrix_in_blocks; + block_capacity = block_width * block_width; + + int symmetric_block_quantity = 0; + + for (int x = 0; x < matrix_width / block_width; x++) + for (int y = 0; y < matrix_width / block_width; y++) + if (x < y) symmetric_block_quantity++; + + matrix_capacity = (block_quantity - symmetric_block_quantity) * block_capacity; + data = new int[matrix_capacity]; + + tmp = new int[block_capacity]; + + zerofication(); +} + +SymmetrMatrix::~SymmetrMatrix() +{ + delete[] data; + delete[] tmp; +} + +int SymmetrMatrix::getValue(int row, int column) +{ + if (column < row) + { + std::swap(row, column); + } + return data[getElementBlock(column, row)]; +} + +void SymmetrMatrix::setValue(int row, int column, int new_value) +{ + data[getElementBlock(row, column)] = new_value; +} + +int* SymmetrMatrix::getBlock(int blockY, int blockX) +{ + if (blockX > blockY) + { + std::swap(blockX, blockY); + + int* block = data + getFirstElementBlock(blockY, blockX); + + int index_in_tmp_block = 0; + + for (int i = 0; i < block_width; i++) + { + for (int j = i; j < block_capacity; j += block_width) + { + tmp[index_in_tmp_block] = block[j]; + index_in_tmp_block++; + } + } + return tmp; + } + else + { + int* block = data + getFirstElementBlock(blockY, blockX); + return block; + } +} + + +void SymmetrMatrix::readMatrixFromFile(std::string filePath) { + zerofication(); + std::fstream in(filePath); + std::string line; + int i = 0; + + while (std::getline(in, line)) { + int j = 0; + std::stringstream linestream(line); + + int value; + while (linestream >> value) + { + setValue(i, j, value); + ++j; + } + ++i; + } + + //if (in.is_open()) { + in.close(); + //} +} + +void SymmetrMatrix::printMatrix() { + + for (int i = 0;i < matrix_width;++i) { + for (int j = 0;j < matrix_width;++j) + std::cout << getValue(i, j) << " "; + std::cout << std::endl; + } + std::cout << std::endl; +} + +void SymmetrMatrix::generateMatrix(int min_val, int max_val) +{ + std::mt19937 gen(time(0)); + std::uniform_int_distribution<> uid(min_val, max_val); + + for (int i = 0; i < matrix_width; i++) + for (int j = i; j < matrix_width; ++j) + { + int rnd_num = uid(gen); + //this->setValue(j, i, rnd_num); + this->setValue(i, j, rnd_num); + this->setValue(j, i, rnd_num); + } + +} + + diff --git a/VTMatrix.h b/VTMatrix.h new file mode 100644 index 0000000..21e93c4 --- /dev/null +++ b/VTMatrix.h @@ -0,0 +1,174 @@ +#pragma once +#include + +class VTMatrix +{ +private: + int *data;//Чистые данные + int *zero_block;//Нулевой блок + + int block_quantity;//Кол-во блоков + int block_width;//Ширина блока в элементах + int block_capacity;//Кол-во элементов в блоке + int matrix_width;//Ширина матрицы в элементах + int matrix_capacity;//Кол-во элементов в матрице + int width_matrix_in_blocks;//Ширина матрицы в блоках + + //Получение индекса первого элемента конкретного блока + int getFirstElementBlock(int blockY, int blockX); + //Получение индекса элемента уже внутри блока относительно глобальной нумерации в матрице + int getElementBlock(int row, int column); + //Зануление всех элементов матрицы + void zerofication(); + +public: + //Конструктор верхне-треугольной матрицы + VTMatrix(int matrix_width, int block_width); + //Деструктор верхне-треугольной матрицы + ~VTMatrix(); + + int getValue(int row, int column);//Получение элемента из матрицы + void setValue(int row, int column, int value);//Установка значения конкретного элемента матрицы + int *getBlock(int blockY, int blockX);//Получение блока + void readMatrixFromFile(std::string filePath);//Чтение матрицы из файла + void printMatrix();//Вывод матрицы на печать + void generateMatrix(int min_val, int max_val); +}; + +int VTMatrix::getFirstElementBlock(int blockY, int blockX) +{ + // По строкам + int block_number = blockY * width_matrix_in_blocks - ((2.0 + (double)blockY - 1) / 2.0)*(double)blockY + blockX; + return block_number * block_capacity; +} + +int VTMatrix::getElementBlock(int row, int column) +{ + int element_number = (row % block_width) * block_width + (column % block_width); + + int blockY = row / block_width; + int blockX = column / block_width; + + int memory_shift = getFirstElementBlock(blockY, blockX); + return element_number + memory_shift; +} + +void VTMatrix::zerofication() +{ + for (int i = 0; i < matrix_capacity; i++) + data[i] = 0; + for (int i = 0; i < block_capacity; i++) + zero_block[i] = 0; +} + +VTMatrix::VTMatrix(int matrix_width, int block_width) +{ + this->block_width = block_width; + this->matrix_width = matrix_width; + + width_matrix_in_blocks = matrix_width / block_width; + + block_quantity = width_matrix_in_blocks * width_matrix_in_blocks; + block_capacity = block_width * block_width; + + // Подсчет нулевых блоков для оптимизированной аллокации памяти + int zero_block_quantity = 0; + for (int x = 0; x < matrix_width / block_width; x++) + for (int y = 0; y < matrix_width / block_width; y++) + if (x < y) + zero_block_quantity++; + + // Выделение памяти производится без учета нулевых блоков + matrix_capacity = (block_quantity - zero_block_quantity) * block_capacity; + data = new int[matrix_capacity]; + + //Выделение памяти для 1 нулевого блока + zero_block = new int[block_capacity]; + zerofication(); +} + +VTMatrix::~VTMatrix() +{ + delete[] data; + delete[] zero_block; +} + +int VTMatrix::getValue(int row, int column) +{ + if (column < row) + return 0; + return data[getElementBlock(row, column)]; +} + +void VTMatrix::setValue(int row, int column, int new_value) +{ + if (column < row) + return; + data[getElementBlock(row, column)] = new_value; +} + +int* VTMatrix::getBlock(int blockY, int blockX) +{ + int* block; + + if (blockX < blockY) + block = zero_block; + else + block = data + getFirstElementBlock(blockY, blockX); + return block; +} + +void VTMatrix::readMatrixFromFile(std::string filePath) +{ + zerofication(); + std::fstream in(filePath); + std::string line; + int i = 0; + + while (std::getline(in, line)) { + int j = 0; + std::stringstream linestream(line); + + int value; + while (linestream >> value) { + setValue(i, j, value); + ++j; + } + ++i; + } + + //if (in.is_open()) { + in.close(); + //} +} + +void VTMatrix::printMatrix() { + { + for (int i = 0;i < matrix_width;++i) { + for (int j = 0;j < matrix_width;++j) + std::cout << getValue(i, j) << " "; + std::cout << std::endl; + } + } + std::cout << std::endl; +} + +void VTMatrix::generateMatrix(int min_val, int max_val) +{ + std::mt19937 gen(time(0)); + std::uniform_int_distribution<> uid(min_val, max_val); + + for (int i = 0; i < matrix_width; i++) + { + for (int j = 0; j < matrix_width; j++) + { + if (i > j) + this->setValue(i, j, 0); + else + { + int rnd_num = uid(gen); + this->setValue(i, j, rnd_num); + } + } + } +} \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..d1030e6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,123 @@ +#define MATRIX_SIZE 1440 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SymmetrMatrix.h" +#include "VTMatrix.h" +#include "ResultMatrix.h" + +auto blocks = { 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 30, +32, 36, 40, 45, 48, 60, 72, 80, 90, 96, 120, 144, 160, 180, +240, 288, 360, 480, 720, 1440 }; + +std::string matrixFile(int blockLen, std::string fname) +{ + return std::to_string(blockLen)+ fname + ".txt"; +} +//Перемножение 2-ух блоков +void multiplyBlocks(int *A, int *B, int *C, int block_size) +{ + for (int i = 0; i < block_size; i++) + for (int j = 0; j < block_size; j++) + for (int k = 0; k < block_size; k++) + C[i * block_size + j] += A[i * block_size + k] * B[k * block_size + j]; +} +//Параллельное перемножение 2-ух блоков +void multiplyBlocksParallel(int *A, int *B, int *C, int block_size) +{ +#pragma omp parallel for + for (int i = 0; i < block_size; i++) + for (int j = 0; j < block_size; j++) + for (int k = 0; k < block_size; k++) + C[i * block_size + j] += A[i * block_size + k] * B[k * block_size + j]; +} +//Последовательное умножение +void serialMultiplication(VTMatrix *A, SymmetrMatrix *B, ResultMatrix *C) +{ + int blocks_on_line = C->getWidthMatrixInBlocks(); + + for (int i = 0; i < blocks_on_line; i++) + for (int j = 0; j < blocks_on_line; j++) + for (int k = 0; k < blocks_on_line; k++) + multiplyBlocks(A->getBlock(i, k), B->getBlock(k, j), C->getBlock(i, j), C->getBlockWidth()); +} + +// Параллельное умножение внутри блоков +void InBlockParallelMultiplication(VTMatrix *A, SymmetrMatrix *B, ResultMatrix *C) +{ + int block_quantity = C->getWidthMatrixInBlocks(); + + for (int i = 0; i < block_quantity; i++) + for (int j = 0; j < block_quantity; j++) + for (int k = 0; k < block_quantity; k++) + multiplyBlocksParallel(A->getBlock(i, k), B->getBlock(k, j), C->getBlock(i, j), C->getBlockWidth()); +} + +// Параллельное умножение нескольких пар блоков +void PairParallelMultiplication(VTMatrix *A, SymmetrMatrix *B, ResultMatrix *C) +{ + int block_quantity = C->getWidthMatrixInBlocks(); + +#pragma omp parallel for + for (int i = 0; i < block_quantity; i++) + for (int j = 0; j < block_quantity; j++) + for (int k = 0; k < block_quantity; k++) + multiplyBlocks(A->getBlock(i, k), B->getBlock(k, j), C->getBlock(i, j), C->getBlockWidth()); +} + + +int main() +{ + double start_time[3], end_time[3]; + setlocale(LC_ALL, ""); + //int blockLen = 5; + for (auto blockLen : blocks) + { + std::cout << "Длина блока: " << blockLen << std::endl; + + VTMatrix *A = new VTMatrix(MATRIX_SIZE, blockLen); + A->generateMatrix(1, 9); + //A->printMatrix(); + + SymmetrMatrix *B = new SymmetrMatrix(MATRIX_SIZE, blockLen); + B->generateMatrix(1, 9); + //B->printMatrix(); + + ResultMatrix *C = new ResultMatrix(MATRIX_SIZE, blockLen); + C->zerofication(); + auto start = std::chrono::system_clock::now(); + serialMultiplication(A, B, C); + auto end = std::chrono::system_clock::now(); + //C->printMatrix(); + std::chrono::duration elapsed = end - start; + + std::cout << "Последовательный: " << elapsed.count() << std::endl; + C->zerofication(); + + start_time[0] = omp_get_wtime(); + InBlockParallelMultiplication(A, B, C); + end_time[0] = omp_get_wtime(); + std::cout << "2 блока: " << end_time[0] - start_time[0] << std::endl; + C->zerofication(); + + start_time[1] = omp_get_wtime(); + PairParallelMultiplication(A, B, C); + end_time[1] = omp_get_wtime(); + std::cout << "2 разных блока: " << end_time[1] - start_time[1] << std::endl; + C->zerofication(); + + delete A; + delete B; + delete C; + std::cout << "===============================" << std::endl; + } + system("pause"); + return 0; +} \ No newline at end of file diff --git "a/\320\242\320\265\320\277\320\273\321\216\320\272\320\276\320\262 \320\224\320\265\320\275\320\270\321\201 \320\276\321\202\321\207\320\265\321\202.docx" "b/\320\242\320\265\320\277\320\273\321\216\320\272\320\276\320\262 \320\224\320\265\320\275\320\270\321\201 \320\276\321\202\321\207\320\265\321\202.docx" new file mode 100644 index 0000000..e4f20a3 Binary files /dev/null and "b/\320\242\320\265\320\277\320\273\321\216\320\272\320\276\320\262 \320\224\320\265\320\275\320\270\321\201 \320\276\321\202\321\207\320\265\321\202.docx" differ