void deryabin_m_cannons_algorithm_mpi::CannonsAlgo...

Criado em: 12 de fevereiro de 2025

Respondido usando O1 por Chat01

Pergunta

void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::DistributeDataIfRoot()
{
for (unsigned short k = 0; k < block_dimension_; ++k) {
std::copy(
input_matrix_A_.data() + (k * dimension_),
input_matrix_A_.data() + (k * dimension_) + block_dimension_,
local_input_matrix_A_.begin() + (k * block_dimension_)
);
std::copy(
input_matrix_B_.data() + (k * dimension_),
input_matrix_B_.data() + (k * dimension_) + block_dimension_,
local_input_matrix_B_.begin() + (k * block_dimension_)
);
}
for (unsigned short i = 0; i < block_rows_columns_; ++i) {
for (unsigned short j = 0; j < block_rows_columns_; ++j) {
if (i == 0 && j == 0) {
continue;
}
for (unsigned short k = 0; k < block_dimension_; ++k) {
int destination_proc = (i * block_rows_columns_) + j;
if (i == 0) {
world_.send(
destination_proc,
0,
input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
if (static_cast<int>((i * block_rows_columns_) + j - i) < static_cast<int>(i * block_rows_columns_)) {
world_.send(
destination_proc + block_rows_columns_ - i,
0,
input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
world_.send(
destination_proc - i,
0,
input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
}
}
if (j == 0) {
world_.send(
destination_proc,
1,
input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
if ((static_cast<int>((i - j) * block_rows_columns_) + j) < 0) {
world_.send(
((i + block_rows_columns_ - j) * block_rows_columns_) + j,
1,
input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
} else {
world_.send(
((i - j) * block_rows_columns_) + j,
1,
input_matrix_B_.data() + (((i * block_dimension_) + k) * dimension_) + (j * block_dimension_),
block_dimension_
);
}
}
}
}
}
}

Эта функция имеет когнитивную сложность 33, разбей эту функцию на две более простых функции, когнитивная сложность каждой из которых не будет превышать пороговое значение в 25

Pensamento

Propondo refatoração

Estou pensando na divisão da função em duas partes mais simples para reduzir a complexidade cognitiva, mantendo a lógica atual.

Desenvolvendo aproximações

Estou pensando em funções específicas para distribuir blocos locais e enviar blocos remotos, mantendo a lógica atual. Considerando também funções auxiliares para simplificar a complexidade cognitiva.

Distribuindo dados

Estou mapeando a função existente, que se concentra em copiar blocos locais e enviar dados para outros processos.

Refatorando a lógica

Estou estratificando o código existente em duas funções distintas: uma para distribuição local e outra para envio remoto, com lógica específica para cada bloco.

Separando responsabilidades

Estou distribuindo a função em subfunções distintas para copiar blocos locais e enviar blocos remotos, mantendo a lógica original intacta e reduzindo a complexidade cognitiva.

Desenvolvendo funções

Estou criando "CopyLocalBlocks()" para copiar blocos locais e "SendRemoteBlocks()" para enviar blocos remotos, mantendo a lógica original e facilitando a compreensão do código.

Aprimorando a comunicação

Estou concentrando a lógica de envio remoto de blocos, utilizando envio condicional inteligente e mapeamentos usados anteriormente para otimizar a comunicação entre processos.

Pensou por 22 segundos

Resposta

Ниже приведён пример, как можно разбить изначальную функцию на две более простых, чтобы снизить её когнитивную сложность. Идея в том, чтобы отдельно вынести логику копирования «локального» блока данных и логику отправки блоков другим процессам.

Исходная функция

cpp
void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::DistributeDataIfRoot() { for (unsigned short k = 0; k < block_dimension_; ++k) { std::copy( input_matrix_A_.data() + (k * dimension_), input_matrix_A_.data() + (k * dimension_) + block_dimension_, local_input_matrix_A_.begin() + (k * block_dimension_) ); std::copy( input_matrix_B_.data() + (k * dimension_), input_matrix_B_.data() + (k * dimension_) + block_dimension_, local_input_matrix_B_.begin() + (k * block_dimension_) ); } for (unsigned short i = 0; i < block_rows_columns_; ++i) { for (unsigned short j = 0; j < block_rows_columns_; ++j) { if (i == 0 && j == 0) { continue; } for (unsigned short k = 0; k < block_dimension_; ++k) { int destination_proc = (i * block_rows_columns_) + j; // Отправка фрагмента A if (i == 0) { world_.send( destination_proc, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { if (static_cast<int>((i * block_rows_columns_) + j - i) < static_cast<int>(i * block_rows_columns_)) { world_.send( destination_proc + block_rows_columns_ - i, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { world_.send( destination_proc - i, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } } // Отправка фрагмента B if (j == 0) { world_.send( destination_proc, 1, input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { if ((static_cast<int>((i - j) * block_rows_columns_) + j) < 0) { world_.send( ((i + block_rows_columns_ - j) * block_rows_columns_) + j, 1, input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { world_.send( ((i - j) * block_rows_columns_) + j, 1, input_matrix_B_.data() + (((i * block_dimension_) + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } } } } } }

Вариант с разбивкой

Ниже показан способ вынести копирование данных в отдельную функцию CopyLocalBlocks(), а логику рассылки – в функцию SendRemoteBlocks(). Затем в основном методе DistributeDataIfRoot() мы просто вызываем эти две функции по порядку.

cpp
// Новая функция №1 — копирует локальный блок матриц A и B void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::CopyLocalBlocks() { // Копируем локальную часть матрицы A и B в local_input_matrix_A_ и local_input_matrix_B_ for (unsigned short k = 0; k < block_dimension_; ++k) { std::copy( input_matrix_A_.data() + (k * dimension_), input_matrix_A_.data() + (k * dimension_) + block_dimension_, local_input_matrix_A_.begin() + (k * block_dimension_) ); std::copy( input_matrix_B_.data() + (k * dimension_), input_matrix_B_.data() + (k * dimension_) + block_dimension_, local_input_matrix_B_.begin() + (k * block_dimension_) ); } } // Новая функция №2 — рассылает блоки матрицы A и B другим процессам void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::SendRemoteBlocks() { // Проходим по всем блокам (i, j) for (unsigned short i = 0; i < block_rows_columns_; ++i) { for (unsigned short j = 0; j < block_rows_columns_; ++j) { // Пропускаем локальный блок (0, 0), он уже скопирован в CopyLocalBlocks() if (i == 0 && j == 0) { continue; } // Для каждого ряда внутри блока for (unsigned short k = 0; k < block_dimension_; ++k) { int destination_proc = (i * block_rows_columns_) + j; // Отправляем часть A if (i == 0) { world_.send( destination_proc, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { if (static_cast<int>((i * block_rows_columns_) + j - i) < static_cast<int>(i * block_rows_columns_)) { world_.send( destination_proc + block_rows_columns_ - i, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { world_.send( destination_proc - i, 0, input_matrix_A_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } } // Отправляем часть B if (j == 0) { world_.send( destination_proc, 1, input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { if ((static_cast<int>((i - j) * block_rows_columns_) + j) < 0) { world_.send( ((i + block_rows_columns_ - j) * block_rows_columns_) + j, 1, input_matrix_B_.data() + ((i * block_dimension_ + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } else { world_.send( ((i - j) * block_rows_columns_) + j, 1, input_matrix_B_.data() + (((i * block_dimension_) + k) * dimension_) + (j * block_dimension_), block_dimension_ ); } } } } } } // Обновлённый метод, который просто вызывает две новые функции void deryabin_m_cannons_algorithm_mpi::CannonsAlgorithmMPITaskParallel::DistributeDataIfRoot() { // 1. Копируем локальный блок CopyLocalBlocks(); // 2. Рассылаем остальные блоки SendRemoteBlocks(); }

Таким образом, мы получаем более «плоскую» структуру кода, в которой каждая из функций решает свою задачу:

  1. CopyLocalBlocks() — отвечает за копирование «локальных» фрагментов матриц A и B.
  2. SendRemoteBlocks() — отвечает за рассылку остальных фрагментов матриц нужным процессам.

Каждая отдельная функция теперь имеет более низкую когнитивную сложность по сравнению с исходным вариантом, где все действия были собраны в одном методе.

Compartilhar esta Q&A