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.
This commit is contained in:
Miguel M 2023-04-29 18:30:56 +01:00
parent da3327ce7e
commit 6531273021
3 changed files with 165 additions and 165 deletions

View File

@ -21,4 +21,14 @@ 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
// l is an m-sized column vector. This input is given in standard input as
// whitespace separated entries.
//
// Arguments:
// row_len The number of entries in one row.
matrix_t ParseMatrix(size_t row_len);
#endif // ACED_INCLUDES_MATRIX_H_

View File

@ -13,170 +13,6 @@ static void ReadArguments(char *from, size_t *restrict into, const char *varname
}
}
static matrix_t ReadInput(size_t a_out, size_t b_out, size_t a_in, size_t 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) +
1; // +1 accounts for the L column.
size_t row_size = a_out * a_in * b_out * b_in + 1;
size_t row_cap = 16; // Arbitrary.
size_t row_count = 0;
matrix_data_t *data = malloc(row_size * row_cap * sizeof(matrix_data_t));
if (data == NULL)
{
fprintf(stderr, "Failed to allocate initial space for matrix entries in P form. "
"Was trying to allocate %zu bytes. Aborting.",
row_count * row_cap * sizeof(matrix_data_t));
exit(EXIT_FAILURE);
}
// Read rows from input, which arrive in CG notation.
matrix_data_t *row_buf = malloc(cg_row_size * sizeof(matrix_data_t));
if (row_buf == NULL)
{
fprintf(stderr, "Failed to allocate space for temporary input buffer. "
"Was trying to allocate %zu bytes. Aborting.",
cg_row_size * sizeof(matrix_data_t));
exit(EXIT_FAILURE);
}
while (1)
{
// Read the first entry to check if there's more data incoming.
matrix_data_t entry;
int scan_result = scanf("%" SCNmDATA, &entry);
if (scan_result == EOF)
{
break; // Done reading data.
}
if (scan_result != 1)
{
fprintf(stderr, "Failed to read row %zu at entry 1. Aborting", row_count);
exit(EXIT_FAILURE);
}
row_buf[0] = entry;
// Read the remaining entries.
for (size_t i = 1; i < cg_row_size; i++)
{
scan_result = scanf("%" SCNmDATA, &entry);
if (scan_result != 1)
{
fprintf(stderr, "Failed to read row %zu at entry %zu. Aborting", row_count, i + 1);
exit(EXIT_FAILURE);
}
row_buf[i] = entry;
}
row_count++;
// Increase the data buffer if necessary.
if (row_count > row_cap)
{
row_cap <<= 1;
data = realloc(data, row_count * row_cap * sizeof(matrix_data_t));
if (data == NULL)
{
fprintf(stderr, "Failed to reallocate space for matrix entries in P form. "
"Was trying to allocate %zu bytes. Aborting.",
row_count * row_cap * sizeof(matrix_data_t));
exit(EXIT_FAILURE);
}
}
// Convert the buffered CG notation to P notation and copy.
// The order for the symbolic entries of the probabilities vector is known, and
// follows the pattern (for notation P[A outputs, B outputs | A inputs, B inputs]):
//
// P[0,0|0,0] ... P[<A outputs>-2,<B outputs>-2|<A inputs>-1,<B outputs>-1],
// P_A[0|0] ... P_A[<A outputs>-2|<A inputs>-1]
// P_B[0|0] ... P_B[<B outputs>-2|<B inputs>-1]
//
// For the elisions, the indexing order is B's outputs varying first, then B's
// inputs, then A's outputs, then A's inputs. For the partials, we consider
// (following the same reasoning) that the outputs vary "faster" than the inputs.
matrix_data_t *row = data + (row_count - 1) * row_size;
// Copy L
row[row_size - 1] = row_buf[cg_row_size - 1];
// Copy the joint probabilities.
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 - 1; 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 - 1; b_out_i++)
{
size_t cg_index = b_out_i + (b_out - 1) * (b_in_i + b_in * (a_out_i + (a_out - 1) * a_in_i));
size_t index = b_out_i + b_out * (b_in_i + b_in * (a_out_i + a_out * a_in_i));
row[index] = row_buf[cg_index];
}
}
}
}
// Account for the marginal probabilities given.
// The convention will be that, where ambiguous, i.e., in the input of the
// other party, we will take it to be 0.
// A's marginals:
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 - 1; a_out_i++)
{
size_t cg_index = (a_out - 1) * (b_out - 1) * a_in * b_in + (a_out - 1) * a_in_i + a_out_i;
matrix_data_t a_marginal = row_buf[cg_index];
for (size_t b_out_i = 0; b_out_i < b_out; b_out_i++)
{
size_t index = b_out_i + b_out * (0 + b_in * (a_out_i + a_out * a_in_i));
row[index] += a_marginal;
}
}
}
// B's marginals:
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 - 1; b_out_i++)
{
size_t cg_index = (a_out - 1) * (b_out - 1) * a_in * b_in + (a_out - 1) * a_in + (b_out - 1) * b_in_i + b_out_i;
matrix_data_t b_marginal = row_buf[cg_index];
for (size_t a_in_i = 0; a_in_i < a_out; a_in_i++)
{
size_t index = b_out_i + b_out * (b_in_i + b_in * (0 + a_out * a_in_i));
row[index] += b_marginal;
}
}
}
}
// Done reading input.
free(row_buf);
// Compact the memory representation of the P matrix.
data = realloc(data, row_size * row_count * sizeof(matrix_data_t));
if (data == NULL)
{
fprintf(stderr, "Failed to compact the P matrix data buffer. Aborting.");
exit(EXIT_FAILURE);
}
matrix_t matrix = {
.row_len = row_size,
.head = data,
.len = (row_count * row_size),
};
return matrix;
}
int main(int argc, char *argv[])
{
if (argc < 5)
@ -191,7 +27,8 @@ int main(int argc, char *argv[])
ReadArguments(argv[3], &a_in, "A inputs");
ReadArguments(argv[4], &b_in, "B inputs");
matrix_t matrix = ReadInput(a_out, b_out, a_in, b_in);
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;

View File

@ -34,3 +34,156 @@ void PrintMatrixRow(matrix_t *matrix, size_t row) {
}
printf("\n");
}
// Parameters for `increase_input_buffers`.
typedef struct
{
size_t capacity;
data_t *head;
} matrix_bufs_t;
// Increases the data buffers used in `parse_input`.
//
// 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)
{
bufs.capacity *= 2;
bufs.head = realloc(bufs.head, bufs.capacity * sizeof(data_t));
if (bufs.head == NULL)
{
printf(
"Failed to reallocate bigger buffer for input data. Was trying to "
"allocate %zu entries, aborting.",
bufs.capacity);
exit(EXIT_FAILURE);
}
return 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(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);
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;
}
// 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.
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)
{
// Finished reading string.
// Push the numerical entry into the matrix.
data_t value = as_matrix_entry(scan_str, scan_len);
head[len-1] = value;
}
spaces = 1;
}
else
{
// A little input sanitization.
if (!(isdigit(scanned) || (scanned == '-')))
{
fprintf(
stderr,
"Foreign character %c (%x) found when processing input, aborting.",
scanned, scanned);
exit(EXIT_FAILURE);
}
if (spaces)
{
// New string
len++;
scan_len = 0;
// Check if we need to resize the buffer.
if (len > capacity)
{
matrix_bufs_t bufs = {
.capacity = capacity,
.head = head,
};
bufs = increase_input_buffers(bufs);
capacity = bufs.capacity;
head = bufs.head;
}
}
spaces = 0;
// Save the character to the entry string
scan_str[scan_len] = scanned;
scan_len++;
if (scan_len == 50)
{
fprintf(stderr, "An entry in the matrix is too long (over 50 characters).");
exit(EXIT_FAILURE);
}
}
} // 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;
}
// 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))
{
fprintf(stderr,
"Number of entries is not consistent with provided row length. "
"Got row length of %zu, and read %zu entries. Aborting.",
row_len, len);
// No need to free the buffers.
exit(EXIT_FAILURE);
}
matrix_t matrix = {
.row_len = row_len,
.head = head,
.len = len,
};
compact_buffers(&matrix);
return matrix;
}