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:
parent
da3327ce7e
commit
6531273021
|
@ -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_
|
167
src/main.c
167
src/main.c
|
@ -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;
|
||||
|
||||
|
|
153
src/matrix.c
153
src/matrix.c
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue