Compare commits

...

6 Commits

Author SHA1 Message Date
6fb7e5bf68 Batch behavior parity 3 2024-10-14 12:36:49 -03:00
d3b3e682db Raise temperature and do some more changes 2024-10-14 00:03:11 -03:00
5c9ba9cfdf Raise the temperature!
It gives relatively good results with lesser time, I'll still
try to optmize this algorithm though.
2024-10-13 19:44:44 -03:00
40f7dc5b49 Change the algorithm for the neighbor set 2024-10-13 19:31:00 -03:00
6c7ba28320 Upgrade the script 2024-10-13 11:41:05 -03:00
d3871084e6 Merge pull request 'Adicionados flags para truncar saída' (#4) from dnk-general into master 2024-10-13 09:03:25 -03:00
5 changed files with 234 additions and 99 deletions

View File

@ -8,7 +8,7 @@
#endif #endif
#ifndef ALPHA #ifndef ALPHA
#define ALPHA 0.99 #define ALPHA 0.999
#endif #endif
#ifndef TEMP_MIN #ifndef TEMP_MIN

43
run.bat
View File

@ -1,19 +1,46 @@
:: Uso: [set EXEC="caminho/do/executavel.exe"] && [set TEST_FOLDER=caminho/dos/casetests] && [set ARGS=ic] && run.bat :: Uso: [set EXEC="caminho\do\executavel.exe"]&&[set TEST_FOLDER=caminho\dos\casetests]&&[set ARGS=ic]&&[set SOLUTIONS_FILE=arquivo\de\solucoes.txt]&&run.bat
@ECHO off @ECHO off
setlocal enabledelayedexpansion
echo %TIME%
if not defined EXEC ( if not defined EXEC (
set EXEC="build/solucao.exe" set EXEC="build\solucao.exe"
) )
if not defined TEST_FOLDER ( if not defined TEST_FOLDER (
set TEST_FOLDER=test set TEST_FOLDER=Teste\Casos
)
if not defined SOLUTIONS_FILE (
set SOLUTIONS_FILE=Teste\Solucoes.txt
) )
for %%g in (%TEST_FOLDER%/*) do (
echo Arquivo de teste: %TEST_FOLDER%/%%g
if defined ARGS ( if defined ARGS (
%EXEC% -%ARGS% < %TEST_FOLDER%/%%g set ARGS=-%ARGS%
)
for /f "tokens=1,2 skip=1" %%a in (%SOLUTIONS_FILE%) do (
set solutions[%%a]=%%b
)
for %%g in (%TEST_FOLDER%\*) do (
for %%h in (%%g) do set testname=%%~nxh
for /f "delims=" %%h in ("!testname!") do set optimal=!solutions[%%h]!
echo Arquivo de teste: %%g
for /f "tokens=4" %%h in ('!EXEC! !ARGS! ^< %%g') do set res=%%h
echo Resultado do programa: !res!
echo Resultado ótimo: !optimal!
if !res! EQU !optimal! (
echo Resultado ótimo^^!
) else ( ) else (
%EXEC% < %TEST_FOLDER%/%%g set /a diff= !res!-!optimal!
echo Diferença de !diff!
) )
) )
echo %TIME%
endlocal
set EXEC=
set TEST_FOLDER=
set SOLUTIONS_FILE=
set ARGS=
goto :eof

19
run.sh
View File

@ -10,7 +10,24 @@ if [[ -z $TEST_FOLDER ]]; then
TEST_FOLDER="test" TEST_FOLDER="test"
fi fi
if [[ -z $SOLUTIONS_FILE ]]; then
SOLUTIONS_FILE=solucoes.txt
fi
declare -A solutions
while read line; do
solutions[$(awk '{print $1}' <<< "$line")]=$(awk '{print $2}' <<< "$line")
done < "$SOLUTIONS_FILE"
for file in $(find "$TEST_FOLDER" -type f); do for file in $(find "$TEST_FOLDER" -type f); do
echo "Arquivo de teste: $file" echo "Arquivo de teste: $file"
"$EXEC" < "$file" res=$("$EXEC" -i -c < "$file" | awk '{print $4}')
optimal=${solutions[$(basename "$file")]}
echo "Resultado do programa: ${res}"
echo "Resultado ótimo: ${optimal}"
if [[ $res = $optimal ]]; then
echo "Resultado ótimo!"
else
echo "Diferença de $(bc <<< "${res} - ${optimal}")"
fi
done done

3
sa.cpp
View File

@ -21,13 +21,12 @@ 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;
if (prev.fitness < best.fitness) { if (prev.fitness < best.fitness) {
std::cout << prev.fitness << ' ' << best.fitness << '\n';
best = prev; best = prev;
} }
} }

216
sa.hpp
View File

@ -1,54 +1,145 @@
#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 <utility>
#include <vector>
#include <queue>
namespace sa { namespace sa {
using content = std::priority_queue<long long, std::vector<long long>, std::greater<>>;
class box {
content items;
long long fullness{};
friend void swap(box &one, box &two) {
using std::swap;
swap(one.items, two.items);
swap(one.fullness, two.fullness);
}
void pop() {
fullness -= items.top();
items.pop();
}
public:
box() = default;
box(const content &items, long long fullness):
items(items), fullness(fullness) {}
void add_item(long long item) {
fullness += item;
items.push(item);
}
void clear() {
while (!items.empty()) {
items.pop();
}
fullness = 0;
}
auto swappable10(box &other, int capacity) -> bool {
return items.top() + other.fullness <= capacity;
}
void swap10(box &other) {
other.add_item(items.top());
pop();
}
auto swappable11(box &other, int capacity) -> bool {
long long choice1 = items.top();
long long choice2 = other.items.top();
return choice1 + other.fullness - choice2 <= capacity &&
choice2 + fullness - choice1 <= capacity;
}
void swap11(box &other) {
long long choice1 = items.top();
long long choice2 = other.items.top();
pop();
other.pop();
add_item(choice2);
other.add_item(choice1);
}
void print(int ind) {
std::cout << "Caixa " << ind << ":";
content tmp;
while (!items.empty()) {
std::cout << ' ' << items.top();
items.pop();
}
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; void random_swap(int choice, std::vector<int> &sequence10, std::vector<int> &sequence11) {
typedef void (box::*swap)(box&);
swap swaps[2] = {
&box::swap10,
&box::swap11
};
std::vector<int>* sequences[2] = {
&sequence10,
&sequence11
};
std::uniform_real_distribution<> rand(0, 1);
int now = rand(gen) > 0.3 ? 0 : 1;
if (sequences[now]->empty()) {
now ^= 1;
if (sequences[now]->empty()) {
return;
}
} }
static void print_box(int box, std::queue<long long> &stored) { std::uniform_int_distribution<> dist(0, (int)sequences[now]->size() - 1);
std::cout << "Caixa " << box << ":"; (boxes[choice].*swaps[now])(boxes[(*sequences[now])[dist(gen)]]);
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) {}
@ -60,10 +151,8 @@ class solution {
its.insert(i); its.insert(i);
} }
this->items.resize(items.size());
size_t i = 0;
long long cap = capacity; long long cap = capacity;
box tmp;
while (!its.empty()) { while (!its.empty()) {
auto itr = its.upper_bound(cap); auto itr = its.upper_bound(cap);
@ -71,43 +160,60 @@ class solution {
cap = capacity; cap = capacity;
cap -= *its.begin(); cap -= *its.begin();
itr = its.begin(); itr = its.begin();
this->boxes.emplace_back(tmp);
tmp.clear();
} else { } else {
itr--; itr--;
cap -= *itr; cap -= *itr;
} }
this->items[i] = *itr; tmp.add_item(*itr);
its.erase(itr); its.erase(itr);
i++;
} }
fitness = calculate_boxes(); if (!tmp.empty()) {
this->boxes.emplace_back(tmp);
}
fitness = (int)this->boxes.size();
} }
void setneighbor() { // Gera um vizinho da solução void setneighbor() { // Gera um vizinho da solução
std::uniform_int_distribution<> dist(0, items.size() - 1); int choice = std::uniform_int_distribution<>(0, (int)boxes.size() - 1)(gen);
int first = dist(gen); std::vector<int> sequence10;
int second = 0; std::vector<int> sequence11;
while ((second = dist(gen)) == first) {}
std::swap(items[first], items[second]); sequence10.reserve(boxes.size());
fitness = calculate_boxes(); sequence11.reserve(boxes.size());
for (size_t i = 0; i < choice; i++) {
if (boxes[choice].swappable10(boxes[i], capacity)) {
sequence10.push_back((int)i);
}
if (boxes[choice].swappable11(boxes[i], capacity)) {
sequence11.push_back((int)i);
}
}
for (size_t i = choice + 1; i < boxes.size(); i++) {
if (boxes[choice].swappable10(boxes[i], capacity)) {
sequence10.push_back((int)i);
}
if (boxes[choice].swappable11(boxes[i], capacity)) {
sequence11.push_back((int)i);
}
}
random_swap(choice, sequence10, sequence11);
if (boxes[choice].empty()) {
swap(boxes[choice], boxes[boxes.size() - 1]);
boxes.pop_back();
fitness = (int)boxes.size();
}
} }
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) { void print_sol(char flags = 0) {
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 {
if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWITRNUM)){ if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWITRNUM)){
std::cout << "Iteração da solução: " << iteration << '\n'; std::cout << "Iteração da solução: " << iteration << '\n';
std::cout << "Número de iterações calculadas: " << iterations << '\n'; std::cout << "Número de iterações calculadas: " << iterations << '\n';
@ -115,23 +221,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';
} }
} }