Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Submissão do problema 01 #14

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions submissions/felipemarkson/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.vscode/*
p1
p1d
22 changes: 22 additions & 0 deletions submissions/felipemarkson/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
MIT License

Copyright (c) 2023 Felipe Markson dos Santos Monteiro

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
58 changes: 58 additions & 0 deletions submissions/felipemarkson/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Rinha de Algoritmos -- Problema 01: Lucro de Plantação no Stardew Valley

> Todos os testes foram feitos em um Arch Linux utilizando o GCC `13.2.1` e clang `16.0.6`

> O programa utiliza apenas uma thread e é previsto uma utilização de memória de até 11 MB para a maior instância do problema.

## Build

Para build, você precisará de um compilador C que supporte C99
(praticamente qualquer compilador C moderno) e habilitar flags de otimização
(`-Ofast` para GCC e clang).

> **NOTE**: Se você estiver em um Linux, pode executar o arquivo `build.sh` para realizar o build. Esse script criará uma versão de release `p1` e uma versão de debug `p1d` (veja a sessão de Debug).

Veja os exemplos abaixo.

### GCC

```bash
gcc -Ofast -o p1 problema-1.c
```
### clang

```bash
clang -Ofast -o p1 problema-1.c
```

## Execução

O programa aceita o caminho para o arquivo como primeiro parâmetro no CLI.
Caso o arquivo não seja passado, o programa irá quebrar.
Veja exemplo de utilização abaixo.

```bash
./p1 test.txt
```

## Debug

As vezes coisas estranhas acontecem. Para isso há uma versão de debug `p1d` que é gerada pelo script `build.sh`.

Nessa versão, vários logs são escritos, tanto no `stdout` quanto no `stderr`. Redicione eles corretamente para arquivos afim de obter mais informações de execução.

## Gerando novos casos

O arquivo `gen_case.py` gera casos pseudo-randomicos baseado em um seed passado como primeiro parâmetro. O caso é escrito no `stdout`, redirecione-o de acordo.

Veja o exemplo abaixo.

```bash
python3 gen_case.py myseed > test_myseed.txt
```

## Copyright

Copyright (c) 2023 Felipe Markson dos Santos Monteiro

Os arquivos nesta pasta estão sob licensa MIT. Veja `LICENSE` para mais detalhes.
2 changes: 2 additions & 0 deletions submissions/felipemarkson/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gcc -O0 -ggdb -Wall -Wextra -std=c99 -pedantic -DDEBUG -o p1d problema-1.c
gcc -Ofast -o p1 problema-1.c
103 changes: 103 additions & 0 deletions submissions/felipemarkson/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
LICENSE

Copyright (c) 2023 Felipe Markson dos Santos Monteiro

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/


#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef inner_assert
#define inner_assert(expr, cstr_msg_err) \
do { \
if (!(expr)) { \
fprintf(stderr, "FATAL ERROR!\n %s:%d\n %s\n Caused by: %s\n", \
__FILE__, __LINE__, (cstr_msg_err), #expr); \
exit(1); \
} \
} while (0)
#endif

typedef struct {
char* items;
size_t length;
size_t capacity;
} str;

typedef struct {
const char* items;
size_t length;
} view_str;

str readfile(const char* path) {
FILE* file = fopen(path, "r");
long file_size = 0;
char* data = 0;
long ret = 0;

inner_assert(file, "Could not open the file");
ret = fseek(file, 0, SEEK_END) == 0;
inner_assert(ret >= 0, strerror(errno));
file_size = ftell(file);
inner_assert((file_size) > 0, strerror(errno));
ret = fseek(file, 0, SEEK_SET);
inner_assert(ret >= 0, strerror(errno));
data = malloc(file_size + 1);
inner_assert(data, strerror(errno));
ret = fread(data, file_size, 1, file);
inner_assert(ret == 1, "fread fail");
fclose(file);
data[file_size] = '\0';
return (str){.items = data, .length = file_size, .capacity = file_size};
}

view_str pop_until(view_str* data, char delim) {
view_str str = {0};
if (data->length == 0)
return str;
if (data->length == 1) {
if (data->items[0] == delim)
return str;
str = *data;
data->items = 0;
data->length = 0;
return str;
}
str.items = data->items;
for (size_t i = 0; i < data->length; i++) {
if (data->items[i] == delim) {
data->items = (data->items + i + 1);
data->length -= i + 1;
return str;
} else {
str.length += 1;
}
}
str.length = data->length;
data->items = NULL;
data->length = 0;
return str;
}
46 changes: 46 additions & 0 deletions submissions/felipemarkson/gen_case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
LICENSE

Copyright (c) 2023 Felipe Markson dos Santos Monteiro

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""

import random as rng
import sys

class WrongNumberOfArguments(TypeError):
pass

W = 2666
N = 1000
vlimits = (30, 200)
wlimits = (1, 7)

if __name__ == "__main__":
if len(sys.argv) != 2:
raise WrongNumberOfArguments

rng.seed(sys.argv[1])
print(f"{N} {W}")
for _ in range(N):
w = rng.randint(*wlimits)
v = rng.randint(*vlimits)
print(f"{w}\t{v}")
153 changes: 153 additions & 0 deletions submissions/felipemarkson/problema-1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
LICENSE

Copyright (c) 2023 Felipe Markson dos Santos Monteiro

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// Some macro magics to debug memory issues
#ifdef DEBUG
#define MATRIX(i_, j_) (*(matrix((i_), (j_), __LINE__)))
#define w(i_) (*(weigths(i_, __LINE__)))
#define v(i_) (*(values(i_, __LINE__)))
#define LOG(...) printf(__VA_ARGS__)
#define ASSERT(...) inner_assert(__VA_ARGS__)
#define LOGMEM(...) fprintf(stderr, __VA_ARGS__)

#else
#define MATRIX(i_, j_) buffer[(i_) * NCOL_MATRIX + (j_)]
#define w(i_) wt[(i_)]
#define v(i_) vl[(i_)]
#define LOG(...)
#define ASSERT(...)
#define LOGMEM(...)

// For common.c
#define inner_assert(...)
#endif // DEBUG

#include "common.c" // Just to reduce the compilation complexity
#define Int int32_t

// Dynamic memory meta-data
Int* buffer = 0;
Int* wt = 0;
Int* vl = 0;
Int N = 0; // MAX 1000
Int W = 0; // MAX 2666
#define NROW_MATRIX (N + 1)
#define NCOL_MATRIX (W + 1)
#define SIZE_MATRIX (NROW_MATRIX * NCOL_MATRIX) // MAX 2669667
#define SIZE_BUFFER (SIZE_MATRIX + (N + N)) // MAX 2671667 => 10_686_668 Bytes or 11MB

// Helper functions to debug memory issues (used only in DEBUG mode).
Int* matrix(Int i, Int j, Int line) {
Int local = i * NCOL_MATRIX + j;
LOGMEM("M L:%d -> Accessing %d:(%d, %d) in %d\n", line, local, i, j, SIZE_MATRIX - 1);

ASSERT(i < NROW_MATRIX, "Invalid access in row");
ASSERT(j < NCOL_MATRIX, "Invalid access in col");
ASSERT(local < SIZE_BUFFER, "Invalid access in buffer");
return buffer + local;
}
Int* weigths(Int i, Int line) {
LOGMEM("W L:%d -> Accessing %d in %d\n", line, i, N - 1);

ASSERT(i < N, "Invalid access in w");
return wt + i;
}
Int* values(Int i, Int line) {
LOGMEM("V L:%d -> Accessing %d in %d\n", line, i, N - 1);

ASSERT(i < N, "Invalid access in v");
return vl + i;
}

// Here is where the magic happen
void recursive_knapsack(Int i, Int j) {
ASSERT(i < NROW_MATRIX, "Invalid access in row");
ASSERT(j < NCOL_MATRIX, "Invalid access in col");
Int k = i - 1;
Int wk = w(k);
Int vk = v(k);
if ((i == 0) || (j == 0)) {
MATRIX(i, j) = 0;
return;
}

if (MATRIX(k, j) == -1)
recursive_knapsack(k, j);

if (wk > j) {
MATRIX(i, j) = MATRIX(k, j);
} else {
if (MATRIX(k, j - wk) == -1)
recursive_knapsack(k, j - wk);
Int value1 = MATRIX(k, j - wk) + vk;
Int value2 = MATRIX(k, j);
MATRIX(i, j) = (value1 > value2) ? value1 : value2;
}
}

int main(int argc, char const* argv[]) {
ASSERT(argc == 2, "Provide the file path");
// General purpose Int
Int i = 0;
Int j = 0;

// File Handlers
str file = readfile(argv[1]);
view_str file_view = {file.items, file.length};
view_str line = pop_until(&file_view, '\n');

ASSERT(line.length > 0, "could not read the file");
i = sscanf(line.items, "%d %d", &N, &W);
ASSERT(i == 2, "Could not read the N and W");

LOG("Alocating %lu KB for the problem N: %d, W: %d\n", (SIZE_BUFFER * sizeof(buffer[0])) / 1000, N, W);

// We call only one malloc to store the matrix, weights, and values.
// Therefore, we will have only one big chunk of memory which (hopefully) can be
// stored in the cache, improving the time to access memory.
// Also, we do only one syscall insted of reallocing memory.
buffer = malloc(SIZE_BUFFER * sizeof(buffer[0]));
ASSERT(buffer != NULL, "Could not allocated memory");

// Hopefully the compiller will optimize it for some sort of memset.
for (j = 0; j < SIZE_BUFFER; j++)
buffer[j] = -1;
wt = buffer + SIZE_MATRIX;
vl = wt + N;

for (i = 0; i < N; i++) {
line = pop_until(&file_view, '\n');
j = sscanf(line.items, "%d\t%d", &(wt[i]), &(vl[i]));
ASSERT(j == 2, "Could not read the value and weigth");
LOG("v: %d | w: %d\n", vl[i], wt[i]);
}

recursive_knapsack(N, W);
printf("%d\n", MATRIX(N, W));

free(file.items);
free(buffer);
return 0;
}