Compare commits

..

19 Commits

Author SHA1 Message Date
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
6261 changed files with 2997428 additions and 51 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)

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)

43
run.bat
View File

@@ -1,18 +1,17 @@
:: 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
:: 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
if not defined EXEC (
set EXEC="build\solucao.exe"
set EXEC="build\sabp.exe"
)
if not defined TEST_FOLDER (
set TEST_FOLDER=Teste\Casos
set TEST_FOLDER=test\reduced
)
if defined ARGS (
set ARGS=-%ARGS%
)
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 (
@@ -25,7 +24,12 @@ for %%g in (%TEST_FOLDER%\*) do (
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!
@@ -36,6 +40,7 @@ for %%g in (%TEST_FOLDER%\*) do (
echo Diferença de !diff!
)
)
echo Tempo de execução: !difference! segundos
)
endlocal
@@ -43,4 +48,30 @@ 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

6
run.sh
View File

@@ -3,15 +3,15 @@
IFS=$'\n'
if [[ -z $EXEC ]]; then
EXEC="build/main.out"
EXEC="build/sabp"
fi
if [[ -z $TEST_FOLDER ]]; then
TEST_FOLDER="test"
TEST_FOLDER="test/reduced"
fi
if [[ -z $SOLUTIONS_FILE ]]; then
SOLUTIONS_FILE=solucoes.txt
SOLUTIONS_FILE=test/solucoes.txt
fi
declare -A solutions

View File

@@ -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;

View File

@@ -1,6 +1,10 @@
#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
@@ -16,7 +20,7 @@ auto sa::solution::simulated_annealing(int capacity, const std::vector<long long
neighbor.setneighbor();
long long diff = neighbor.fitness - prev.fitness;
if (diff < 0 || rng::random_double<0, 1>() / temp < 0.8) {
if (diff < 0 || rng::random_double<0, 1>() / temp < 0.05) {
swap(prev, neighbor);
}

View File

@@ -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<int> &sequence10, std::vector<int> &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<long long> &items, int capacity): // Gera a solução inicial
/* 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;
std::multiset<long long> 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,15 +210,16 @@ 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<int> sequence10;
std::vector<int> sequence11;
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 < choice; i++) {
for (size_t i = 0; i < (size_t)choice; i++) {
if (boxes[choice].swappable10(boxes[i], capacity)) {
sequence10.push_back((int)i);
}
@@ -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<long long> &items,
double alpha, double temp,
double temp_min) -> solution;

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

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