Compare commits

..

51 Commits

Author SHA1 Message Date
3998caf079 Merge pull request 'Last one' (#12) from dnk-general into master 2024-10-16 01:10:40 -03:00
aec9898091 Hardcoded ARGS to -ic, the script is bugged and i'm tired 2024-10-16 01:04:55 -03:00
3c8bed290d Recreated readme 2024-10-16 00:44:23 -03:00
13ab972fdc Que raiva 2024-10-16 00:20:00 -03:00
4ca1da90fb Merge pull request 'dnk-general' (#11) from dnk-general into master 2024-10-16 00:03:26 -03:00
6bab964dd5 Added build directory recipe 2024-10-16 00:02:15 -03:00
d7d9d5e6ea Changed expected executable name in batch 2024-10-16 00:00:17 -03:00
46d3a584b4 revert f5a8420025
revert Merge pull request 'Receba Makefile' (#10) from dnk-general into master
Deu bosta, makefile só funciona no Linux por enquanto, outro dia a gente arruma pra funcionar nos 2 OS's
2024-10-15 23:58:32 -03:00
f5a8420025 Merge pull request 'Receba Makefile' (#10) from dnk-general into master 2024-10-15 23:51:10 -03:00
1e7ad317b8 Receba Makefile 2024-10-15 23:48:57 -03:00
0a47e5ffcb Update pretty much everything so that it compiles
Also update the script so that it uses the correct executable
2024-10-15 23:19:06 -03:00
5f153a71d3 Create makefile 2024-10-15 22:56:17 -03:00
901e3a00ff Consertei? 2024-10-15 22:54:24 -03:00
10b10a4f61 Comments re-added 2024-10-15 22:45:20 -03:00
7b3b1eb23e Bruh, rm 2024-10-15 22:26:22 -03:00
2f3c0c82b7 Batch script now follows new default paths 2024-10-15 22:19:52 -03:00
caac7b03f9 Major project file restructuring 2024-10-15 22:17:02 -03:00
87528c097e Comment the code 2024-10-15 20:33:43 -03:00
dcafbce924 Merge pull request 'Batch now displays call execution time' (#7) from dnk-general into master 2024-10-15 12:32:09 -03:00
cb6d8ced33 Batch now displays call execution time 2024-10-15 12:29:31 -03:00
5e1de21a22 Prevent swapping two equal items 2024-10-15 11:36:59 -03:00
11d8f8e757 Increase minimal temperature
It should be a lot faster now, although the answers might be a little
worse
2024-10-15 10:37:17 -03:00
de7d671411 Merge pull request 'Optimal comparisson no longer on by default (BATCH)' (#6) from dnk-general into master 2024-10-14 23:28:20 -03:00
41245cae8f Update the script so that it doesn't need a solution 2024-10-14 23:27:27 -03:00
6dc06d021a Optimal comparisson no longer on by default 2024-10-14 23:04:58 -03:00
ad5aedd454 Make everything use the same random pool 2024-10-14 15:14:28 -03:00
2f53e5de27 Merge pull request 'Batch behavior parity 3' (#5) from dnk-general into master
Reviewed-on: https://git.puffypony.party:4433/Segcolt/Bin-packing-SA-solution/pulls/5
2024-10-14 12:38:49 -03:00
6fb7e5bf68 Batch behavior parity 3 2024-10-14 12:36:49 -03:00
a1d6ed7d75 Change from default_random_engine to mt19937_64
It should give better random numbers now.
2024-10-14 12:12:48 -03:00
07cea8fa77 Change some stuff 2024-10-14 11:19:21 -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
dd2aacb284 Adicionados flags para truncar saída 2024-10-13 08:53:37 -03:00
19ece6f700 Reduce temp and alpha because why not 2024-10-12 22:13:53 -03:00
7aad87810f Stop pushing on the vector
For better performance
2024-10-12 21:24:16 -03:00
65aed86783 Merge branch 'master' of https://git.puffypony.party:4433/Segcolt/Bin-packing-SA-solution 2024-10-12 21:18:24 -03:00
01d9f25220 Somehow this works better than the metaheuristic? 2024-10-12 21:18:15 -03:00
93d580a299 Merge pull request 'Batch behavior parity 2' (#3) from dnk-general into master
Reviewed-on: https://git.puffypony.party:4433/Segcolt/Bin-packing-SA-solution/pulls/3
2024-10-12 19:45:11 -03:00
64d4d6c71c Batch behavior parity 2 2024-10-12 19:43:33 -03:00
70f0125d13 Add number of iterations of the solution as well 2024-10-12 19:42:48 -03:00
859b34308c Fix this stupid mistake
Now it works!
2024-10-12 19:11:24 -03:00
d8086caa18 I am an idiot :) 2024-10-12 18:53:12 -03:00
cd382540a4 Merge pull request 'Criação do script Batch' (#2) from dnk-general into master
Reviewed-on: https://git.puffypony.party:4433/Segcolt/Bin-packing-SA-solution/pulls/2
2024-10-12 18:48:43 -03:00
e045407993 Fix indentation... 2024-10-12 18:35:39 -03:00
877ad0ad1a Change tab to spaces for alignment 2024-10-12 18:34:02 -03:00
510415982d Remove argv 2024-10-12 18:25:03 -03:00
1b976d4d32 Change the alpha 2024-10-12 18:17:02 -03:00
0a8d951cfa Upgrade the script a little 2024-10-12 18:09:01 -03:00
6264 changed files with 2997822 additions and 197 deletions

1
.gitignore vendored
View File

@@ -32,3 +32,4 @@
*.out
*.app
build

Binary file not shown.

View File

@@ -1,46 +1,43 @@
# Pontifícia Universidade Católica de Goiás
# Solução para o problema Bin Packing
## Escola Politécnica e de Artes
Este projeto é a solução do Danilo Barcelos e do Allann Cintra para o 2º Desafio em Otimização com Meta-heurística. Ele segue esta seguinte estrutura de arquivos:
### Ciência da Computação
- A pasta "src" contém o código-fonte do programa da solução
- A pasta "Docs" contém o arquivo do Writer que foi convertido em PDF para submissão
- A pasta "test" contém os casos de teste utilizados. Ela contém o conjunto completo de casos de teste, o conjunto reduzido para debugging, e o arquivo contendo as soluções ótimas de todos os casos
- Na pasta raiz você encontrará os scripts que ajudam a testar vários casos de teste de forma rápida
Alunos: Allann Barbosa Cintra, Danilo Matias Barcelos
# Modo de Usar
***
## No Linux
## 2º Desafio em Otimização com Meta-heurística
Compile o programa usando makefile `> make`, ou manualmente `> g++ src/main.cpp src/random.cpp src/sa.cpp -o build/sabp`. Após isso você pode rodar o programa manualmente `> build/sabp`, digitando o caso de teste no terminal, ou usando o script "run.sh".
### Problema do Empacotamento Solução com Recozimento Simulado
Para usar ele, basta chamá-lo, por padrão ele busca o executável no lugar onde o makefile compila, e os testes em `test/reduced`. Caso queira mudar onde ele busca as coisas, pode-se usar estas variáveis:
#### Tópicos:
- EXEC: Caminho do executável
- TEST_FOLDER: Caminho da pasta que contém casos de teste. Cada caso deve ser um arquivo de texto
- SOLUTIONS_FILE: Caminho do arquivo de soluções
1. Introdução
Aqui vai um exemplo de comando para usar o script, supondo que todos os arquivos necessários estão em `/tmp/files`:
1.1. Ambiente de Teste & Desenvolvimento
`EXEC=/tmp/files/exec.out TEST_FOLDER=/tmp/files/tests SOLUTIONS_FILE=/tmp/files/solucoes.txt ./run.sh`
1.2. Instâncias Utilizadas
NOTA: O script bash não diz quanto tempo cada caso de teste levou
2. Meta-heurística utilizada
## No Windows
2.1. Descrição
Compile o programa manualmente, pois o makefile não funciona no Windows `> g++ src/main.cpp src/random.cpp src/sa.cpp -o build/sabp.exe`. Após isso você pode rodar o programa manualmente `> build\sabp.exe`, digitando o caso de teste no terminal, ou usando o script "run.bat".
2.2. Implementação
Para usar ele, basta chamálo, por padrão ele busca o executável no lugar onde ele estaria se o makefile funcionasse no Windows (`build\sabp.exe`), e os testes em `test\reduced`. Caso queira mudar seu comportamento, pode-se usar estas variáveis:
2.3. Variações Testadas
- EXEC: Caminho do executável (Parece que precisa estar em aspas? Batch é estranho)
- TEST_FOLDER: Caminho da pasta que contém casos de teste. Cada caso deve ser um arquivo de texto
- ARGS: Define os argumentos a se passar para o programa. O programa suporta 2 argumentos: i=Não imprimir informações sobre as iterações; c=Não imprimir conteúdos das caixas
- SOLUTIONS_FILE: Caminho do arquivo de soluções
2.4. Resultados
Aqui vai um exemplo de comando para usar o script, supondo que todos os arquivos necessários estão em `C:\arquivos`, e que você está interessado no conteúdo das caixas, mas não nas informações sobre iterações:
3. Conclusão
`set EXEC="C:\arquivos\prog.exe"&& set TEST_FOLDER=C:\arquivos\testes&& set SOLUTIONS_FILE=C:\arquivos\testes\Solucoes.txt&& set ARGS=i&& run.bat`
***
## Introdução
Este documento é a entrega única do nosso grupo, ele contém todas as informações requisitadas para a submissão do desafio.
### Ambiente de Teste & Desenvolvimento
Os computadores pessoais dos dois integrantes foram utilizados em todos os processos deste desafio.
O computador do integrante Danilo Barcelos é um computador de mesa sem modelo, possui o processador Ryzen 5 3400G, a placa-mãe ASUS A320M, e 12 GB de memória RAM com 2666 MHz de velocidade. Não possui GPU dedicada. Usa o sistema operacional Windows 10, e o IDE Visual Studio Code.
O integrante Allann Cintra possui ???. Ele usa o sistema operacional Linux, com a distribuição Gentoo, e programa na IDE NeoVim.
Os resultados dos testes contidos neste documento foram obtidos executando o algoritmo através do script “launch.bat” contido no diretório raiz do projeto no repositório. Todos os testes foram realizados no computador do Danilo. Para executar o algoritmo em um ambiente Linux, basta executar o script “launch.sh”.
Este script não procura o arquivo de soluções por padrão, mas diz quantos segundos cada caso de teste levou para ser processado. Se a saída deste script for redirecionada para um arquivo, e um arquivo de soluções foi especificado, pode-se usar o script getstats.py para obter estatísticas do teste.

32
getstats.py Normal file
View File

@@ -0,0 +1,32 @@
arqname = input("Escreva o nome do arquivo de saída (Deve estar no formato de saída dos scripts, com arquivo de resposta ótima, e com os argumentos -i e -c)\n> ")
arq = open(arqname, "r", -1, "UTF-8")
caseqtd = 0
accuracy = 1.0
timetot = 0
largesterr = 0
while True:
arq.readline()
l2 = arq.readline().split(" ")
l3 = arq.readline().split(" ")
arq.readline()
l5 = arq.readline().split(" ")
if len(l5) < 5: break
progres = int(l2[len(l2)-1])
optires = int(l3[len(l3)-1])
extime = int(l5[len(l5)-2])
caseqtd += 1
timetot += extime
diff = progres-optires
if diff > largesterr: largesterr = diff
accuracy = (accuracy + 1 - (progres-optires)/optires)/2.0
print("----------Statistics----------")
print("Cases parsed...........: %d" %caseqtd)
print("Average execution time.: %f" %(timetot/caseqtd))
print("Average answer accuracy: %f%%" %(accuracy*100.0))
print("Largest error..........: %d" %largesterr)

View File

@@ -1,29 +0,0 @@
#include <iostream>
#include <vector>
#include "sa.hpp"
#ifndef TEMP
#define TEMP 1000
#endif
#ifndef ALPHA
#define ALPHA 0.99
#endif
int main(int argc, char *argv[])
{
int number_of_items = 0;
int capacity = 0;
std::cin >> number_of_items >> capacity;
std::vector<long long> items(number_of_items);
for (auto &i : items) {
std::cin >> i;
}
sa::solution act = sa::solution::simulated_annealing(capacity, items,
TEMP, ALPHA);
act.print_sol();
}

47
makefile Normal file
View File

@@ -0,0 +1,47 @@
# Flag para alterar o padrão do compilador
standart = -std=c++17
# Flags para otimizar o arquivo executável
optimize_flags = -O3 -pipe -flto
# Flags para ativar todos os avisos do compilador
warnings = -Wall -Wextra -Werror -Wformat=2 -Wno-maybe-uninitialized \
-Wformat-overflow=2 -Wundef -Wconversion -Wwrite-strings
# Flags para depurar o código
sanitize = -fsanitize=address,undefined,pointer-compare,pointer-subtract
debug_flags = -ggdb3 -Og -DDEBUG -Wformat-truncation=2 $(sanitize)
CC := /usr/bin/gcc
CXX := /usr/bin/g++
builddir := build
objectname = sabp
objectdir = $(builddir)/$(objectname)
.PHONY: all debug
all:set_flags $(objectdir)
debug:set_debug_flags $(objectdir)
$(objectdir):$(builddir) $(builddir)/random.o $(builddir)/sa.o src/main.cpp
$(CXX) $(CPPFLAGS) $(builddir)/random.o $(builddir)/sa.o src/main.cpp -o $(objectdir)
$(builddir)/random.o:src/random.cpp
$(CXX) $(CPPFLAGS) src/random.cpp -o $(builddir)/random.o -c
$(builddir)/sa.o:src/sa.cpp
$(CXX) $(CPPFLAGS) src/sa.cpp -o $(builddir)/sa.o -c
$(builddir):
mkdir -p $(builddir)
set_flags:
$(eval override CPPFLAGS += $(warnings) $(optimize_flags) $(standart))
set_debug_flags:
$(eval override CPPFLAGS += $(warnings) $(sanitize) $(debug_flags))
clean:
rm -rf $(builddir)

78
run.bat
View File

@@ -1,5 +1,77 @@
:: 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 [> arq\de\saida.txt]
@ECHO off
setlocal enabledelayedexpansion
for %%g in (test/*) do (
"build/solucao.exe" < test/%%g
)
if not defined EXEC (
set EXEC="build\sabp.exe"
)
if not defined TEST_FOLDER (
set TEST_FOLDER=test\reduced
)
rem I need to fix this later, dear God...
set ARGS=-ic
if defined SOLUTIONS_FILE (
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
set start_t=!TIME!
for /f "tokens=4" %%h in ('!EXEC! !ARGS! ^< %%g') do set res=%%h
set end_t=!TIME!
call :difftime !start_t! !end_t! difference
echo Resultado do programa: !res!
if defined optimal (
echo Resultado ótimo: !optimal!
if !res! EQU !optimal! (
echo Resultado ótimo^^!
) else (
set /a diff= !res!-!optimal!
echo Diferença de !diff!
)
)
echo Tempo de execução: !difference! segundos
)
endlocal
set EXEC=
set TEST_FOLDER=
set SOLUTIONS_FILE=
set ARGS=
goto :eof
rem Function that gets the difference between two %TIME% variables, expects args= start(VAL), end(VAL), ret(VARNAME)
rem This function assumes that the difference in time is LESS THAN 24 HOURS; If the difference is larger, return is incorrect
:difftime
setlocal
for /f "tokens=1-3 delims=:" %%a in ("%~1") do (
set /a start_h= ^(1%%a-100^) * 3600
set /a start_m= ^(1%%b-100^) * 60
set /a start_s= ^(1%%c-100^)
)
for /f "tokens=1-3 delims=:" %%a in ("%~3") do (
set /a end_h= ^(1%%a-100^) * 3600
set /a end_m= ^(1%%b-100^) * 60
set /a end_s= ^(1%%c-100^)
)
set /a start_i= %start_h% + %start_m% + %start_s%
set /a end_i= %end_h% + %end_m% + %end_s%
set /a diff_t= %end_i% - %start_i%
if diff_t LSS 0 set /a diff_t= %diff_t%+86400
endlocal & set %~5=%diff_t%
goto :eof

34
run.sh
View File

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

33
sa.cpp
View File

@@ -1,33 +0,0 @@
#include "sa.hpp"
#include <cmath>
auto sa::solution::simulated_annealing(int capacity, const std::vector<long long> &items,
const double alpha, double temp)->sa::solution
{
sa::solution best(items, capacity);
best.randomize();
sa::solution prev = best;
std::random_device rdevice;
std::default_random_engine eng(rdevice());
std::uniform_real_distribution<> rand(0, 1);
const double temp_min = 0.30;
while (temp < temp_min) {
sa::solution neighbor(prev);
neighbor.setneighbor();
int diff = prev.fitness - neighbor.fitness;
if (diff <= 0 || std::exp(-diff / temp) > rand(eng)) {
prev.swap(neighbor);
}
temp *= alpha;
if (prev.fitness < best.fitness) {
best = prev;
}
}
return best;
}

101
sa.hpp
View File

@@ -1,101 +0,0 @@
#ifndef SIMULATED_ANNEALING_HEADER_12647_H
#define SIMULATED_ANNEALING_HEADER_12647_H
#include <algorithm>
#include <iostream>
#include <queue>
#include <random>
#include <vector>
namespace sa {
class solution {
std::vector<long long> items;
std::default_random_engine gen;
int capacity;
int fitness;
auto calculate_boxes()->int {
int count = 1;
long long now = 0;
for (auto i : items) {
if (now + i > capacity) {
count++;
now = i;
continue;
}
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:
solution() = default;
solution(const std::vector<long long> &items, int capacity): // Gera a solução inicial
items(items), gen(std::random_device()()), capacity(capacity),
fitness(calculate_boxes()) {}
void setneighbor() { // Gera um vizinho da solução
std::uniform_int_distribution<> dist(0, items.size() - 1);
int first = dist(gen);
int second = 0;
while ((second = dist(gen)) == first) {}
std::swap(items[first], items[second]);
fitness = calculate_boxes();
}
void randomize() {
std::shuffle(items.begin(), items.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);
}
void print_sol() const {
std::cout << "Número de caixas: " << fitness << '\n';
int box_now = 1;
long long now = 0;
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';
}
static auto simulated_annealing(int capacity, const std::vector<long long> &items,
double alpha, double temp)->solution;
};
} // namespace sa
#endif

51
src/main.cpp Normal file
View File

@@ -0,0 +1,51 @@
#include <iostream>
#include <vector>
#include "sa.hpp"
#ifndef TEMP
#define TEMP 1000
#endif
#ifndef ALPHA
#define ALPHA 0.999
#endif
#ifndef TEMP_MIN
#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;
for(int i = 1; i < argc; i++){
if(argv[i][0] == '-'){
int j = 1;
while(argv[i][j] != '\0'){
if(argv[i][j] == 'i') flags |= SIMULATED_ANNEALING_DISABLE_SHOWITRNUM;
else if(argv[i][j] == 'c') flags |= SIMULATED_ANNEALING_DISABLE_SHOWCRATES;
j++;
}
}
}
int number_of_items = 0;
int capacity = 0;
std::cin >> number_of_items >> capacity;
std::vector<long long> items(number_of_items);
for (auto &i : items) {
std::cin >> i;
}
sa::solution act = sa::solution::simulated_annealing(capacity, items,
ALPHA, TEMP, TEMP_MIN);
act.print_sol(flags);
}

4
src/random.cpp Normal file
View File

@@ -0,0 +1,4 @@
#include "random.hpp"
std::random_device rdevice;
std::mt19937_64 rng::rng(rdevice());

24
src/random.hpp Normal file
View File

@@ -0,0 +1,24 @@
#ifndef RANDOM_HPP_RANDOMNESS_WHATEVER_HEADER_238947837827_H
#define RANDOM_HPP_RANDOMNESS_WHATEVER_HEADER_238947837827_H
#include <random>
namespace rng {
extern std::mt19937_64 rng;
template<long long start, long long end>
auto random_int() -> int
{
static std::uniform_int_distribution<> rint(start, end);
return rint(rng);
}
template<int start, int end>
auto random_double() -> double
{
static std::uniform_real_distribution<> rdouble(start, end);
return rdouble(rng);
}
} // namespace rng
#endif

36
src/sa.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include "sa.hpp"
#include <cmath>
/*
* Implementação do algoritmo de SA.
*/
auto sa::solution::simulated_annealing(int capacity, const std::vector<long long> &items,
const double alpha, double temp,
const double temp_min)->sa::solution
{
sa::solution best(items, capacity);
sa::solution prev = best;
int iteration = 0;
while (temp > temp_min) {
iteration++;
sa::solution neighbor(prev, iteration);
neighbor.setneighbor();
long long diff = neighbor.fitness - prev.fitness;
if (diff < 0 || rng::random_double<0, 1>() / temp < 0.05) {
swap(prev, neighbor);
}
temp *= alpha;
if (prev.fitness < best.fitness) {
best = prev;
}
}
best.setiterations(iteration);
return best;
}

287
src/sa.hpp Normal file
View File

@@ -0,0 +1,287 @@
#ifndef SIMULATED_ANNEALING_HEADER_12647_H
#define SIMULATED_ANNEALING_HEADER_12647_H
#define SIMULATED_ANNEALING_DISABLE_SHOWCRATES 1
#define SIMULATED_ANNEALING_DISABLE_SHOWITRNUM 2
#include <algorithm>
#include <iostream>
#include <queue>
#include <random>
#include <set>
#include <utility>
#include <vector>
#include "random.hpp"
namespace sa {
using content = std::priority_queue<long long, std::vector<long long>, std::greater<>>;
class box {
content items;
long long fullness{};
/* Troca uma caixa com a outra. */
friend void swap(box &one, box &two) {
using std::swap;
swap(one.items, two.items);
swap(one.fullness, two.fullness);
}
/* Remove o menor item da caixa. */
void pop() {
fullness -= items.top();
items.pop();
}
public:
box() = default;
/*
* 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();
}
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();
return choice1 != choice2 &&
choice1 + other.fullness - choice2 <= capacity &&
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();
pop();
other.pop();
add_item(choice2);
other.add_item(choice1);
}
/* Imprime todos os items da caixa junto com um identificador. */
void print(int ind) {
std::cout << "Caixa " << ind << ":";
content tmp;
while (!items.empty()) {
std::cout << ' ' << items.top();
items.pop();
}
std::cout << '\n';
}
/* Retorna um booleano indicando se a caixa está vazia. */
[[nodiscard]] auto empty() const -> bool {
return fullness == 0;
}
};
class solution {
std::vector<box> boxes;
long long fitness;
int capacity;
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;
swap(one.boxes, two.boxes);
swap(one.capacity, two.capacity);
swap(one.fitness, two.fitness);
swap(one.iterations, two.iterations);
swap(one.iteration, two.iteration);
}
/*
* Função para usar o swap10 ou swap11 aleatoriamente quando
* possível.
*/
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
};
int now = rng::random_double<0, 1>() > 0.3 ? 0 : 1;
if (sequences[now]->empty()) {
now ^= 1;
if (sequences[now]->empty()) {
return;
}
}
std::uniform_int_distribution<> dist(0, (int)sequences[now]->size() - 1);
(boxes[choice].*swaps[now])(boxes[(*sequences[now])[dist(rng::rng)]]);
}
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) {}
/* Gera a solução inicial a partir dos items disponíveis. */
solution(const std::vector<long long> &items, int capacity):
capacity(capacity), iteration(0) {
std::multiset<long long> its; // Items ordenados.
for (auto i : items) {
its.insert(i);
}
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()) { // Caixa está cheia, cria-se outra.
cap = capacity;
cap -= *its.begin();
itr = its.begin();
this->boxes.emplace_back(tmp);
tmp.clear();
} else { // Caixa consegue colocar outro elemento.
itr--;
cap -= *itr;
}
tmp.add_item(*itr);
its.erase(itr);
}
if (!tmp.empty()) {
this->boxes.emplace_back(tmp);
}
fitness = (int)this->boxes.size();
}
/* 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<int> sequence10; // Possíveis candidatos para swap10
std::vector<int> sequence11; // Possíveis candidatos para swap11
sequence10.reserve(boxes.size());
sequence11.reserve(boxes.size());
for (size_t i = 0; i < (size_t)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()) {
/*
* 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';
std::cout << "Número de iterações calculadas: " << iterations << '\n';
}
std::cout << "Número de caixas: " << fitness << '\n';
if(!(flags & SIMULATED_ANNEALING_DISABLE_SHOWCRATES)){
for (size_t i = 0; i < boxes.size(); i++) {
boxes[i].print((int)i + 1);
}
}
}
/* 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<long long> &items,
double alpha, double temp,
double temp_min) -> solution;
};
} // namespace sa
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More