/*************************************************************************/
/* Copyright (c) 2008, 2009, 2014 Linas Vepstas */
/* All rights reserved */
/* */
/* Use of the link grammar parsing system is subject to the terms of the */
/* license set forth in the LICENSE file included with this software. */
/* This license allows free redistribution and use in source and binary */
/* forms, with or without modification, subject to certain conditions. */
/* */
/*************************************************************************/
/*
* lisjuncts.c
*
* Miscellaneous utilities for returning the list of disjuncts that
* were actually used in a given parse of a sentence.
*/
#include <stdlib.h>
#include <string.h>
#include "api-structures.h"
#include "connectors.h"
#include "disjunct-utils.h"
#include "linkage.h"
#include "lisjuncts.h"
#include "string-set.h"
#ifdef DEBUG_lisjuncts
#include "print/print-util.h"
static void assert_same_disjunct(Linkage, WordIdx, const char *);
#endif /* DEBUG_lisjuncts */
/**
* lg_compute_disjunct_strings -- Given sentence, compute disjuncts.
*
* This routine will compute the string representation of the disjunct
* used for each word in parsing the given sentence.
*
* The connectors are extracted from link_array (and not chosen_disjuncts)
* so the lexical links remain hidden when HIDE_MORPHO is true (see
* compute_chosen_disjuncts()).
*
* In order that multi-connectors will not be extracted several times
* for each disjunct (if they connect to multiple words) their tracon_id
* is checked for duplication.
*/
void lg_compute_disjunct_strings(Linkage lkg)
{
char djstr[MAX_LINK_NAME_LENGTH*20]; /* no word will have more than 20 links */
size_t nwords = lkg->num_words;
if (lkg->disjunct_list_str) return;
lkg->disjunct_list_str = malloc(nwords * sizeof(char *));
for (WordIdx w = 0; w < nwords; w++)
{
size_t len = 0;
for (int dir = 0; dir < 2; dir++)
{
int last_multi_tracon_id = 0; /* last multi-connector */
for (LinkIdx i = lkg->num_links-1; i != (WordIdx)-1; i--)
{
Link *lnk = &lkg->link_array[i];
Connector *c;
if (0 == dir)
{
if (lnk->rw != w) continue;
c = lnk->rc;
}
else
{
if (lnk->lw != w) continue;
c = lnk->lc;
}
if (c->multi)
{
if (last_multi_tracon_id == c->tracon_id) continue; /* already included */
last_multi_tracon_id = c->tracon_id;
djstr[len++] = '@';
}
len += lg_strlcpy(djstr+len, connector_string(c), sizeof(djstr)-len);
if (len >= sizeof(djstr) - 3)
{
len = sizeof(djstr) - 1;
break;
}
djstr[len++] = (dir == 0) ? '-' : '+';
djstr[len++] = ' ';
}
}
if ((len > 0) && (djstr[len-1] == ' ')) len--;
djstr[len++] = '\0';
#ifdef DEBUG_lisjuncts
assert_same_disjunct(lkg, w, djstr);
#endif /* DEBUG_lisjuncts */
lkg->disjunct_list_str[w] = string_set_add(djstr, lkg->sent->string_set);
}
}
void lg_free_disjunct_strings(Linkage lkg)
{
free(lkg->disjunct_list_str);
}
#ifdef DEBUG_lisjuncts
/* Cannot be used when morphology is not suppressed and lexical links exist. */
static void assert_same_disjunct(Linkage lkg, WordIdx w, const char *djstr)
{
char *cs;
if (lkg->chosen_disjuncts[w])
{
cs = print_one_disjunct(lkg->chosen_disjuncts[w]);
char *cs_lastchar = &cs[strlen(cs)-1];
if (*cs_lastchar == ' ') *cs_lastchar = '\0';
}
else
cs = (char *)"";
assert(strcmp(cs, djstr) == 0,
"Word %zu: Inconsistent disjunct string %s (link_array %s)",
w, cs, djstr);
if (lkg->chosen_disjuncts[w])
free(cs);
}
#endif /* DEBUG_lisjuncts */