Change the algorithm for the neighbor set

This commit is contained in:
Segcolt 2024-10-13 19:31:00 -03:00
parent 6c7ba28320
commit 40f7dc5b49
2 changed files with 143 additions and 88 deletions

2
sa.cpp
View File

@ -21,7 +21,7 @@ auto sa::solution::simulated_annealing(int capacity, const std::vector<long long
int diff = neighbor.fitness - prev.fitness; int diff = neighbor.fitness - prev.fitness;
if (diff <= 0 || std::exp(-diff / temp) > rand(eng)) { if (diff <= 0 || std::exp(-diff / temp) > rand(eng)) {
prev.swap(neighbor); swap(prev, neighbor);
} }
temp *= alpha; temp *= alpha;

229
sa.hpp
View File

@ -1,110 +1,179 @@
#ifndef SIMULATED_ANNEALING_HEADER_12647_H #ifndef SIMULATED_ANNEALING_HEADER_12647_H
#define SIMULATED_ANNEALING_HEADER_12647_H #define SIMULATED_ANNEALING_HEADER_12647_H
#define SIMULATED_ANNEALING_DISABLE_SHOWCRATES 1 #define SIMULATED_ANNEALING_DISABLE_SHOWCRATES 1
#define SIMULATED_ANNEALING_DISABLE_SHOWITRNUM 2 #define SIMULATED_ANNEALING_DISABLE_SHOWITRNUM 2
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <queue>
#include <random> #include <random>
#include <vector>
#include <set> #include <set>
#include <vector>
namespace sa { namespace sa {
class box {
std::multiset<long long> items;
long long fullness{};
friend void swap(box &one, box &two) {
using std::swap;
swap(one.items, two.items);
swap(one.fullness, two.fullness);
}
public:
box() = default;
box(const std::multiset<long long> &multiset, long long fullness):
items(multiset), fullness(fullness) {}
void add_item(long long item) {
fullness += item;
items.insert(item);
}
void clear() {
items.clear();
fullness = 0;
}
void pop() {
fullness -= *items.begin();
items.erase(items.begin());
}
auto swap10(box &other, int capacity) -> bool {
if (*items.begin() + other.fullness > capacity) {
return false;
}
other.add_item(*items.begin());
pop(); return true; }
auto swap11(box &other, int capacity) -> bool {
long long choice1 = *items.begin();
long long choice2 = *other.items.begin();
if (choice1 + other.fullness - choice2 > capacity ||
choice2 + fullness - choice1 > capacity) {
return false;
}
pop();
other.pop();
add_item(choice2);
other.add_item(choice1);
return true;
}
void print(int ind) const {
std::cout << "Caixa " << ind << ":";
for (auto item : items) {
std::cout << ' ' << item;
}
std::cout << '\n';
}
[[nodiscard]] auto empty() const -> bool {
return fullness == 0;
}
};
class solution { class solution {
std::vector<long long> items; std::vector<box> boxes;
std::default_random_engine gen; std::default_random_engine gen;
int capacity; int capacity;
int fitness; int fitness;
int iterations; int iterations;
int iteration; int iteration;
auto calculate_boxes()->int { friend void swap(solution &one, solution &two) {
int count = 1; using std::swap;
long long now = 0;
for (auto i : items) { swap(one.boxes, two.boxes);
if (now + i > capacity) { swap(one.gen, two.gen);
count++; swap(one.capacity, two.capacity);
now = i; swap(one.fitness, two.fitness);
continue; swap(one.iterations, two.iterations);
} swap(one.iteration, two.iteration);
now += i;
}
return count;
}
static void print_box(int box, std::queue<long long> &stored) {
std::cout << "Caixa " << box << ":";
while (!stored.empty()) {
std::cout << ' ' << stored.front();
stored.pop();
}
std::cout << '\n';
} }
public: public:
solution() = default; solution() = default;
solution(const solution &other, int itr): items(other.items), gen(other.gen), solution(const solution &other, int itr): boxes(other.boxes), gen(other.gen),
capacity(other.capacity), fitness(other.fitness), capacity(other.capacity), fitness(other.fitness),
iteration(itr) {} iteration(itr) {}
solution(const std::vector<long long> &items, int capacity): // Gera a solução inicial solution(const std::vector<long long> &items, int capacity): // Gera a solução inicial
gen(std::random_device()()), capacity(capacity), gen(std::random_device()()), capacity(capacity),
iteration(0) { iteration(0) {
std::multiset<long long> its; std::multiset<long long> its;
for (auto i : items) { for (auto i : items) {
its.insert(i); its.insert(i);
}
this->items.resize(items.size());
size_t i = 0;
long long cap = capacity;
while (!its.empty()) {
auto itr = its.upper_bound(cap);
if (itr == its.begin()) {
cap = capacity;
cap -= *its.begin();
itr = its.begin();
} else {
itr--;
cap -= *itr;
}
this->items[i] = *itr;
its.erase(itr);
i++;
}
fitness = calculate_boxes();
} }
void setneighbor() { // Gera um vizinho da solução long long cap = capacity;
std::uniform_int_distribution<> dist(0, items.size() - 1); box tmp;
int first = dist(gen);
int second = 0;
while ((second = dist(gen)) == first) {}
std::swap(items[first], items[second]); while (!its.empty()) {
fitness = calculate_boxes(); auto itr = its.upper_bound(cap);
if (itr == its.begin()) {
cap = capacity;
cap -= *its.begin();
itr = its.begin();
this->boxes.emplace_back(tmp);
tmp.clear();
} else {
itr--;
cap -= *itr;
}
tmp.add_item(*itr);
its.erase(itr);
}
if (!tmp.empty()) {
this->boxes.emplace_back(tmp);
}
fitness = (int)this->boxes.size();
}
void setneighbor() { // Gera um vizinho da solução
std::uniform_int_distribution<> dist(0, (int)boxes.size() - 1);
int choice = dist(gen);
std::vector<int> sequence(boxes.size() - 1);
for (size_t i = 0; i < choice; i++) {
sequence[i] = i;
}
for (size_t i = choice + 1; i < boxes.size(); i++) {
sequence[i - 1] = i;
}
shuffle(sequence.begin(), sequence.end(), gen);
for (auto ind : sequence) {
if (boxes[choice].swap10(boxes[ind], capacity)) {
if (boxes[choice].empty()) {
boxes.erase(boxes.begin() + choice);
}
fitness = (int)boxes.size();
return;
}
}
for (auto ind : sequence) {
if (boxes[choice].swap11(boxes[ind], capacity)) {
return;
}
}
} }
void randomize() { void randomize() {
std::shuffle(items.begin(), items.end(), gen); std::shuffle(boxes.begin(), boxes.end(), gen);
fitness = calculate_boxes();
}
void swap(solution &other) {
std::swap(fitness, other.fitness);
std::swap(items, other.items);
std::swap(capacity, other.capacity);
std::swap(gen, other.gen);
std::swap(iteration, other.iteration);
} }
void print_sol(char flags = 0) const { void print_sol(char flags = 0) const {
@ -115,23 +184,9 @@ class solution {
std::cout << "Número de caixas: " << fitness << '\n'; std::cout << "Número de caixas: " << fitness << '\n';
if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWCRATES)){ if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWCRATES)){
int box_now = 1; for (size_t i = 0; i < boxes.size(); i++) {
long long now = 0; boxes[i].print((int)i + 1);
std::queue<long long> items_stored;
for (auto i : items) {
if (now + i > capacity) {
print_box(box_now, items_stored);
box_now++;
now = i;
} else {
now += i;
}
items_stored.push(i);
} }
print_box(box_now, items_stored);
std::cout << '\n';
} }
} }
@ -141,7 +196,7 @@ class solution {
static auto simulated_annealing(int capacity, const std::vector<long long> &items, static auto simulated_annealing(int capacity, const std::vector<long long> &items,
double alpha, double temp, double alpha, double temp,
double temp_min)->solution; double temp_min) -> solution;
}; };
} // namespace sa } // namespace sa