Compare commits

...

9 Commits

Author SHA1 Message Date
Miguel M 37f8b0a30a Checkpoint: about to rewrite/erase this approach, because CG-P-CG conversions are needed 2023-04-29 18:35:25 +01:00
Miguel M 6531273021 Matrix is again parsed form input as-is
CG-P conversions will be handled separately. See also 1bf3c6a1, from
which a lot of the changes in matrix.c and matrix.h are lifted.
2023-04-29 18:30:56 +01:00
Miguel M da3327ce7e Abstract the working data type to its own header 2023-04-29 18:24:37 +01:00
Miguel M a614b03229 fixes to compilation toolchain 2023-04-29 16:58:53 +01:00
Miguel M 44df5472c8 Rewrite after new problem statement
Still not working, but probably for theoretical reasons, now.
2023-04-29 16:53:36 +01:00
Miguel M cf685d6a91 Fix to permutations.c 2023-04-29 16:52:47 +01:00
Miguel M 83fcf178a9 Heap's algorithm to generate permutations 2023-04-29 09:58:13 +01:00
Miguel M 13c6d00ff6 tighter compilation 2023-04-27 16:28:45 +01:00
Miguel M 7346b90d76 Commit before starting over
Turns out I had the wrong problem statement. I'm given input in CG
notation, but it is not enough to check under permutations for this
representation. Therefore, I should instead first convert to joint
probability representation before checking the permutations, which then
become trivial.
2023-04-27 16:27:39 +01:00
10 changed files with 324 additions and 62 deletions

2
.vscode/launch.json vendored
View File

@ -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": [],

View File

@ -1,3 +0,0 @@
#!/bin/bash
path=$(realpath “${BASH_SOURCE:-$0})
cat "$path/../data/test_mat.txt" | "$path/../main.exe"

2
.vscode/tasks.json vendored
View File

@ -3,7 +3,7 @@
"tasks": [
{
"label": "compile",
"command": "python make.py compile",
"command": "python make.py link",
"type": "shell"
}
]

12
includes/data.h Normal file
View File

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

View File

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

48
includes/permutation.h Normal file
View File

@ -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
View File

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

View File

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

View File

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

78
src/permutation.c Normal file
View File

@ -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.
}