Compare commits

...

4 Commits

Author SHA1 Message Date
Miguel M 94c1aa1ae8 Added comparison code; not working, but a good skeleton 2023-05-01 15:26:36 +01:00
Miguel M 678d1e1008 cg-p conversion accounts for permutations 2023-05-01 14:49:36 +01:00
Miguel M 4b1db5cec0 checkpoint commit 2023-05-01 14:38:56 +01:00
Miguel M bba8aa9e17 Formatting to match Google style 2023-04-30 20:21:12 +01:00
7 changed files with 320 additions and 184 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.",

View File

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