diff --git a/src/main.cpp b/src/main.cpp index b3a5052..ea1d53b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,12 @@ #define TEMP_MIN 10 #endif +/* + * Função main. + * Usada apenas para ler os items, a capacidade máxima e + * imprimir os dados da melhor solução encontrada. + */ + int main(int argc, char *argv[]) { char flags = 0; diff --git a/src/sa.cpp b/src/sa.cpp index 203b515..cfdca38 100644 --- a/src/sa.cpp +++ b/src/sa.cpp @@ -1,6 +1,10 @@ #include "sa.hpp" #include +/* + * Implementação do algoritmo de SA. + */ + auto sa::solution::simulated_annealing(int capacity, const std::vector &items, const double alpha, double temp, const double temp_min)->sa::solution diff --git a/src/sa.hpp b/src/sa.hpp index b5fc1dd..6353f8f 100644 --- a/src/sa.hpp +++ b/src/sa.hpp @@ -22,6 +22,7 @@ class box { content items; long long fullness{}; + /* Troca uma caixa com a outra. */ friend void swap(box &one, box &two) { using std::swap; @@ -29,6 +30,7 @@ class box { swap(one.fullness, two.fullness); } + /* Remove o menor item da caixa. */ void pop() { fullness -= items.top(); items.pop(); @@ -38,14 +40,20 @@ class box { box() = default; - box(const content &items, long long fullness): - items(items), fullness(fullness) {} + /* + * Inicialia uma caixa a partir de um conjunto de items e da soma total + * dos items. + */ + box(content items, long long fullness): + items(std::move(items)), fullness(fullness) {} + /* Adiciona um item a caixa. */ void add_item(long long item) { fullness += item; items.push(item); } + /* Limpa a caixa. */ void clear() { while (!items.empty()) { items.pop(); @@ -53,15 +61,27 @@ class box { fullness = 0; } + /* + * Verifica se é possível move o menor item da caixa atual para a + * caixa "other" sem violar as restrições de capacidade. + */ auto swappable10(box &other, int capacity) -> bool { return items.top() + other.fullness <= capacity; } + /* + * Move o menor item da caixa atual para a caixa "other". + */ void swap10(box &other) { other.add_item(items.top()); pop(); } + /* + * Verifica se é possivel realizar "swap11" com a caixa "other" sem + * violar as restrições de capacidade, também verificando se ambos os menores + * items são os mesmos. + */ auto swappable11(box &other, int capacity) -> bool { long long choice1 = items.top(); long long choice2 = other.items.top(); @@ -70,6 +90,10 @@ class box { choice2 + fullness - choice1 <= capacity; } + /* + * Troca o menor item da caixa atual com o menor item da caixa + * "other" + */ void swap11(box &other) { long long choice1 = items.top(); long long choice2 = other.items.top(); @@ -80,6 +104,7 @@ class box { other.add_item(choice1); } + /* Imprime todos os items da caixa junto com um identificador. */ void print(int ind) { std::cout << "Caixa " << ind << ":"; content tmp; @@ -90,6 +115,7 @@ class box { std::cout << '\n'; } + /* Retorna um booleano indicando se a caixa está vazia. */ [[nodiscard]] auto empty() const -> bool { return fullness == 0; } @@ -102,6 +128,10 @@ class solution { int iterations; int iteration; + /* + * Função para trocar duas soluções. + * Overload da função std::swap. + */ friend void swap(solution &one, solution &two) { using std::swap; @@ -112,6 +142,10 @@ class solution { swap(one.iteration, two.iteration); } + /* + * Função para usar o swap10 ou swap11 aleatoriamente quando + * possível. + */ void random_swap(int choice, std::vector &sequence10, std::vector &sequence11) { typedef void (box::*swap)(box&); swap swaps[2] = { @@ -139,28 +173,30 @@ class solution { public: solution() = default; + /* Inicializa uma solução a partir da outra. */ solution(const solution &other, int itr): boxes(other.boxes), fitness(other.fitness), capacity(other.capacity), iteration(itr) {} - solution(const std::vector &items, int capacity): // Gera a solução inicial + /* Gera a solução inicial a partir dos items disponíveis. */ + solution(const std::vector &items, int capacity): capacity(capacity), iteration(0) { - std::multiset its; + std::multiset its; // Items ordenados. for (auto i : items) { its.insert(i); } - long long cap = capacity; - box tmp; + long long cap = capacity; // Capacidade restante da caixa atual. + box tmp; // Caixa atual. while (!its.empty()) { auto itr = its.upper_bound(cap); - if (itr == its.begin()) { + if (itr == its.begin()) { // Caixa está cheia, cria-se outra. cap = capacity; cap -= *its.begin(); itr = its.begin(); this->boxes.emplace_back(tmp); tmp.clear(); - } else { + } else { // Caixa consegue colocar outro elemento. itr--; cap -= *itr; } @@ -174,10 +210,11 @@ class solution { fitness = (int)this->boxes.size(); } - void setneighbor() { // Gera um vizinho da solução + /* Muda a solução atual para um de seus vizinhos. */ + void setneighbor() { int choice = std::uniform_int_distribution<>(0, (int)boxes.size() - 1)(rng::rng); - std::vector sequence10; - std::vector sequence11; + std::vector sequence10; // Possíveis candidatos para swap10 + std::vector sequence11; // Possíveis candidatos para swap11 sequence10.reserve(boxes.size()); sequence11.reserve(boxes.size()); @@ -201,12 +238,22 @@ class solution { random_swap(choice, sequence10, sequence11); if (boxes[choice].empty()) { + /* + * Caixa agora está vazia, é possível remove-la. + */ swap(boxes[choice], boxes[boxes.size() - 1]); boxes.pop_back(); fitness = (int)boxes.size(); } } + /* + * Imprime todas as informações da solução: + * - Número de caixas + * - Items em cada caixa + * - Iteração onde foi encontrada a solução + * - Iterações totais ate o fim do algoritmo + */ void print_sol(char flags = 0) { if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWITRNUM)){ std::cout << "Iteração da solução: " << iteration << '\n'; @@ -221,10 +268,15 @@ class solution { } } + /* Pôe o número de iterações totais para a solução. */ void setiterations(int itr) { iterations = itr; } + /* + * Declaração do algoritmo, sua implementação está no arquivo + * sa.cpp. + */ static auto simulated_annealing(int capacity, const std::vector &items, double alpha, double temp, double temp_min) -> solution;