Current section
Files
Jump to
Current section
Files
c_src/deps/crfsuite/lib/crf/src/crf1d_model.c
/*
* CRF1d model.
*
* Copyright (c) 2007-2010, Naoaki Okazaki
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the names of the authors nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* $Id$ */
#include "os.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cqdb.h>
#include <crfsuite.h>
#include "crf1d.h"
#define FILEMAGIC "lCRF"
#define MODELTYPE "FOMC"
#define VERSION_NUMBER (100)
#define CHUNK_LABELREF "LFRF"
#define CHUNK_ATTRREF "AFRF"
#define CHUNK_FEATURE "FEAT"
#define HEADER_SIZE 48
#define CHUNK_SIZE 12
#define FEATURE_SIZE 20
enum {
WSTATE_NONE,
WSTATE_LABELS,
WSTATE_ATTRS,
WSTATE_LABELREFS,
WSTATE_ATTRREFS,
WSTATE_FEATURES,
};
typedef struct {
uint8_t magic[4]; /* File magic. */
uint32_t size; /* File size. */
uint8_t type[4]; /* Model type */
uint32_t version; /* Version number. */
uint32_t num_features; /* Number of features. */
uint32_t num_labels; /* Number of labels. */
uint32_t num_attrs; /* Number of attributes. */
uint32_t off_features; /* Offset to features. */
uint32_t off_labels; /* Offset to label CQDB. */
uint32_t off_attrs; /* Offset to attribute CQDB. */
uint32_t off_labelrefs; /* Offset to label feature references. */
uint32_t off_attrrefs; /* Offset to attribute feature references. */
} header_t;
typedef struct {
uint8_t chunk[4]; /* Chunk id */
uint32_t size; /* Chunk size. */
uint32_t num; /* Number of items. */
uint32_t offsets[1]; /* Offsets. */
} featureref_header_t;
typedef struct {
uint8_t chunk[4]; /* Chunk id */
uint32_t size; /* Chunk size. */
uint32_t num; /* Number of items. */
} feature_header_t;
struct tag_crf1dm {
uint8_t* buffer_orig;
const uint8_t* buffer;
uint32_t size;
header_t* header;
cqdb_t* labels;
cqdb_t* attrs;
};
struct tag_crf1dmw {
FILE *fp;
int state;
header_t header;
cqdb_writer_t* dbw;
featureref_header_t* href;
feature_header_t* hfeat;
};
enum {
KT_GLOBAL = 'A',
KT_NUMATTRS,
KT_NUMLABELS,
KT_STR2LID,
KT_LID2STR,
KT_STR2AID,
KT_FEATURE,
};
static int write_uint8(FILE *fp, uint8_t value)
{
return fwrite(&value, sizeof(value), 1, fp) == 1 ? 0 : 1;
}
static int read_uint8(const uint8_t* buffer, uint8_t* value)
{
*value = *buffer;
return sizeof(*value);
}
static int write_uint32(FILE *fp, uint32_t value)
{
uint8_t buffer[4];
buffer[0] = (uint8_t)(value & 0xFF);
buffer[1] = (uint8_t)(value >> 8);
buffer[2] = (uint8_t)(value >> 16);
buffer[3] = (uint8_t)(value >> 24);
return fwrite(buffer, sizeof(uint8_t), 4, fp) == 4 ? 0 : 1;
}
static int read_uint32(const uint8_t* buffer, uint32_t* value)
{
*value = ((uint32_t)buffer[0]);
*value |= ((uint32_t)buffer[1] << 8);
*value |= ((uint32_t)buffer[2] << 16);
*value |= ((uint32_t)buffer[3] << 24);
return sizeof(*value);
}
static int write_uint8_array(FILE *fp, uint8_t *array, size_t n)
{
size_t i;
int ret = 0;
for (i = 0;i < n;++i) {
ret |= write_uint8(fp, array[i]);
}
return ret;
}
static int read_uint8_array(const uint8_t* buffer, uint8_t *array, size_t n)
{
size_t i;
int ret = 0;
for (i = 0;i < n;++i) {
int size = read_uint8(buffer, &array[i]);
buffer += size;
ret += size;
}
return ret;
}
static void write_float(FILE *fp, floatval_t value)
{
/*
We assume:
- sizeof(floatval_t) = sizeof(double) = sizeof(uint64_t)
- the byte order of floatval_t and uint64_t is the same
- ARM's mixed-endian is not supported
*/
uint64_t iv;
uint8_t buffer[8];
/* Copy the memory image of floatval_t value to uint64_t. */
memcpy(&iv, &value, sizeof(iv));
buffer[0] = (uint8_t)(iv & 0xFF);
buffer[1] = (uint8_t)(iv >> 8);
buffer[2] = (uint8_t)(iv >> 16);
buffer[3] = (uint8_t)(iv >> 24);
buffer[4] = (uint8_t)(iv >> 32);
buffer[5] = (uint8_t)(iv >> 40);
buffer[6] = (uint8_t)(iv >> 48);
buffer[7] = (uint8_t)(iv >> 56);
fwrite(buffer, sizeof(uint8_t), 8, fp);
}
static int read_float(const uint8_t* buffer, floatval_t* value)
{
uint64_t iv;
iv = ((uint64_t)buffer[0]);
iv |= ((uint64_t)buffer[1] << 8);
iv |= ((uint64_t)buffer[2] << 16);
iv |= ((uint64_t)buffer[3] << 24);
iv |= ((uint64_t)buffer[4] << 32);
iv |= ((uint64_t)buffer[5] << 40);
iv |= ((uint64_t)buffer[6] << 48);
iv |= ((uint64_t)buffer[7] << 56);
memcpy(value, &iv, sizeof(*value));
return sizeof(*value);
}
crf1dmw_t* crf1mmw(const char *filename)
{
header_t *header = NULL;
crf1dmw_t *writer = NULL;
/* Create a writer instance. */
writer = (crf1dmw_t*)calloc(1, sizeof(crf1dmw_t));
if (writer == NULL) {
goto error_exit;
}
/* Open the file for writing. */
writer->fp = fopen(filename, "wb");
if (writer->fp == NULL) {
goto error_exit;
}
/* Fill the members in the header. */
header = &writer->header;
memcpy(header->magic, FILEMAGIC, 4);
memcpy(header->type, MODELTYPE, 4);
header->version = VERSION_NUMBER;
/* Advance the file position to skip the file header. */
if (fseek(writer->fp, HEADER_SIZE, SEEK_CUR) != 0) {
goto error_exit;
}
return writer;
error_exit:
if (writer != NULL) {
if (writer->fp != NULL) {
fclose(writer->fp);
}
free(writer);
}
return NULL;
}
int crf1dmw_close(crf1dmw_t* writer)
{
FILE *fp = writer->fp;
header_t *header = &writer->header;
/* Store the file size. */
header->size = (uint32_t)ftell(fp);
/* Move the file position to the head. */
if (fseek(fp, 0, SEEK_SET) != 0) {
goto error_exit;
}
/* Write the file header. */
write_uint8_array(fp, header->magic, sizeof(header->magic));
write_uint32(fp, header->size);
write_uint8_array(fp, header->type, sizeof(header->type));
write_uint32(fp, header->version);
write_uint32(fp, header->num_features);
write_uint32(fp, header->num_labels);
write_uint32(fp, header->num_attrs);
write_uint32(fp, header->off_features);
write_uint32(fp, header->off_labels);
write_uint32(fp, header->off_attrs);
write_uint32(fp, header->off_labelrefs);
write_uint32(fp, header->off_attrrefs);
/* Check for any error occurrence. */
if (ferror(fp)) {
goto error_exit;
}
/* Close the writer. */
fclose(fp);
free(writer);
return 0;
error_exit:
if (writer != NULL) {
if (writer->fp != NULL) {
fclose(writer->fp);
}
free(writer);
}
return 1;
}
int crf1dmw_open_labels(crf1dmw_t* writer, int num_labels)
{
/* Check if we aren't writing anything at this moment. */
if (writer->state != WSTATE_NONE) {
return 1;
}
/* Store the current offset. */
writer->header.off_labels = (uint32_t)ftell(writer->fp);
/* Open a CQDB chunk for writing. */
writer->dbw = cqdb_writer(writer->fp, 0);
if (writer->dbw == NULL) {
writer->header.off_labels = 0;
return 1;
}
writer->state = WSTATE_LABELS;
writer->header.num_labels = num_labels;
return 0;
}
int crf1dmw_close_labels(crf1dmw_t* writer)
{
/* Make sure that we are writing labels. */
if (writer->state != WSTATE_LABELS) {
return 1;
}
/* Close the CQDB chunk. */
if (cqdb_writer_close(writer->dbw)) {
return 1;
}
writer->dbw = NULL;
writer->state = WSTATE_NONE;
return 0;
}
int crf1dmw_put_label(crf1dmw_t* writer, int lid, const char *value)
{
/* Make sure that we are writing labels. */
if (writer->state != WSTATE_LABELS) {
return 1;
}
/* Put the label. */
if (cqdb_writer_put(writer->dbw, value, lid)) {
return 1;
}
return 0;
}
int crf1dmw_open_attrs(crf1dmw_t* writer, int num_attrs)
{
/* Check if we aren't writing anything at this moment. */
if (writer->state != WSTATE_NONE) {
return 1;
}
/* Store the current offset. */
writer->header.off_attrs = (uint32_t)ftell(writer->fp);
/* Open a CQDB chunk for writing. */
writer->dbw = cqdb_writer(writer->fp, 0);
if (writer->dbw == NULL) {
writer->header.off_attrs = 0;
return 1;
}
writer->state = WSTATE_ATTRS;
writer->header.num_attrs = num_attrs;
return 0;
}
int crf1dmw_close_attrs(crf1dmw_t* writer)
{
/* Make sure that we are writing attributes. */
if (writer->state != WSTATE_ATTRS) {
return 1;
}
/* Close the CQDB chunk. */
if (cqdb_writer_close(writer->dbw)) {
return 1;
}
writer->dbw = NULL;
writer->state = WSTATE_NONE;
return 0;
}
int crf1dmw_put_attr(crf1dmw_t* writer, int aid, const char *value)
{
/* Make sure that we are writing labels. */
if (writer->state != WSTATE_ATTRS) {
return 1;
}
/* Put the attribute. */
if (cqdb_writer_put(writer->dbw, value, aid)) {
return 1;
}
return 0;
}
int crf1dmw_open_labelrefs(crf1dmw_t* writer, int num_labels)
{
uint32_t offset;
FILE *fp = writer->fp;
featureref_header_t* href = NULL;
size_t size = CHUNK_SIZE + sizeof(uint32_t) * num_labels;
/* Check if we aren't writing anything at this moment. */
if (writer->state != WSTATE_NONE) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Allocate a feature reference array. */
href = (featureref_header_t*)calloc(size, 1);
if (href == NULL) {
return CRFSUITEERR_OUTOFMEMORY;
}
/* Align the offset to a DWORD boundary. */
offset = (uint32_t)ftell(fp);
while (offset % 4 != 0) {
uint8_t c = 0;
fwrite(&c, sizeof(uint8_t), 1, fp);
++offset;
}
/* Store the current offset position to the file header. */
writer->header.off_labelrefs = offset;
fseek(fp, size, SEEK_CUR);
/* Fill members in the feature reference header. */
memcpy(href->chunk, CHUNK_LABELREF, 4);
href->size = 0;
href->num = num_labels;
writer->href = href;
writer->state = WSTATE_LABELREFS;
return 0;
}
int crf1dmw_close_labelrefs(crf1dmw_t* writer)
{
uint32_t i;
FILE *fp = writer->fp;
featureref_header_t* href = writer->href;
uint32_t begin = writer->header.off_labelrefs, end = 0;
/* Make sure that we are writing label feature references. */
if (writer->state != WSTATE_LABELREFS) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Store the current offset position. */
end = (uint32_t)ftell(fp);
/* Compute the size of this chunk. */
href->size = (end - begin);
/* Write the chunk header and offset array. */
fseek(fp, begin, SEEK_SET);
write_uint8_array(fp, href->chunk, 4);
write_uint32(fp, href->size);
write_uint32(fp, href->num);
for (i = 0;i < href->num;++i) {
write_uint32(fp, href->offsets[i]);
}
/* Move the file pointer to the tail. */
fseek(fp, end, SEEK_SET);
/* Uninitialize. */
free(href);
writer->href = NULL;
writer->state = WSTATE_NONE;
return 0;
}
int crf1dmw_put_labelref(crf1dmw_t* writer, int lid, const feature_refs_t* ref, int *map)
{
int i, fid;
uint32_t n = 0, offset = 0;
FILE *fp = writer->fp;
featureref_header_t* href = writer->href;
/* Make sure that we are writing label feature references. */
if (writer->state != WSTATE_LABELREFS) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Store the current offset to the offset array. */
href->offsets[lid] = ftell(fp);
/* Count the number of references to active features. */
for (i = 0;i < ref->num_features;++i) {
if (0 <= map[ref->fids[i]]) ++n;
}
/* Write the feature reference. */
write_uint32(fp, (uint32_t)n);
for (i = 0;i < ref->num_features;++i) {
fid = map[ref->fids[i]];
if (0 <= fid) write_uint32(fp, (uint32_t)fid);
}
return 0;
}
int crf1dmw_open_attrrefs(crf1dmw_t* writer, int num_attrs)
{
uint32_t offset;
FILE *fp = writer->fp;
featureref_header_t* href = NULL;
size_t size = CHUNK_SIZE + sizeof(uint32_t) * num_attrs;
/* Check if we aren't writing anything at this moment. */
if (writer->state != WSTATE_NONE) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Allocate a feature reference array. */
href = (featureref_header_t*)calloc(size, 1);
if (href == NULL) {
return CRFSUITEERR_OUTOFMEMORY;
}
/* Align the offset to a DWORD boundary. */
offset = (uint32_t)ftell(fp);
while (offset % 4 != 0) {
uint8_t c = 0;
fwrite(&c, sizeof(uint8_t), 1, fp);
++offset;
}
/* Store the current offset position to the file header. */
writer->header.off_attrrefs = offset;
fseek(fp, size, SEEK_CUR);
/* Fill members in the feature reference header. */
memcpy(href->chunk, CHUNK_ATTRREF, 4);
href->size = 0;
href->num = num_attrs;
writer->href = href;
writer->state = WSTATE_ATTRREFS;
return 0;
}
int crf1dmw_close_attrrefs(crf1dmw_t* writer)
{
uint32_t i;
FILE *fp = writer->fp;
featureref_header_t* href = writer->href;
uint32_t begin = writer->header.off_attrrefs, end = 0;
/* Make sure that we are writing attribute feature references. */
if (writer->state != WSTATE_ATTRREFS) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Store the current offset position. */
end = (uint32_t)ftell(fp);
/* Compute the size of this chunk. */
href->size = (end - begin);
/* Write the chunk header and offset array. */
fseek(fp, begin, SEEK_SET);
write_uint8_array(fp, href->chunk, 4);
write_uint32(fp, href->size);
write_uint32(fp, href->num);
for (i = 0;i < href->num;++i) {
write_uint32(fp, href->offsets[i]);
}
/* Move the file pointer to the tail. */
fseek(fp, end, SEEK_SET);
/* Uninitialize. */
free(href);
writer->href = NULL;
writer->state = WSTATE_NONE;
return 0;
}
int crf1dmw_put_attrref(crf1dmw_t* writer, int aid, const feature_refs_t* ref, int *map)
{
int i, fid;
uint32_t n = 0, offset = 0;
FILE *fp = writer->fp;
featureref_header_t* href = writer->href;
/* Make sure that we are writing attribute feature references. */
if (writer->state != WSTATE_ATTRREFS) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Store the current offset to the offset array. */
href->offsets[aid] = ftell(fp);
/* Count the number of references to active features. */
for (i = 0;i < ref->num_features;++i) {
if (0 <= map[ref->fids[i]]) ++n;
}
/* Write the feature reference. */
write_uint32(fp, (uint32_t)n);
for (i = 0;i < ref->num_features;++i) {
fid = map[ref->fids[i]];
if (0 <= fid) write_uint32(fp, (uint32_t)fid);
}
return 0;
}
int crf1dmw_open_features(crf1dmw_t* writer)
{
FILE *fp = writer->fp;
feature_header_t* hfeat = NULL;
/* Check if we aren't writing anything at this moment. */
if (writer->state != WSTATE_NONE) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Allocate a feature chunk header. */
hfeat = (feature_header_t*)calloc(sizeof(feature_header_t), 1);
if (hfeat == NULL) {
return CRFSUITEERR_OUTOFMEMORY;
}
writer->header.off_features = (uint32_t)ftell(fp);
fseek(fp, CHUNK_SIZE, SEEK_CUR);
memcpy(hfeat->chunk, CHUNK_FEATURE, 4);
writer->hfeat = hfeat;
writer->state = WSTATE_FEATURES;
return 0;
}
int crf1dmw_close_features(crf1dmw_t* writer)
{
FILE *fp = writer->fp;
feature_header_t* hfeat = writer->hfeat;
uint32_t begin = writer->header.off_features, end = 0;
/* Make sure that we are writing attribute feature references. */
if (writer->state != WSTATE_FEATURES) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* Store the current offset position. */
end = (uint32_t)ftell(fp);
/* Compute the size of this chunk. */
hfeat->size = (end - begin);
/* Write the chunk header and offset array. */
fseek(fp, begin, SEEK_SET);
write_uint8_array(fp, hfeat->chunk, 4);
write_uint32(fp, hfeat->size);
write_uint32(fp, hfeat->num);
/* Move the file pointer to the tail. */
fseek(fp, end, SEEK_SET);
/* Uninitialize. */
free(hfeat);
writer->hfeat = NULL;
writer->state = WSTATE_NONE;
return 0;
}
int crf1dmw_put_feature(crf1dmw_t* writer, int fid, const crf1dm_feature_t* f)
{
FILE *fp = writer->fp;
feature_header_t* hfeat = writer->hfeat;
/* Make sure that we are writing attribute feature references. */
if (writer->state != WSTATE_FEATURES) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
/* We must put features #0, #1, ..., #(K-1) in this order. */
if (fid != hfeat->num) {
return CRFSUITEERR_INTERNAL_LOGIC;
}
write_uint32(fp, f->type);
write_uint32(fp, f->src);
write_uint32(fp, f->dst);
write_float(fp, f->weight);
++hfeat->num;
return 0;
}
static crf1dm_t* crf1dm_new_impl(uint8_t* buffer_orig, const uint8_t* buffer, uint32_t size)
{
const uint8_t* p = NULL;
crf1dm_t *model = NULL;
header_t *header = NULL;
model = (crf1dm_t*)calloc(1, sizeof(crf1dm_t));
if (model == NULL) {
goto error_exit;
}
model->buffer_orig = buffer_orig;
model->buffer = buffer;
model->size = size;
if (model->size <= sizeof(header_t)) {
goto error_exit;
}
header = (header_t*)calloc(1, sizeof(header_t));
if (header == NULL) {
goto error_exit;
}
/* Read the file header. */
p = model->buffer;
p += read_uint8_array(p, header->magic, sizeof(header->magic));
p += read_uint32(p, &header->size);
p += read_uint8_array(p, header->type, sizeof(header->type));
p += read_uint32(p, &header->version);
p += read_uint32(p, &header->num_features);
p += read_uint32(p, &header->num_labels);
p += read_uint32(p, &header->num_attrs);
p += read_uint32(p, &header->off_features);
p += read_uint32(p, &header->off_labels);
p += read_uint32(p, &header->off_attrs);
p += read_uint32(p, &header->off_labelrefs);
p += read_uint32(p, &header->off_attrrefs);
model->header = header;
model->labels = cqdb_reader(
model->buffer + header->off_labels,
model->size - header->off_labels
);
model->attrs = cqdb_reader(
model->buffer + header->off_attrs,
model->size - header->off_attrs
);
return model;
error_exit:
free(header);
free(model);
free(buffer_orig);
return NULL;
}
crf1dm_t* crf1dm_new(const char *filename)
{
FILE *fp = NULL;
uint32_t size = 0;
uint8_t* buffer_orig = NULL;
uint8_t* buffer = NULL;
fp = fopen(filename, "rb");
if (fp == NULL) {
goto error_exit;
}
fseek(fp, 0, SEEK_END);
size = (uint32_t)ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = buffer_orig = (uint8_t*)malloc(size + 16);
if (buffer_orig == NULL) {
goto error_exit;
}
/* Align the buffer to 16 bytes. */
while ((uintptr_t)buffer % 16 != 0) {
++buffer;
}
if (fread(buffer, 1, size, fp) != size) {
goto error_exit;
}
fclose(fp);
return crf1dm_new_impl(buffer_orig, buffer, size);
error_exit:
free(buffer_orig);
if (fp != NULL) {
fclose(fp);
}
return NULL;
}
crf1dm_t* crf1dm_new_from_memory(const void *data, size_t size)
{
return crf1dm_new_impl(NULL, data, size);
}
void crf1dm_close(crf1dm_t* model)
{
if (model->labels != NULL) {
cqdb_delete(model->labels);
}
if (model->attrs != NULL) {
cqdb_delete(model->attrs);
}
if (model->header != NULL) {
free(model->header);
model->header = NULL;
}
if (model->buffer_orig != NULL) {
free(model->buffer_orig);
model->buffer_orig = NULL;
}
model->buffer = NULL;
free(model);
}
int crf1dm_get_num_attrs(crf1dm_t* model)
{
return model->header->num_attrs;
}
int crf1dm_get_num_labels(crf1dm_t* model)
{
return model->header->num_labels;
}
const char *crf1dm_to_label(crf1dm_t* model, int lid)
{
if (model->labels != NULL) {
return cqdb_to_string(model->labels, lid);
} else {
return NULL;
}
}
int crf1dm_to_lid(crf1dm_t* model, const char *value)
{
if (model->labels != NULL) {
return cqdb_to_id(model->labels, value);
} else {
return -1;
}
}
int crf1dm_to_aid(crf1dm_t* model, const char *value)
{
if (model->attrs != NULL) {
return cqdb_to_id(model->attrs, value);
} else {
return -1;
}
}
const char *crf1dm_to_attr(crf1dm_t* model, int aid)
{
if (model->attrs != NULL) {
return cqdb_to_string(model->attrs, aid);
} else {
return NULL;
}
}
int crf1dm_get_labelref(crf1dm_t* model, int lid, feature_refs_t* ref)
{
const uint8_t *p = model->buffer;
uint32_t offset;
uint32_t num_features;
p += model->header->off_labelrefs;
p += CHUNK_SIZE;
p += sizeof(uint32_t) * lid;
read_uint32(p, &offset);
p = model->buffer + offset;
p += read_uint32(p, &num_features);
ref->num_features = num_features;
ref->fids = (int*)p;
return 0;
}
int crf1dm_get_attrref(crf1dm_t* model, int aid, feature_refs_t* ref)
{
const uint8_t *p = model->buffer;
uint32_t offset;
uint32_t num_features;
p += model->header->off_attrrefs;
p += CHUNK_SIZE;
p += sizeof(uint32_t) * aid;
read_uint32(p, &offset);
p = model->buffer + offset;
p += read_uint32(p, &num_features);
ref->num_features = num_features;
ref->fids = (int*)p;
return 0;
}
int crf1dm_get_featureid(feature_refs_t* ref, int i)
{
uint32_t fid;
uint8_t* p = (uint8_t*)ref->fids;
p += sizeof(uint32_t) * i;
read_uint32(p, &fid);
return (int)fid;
}
int crf1dm_get_feature(crf1dm_t* model, int fid, crf1dm_feature_t* f)
{
const uint8_t *p = NULL;
uint32_t val = 0;
uint32_t offset = model->header->off_features + CHUNK_SIZE;
offset += FEATURE_SIZE * fid;
p = model->buffer + offset;
p += read_uint32(p, &val);
f->type = val;
p += read_uint32(p, &val);
f->src = val;
p += read_uint32(p, &val);
f->dst = val;
p += read_float(p, &f->weight);
return 0;
}
void crf1dm_dump(crf1dm_t* crf1dm, FILE *fp)
{
int j;
uint32_t i;
feature_refs_t refs;
const header_t* hfile = crf1dm->header;
/* Dump the file header. */
fprintf(fp, "FILEHEADER = {\n");
fprintf(fp, " magic: %c%c%c%c\n",
hfile->magic[0], hfile->magic[1], hfile->magic[2], hfile->magic[3]);
fprintf(fp, " size: %" PRIu32 "\n", hfile->size);
fprintf(fp, " type: %c%c%c%c\n",
hfile->type[0], hfile->type[1], hfile->type[2], hfile->type[3]);
fprintf(fp, " version: %" PRIu32 "\n", hfile->version);
fprintf(fp, " num_features: %" PRIu32 "\n", hfile->num_features);
fprintf(fp, " num_labels: %" PRIu32 "\n", hfile->num_labels);
fprintf(fp, " num_attrs: %" PRIu32 "\n", hfile->num_attrs);
fprintf(fp, " off_features: 0x%" PRIX32 "\n", hfile->off_features);
fprintf(fp, " off_labels: 0x%" PRIX32 "\n", hfile->off_labels);
fprintf(fp, " off_attrs: 0x%" PRIX32 "\n", hfile->off_attrs);
fprintf(fp, " off_labelrefs: 0x%" PRIX32 "\n", hfile->off_labelrefs);
fprintf(fp, " off_attrrefs: 0x%" PRIX32 "\n", hfile->off_attrrefs);
fprintf(fp, "}\n");
fprintf(fp, "\n");
/* Dump the labels. */
fprintf(fp, "LABELS = {\n");
for (i = 0;i < hfile->num_labels;++i) {
const char *str = crf1dm_to_label(crf1dm, i);
#if 0
int check = crf1dm_to_lid(crf1dm, str);
if (i != check) {
fprintf(fp, "WARNING: inconsistent label CQDB\n");
}
#endif
fprintf(fp, " %5" PRIu32 ": %s\n", i, str);
}
fprintf(fp, "}\n");
fprintf(fp, "\n");
/* Dump the attributes. */
fprintf(fp, "ATTRIBUTES = {\n");
for (i = 0;i < hfile->num_attrs;++i) {
const char *str = crf1dm_to_attr(crf1dm, i);
#if 0
int check = crf1dm_to_aid(crf1dm, str);
if (i != check) {
fprintf(fp, "WARNING: inconsistent attribute CQDB\n");
}
#endif
fprintf(fp, " %5" PRIu32 ": %s\n", i, str);
}
fprintf(fp, "}\n");
fprintf(fp, "\n");
/* Dump the transition features. */
fprintf(fp, "TRANSITIONS = {\n");
for (i = 0;i < hfile->num_labels;++i) {
crf1dm_get_labelref(crf1dm, i, &refs);
for (j = 0;j < refs.num_features;++j) {
crf1dm_feature_t f;
int fid = crf1dm_get_featureid(&refs, j);
const char *from = NULL, *to = NULL;
crf1dm_get_feature(crf1dm, fid, &f);
from = crf1dm_to_label(crf1dm, f.src);
to = crf1dm_to_label(crf1dm, f.dst);
fprintf(fp, " (%d) %s --> %s: %f\n", f.type, from, to, f.weight);
}
}
fprintf(fp, "}\n");
fprintf(fp, "\n");
/* Dump the transition features. */
fprintf(fp, "STATE_FEATURES = {\n");
for (i = 0;i < hfile->num_attrs;++i) {
crf1dm_get_attrref(crf1dm, i, &refs);
for (j = 0;j < refs.num_features;++j) {
crf1dm_feature_t f;
int fid = crf1dm_get_featureid(&refs, j);
const char *attr = NULL, *to = NULL;
crf1dm_get_feature(crf1dm, fid, &f);
#if 0
if (f.src != i) {
fprintf(fp, "WARNING: an inconsistent attribute reference.\n");
}
#endif
attr = crf1dm_to_attr(crf1dm, f.src);
to = crf1dm_to_label(crf1dm, f.dst);
fprintf(fp, " (%d) %s --> %s: %f\n", f.type, attr, to, f.weight);
}
}
fprintf(fp, "}\n");
fprintf(fp, "\n");
}