Compare commits
4 Commits
216836f7f9
...
94c1aa1ae8
Author | SHA1 | Date |
---|---|---|
Miguel M | 94c1aa1ae8 | |
Miguel M | 678d1e1008 | |
Miguel M | 4b1db5cec0 | |
Miguel M | bba8aa9e17 |
|
@ -33,24 +33,30 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "../includes/data.h"
|
||||
#include "../includes/permutation.h"
|
||||
|
||||
// Convert from CG representation to P representation.
|
||||
// Convert from CG representation to P representation, under a given
|
||||
// permutation.
|
||||
//
|
||||
// `p` isn't required to be initialized, as this function will overwrite every
|
||||
// entry (provided that `p` is of the expected size).row
|
||||
// `p` isn't required to be initialized, only allocated.
|
||||
void FromCgToP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
||||
const data_t* restrict cg, data_t* restrict p);
|
||||
const data_t* restrict cg, data_t* restrict p,
|
||||
const size_t* a_in_perm, const size_t* b_in_perm,
|
||||
const permutation_generator_t* restrict a_out_perms,
|
||||
const permutation_generator_t* restrict b_out_perms);
|
||||
|
||||
// Convert from P representation to CG representation.
|
||||
//
|
||||
// `cg` isn't required to be initialized, only allocated.
|
||||
void FromPToCg(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
||||
data_t* restrict cg, const data_t* restrict p);
|
||||
|
||||
// Debug print a CG row.
|
||||
void PrintCg(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
||||
const data_t* cg);
|
||||
const data_t* cg);
|
||||
|
||||
// Debug print a P row.
|
||||
void PrintP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
||||
const data_t* p);
|
||||
const data_t* p);
|
||||
|
||||
#endif
|
|
@ -2,17 +2,17 @@
|
|||
#define ACED_INCLUDES_MATRIX_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../includes/data.h"
|
||||
|
||||
// Struct representing the input matrix.
|
||||
typedef struct
|
||||
{
|
||||
// Number of elements in one row.
|
||||
size_t row_len;
|
||||
// Pointer to the buffer containing the matrix's entries.
|
||||
data_t *head;
|
||||
// Number of entries in the matrix.
|
||||
size_t len;
|
||||
typedef struct {
|
||||
// Number of elements in one row.
|
||||
size_t row_len;
|
||||
// Pointer to the buffer containing the matrix's entries.
|
||||
data_t *head;
|
||||
// Number of entries in the matrix.
|
||||
size_t len;
|
||||
} matrix_t;
|
||||
|
||||
// Prints a debug view of a `matrix_t` to standard output.
|
||||
|
@ -22,7 +22,7 @@ void DebugPrintMatrix(matrix_t *matrix);
|
|||
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
|
||||
// l is an m-sized column vector. This input is given in standard input as
|
||||
// whitespace separated entries.
|
||||
|
@ -31,4 +31,4 @@ void PrintMatrixRow(matrix_t *matrix, size_t row);
|
|||
// row_len The number of entries in one row.
|
||||
matrix_t ParseMatrix(size_t row_len);
|
||||
|
||||
#endif // ACED_INCLUDES_MATRIX_H_
|
||||
#endif // ACED_INCLUDES_MATRIX_H_
|
|
@ -9,23 +9,22 @@
|
|||
// References:
|
||||
// [1]: https://en.m.wikipedia.org/wiki/Heap%27s_algorithm
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.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;
|
||||
typedef struct {
|
||||
size_t len; // The number of elements being permuted.
|
||||
size_t *restrict permutation; // Current permutation, as indices.
|
||||
_Bool exhausted; // Whether there are any permutations left to generate.
|
||||
size_t *restrict 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);
|
||||
|
@ -35,7 +34,7 @@ permutation_generator_t PermutationNewGenerator(size_t len);
|
|||
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);
|
||||
|
@ -45,4 +44,4 @@ void PermutationNext(permutation_generator_t *permutation_generator);
|
|||
// This will invalidate the generator.
|
||||
void PermutationFree(permutation_generator_t *permutation_generator);
|
||||
|
||||
#endif //ACED_INCLUDES_PERMUTATION_H_
|
||||
#endif // ACED_INCLUDES_PERMUTATION_H_
|
76
src/cg.c
76
src/cg.c
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
static inline size_t CgJointIndex(size_t a_out, size_t b_out, size_t a_in __attribute__((unused)),
|
||||
static inline size_t CgJointIndex(size_t a_out, size_t b_out,
|
||||
size_t a_in __attribute__((unused)),
|
||||
size_t b_in, size_t a_out_i, size_t b_out_i,
|
||||
size_t a_in_i, size_t b_in_i) {
|
||||
return b_out_i +
|
||||
|
@ -23,14 +24,36 @@ static inline size_t CgBMarginalIndex(size_t a_out, size_t b_out, size_t a_in,
|
|||
b_out_i + (b_out - 1) * b_in_i;
|
||||
}
|
||||
|
||||
static inline size_t PIndex(size_t a_out, size_t b_out, size_t a_in __attribute__((unused)),
|
||||
size_t b_in, size_t a_out_i, size_t b_out_i,
|
||||
size_t a_in_i, size_t b_in_i) {
|
||||
static inline size_t PIndex(size_t a_out, size_t b_out,
|
||||
size_t a_in __attribute__((unused)), size_t b_in,
|
||||
size_t a_out_i, size_t b_out_i, size_t a_in_i,
|
||||
size_t b_in_i) {
|
||||
return b_out_i + b_out * (b_in_i + b_in * (a_out_i + a_out * a_in_i));
|
||||
}
|
||||
|
||||
static inline size_t AInPermuted(size_t a_in_i, const size_t *a_in_perm) {
|
||||
return a_in_perm[a_in_i];
|
||||
}
|
||||
|
||||
static inline size_t BInPermuted(size_t b_in_i, const size_t *b_in_perm) {
|
||||
return b_in_perm[b_in_i];
|
||||
}
|
||||
|
||||
static inline size_t AOutPermuted(size_t a_out_i, size_t a_in_i,
|
||||
const permutation_generator_t *a_out_perms) {
|
||||
return a_out_perms[a_in_i].permutation[a_out_i];
|
||||
}
|
||||
|
||||
static inline size_t BOutPermuted(size_t b_out_i, size_t b_in_i,
|
||||
const permutation_generator_t *b_out_perms) {
|
||||
return b_out_perms[b_in_i].permutation[b_out_i];
|
||||
}
|
||||
|
||||
void FromCgToP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
||||
const data_t *restrict cg, data_t *restrict p) {
|
||||
const data_t *restrict cg, data_t *restrict p,
|
||||
const size_t *a_in_perm, const size_t *b_in_perm,
|
||||
const permutation_generator_t *restrict a_out_perms,
|
||||
const permutation_generator_t *restrict b_out_perms) {
|
||||
// size_t p_row_size = a_out * a_in * b_out * b_in;
|
||||
size_t cg_row_size = ((a_out - 1) * (b_out - 1) * a_in * b_in +
|
||||
(a_out - 1) * a_in + (b_out - 1) * b_in) +
|
||||
|
@ -44,21 +67,30 @@ void FromCgToP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
|||
for (size_t b_out_i = 0; b_out_i < b_out - 1; b_out_i++) {
|
||||
size_t cg_index = CgJointIndex(a_out, b_out, a_in, b_in, a_out_i,
|
||||
b_out_i, a_in_i, b_in_i);
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in, a_out_i, b_out_i,
|
||||
a_in_i, b_in_i);
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in,
|
||||
AOutPermuted(a_out_i, a_in_i, a_out_perms),
|
||||
BOutPermuted(b_out_i, b_in_i, b_out_perms),
|
||||
AInPermuted(a_in_i, a_in_perm),
|
||||
BInPermuted(b_in_i, b_in_perm));
|
||||
p[p_index] = cg[cg_index];
|
||||
}
|
||||
|
||||
{
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in, a_out_i, b_out - 1,
|
||||
a_in_i, b_in_i);
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in,
|
||||
AOutPermuted(a_out_i, a_in_i, a_out_perms),
|
||||
BOutPermuted(b_out - 1, b_in_i, b_out_perms),
|
||||
AInPermuted(a_in_i, a_in_perm),
|
||||
BInPermuted(b_in_i, b_in_perm));
|
||||
p[p_index] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t b_out_i = 0; b_out_i < b_out; b_out_i++) {
|
||||
size_t p_index =
|
||||
PIndex(a_out, b_out, a_in, b_in, a_in - 1, b_out_i, a_in_i, b_in_i);
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in,
|
||||
AOutPermuted(a_out - 1, a_in_i, a_out_perms),
|
||||
BOutPermuted(b_out_i, b_in_i, b_out_perms),
|
||||
AInPermuted(a_in_i, a_in_perm),
|
||||
BInPermuted(b_in_i, b_in_perm));
|
||||
p[p_index] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +102,11 @@ void FromCgToP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
|||
|
||||
for (size_t a_out_i = 0; a_out_i < a_out; a_out_i++) {
|
||||
for (size_t b_out_i = 0; b_out_i < b_out; b_out_i++) {
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in, a_out_i, b_out_i, 0, 0);
|
||||
size_t a_in_i = 0;
|
||||
size_t b_in_i = 0;
|
||||
size_t p_index = PIndex(
|
||||
a_out, b_out, a_in, b_in, AOutPermuted(a_out_i, a_in_i, a_out_perms),
|
||||
BOutPermuted(b_out_i, b_in_i, b_out_perms), a_in_i, b_in_i);
|
||||
// Negative sign comes from moving L to the LHS of the inequality
|
||||
p[p_index] -= l;
|
||||
}
|
||||
|
@ -91,8 +127,12 @@ void FromCgToP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
|||
}
|
||||
|
||||
for (size_t b_out_i = 0; b_out_i < b_out; b_out_i++) {
|
||||
size_t p_index =
|
||||
PIndex(a_out, b_out, a_in, b_in, a_out_i, b_out_i, a_in_i, 0);
|
||||
size_t b_in_i = 0;
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in,
|
||||
AOutPermuted(a_out_i, a_in_i, a_out_perms),
|
||||
BOutPermuted(b_out_i, b_in_i, b_out_perms),
|
||||
AInPermuted(a_in_i, a_in_perm),
|
||||
BInPermuted(b_in_i, b_in_perm));
|
||||
p[p_index] += a_marginal;
|
||||
// PrintP(a_out, b_out, a_in, b_in, p);
|
||||
}
|
||||
|
@ -110,8 +150,12 @@ void FromCgToP(size_t a_out, size_t b_out, size_t a_in, size_t b_in,
|
|||
}
|
||||
|
||||
for (size_t a_out_i = 0; a_out_i < a_out; a_out_i++) {
|
||||
size_t p_index =
|
||||
PIndex(a_out, b_out, a_in, b_in, a_out_i, b_out_i, 0, b_in_i);
|
||||
size_t a_in_i = 0;
|
||||
size_t p_index = PIndex(a_out, b_out, a_in, b_in,
|
||||
AOutPermuted(a_out_i, a_in_i, a_out_perms),
|
||||
BOutPermuted(b_out_i, b_in_i, b_out_perms),
|
||||
AInPermuted(a_in_i, a_in_perm),
|
||||
BInPermuted(b_in_i, b_in_perm));
|
||||
p[p_index] += b_marginal;
|
||||
// PrintP(a_out, b_out, a_in, b_in, p);
|
||||
}
|
||||
|
|
120
src/main.c
120
src/main.c
|
@ -1,18 +1,37 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../includes/cg.h"
|
||||
#include "../includes/matrix.h"
|
||||
#include "../includes/permutation.h"
|
||||
#include "../includes/cg.h"
|
||||
|
||||
static void ReadArguments(char *from, size_t *restrict into,
|
||||
const char *varname) {
|
||||
static void ReadArguments(char *from, size_t *into, const char *varname) {
|
||||
if (!sscanf(from, "%zu", into)) {
|
||||
fprintf(stderr, "Failed to read %s.", varname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void AdvanceConditionalPermutations(
|
||||
permutation_generator_t *generators, size_t count) {
|
||||
PermutationNext(generators);
|
||||
for (size_t i = 0; i < count - 1; i++) {
|
||||
if (generators[i].exhausted) {
|
||||
PermutationReset(generators + i);
|
||||
PermutationNext(generators + i + 1);
|
||||
}
|
||||
}
|
||||
// If generators[-1] is exhausted, the conditional permutations are exhausted.
|
||||
}
|
||||
|
||||
static inline void ResetConditionalPermutations(
|
||||
permutation_generator_t *generators, size_t count) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
PermutationReset(generators + i);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 5) {
|
||||
fprintf(
|
||||
|
@ -30,18 +49,93 @@ int main(int argc, char *argv[]) {
|
|||
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);
|
||||
// DebugPrintMatrix(&matrix);
|
||||
size_t row_count = matrix.len / matrix.row_len;
|
||||
|
||||
data_t *p = malloc(a_out * b_out * a_in * b_in * sizeof(data_t));
|
||||
|
||||
data_t *p_buf = malloc(a_out * b_out * a_in * b_in * sizeof(data_t));
|
||||
data_t *cg_buf =
|
||||
malloc((a_out - 1) * (b_out - 1) * a_in * b_in * sizeof(data_t));
|
||||
_Bool *seen = calloc(row_count, sizeof(_Bool));
|
||||
|
||||
// This is a lot of separate allocations, but this section isn't expected to
|
||||
// be hot.
|
||||
permutation_generator_t a_in_perm = PermutationNewGenerator(a_in);
|
||||
permutation_generator_t b_in_perm = PermutationNewGenerator(b_in);
|
||||
permutation_generator_t *a_out_perms =
|
||||
malloc(a_in * sizeof(permutation_generator_t));
|
||||
permutation_generator_t *b_out_perms =
|
||||
malloc(b_in * sizeof(permutation_generator_t));
|
||||
for (size_t i = 0; i < a_in; i++) {
|
||||
a_out_perms[i] = PermutationNewGenerator(a_out);
|
||||
}
|
||||
for (size_t i = 0; i < b_in; i++) {
|
||||
b_out_perms[i] = PermutationNewGenerator(b_out);
|
||||
}
|
||||
|
||||
// Start testing for equivalences.
|
||||
|
||||
for (size_t lhs_i = 0; lhs_i < row_count - 1; lhs_i++) {
|
||||
data_t *lhs = matrix.head + lhs_i * matrix.row_len;
|
||||
|
||||
if (seen[lhs_i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t rhs_i = lhs_i + 1; rhs_i < row_count; rhs_i++) {
|
||||
if (seen[rhs_i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data_t *rhs = matrix.head + rhs_i * matrix.row_len;
|
||||
|
||||
PermutationReset(&a_in_perm);
|
||||
while (!a_in_perm.exhausted) {
|
||||
PermutationReset(&b_in_perm);
|
||||
while (!b_in_perm.exhausted) {
|
||||
|
||||
ResetConditionalPermutations(a_out_perms, a_out);
|
||||
while (!a_out_perms[a_out - 1].exhausted) {
|
||||
ResetConditionalPermutations(b_out_perms, b_out);
|
||||
while (!b_out_perms[b_out - 1].exhausted) {
|
||||
// Compare the two rows
|
||||
_Bool equivalent = 1;
|
||||
FromCgToP(a_out, b_out, a_in, b_in, rhs, p_buf,
|
||||
a_in_perm.permutation, b_in_perm.permutation,
|
||||
a_out_perms, b_out_perms);
|
||||
FromPToCg(a_out, b_out, a_in, b_in, cg_buf, p_buf);
|
||||
for (size_t i = 0; i < row_len; i++) {
|
||||
if (lhs[i] != cg_buf[i]) {
|
||||
equivalent = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (equivalent) {
|
||||
seen[rhs_i] = 1;
|
||||
goto skip_permutations;
|
||||
}
|
||||
|
||||
AdvanceConditionalPermutations(b_out_perms, b_out);
|
||||
}
|
||||
|
||||
AdvanceConditionalPermutations(a_out_perms, a_out);
|
||||
}
|
||||
|
||||
PermutationNext(&b_in_perm);
|
||||
}
|
||||
|
||||
PermutationNext(&a_in_perm);
|
||||
}
|
||||
|
||||
skip_permutations:;
|
||||
} // For loop over rhs_i
|
||||
} // For loop over lhs_i
|
||||
|
||||
// Print every unique row
|
||||
for (size_t i = 0; i < row_count; i++) {
|
||||
data_t *row = matrix.head + i * row_len;
|
||||
printf("%zu:--------------------------------\n", i);
|
||||
PrintCg(a_out, b_out, a_in, b_in, row);
|
||||
FromCgToP(a_out, b_out, a_in, b_in, row, p);
|
||||
PrintP(a_out, b_out, a_in, b_in, p);
|
||||
FromPToCg(a_out, b_out, a_in, b_in, row, p);
|
||||
PrintCg(a_out, b_out, a_in, b_in, row);
|
||||
if (!seen[i]) {
|
||||
PrintMatrixRow(&matrix, i);
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
114
src/matrix.c
114
src/matrix.c
|
@ -1,22 +1,18 @@
|
|||
#include "../includes/matrix.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// Prints a debug view of a `matrix_t` to standard output.
|
||||
void DebugPrintMatrix(matrix_t *matrix)
|
||||
{
|
||||
printf("Grid ( len: %zu, head: %p ) { ",
|
||||
(matrix->len), (void *)(matrix->head));
|
||||
void DebugPrintMatrix(matrix_t *matrix) {
|
||||
printf("Grid ( len: %zu, head: %p ) { ", (matrix->len),
|
||||
(void *)(matrix->head));
|
||||
printf("data: [");
|
||||
for (size_t i = 0; i < matrix->len; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
for (size_t i = 0; i < matrix->len; i++) {
|
||||
if (i > 0) {
|
||||
printf(", ");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%" PRImDATA, *(matrix->head + i));
|
||||
|
@ -26,7 +22,7 @@ void DebugPrintMatrix(matrix_t *matrix)
|
|||
|
||||
// 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 ++) {
|
||||
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(", ");
|
||||
|
@ -36,8 +32,7 @@ void PrintMatrixRow(matrix_t *matrix, size_t row) {
|
|||
}
|
||||
|
||||
// Parameters for `increase_input_buffers`.
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
size_t capacity;
|
||||
data_t *head;
|
||||
} matrix_bufs_t;
|
||||
|
@ -46,12 +41,10 @@ typedef struct
|
|||
//
|
||||
// As reallocation will happen, the updated pointers and capacity are returned
|
||||
// in an updated parameters object.
|
||||
static matrix_bufs_t increase_input_buffers(matrix_bufs_t bufs)
|
||||
{
|
||||
static matrix_bufs_t increase_input_buffers(matrix_bufs_t bufs) {
|
||||
bufs.capacity *= 2;
|
||||
bufs.head = realloc(bufs.head, bufs.capacity * sizeof(data_t));
|
||||
if (bufs.head == NULL)
|
||||
{
|
||||
if (bufs.head == NULL) {
|
||||
printf(
|
||||
"Failed to reallocate bigger buffer for input data. Was trying to "
|
||||
"allocate %zu entries, aborting.",
|
||||
|
@ -62,64 +55,54 @@ 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)
|
||||
{
|
||||
static void compact_buffers(matrix_t *matrix) {
|
||||
matrix->head = realloc(matrix->head, matrix->len * sizeof(data_t));
|
||||
if ((matrix->head == NULL))
|
||||
{
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to reallocate matrix data buffers. Was trying to "
|
||||
"allocate for %zu data entries, aborting.",
|
||||
matrix->len);
|
||||
if ((matrix->head == NULL)) {
|
||||
fprintf(stderr,
|
||||
"Failed to reallocate matrix data buffers. Was trying to "
|
||||
"allocate for %zu data entries, aborting.",
|
||||
matrix->len);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Failed to parse this as an entry.
|
||||
fprintf(stderr, "Cannot parse %s as a numerical matrix entry, aborting.", str);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return value;
|
||||
data_t value;
|
||||
str[str_len] = 0; // Null-terminate the string.
|
||||
int result = sscanf(str, "%" SCNmDATA, &value);
|
||||
if (result == 0 || result == EOF) {
|
||||
// Failed to parse this as an entry.
|
||||
fprintf(stderr, "Cannot parse %s as a numerical matrix entry, aborting.",
|
||||
str);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Parse a `matrix_t` by reading from standard input.
|
||||
//
|
||||
// We expect whitespace separated (possibly signed) integer values.
|
||||
matrix_t ParseMatrix(size_t row_len)
|
||||
{
|
||||
size_t capacity = 32; // Initial value is arbitrary.
|
||||
size_t len = 0; // Number of entries stored.
|
||||
matrix_t ParseMatrix(size_t row_len) {
|
||||
size_t capacity = 32; // Initial value is arbitrary.
|
||||
size_t len = 0; // Number of entries stored.
|
||||
data_t *head = malloc(capacity * sizeof(data_t));
|
||||
|
||||
_Bool spaces = 1;
|
||||
char scanned;
|
||||
char scan_str[50];
|
||||
size_t scan_len = 0;
|
||||
while (scanf("%c", &scanned) != EOF)
|
||||
{
|
||||
if (isspace(scanned))
|
||||
{
|
||||
if (!spaces)
|
||||
{
|
||||
while (scanf("%c", &scanned) != EOF) {
|
||||
if (isspace(scanned)) {
|
||||
if (!spaces) {
|
||||
// Finished reading string.
|
||||
// Push the numerical entry into the matrix.
|
||||
data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
head[len-1] = value;
|
||||
head[len - 1] = value;
|
||||
}
|
||||
spaces = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// A little input sanitization.
|
||||
if (!(isdigit(scanned) || (scanned == '-')))
|
||||
{
|
||||
if (!(isdigit(scanned) || (scanned == '-'))) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Foreign character %c (%x) found when processing input, aborting.",
|
||||
|
@ -127,15 +110,13 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (spaces)
|
||||
{
|
||||
if (spaces) {
|
||||
// New string
|
||||
len++;
|
||||
scan_len = 0;
|
||||
|
||||
// Check if we need to resize the buffer.
|
||||
if (len > capacity)
|
||||
{
|
||||
if (len > capacity) {
|
||||
matrix_bufs_t bufs = {
|
||||
.capacity = capacity,
|
||||
.head = head,
|
||||
|
@ -151,24 +132,23 @@ matrix_t ParseMatrix(size_t row_len)
|
|||
scan_str[scan_len] = scanned;
|
||||
scan_len++;
|
||||
|
||||
if (scan_len == 50)
|
||||
{
|
||||
fprintf(stderr, "An entry in the matrix is too long (over 50 characters).");
|
||||
if (scan_len == 50) {
|
||||
fprintf(stderr,
|
||||
"An entry in the matrix is too long (over 50 characters).");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
} // End of scan loop
|
||||
|
||||
} // End of scan loop
|
||||
|
||||
// Write the last entry if necessary
|
||||
if (!spaces) {
|
||||
data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
head[len] = value;
|
||||
data_t value = as_matrix_entry(scan_str, scan_len);
|
||||
head[len] = value;
|
||||
}
|
||||
|
||||
// Input sanitization: confirm that the number of entries read is a multiple
|
||||
// of the number of entries in a row.
|
||||
if (!((len % row_len) == 0))
|
||||
{
|
||||
if (!((len % row_len) == 0)) {
|
||||
fprintf(stderr,
|
||||
"Number of entries is not consistent with provided row length. "
|
||||
"Got row length of %zu, and read %zu entries. Aborting.",
|
||||
|
|
|
@ -1,78 +1,91 @@
|
|||
#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;
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
permutation_generator_t generator = {
|
||||
.len = len,
|
||||
.permutation = permutation,
|
||||
.stack = stack,
|
||||
};
|
||||
permutation_generator_t PermutationNewGenerator(size_t len) {
|
||||
size_t *permutation = malloc(2 * len * sizeof(size_t));
|
||||
size_t *stack = permutation + len;
|
||||
|
||||
return generator;
|
||||
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;
|
||||
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);
|
||||
// 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;
|
||||
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 {
|
||||
stack[*stack_ptr] = 0;
|
||||
*stack_ptr += 1;
|
||||
if (*stack_ptr < len) {
|
||||
goto repeat;
|
||||
} else {
|
||||
*exhausted = true;
|
||||
}
|
||||
// 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);
|
||||
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.
|
||||
void PermutationFree(permutation_generator_t *permutation_generator) {
|
||||
free(permutation_generator->permutation);
|
||||
// No need to free permutation_generator->stack, since it's contiguous.
|
||||
}
|
||||
|
||||
void PrintPermutation(permutation_generator_t *permutation_generator) {
|
||||
printf("Permutation{");
|
||||
for (size_t i = 0; i < permutation_generator->len - 1; i++) {
|
||||
printf("%zu, ", permutation_generator->permutation[i]);
|
||||
}
|
||||
if (permutation_generator->len > 0) {
|
||||
printf("%zu}\n",
|
||||
permutation_generator->permutation[permutation_generator->len - 1]);
|
||||
} else {
|
||||
printf("}\n");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue