Compare commits
9 Commits
1bf3c6a19d
...
37f8b0a30a
Author | SHA1 | Date |
---|---|---|
Miguel M | 37f8b0a30a | |
Miguel M | 6531273021 | |
Miguel M | da3327ce7e | |
Miguel M | a614b03229 | |
Miguel M | 44df5472c8 | |
Miguel M | cf685d6a91 | |
Miguel M | 83fcf178a9 | |
Miguel M | 13c6d00ff6 | |
Miguel M | 7346b90d76 |
|
@ -9,7 +9,7 @@
|
|||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/main.exe",
|
||||
"args": ["<", "${workspaceFolder}/data/test_mat.txt"],
|
||||
"args": ["2", "2", "2", "2", "<", "${workspaceFolder}/data/2222_inq.txt"],
|
||||
"stopAtEntry": true,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
path=$(realpath “${BASH_SOURCE:-$0}”)
|
||||
cat "$path/../data/test_mat.txt" | "$path/../main.exe"
|
|
@ -3,7 +3,7 @@
|
|||
"tasks": [
|
||||
{
|
||||
"label": "compile",
|
||||
"command": "python make.py compile",
|
||||
"command": "python make.py link",
|
||||
"type": "shell"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef ACED_INCLUDES_DATA_H
|
||||
#define ACED_INCLUDES_DATA_H
|
||||
|
||||
// Definition of the datatype representing the input.
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PRImDATA PRIiFAST32
|
||||
#define SCNmDATA SCNiFAST32
|
||||
typedef int_fast32_t data_t;
|
||||
|
||||
#endif
|
|
@ -1,12 +1,8 @@
|
|||
#ifndef ACED__MATRIX_H_
|
||||
#define ACED__MATRIX_H_
|
||||
#ifndef ACED_INCLUDES_MATRIX_H_
|
||||
#define ACED_INCLUDES_MATRIX_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define PRImDATA PRIiFAST32
|
||||
#define SCNmDATA SCNiFAST32
|
||||
typedef int_fast32_t matrix_data_t;
|
||||
#include "../includes/data.h"
|
||||
|
||||
// Struct representing the input matrix.
|
||||
typedef struct
|
||||
|
@ -14,7 +10,7 @@ typedef struct
|
|||
// Number of elements in one row.
|
||||
size_t row_len;
|
||||
// Pointer to the buffer containing the matrix's entries.
|
||||
matrix_data_t *head;
|
||||
data_t *head;
|
||||
// Number of entries in the matrix.
|
||||
size_t len;
|
||||
} matrix_t;
|
||||
|
@ -22,6 +18,9 @@ typedef struct
|
|||
// Prints a debug view of a `matrix_t` to standard output.
|
||||
void DebugPrintMatrix(matrix_t *matrix);
|
||||
|
||||
// Prints a row of a `matrix_t` to standard output.
|
||||
void PrintMatrixRow(matrix_t *matrix, size_t row);
|
||||
|
||||
// Parse a matrix from the standard input.
|
||||
//
|
||||
// This function parses an extended matrix (C|l), where C is an n×m matrix, and
|
||||
|
@ -32,4 +31,4 @@ void DebugPrintMatrix(matrix_t *matrix);
|
|||
// row_len The number of entries in one row.
|
||||
matrix_t ParseMatrix(size_t row_len);
|
||||
|
||||
#endif // ACED__MATRIX_H_
|
||||
#endif // ACED_INCLUDES_MATRIX_H_
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef ACED_INCLUDES_PERMUTATION_H_
|
||||
#define ACED_INCLUDES_PERMUTATION_H_
|
||||
|
||||
// The permutations are generated according to Heap's method [1].
|
||||
// Because we're not allowed to "yield" (i.e., we don't have co-routines, etc.),
|
||||
// we use a state machine (given by `permutation_generator_t`), adapting the
|
||||
// iterative version of Heap's method to suit this approach.
|
||||
//
|
||||
// References:
|
||||
// [1]: https://en.m.wikipedia.org/wiki/Heap%27s_algorithm
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t len; // The number of elements being permuted.
|
||||
size_t *permutation; // Current permutation, as indices.
|
||||
_Bool exhausted; // Whether there are any permutations left to generate.
|
||||
size_t *stack;
|
||||
size_t pointer;
|
||||
} permutation_generator_t;
|
||||
|
||||
// Create a `permutation_generator_t`.
|
||||
// This needs to be done only once. Afterwards, use only `PermutationReset`.
|
||||
// After getting a new generator, you still need to call `PermutationReset`, or
|
||||
// behaviour is undefined.
|
||||
//
|
||||
// Arguments:
|
||||
// len Number of elements to permute (from `0` to `len-1`).
|
||||
permutation_generator_t PermutationNewGenerator(size_t len);
|
||||
|
||||
// Configure a permutation generator to start generating permutations from the
|
||||
// start.
|
||||
void PermutationReset(permutation_generator_t *permutation_generator);
|
||||
|
||||
// Generate the next permutation.
|
||||
//
|
||||
// Calling this after `permutation_generator->exhausted` is true results in
|
||||
// undefined behaviour.
|
||||
void PermutationNext(permutation_generator_t *permutation_generator);
|
||||
|
||||
// Release the memory associated to a permutation generator.
|
||||
//
|
||||
// This will invalidate the generator.
|
||||
void PermutationFree(permutation_generator_t *permutation_generator);
|
||||
|
||||
#endif //ACED_INCLUDES_PERMUTATION_H_
|
15
make.py
15
make.py
|
@ -6,11 +6,14 @@ from glob import glob
|
|||
from sane import *
|
||||
|
||||
COMPILER = 'gcc'
|
||||
COMPILE_FLAGS = ['-std=c99',
|
||||
COMPILE_FLAGS = ['-std=c11',
|
||||
'-g',
|
||||
'-O0',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Werror',
|
||||
'-Wpedantic',
|
||||
'-pedantic-errors',
|
||||
'-fopenmp']
|
||||
LINK_FLAGS = []
|
||||
OBJ_DIR = 'obj'
|
||||
|
@ -21,6 +24,7 @@ ROOT = os.path.dirname(os.path.realpath(__file__))
|
|||
|
||||
if 'RELEASE' in os.environ:
|
||||
COMPILE_FLAGS[COMPILE_FLAGS.index('-O0')] = '-O2'
|
||||
COMPILE_FLAGS.append('-DRELEASE')
|
||||
|
||||
def as_object(source_path):
|
||||
"""Takes a source path and returns the path to the corresponding compiled object."""
|
||||
|
@ -80,11 +84,4 @@ def link():
|
|||
def clean():
|
||||
shutil.rmtree(OBJ_DIR)
|
||||
|
||||
@recipe(recipe_deps=[link],
|
||||
conditions=[lambda: True],
|
||||
info='Runs the main executable with the test matrix as input.')
|
||||
def run():
|
||||
with open(os.path.join(ROOT, 'data', 'test_mat.txt'), 'r') as test_input:
|
||||
sp.run(os.path.join(ROOT, EXE_NAME), stdin=test_input)
|
||||
|
||||
sane_run(run)
|
||||
sane_run(link)
|
||||
|
|
176
src/main.c
176
src/main.c
|
@ -1,39 +1,159 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../includes/matrix.h"
|
||||
#include "../includes/permutation.h"
|
||||
|
||||
// Temporarily defined here.
|
||||
// Later, should be defined upon compilation, with -D flag (for gcc).
|
||||
#define A_OUTPUTS 3
|
||||
#define B_OUTPUTS 3
|
||||
#define A_INPUTS 3
|
||||
#define B_INPUTS 3
|
||||
|
||||
void PrintRow(matrix_t *matrix, size_t row) {
|
||||
for (size_t entry = 0; entry < matrix->row_len; entry ++) {
|
||||
printf("%" PRImDATA, *(matrix->head + row * (matrix->row_len) + entry));
|
||||
if (entry != matrix->row_len - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
static void ReadArguments(char *from, size_t *restrict into, const char *varname)
|
||||
{
|
||||
if (!sscanf(from, "%zu", into))
|
||||
{
|
||||
fprintf(stderr, "Failed to read %s.", varname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
size_t a_out = A_OUTPUTS;
|
||||
size_t b_out = B_OUTPUTS;
|
||||
size_t a_in = A_INPUTS;
|
||||
size_t b_in = B_INPUTS;
|
||||
size_t row_len = ((a_out-1)*(b_out-1)*a_in*b_in + (a_out-1)*a_in +
|
||||
(b_out-1)*b_in) + 1; // +1 accounts for the L column.
|
||||
matrix_t matrix = ParseMatrix(row_len);
|
||||
DebugPrintMatrix(&matrix);
|
||||
size_t row_count = matrix.len / row_len;
|
||||
|
||||
for (size_t row = 0; row < row_count; row++) {
|
||||
// Compare to the following rows
|
||||
PrintRow(&matrix, row);
|
||||
if (argc < 5)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n ./main.exe <A outputs> <B outputs> <A inputs> <B inputs>");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
size_t a_out, b_out, a_in, b_in;
|
||||
ReadArguments(argv[1], &a_out, "A outputs");
|
||||
ReadArguments(argv[2], &b_out, "B outputs");
|
||||
ReadArguments(argv[3], &a_in, "A inputs");
|
||||
ReadArguments(argv[4], &b_in, "B inputs");
|
||||
|
||||
size_t row_len = (a_out - 1) * (b_out - 1) * a_in * b_in + (a_out - 1) * a_in + (b_out - 1) * b_in + 1;
|
||||
matrix_t matrix = ParseMatrix(row_len);
|
||||
DebugPrintMatrix(&matrix);
|
||||
size_t row_count = matrix.len / matrix.row_len;
|
||||
|
||||
permutation_generator_t perm_a_out = PermutationNewGenerator(a_out);
|
||||
permutation_generator_t perm_b_out = PermutationNewGenerator(b_out);
|
||||
permutation_generator_t perm_a_in = PermutationNewGenerator(a_in);
|
||||
permutation_generator_t perm_b_in = PermutationNewGenerator(b_in);
|
||||
|
||||
_Bool *seen = calloc(row_count, sizeof(_Bool));
|
||||
|
||||
for (size_t base_row_i= 0; base_row_i < row_count - 1; base_row_i++)
|
||||
{
|
||||
if (seen[base_row_i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
data_t *base_row = matrix.head + base_row_i * matrix.row_len;
|
||||
data_t base_l = base_row[matrix.row_len - 1];
|
||||
|
||||
for (size_t cmp_row_i = base_row_i + 1; cmp_row_i < row_count; cmp_row_i++)
|
||||
{
|
||||
data_t *cmp_row = matrix.head + cmp_row_i * matrix.row_len;
|
||||
data_t cmp_l = cmp_row[matrix.row_len - 1];
|
||||
|
||||
if (base_l != cmp_l)
|
||||
{
|
||||
// If the L values are different, the rows cannot be different under permutation.
|
||||
continue; // To next cmp_row_i
|
||||
}
|
||||
|
||||
PermutationReset(&perm_a_in);
|
||||
while (!perm_a_in.exhausted)
|
||||
{
|
||||
PermutationReset(&perm_b_in);
|
||||
while (!perm_b_in.exhausted)
|
||||
{
|
||||
PermutationReset(&perm_a_out);
|
||||
while (!perm_a_out.exhausted)
|
||||
{
|
||||
PermutationReset(&perm_b_out);
|
||||
while (!perm_b_out.exhausted)
|
||||
{
|
||||
// Compare the rows while applying this permutation.
|
||||
// If every entry is the same, the rows are equivalent.
|
||||
_Bool any_different = 0;
|
||||
for (size_t a_in_i = 0; a_in_i < a_in; a_in_i++)
|
||||
{
|
||||
for (size_t a_out_i = 0; a_out_i < a_out; a_out_i++)
|
||||
{
|
||||
for (size_t b_in_i = 0; b_in_i < b_in; b_in_i++)
|
||||
{
|
||||
for (size_t b_out_i = 0; b_out_i < b_out; b_out_i++)
|
||||
{
|
||||
size_t base_idx = b_out_i + b_out * (b_in_i + b_in * (a_out_i + a_out * a_in_i));
|
||||
size_t cmp_idx = (perm_b_out.permutation[b_out_i] +
|
||||
b_out * (perm_b_in.permutation[b_in_i] +
|
||||
b_in * (perm_a_out.permutation[a_out_i] +
|
||||
a_out * perm_a_in.permutation[a_in_i])));
|
||||
|
||||
if (base_row[base_idx] != cmp_row[cmp_idx])
|
||||
{
|
||||
any_different = 1;
|
||||
goto stop_comparison;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stop_comparison:
|
||||
|
||||
if (!any_different)
|
||||
{
|
||||
// The two rows are equivalent under this particular permutation.
|
||||
seen[cmp_row_i] = 1;
|
||||
goto skip_permutations;
|
||||
}
|
||||
|
||||
PermutationNext(&perm_b_out);
|
||||
}
|
||||
PermutationNext(&perm_a_out);
|
||||
}
|
||||
PermutationNext(&perm_b_in);
|
||||
}
|
||||
PermutationNext(&perm_a_in);
|
||||
}
|
||||
skip_permutations:;
|
||||
} // End of loop over comparison rows
|
||||
} // End of loop over base rows
|
||||
|
||||
// Print the non-equivalent rows to stdout.
|
||||
for (size_t i = 0; i < row_count; i++)
|
||||
{
|
||||
if (!seen[i])
|
||||
{
|
||||
#if RELEASE
|
||||
PrintMatrixRow(&matrix, i);
|
||||
#else
|
||||
printf("%zu:\n ", i);
|
||||
data_t *row = matrix.head + i * matrix.row_len;
|
||||
for (size_t a_in_i = 0; a_in_i < a_in; a_in_i++)
|
||||
{
|
||||
for (size_t a_out_i = 0; a_out_i < a_out; a_out_i++)
|
||||
{
|
||||
for (size_t b_in_i = 0; b_in_i < b_in; b_in_i++)
|
||||
{
|
||||
for (size_t b_out_i = 0; b_out_i < b_out; b_out_i++)
|
||||
{
|
||||
size_t idx = b_out_i + b_out * (b_in_i + b_in * (a_out_i + a_out * a_in_i));
|
||||
printf("(%zu,%zu|%zu,%zu): %" PRImDATA ", ", a_out_i, b_out_i, a_in_i, b_in_i, row[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("L: %" PRImDATA, row[matrix.row_len - 1]);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
PermutationFree(&perm_a_in);
|
||||
PermutationFree(&perm_b_in);
|
||||
PermutationFree(&perm_a_out);
|
||||
PermutationFree(&perm_b_out);
|
||||
free(seen);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
33
src/matrix.c
33
src/matrix.c
|
@ -24,11 +24,22 @@ void DebugPrintMatrix(matrix_t *matrix)
|
|||
printf("] }\n");
|
||||
}
|
||||
|
||||
// Prints a row of a `matrix_t` to standard output.
|
||||
void PrintMatrixRow(matrix_t *matrix, size_t row) {
|
||||
for (size_t entry = 0; entry < matrix->row_len; entry ++) {
|
||||
printf("%" PRImDATA, *(matrix->head + row * (matrix->row_len) + entry));
|
||||
if (entry != matrix->row_len - 1) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Parameters for `increase_input_buffers`.
|
||||
typedef struct
|
||||
{
|
||||
size_t capacity;
|
||||
matrix_data_t *head;
|
||||
data_t *head;
|
||||
} matrix_bufs_t;
|
||||
|
||||
// Increases the data buffers used in `parse_input`.
|
||||
|
@ -38,7 +49,7 @@ typedef struct
|
|||
static matrix_bufs_t increase_input_buffers(matrix_bufs_t bufs)
|
||||
{
|
||||
bufs.capacity *= 2;
|
||||
bufs.head = realloc(bufs.head, bufs.capacity * sizeof(matrix_data_t));
|
||||
bufs.head = realloc(bufs.head, bufs.capacity * sizeof(data_t));
|
||||
if (bufs.head == NULL)
|
||||
{
|
||||
printf(
|
||||
|
@ -53,7 +64,7 @@ static matrix_bufs_t increase_input_buffers(matrix_bufs_t bufs)
|
|||
// Compacts the allocated memory to fit exactly the number of elements.
|
||||
static void compact_buffers(matrix_t *matrix)
|
||||
{
|
||||
matrix->head = realloc(matrix->head, matrix->len * sizeof(matrix_data_t));
|
||||
matrix->head = realloc(matrix->head, matrix->len * sizeof(data_t));
|
||||
if ((matrix->head == NULL))
|
||||
{
|
||||
fprintf(
|
||||
|
@ -65,8 +76,8 @@ static void compact_buffers(matrix_t *matrix)
|
|||
}
|
||||
}
|
||||
|
||||
static matrix_data_t as_matrix_entry(char *str, size_t str_len) {
|
||||
matrix_data_t value;
|
||||
static data_t as_matrix_entry(char *str, size_t str_len) {
|
||||
data_t value;
|
||||
str[str_len] = 0; // Null-terminate the string.
|
||||
int result = sscanf(str, "%" SCNmDATA, &value);
|
||||
if (result == 0 || result == EOF)
|
||||
|
@ -85,7 +96,7 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
{
|
||||
size_t capacity = 32; // Initial value is arbitrary.
|
||||
size_t len = 0; // Number of entries stored.
|
||||
matrix_data_t *head = malloc(capacity * sizeof(matrix_data_t));
|
||||
data_t *head = malloc(capacity * sizeof(data_t));
|
||||
|
||||
_Bool spaces = 1;
|
||||
char scanned;
|
||||
|
@ -99,7 +110,7 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
{
|
||||
// Finished reading string.
|
||||
// Push the numerical entry into the matrix.
|
||||
matrix_data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
head[len-1] = value;
|
||||
}
|
||||
spaces = 1;
|
||||
|
@ -119,7 +130,7 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
if (spaces)
|
||||
{
|
||||
// New string
|
||||
len += 1;
|
||||
len++;
|
||||
scan_len = 0;
|
||||
|
||||
// Check if we need to resize the buffer.
|
||||
|
@ -138,7 +149,7 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
|
||||
// Save the character to the entry string
|
||||
scan_str[scan_len] = scanned;
|
||||
scan_len += 1;
|
||||
scan_len++;
|
||||
|
||||
if (scan_len == 50)
|
||||
{
|
||||
|
@ -150,7 +161,7 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
|
||||
// Write the last entry if necessary
|
||||
if (!spaces) {
|
||||
matrix_data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
head[len] = value;
|
||||
}
|
||||
|
||||
|
@ -175,4 +186,4 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
compact_buffers(&matrix);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#include <stdlib.h>
|
||||
#include "../includes/permutation.h"
|
||||
|
||||
permutation_generator_t PermutationNewGenerator(size_t len)
|
||||
{
|
||||
size_t *permutation = malloc(2 * len * sizeof(size_t));
|
||||
size_t *stack = permutation + len;
|
||||
|
||||
permutation_generator_t generator = {
|
||||
.len = len,
|
||||
.permutation = permutation,
|
||||
.stack = stack,
|
||||
};
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
void PermutationReset(permutation_generator_t *permutation_generator)
|
||||
{
|
||||
size_t len = permutation_generator->len;
|
||||
size_t *permutation = permutation_generator->permutation;
|
||||
size_t *stack = permutation_generator->stack;
|
||||
|
||||
// Initialize the permutation array and stack.
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
permutation[i] = i;
|
||||
stack[i] = 0;
|
||||
}
|
||||
|
||||
permutation_generator->pointer = 1;
|
||||
permutation_generator->exhausted = (len == 0);
|
||||
}
|
||||
|
||||
static void _PermutationNext(size_t * restrict permutation, size_t * restrict stack, size_t *stack_ptr, _Bool *exhausted, size_t len) {
|
||||
repeat:
|
||||
if (stack[*stack_ptr] < *stack_ptr) {
|
||||
if (((*stack_ptr) & 1) == 0) { // Is even
|
||||
// Swap A[0] and A[i]
|
||||
size_t tmp = permutation[0];
|
||||
permutation[0] = permutation[*stack_ptr];
|
||||
permutation[*stack_ptr] = tmp;
|
||||
} else {
|
||||
// Swap A[c[i]] and A[i]
|
||||
size_t tmp = permutation[*stack_ptr];
|
||||
permutation[*stack_ptr] = permutation[stack[*stack_ptr]];
|
||||
permutation[stack[*stack_ptr]] = tmp;
|
||||
}
|
||||
|
||||
// Permutation can now be accessed.
|
||||
|
||||
stack[*stack_ptr] += 1;
|
||||
*stack_ptr = 1;
|
||||
} else {
|
||||
stack[*stack_ptr] = 0;
|
||||
*stack_ptr += 1;
|
||||
if (*stack_ptr < len) {
|
||||
goto repeat;
|
||||
} else {
|
||||
*exhausted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PermutationNext(permutation_generator_t *permutation_generator) {
|
||||
size_t *permutation = permutation_generator->permutation;
|
||||
size_t *stack = permutation_generator->stack;
|
||||
size_t *stack_ptr = &(permutation_generator->pointer);
|
||||
size_t len = permutation_generator->len;
|
||||
_Bool *exhausted = &(permutation_generator->exhausted);
|
||||
_PermutationNext(permutation, stack, stack_ptr, exhausted, len);
|
||||
}
|
||||
|
||||
void PermutationFree(permutation_generator_t *permutation_generator)
|
||||
{
|
||||
free(permutation_generator->permutation);
|
||||
// No need to free permutation_generator->stack, since it's contiguous.
|
||||
}
|
Loading…
Reference in New Issue