#include "data.h" #include "printer.h" #include "parser.h" #include //#define DEBUG_PARSER //#define DEBUG_EXPRS PgfAbstractParser::PgfAbstractParser(ref concr) { this->concr = concr; this->current_state = NULL; this->last_fid = concr->last_fid; } void PgfAbstractParser::get_info(CCat *ccat, ref *prule, size_t **pvalues) { if (ccat->epsilon == 0) { Production *prod = ccat->prods[0]; *prule = prod->rule; *pvalues = &prod->vars[0]; } else { ref pitem = ccat->epsilon->items[0]; *prule = pitem->rule; *pvalues = &pitem->vars[0]; } } PgfAbstractParser::CCat *PgfAbstractParser::get_epsilon_ccat(PgfText *name, PgfMetaId fid) { if (fid == 0) return NULL; CCat *&ccat = epsilons[fid]; if (ccat == NULL) { ref arg = epsilontable_get(concr->epsilontable, name, fid); ccat = new CCat; ccat->fid = arg->fid; ccat->epsilon = arg; ccat->cont = NULL; ccat->state = NULL; ccat->lin_idx = arg->lin_idx; ccat->value = arg->value; ccat->covered = true; ccat->viterbi_prob = arg->viterbi_prob; } return ccat; } PgfAbstractParser::CCat::~CCat() { for (Production *prod : prods) { delete prod; } for (ExprState *estate : pending) { delete estate; } } PgfAbstractParser::Cont::~Cont() { for (auto it1 : suspended) { for (auto it2 : it1.second) { for (Item *item : it2.second) { delete item; } } } } PgfAbstractParser::~PgfAbstractParser() { State *state = current_state; while (state != NULL) { for (auto it1 : state->completed) { /* for (auto it2 : it1) { for (auto it3 : it2) { delete it3; } }*/ } for (auto it : state->conts1) { delete it.second; } for (auto it : state->conts2) { delete it.second; } State *next = state->next; delete state; state = next; } } void PgfAbstractParser::process(Item *item, State *state) { #ifdef DEBUG_PARSER print_item(item,state); #endif if (item->dot < item->syms.size()) { symbol(item,state,item->syms[item->dot]); } else if (item->pre_alt > 0) { item->dot = item->pre_dot+1; item->pre_alt = 0; item->pre_dot = 0; item->syms = item->rule->syms.as_vector(); process(item,state); } else { complete(item,state); } } PGF_INTERNAL_DECL int text_symbol_cmp(PgfTextSpot *spot, const uint8_t *end, ref sym, bool case_sensitive); void PgfAbstractParser::symbol(Item *item, State *state, PgfSymbol sym) { switch (ref::get_tag(sym)) { case PgfSymbolCat::tag: { auto symcat = ref::untagged(sym); CCat *ccat = item->args[symcat->d]; if (ccat == NULL) { ref lincat = 0; switch (ref::get_tag(item->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(item->rule->container); lincat = namespace_lookup(concr->lincats, &lin->absfun->type->hypos[symcat->d].type->name); break; } case PgfConcrLincat::tag: { lincat = ref::untagged(item->rule->container); break; } } if (lincat != 0) { size_t n_suspended1 = state->conts1.size(); Cont *&cont = state->conts1[lincat]; if (cont == NULL) { cont = new Cont; cont->ccat = NULL; cont->lincat = lincat; cont->state = state; } interval_t value_i = interval(item->rule, &item->vars[0], item->rule->args[symcat->d]); interval_t lin_idx_i = interval(item->rule, &item->vars[0], ref::from_ptr(&symcat->r)); suspend(cont,item,n_suspended1 == 0,symcat,value_i,lin_idx_i); } } else { interval_t value_i = interval(item->rule, &item->vars[0], item->rule->args[symcat->d]); interval_t lin_idx_i = interval(item->rule, &item->vars[0], ref::from_ptr(&symcat->r)); // the following prevents infinite loops with epsilons bool found = false; CCat *prev_ccat = ccat; while (prev_ccat != NULL && prev_ccat->cont != NULL && prev_ccat->cont->state == state) { if (prev_ccat->value == value_i && prev_ccat->lin_idx == lin_idx_i) { found = true; break; } prev_ccat = prev_ccat->cont->ccat; } if (found) { item->dot++; state->push_item(item); break; } Cont *&cont = state->conts2[ccat]; if (cont == NULL) { cont = new Cont; cont->ccat = ccat; if (ccat->epsilon != 0) cont->lincat = ccat->epsilon->lincat; else cont->lincat = ccat->cont->lincat; cont->state = state; } bool subsumed = false; for (auto it1 : cont->suspended.overlaps(value_i)) { if (it1.first.first <= value_i.first && it1.first.second >= value_i.second) { for (auto it2 : it1.second.overlaps(lin_idx_i)) { if (it2.first.first <= lin_idx_i.first && it2.first.second >= lin_idx_i.second) { subsumed = true; goto found; } } } } found: suspend(cont,item,!subsumed,symcat,value_i,lin_idx_i); } break; } case PgfSymbolKS::tag: { auto symks = ref::untagged(sym); symbol_token(item, state, symks); break; } case PgfSymbolKP::tag: { auto symkp = ref::untagged(sym); Item *new_item = new(item) Item; new_item->pre_alt = 1; new_item->pre_dot = item->dot; new_item->dot = 0; new_item->syms = symkp->default_form; new_item->rule = item->rule; new_item->inside_prob = item->inside_prob; new_item->outside_prob = item->outside_prob; process(new_item, state); for (size_t i = 0; i < symkp->alts.size(); i++) { Item *new_item = new(item) Item; new_item->pre_alt = i+2; new_item->pre_dot = item->dot; new_item->dot = 0; new_item->syms = symkp->alts[i].form; new_item->rule = item->rule; new_item->inside_prob = item->inside_prob; new_item->outside_prob = item->outside_prob; process(new_item, state); } delete item; break; } case PgfSymbolBIND::tag: case PgfSymbolSOFTBIND::tag: case PgfSymbolSOFTSPACE::tag: { symbol_bind(item, state, sym); break; } case PgfSymbolNE::tag: delete item; break; case PgfSymbolCAPIT::tag: case PgfSymbolALLCAPIT::tag: item->dot++; process(item, state); break; } } void PgfAbstractParser::complete(Item *item, State *state) { switch (ref::get_tag(item->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(item->rule->container); interval_t res = interval(item->rule, &item->vars[0], item->rule->res); interval_t lin_idx = interval(item->rule, &item->vars[0], item->rule->lin_idx); CCat *&ccat = state->completed[item->cont][res][lin_idx]; if (ccat == NULL) { ccat = new CCat; ccat->fid = (++last_fid); ccat->epsilon = 0; ccat->cont = item->cont; ccat->state = state; ccat->lin_idx = lin_idx; ccat->value = res; ccat->covered = false; ccat->viterbi_prob = item->inside_prob; #ifdef DEBUG_PARSER { PgfPrinter printer(NULL,0,NULL); if (item->rule->ranges.size() > 0) { printer.lvar_ranges(item->rule->ranges, &item->vars[0]); printer.puts(" "); } printer.nprintf(64,"complete [%zd-%zd; ",item->cont->state->end.pos,state->start.pos); if (ccat->cont->ccat == NULL) { printer.efun(&ccat->cont->lincat->name); printer.puts("("); printer.lparam(item->rule->res); printer.puts(")"); } else { printer.emeta(ccat->cont->ccat->fid); } printer.puts("; "); printer.lparam(item->rule->lin_idx); printer.puts("; "); printer.emeta(ccat->fid); printer.puts("]"); PgfText *text = printer.get_text(); fprintf(stderr, "%s\n", text->text); free(text); } #endif } auto prod = new(item) Production; prod->rule = item->rule; for (size_t i = 0; i < prod->args.size(); i++) { if (prod->args[i] != NULL && prod->args[i] != ccat) prod->args[i]->covered = true; } ccat->prods.push_back(prod); #ifdef DEBUG_PARSER print_prod(ccat, prod); #endif final_item(state, ccat, item, res, lin_idx); if (ccat->cont == NULL) break; if (ccat->prods.size() == 1) { bu_predict(state, item->outside_prob, ccat); for (auto it1 : ccat->cont->suspended.overlaps(ccat->value)) { for (auto it2 : it1.second.overlaps(ccat->lin_idx)) { size_t n_items = it2.second.size(); for (size_t i = 0; i < n_items; i++) { Item *new_item = new (it2.second[i]) Item; combine(state,new_item,ccat); }; } } } else { State *next = state; while (next != NULL) { Cont *cont = next->conts2[ccat]; if (cont != NULL) { for (auto it1 : cont->suspended) { for (auto it2 : it1.second) { Item *item = it2.second[0]; auto symcat = ref::untagged(item->syms[item->dot]); td_predict(next,cont,prod,item,symcat); } } } next = next->next; } } break; } case PgfConcrLincat::tag: { auto lincat = ref::untagged(item->rule->container); interval_t zero = {0,0}; final_item(state, NULL, item, zero, zero); break; } } delete item; } #define ZERO_VALUES(rule) \ ((size_t*) memset(alloca(rule->ranges.size()*sizeof(size_t)), 0, rule->ranges.size()*sizeof(size_t))) #define CLONE_VALUES(rule,values) \ ((size_t*) memcpy(alloca(rule->ranges.size()*sizeof(size_t)), values, rule->ranges.size()*sizeof(size_t))) bool PgfAbstractParser::instantiate(ref rule1, size_t *values1, ref lparam1, ref rule2, size_t *values2, ref lparam2) { size_t i01 = lparam1->i0; for (size_t i = 0; i < lparam1->n_terms; i++) { if (values1[lparam1->terms[i].var] > 0) { i01 += lparam1->terms[i].factor * (values1[lparam1->terms[i].var]-1); } } size_t i02 = lparam2->i0; for (size_t i = 0; i < lparam2->n_terms; i++) { if (values2[lparam2->terms[i].var] > 0) { i02 += lparam2->terms[i].factor * (values2[lparam2->terms[i].var]-1); } } if (i01 > i02) { i01 -= i02; i02 = 0; } else { i02 -= i01; i01 = 0; } size_t i1 = 0, i2 = 0; while (i1 < lparam1->n_terms || i2 < lparam2->n_terms) { size_t scale1 = 0; term t1 = {0,0}; if (i1 < lparam1->n_terms) { t1 = lparam1->terms[i1]; if (values1[t1.var] > 0) { i1++; continue; } scale1 = t1.factor * rule1->ranges[t1.var]; } size_t scale2 = 0; term t2 = {0,0}; if (i2 < lparam2->n_terms) { t2 = lparam2->terms[i2]; if (values2[t2.var] > 0) { i2++; continue; } scale2 = t2.factor * rule2->ranges[t2.var]; } if (scale1 > scale2) { size_t min = (i02 / t1.factor); size_t max = min; while (i2 < lparam2->n_terms) { t2 = lparam2->terms[i2]; size_t f = t2.factor / t1.factor; if (f == 0) break; if (values2[t2.var] == 0) { max += f * (rule2->ranges[t2.var]-1); } i2++; } i02 %= t1.factor; if (min >= rule1->ranges[t1.var]) return false; if (min == max) { if (values1[t1.var] == 0) values1[t1.var] = min+1; else if (values1[t1.var] != min+1) return false; } i1++; } else { size_t min = (i01 / t2.factor); size_t max = min; while (i1 < lparam1->n_terms) { t1 = lparam1->terms[i1]; size_t f = t1.factor / t2.factor; if (f == 0) break; if (values1[t1.var] == 0) { max += f * (rule1->ranges[t1.var]-1); } i1++; } i01 %= t2.factor; if (min >= rule2->ranges[t2.var]) return false; if (min == max) { if (values2[t2.var] == 0) { values2[t2.var] = min+1; } else if (values2[t2.var] != min+1) return false; } i2++; } } return (i01 == i02); } interval_t PgfAbstractParser::interval(ref rule, size_t *values, ref lparam) { interval_t interval; interval.first = lparam->i0; interval.second = interval.first; for (size_t i = 0; i < lparam->n_terms; i++) { size_t var = lparam->terms[i].var; if (values[var] == 0) { interval.second += lparam->terms[i].factor * (rule->ranges[var]-1); } else { size_t value = lparam->terms[i].factor * (values[var]-1); interval.first += value; interval.second += value; } } return interval; } void PgfAbstractParser::combine(State *state, Item *item, CCat *ccat) { PgfSymbol sym = item->rule->syms[item->dot]; auto sym_cat = ref::untagged(sym); ref rule; size_t *values; get_info(ccat, &rule,&values); values = CLONE_VALUES(rule, values); if (!instantiate(item->rule, &item->vars[0], item->rule->args[sym_cat->d], rule, values, rule->res)) { delete item; return; } if (!instantiate(item->rule, &item->vars[0], ref::from_ptr(&sym_cat->r), rule, values, rule->lin_idx)) { delete item; return; } item->dot++; if (item->args[sym_cat->d] != NULL) { item->inside_prob -= item->args[sym_cat->d]->viterbi_prob; } item->args[sym_cat->d] = ccat; item->inside_prob += ccat->viterbi_prob; state->push_item(item); } bool PgfAbstractParser::ItemComparator::operator()(Item *item1, Item *item2) { if (item1->rule.as_object() < item2->rule.as_object()) return true; else if (item1->rule.as_object() > item2->rule.as_object()) return false; for (size_t j = 0; j < item1->args.size(); j++) { if (item1->args[j] < item2->args[j]) return true; else if (item1->args[j] > item2->args[j]) return false; } return false; } void PgfAbstractParser::td_epsilon(State *state, Cont *cont, ref pitem, Item *xitem, ref symcat) { switch (ref::get_tag(pitem->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(pitem->rule->container); for (ref rule : lin->rules) { size_t *values1 = ZERO_VALUES(rule); size_t *values2 = CLONE_VALUES(xitem->rule, &xitem->vars[0]); if (!instantiate(rule, values1, rule->res, xitem->rule, values2, xitem->rule->args[symcat->d])) { continue; } if (!instantiate(rule, values1, rule->lin_idx, xitem->rule, values2, ref::from_ptr(&symcat->r))) { continue; } size_t *values3 = CLONE_VALUES(pitem->rule, &pitem->vars[0]); for (size_t i = 0; i < pitem->args.size(); i++) { if (!instantiate(rule, values1, rule->args[i], pitem->rule, values3, pitem->rule->args[i])) { goto next; } } { Item *item = new (rule) Item; item->cont = cont; item->dot = 0; item->pre_alt = 0; item->pre_dot = 0; item->syms = rule->syms.as_vector(); item->rule = rule; item->inside_prob = lin->absfun->prob; item->outside_prob = xitem->outside_prob+xitem->inside_prob-xitem->args[symcat->d]->viterbi_prob; size_t *values3 = CLONE_VALUES(pitem->rule, &pitem->vars[0]); for (size_t i = 0; i < pitem->args.size(); i++) { if (pitem->args[i] != 0) { if (!instantiate(rule, &item->vars[0], rule->args[i], pitem->rule, values3, pitem->rule->args[i])) { delete item; goto next; } item->args[i] = get_epsilon_ccat(&lin->absfun->type->hypos[i].type->name,pitem->args[i]); item->inside_prob += item->args[i]->viterbi_prob; } } auto res = cont->predicted.insert(item); if (res.second) { state->push_item(item); } else { delete item; } } next:; } } default:; // should not happend } } void PgfAbstractParser::td_predict(State *state, Cont *cont, Production *prod, Item *xitem, ref symcat) { switch (ref::get_tag(prod->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(prod->rule->container); for (ref rule : lin->rules) { size_t *values1 = ZERO_VALUES(rule); size_t *values2 = CLONE_VALUES(xitem->rule, &xitem->vars[0]); if (!instantiate(rule, values1, rule->res, xitem->rule, values2, xitem->rule->args[symcat->d])) { continue; } if (!instantiate(rule, values1, rule->lin_idx, xitem->rule, values2, ref::from_ptr(&symcat->r))) { continue; } size_t *values3 = CLONE_VALUES(prod->rule, &prod->vars[0]); for (size_t i = 0; i < rule->args.size(); i++) { if (!instantiate(rule, values1, rule->args[i], prod->rule, values3, prod->rule->args[i])) { goto next; } } { Item *item = new (rule) Item; item->cont = cont; item->dot = 0; item->pre_alt = 0; item->pre_dot = 0; item->syms = rule->syms.as_vector(); item->rule = rule; item->inside_prob = lin->absfun->prob; item->outside_prob = xitem->outside_prob+xitem->inside_prob-xitem->args[symcat->d]->viterbi_prob; size_t *values3 = CLONE_VALUES(prod->rule, &prod->vars[0]); for (size_t i = 0; i < rule->args.size(); i++) { if (!instantiate(rule, &item->vars[0], rule->args[i], prod->rule, values3, prod->rule->args[i])) { delete item; goto next; } item->args[i] = prod->args[i]; if (item->args[i] != NULL) { item->inside_prob += item->args[i]->viterbi_prob; } } auto res = cont->predicted.insert(item); if (res.second) { state->push_item(item); } else { delete item; } } next:; } } default:; // should not happend } } #ifdef DEBUG_PARSER static void print_symbols(PgfPrinter &printer, PgfConcrRule *rule, vector syms, size_t pre_alt, size_t pre_dot, size_t dot) { for (size_t i = 0; i < syms.size(); i++) { if (pre_alt == 0 && dot == i) { printer.puts(" . "); printer.symbol(syms[i]); } else if (pre_alt > 0 && pre_dot == i) { auto sym_kp = ref::untagged(rule->syms[pre_dot]); printer.puts("pre {"); if (pre_alt == 1) print_symbols(printer, rule, syms, 0, 0, dot); else printer.symbols(sym_kp->default_form); for (size_t i = 0; i < sym_kp->alts.size(); i++) { printer.puts("; "); if (pre_alt-2 == i) print_symbols(printer, rule, syms, 0, 0, dot); else printer.symbols(sym_kp->alts[i].form); printer.puts(" /"); for (size_t j = 0; j < sym_kp->alts[i].prefixes.size(); j++) { printer.puts(" "); printer.lstr(sym_kp->alts[i].prefixes[j]); } } printer.puts("}"); } else { printer.symbol(syms[i]); } } if (pre_alt == 0 && dot >= syms.size()) printer.puts(" . "); } void PgfAbstractParser::print_item(Item *item, State *state) { PgfPrinter printer(NULL,0,NULL); printer.nprintf(32, "[%zd-%zd; ", (item->cont && item->cont->state) ? item->cont->state->end.pos : 0, state->start.pos); if (item->vars.size() > 0) { printer.lvar_ranges(item->rule->ranges, &item->vars[0]); printer.puts(" "); } if (item->cont) { if (item->cont->ccat == NULL) { printer.efun(&item->cont->lincat->name); } else { printer.emeta(item->cont->ccat->fid); } printer.puts("("); printer.lparam(item->rule->res); printer.puts(")"); } printer.puts(" -> "); switch (ref::get_tag(item->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(item->rule->container); printer.efun(&lin->name); printer.puts("["); for (size_t i = 0; i < item->args.size(); i++) { if (i > 0) printer.puts(","); CCat *ccat = item->args[i]; if (ccat == NULL) { printer.efun(&lin->absfun->type->hypos[i].type->name); } else { printer.emeta(ccat->fid); } printer.puts("("); printer.lparam(item->rule->args[i]); printer.puts(")"); } printer.puts("]; "); break; } case PgfConcrLincat::tag: { auto lincat = ref::untagged(item->rule->container); printer.puts("linref "); printer.efun(&lincat->name); printer.puts("["); CCat *ccat = item->args[0]; if (ccat == NULL) { printer.efun(&lincat->name); printer.puts("("); printer.lparam(item->rule->args[0]); printer.puts(")"); } else { printer.emeta(ccat->fid); } printer.puts("]; "); break; } } printer.lparam(item->rule->lin_idx); printer.puts(" : "); print_symbols(printer, item->rule, item->syms, item->pre_alt, item->pre_dot, item->dot); printer.nprintf(40,"; %f+%f=%f]", item->inside_prob, item->outside_prob, item->inside_prob+item->outside_prob); PgfText *text = printer.get_text(); fprintf(stderr, "%s\n", text->text); free(text); } void PgfAbstractParser::print_prod(CCat *ccat, Production *prod) { PgfPrinter printer(NULL,0,NULL); if (prod->vars.size() > 0) { printer.lvar_ranges(prod->rule->ranges, &prod->vars[0]); printer.puts(" "); } printer.emeta(ccat->fid); printer.puts("("); printer.lparam(prod->rule->res); printer.puts(")"); printer.puts(" -> "); switch (ref::get_tag(prod->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(prod->rule->container); printer.efun(&lin->name); printer.puts("["); for (size_t i = 0; i < prod->args.size(); i++) { if (i > 0) printer.puts(","); CCat *ccat = prod->args[i]; if (ccat == NULL) { printer.efun(&lin->absfun->type->hypos[i].type->name); } else { printer.emeta(ccat->fid); } printer.puts("("); printer.lparam(prod->rule->args[i]); printer.puts(")"); } printer.puts("]"); break; } case PgfConcrLincat::tag: { auto lincat = ref::untagged(prod->rule->container); printer.puts("linref "); printer.efun(&lincat->name); printer.puts("["); CCat *ccat = prod->args[0]; if (ccat == NULL) { printer.efun(&lincat->name); printer.puts("("); printer.lparam(prod->rule->args[0]); printer.puts(")"); } else { printer.emeta(ccat->fid); } printer.puts("]"); break; } } PgfText *text = printer.get_text(); fprintf(stderr, "%s\n", text->text); free(text); } #endif PgfParser::PgfParser(ref concr, PgfText *sentence, bool case_sensitive, PgfMarshaller *m, PgfUnmarshaller *u) : PgfAbstractParser(concr) { this->m = m; this->u = u; this->sentence = textdup(sentence); this->end = (uint8_t *) (this->sentence->text+this->sentence->size); this->case_sensitive = case_sensitive; } PgfParser::~PgfParser() { free(sentence); State *state = current_state; while (state != NULL) { for (auto it1 : state->completed) { for (auto it2 : it1.second) { for (auto it3 : it2.second) { if (it3.second->epsilon != 0) continue; for (ExprState *estate : it3.second->pending) { if (estate->expr != 0) u->free_ref(estate->expr); } for (ExprProb &ep : it3.second->exprs) { u->free_ref(ep.expr); } } } } state = state->next; } for (auto it1 : epsilons) { for (ExprState *estate : it1.second->pending) { if (estate->expr != 0) u->free_ref(estate->expr); } for (ExprProb &ep : it1.second->exprs) { u->free_ref(ep.expr); } } } void PgfParser::bu_predict(PgfPhrasetable phrasetable, State *state, prob_t outside_prob, ptrdiff_t min, ptrdiff_t max) { if (phrasetable == 0) return; PgfTextSpot current = state->end; int cmp = text_symbol_cmp(¤t,end,phrasetable->value.key,case_sensitive); if (cmp < 0) { bu_predict(phrasetable->left,state,outside_prob,min,max); } else if (cmp > 0) { ptrdiff_t len = current.ptr - state->end.ptr; if (min <= len-1) bu_predict(phrasetable->left,state,outside_prob,min,len-1); if (len <= max) bu_predict(phrasetable->right,state,outside_prob,len,max); } else { ptrdiff_t len = current.ptr - state->end.ptr; if (min <= len) bu_predict(phrasetable->left,state,outside_prob,min,len); if (len > 0) { for (size_t i = 0; i < phrasetable->value.n_items; i++) { //std::map, bool> visited; //if (!td_reachable(state, phrasetable->items[i], visited)) // continue; Item *item = bu_item(state, outside_prob, phrasetable->value.items[i]); item->dot++; State *next_state = new_state(current,item->outside_prob+item->inside_prob); next_state->push_item(item); } } if (len <= max) bu_predict(phrasetable->right,state,outside_prob,len,max); } } void PgfParser::bu_predict(PgfPhrasetable phrasetable, State *state, prob_t outside_prob) { size_t n_items = 0; vector> items = phrasetable_lookup(concr->phrasetable4, ref(0), &n_items); State *next_state = state->next; if (next_state == NULL || state->end.pos != next_state->start.pos) { next_state = new State; next_state->start = state->end; next_state->end = state->end; next_state->next = state->next; next_state->needs_bind = false; next_state->viterbi_prob = state->viterbi_prob; state->next = next_state; } for (size_t i = 0; i < n_items; i++) { //std::map, bool> visited; //if (!td_reachable(state, phrasetable->items[i], visited)) // continue; Item *item = bu_item(state, outside_prob, items[i]); item->dot++; next_state->push_item(item); } } void PgfParser::bu_predict(State *state, prob_t outside_prob, CCat *ccat) { size_t n_items = 0; vector> items = 0; if (ccat->cont->ccat == NULL) { items = phrasetable_lookup(concr->phrasetable2, ccat->cont->lincat, &n_items); } else if (ccat->cont->ccat->epsilon != 0) { items = phrasetable_lookup(concr->phrasetable3, ccat->cont->ccat->epsilon, &n_items); } for (size_t i = 0; i < n_items; i++) { //std::map, bool> visited; //if (!td_reachable(ccat->cont->state, items[i], visited)) // continue; auto new_item = bu_item(ccat->cont->state, outside_prob, items[i]); combine(state,new_item,ccat); } } bool PgfParser::td_reachable(State *state, ref pitem, std::map, bool> &visited) { switch (ref::get_tag(pitem->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(pitem->rule->container); if (visited[lin->lincat]) return false; visited[lin->lincat] = true; auto it = state->conts1.find(lin->lincat); if (it != state->conts1.end()) { return true; } size_t n_items = 0; vector> items = phrasetable_lookup(concr->phrasetable2, lin->lincat, &n_items); for (size_t i = 0; i < n_items; i++) { if (td_reachable(state, items[i], visited)) return true; } break; } } return false; } PgfAbstractParser::Item *PgfParser::bu_item(State *state, prob_t outside_prob, ref pitem) { Item *item = NULL; switch (ref::get_tag(pitem->rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(pitem->rule->container); Cont *cont; if (pitem->res == 0) { Cont *&tmp = state->conts1[lin->lincat]; if (tmp == NULL) { tmp = new Cont; tmp->ccat = NULL; tmp->lincat = lin->lincat; tmp->state = state; } cont = tmp; } else { CCat *ccat = get_epsilon_ccat(&lin->lincat->name,pitem->res); Cont *&tmp = state->conts2[ccat]; if (tmp == NULL) { tmp = new Cont; tmp->ccat = ccat; tmp->lincat = lin->lincat; tmp->state = state; } cont = tmp; } item = new(pitem->rule) Item; item->cont = cont; item->pre_alt = pitem->pre_alt; item->pre_dot = pitem->pre_dot; item->dot = pitem->dot; item->syms = pitem->rule->syms.as_vector(); item->rule = pitem->rule; item->inside_prob = lin->absfun->prob; item->outside_prob = outside_prob; for (size_t i = 0; i < pitem->args.size(); i++) { item->args[i] = 0; if (pitem->args[i] != 0) { item->args[i] = get_epsilon_ccat(&lin->absfun->type->hypos[i].type->name,pitem->args[i]); item->inside_prob += item->args[i]->viterbi_prob; } } break; } case PgfConcrLincat::tag: { auto lincat = ref::untagged(pitem->rule->container); Cont *&cont = state->conts1[0]; if (cont == NULL) { cont = new Cont; cont->ccat = NULL; cont->lincat = 0; cont->state = state; } item = new(pitem->rule) Item; item->cont = cont; item->pre_alt = pitem->pre_alt; item->pre_dot = pitem->pre_dot; item->dot = pitem->dot; item->syms = pitem->rule->syms.as_vector(); item->rule = pitem->rule; item->inside_prob = 0; item->outside_prob = 0; item->args[0] = 0; break; } } if (item->pre_alt > 0) { auto symkp = ref::untagged(item->syms[item->pre_dot]); if (item->pre_alt == 1) item->syms = symkp->default_form; else item->syms = symkp->alts[item->pre_alt-2].form; } memcpy(&item->vars[0], &pitem->vars[0], sizeof(size_t) * item->vars.size()); return item; } void PgfParser::make_chunks(State *state, std::vector &chunks, prob_t prob) { if (state->completed.size() == 0) { ExprState *estate = new(chunks.size()) ExprState; estate->expr = u->emeta(0); estate->prob = prob; estate->hash = '?'; estate->res = NULL; estate->index = 0; estate->n_args = chunks.size(); for (size_t i = 0; i < estate->n_args; i++) { estate->args[i] = chunks[estate->n_args-i-1]; estate->prob += estate->args[i]->viterbi_prob; } queue.push_back(estate); std::push_heap(queue.begin(), queue.end(), estate_comp); } for (auto it1 : state->completed) { for (auto it2 : it1.second) { for (auto it3 : it2.second) { CCat *ccat = it3.second; if (!ccat->covered && ccat->cont->state != state) { chunks.push_back(ccat); make_chunks(ccat->cont->state, chunks, prob+ccat->cont->lincat->abscat->prob); chunks.pop_back(); } } } } } void PgfParser::prepare(ref start) { #ifdef DEBUG_PARSER fprintf(stderr, "------------------------------------------\n"); #endif PgfTextSpot start_spot = {0, (uint8_t *) sentence->text}; State *state = new_state(start_spot, 0); for (size_t i = start->n_lindefs; i < start->rules.size(); i++) { ref rule = start->rules[i]; Item *item = new(rule) Item; item->cont = NULL; item->dot = 0; item->pre_alt = 0; item->pre_dot = 0; item->syms = rule->syms.as_vector(); item->rule = rule; item->inside_prob = 0; item->outside_prob = 0; state->push_item(item); } } PgfExpr PgfParser::fetch(PgfDB *db, prob_t *prob) { DB_scope scope(db, READER_SCOPE); bool first_fetch = (concr->last_fid == last_fid); for (;;) { State *state = current_state; prob_t min_prob = INFINITY; State *min_state = NULL; if (queue.size() > 0) { min_prob = queue.front()->prob; } while (state != NULL) { if (state->queue.size() > 0) { Item *item = state->queue.front(); prob_t delta = current_state->viterbi_prob - state->viterbi_prob; prob_t prob = item->outside_prob + item->inside_prob + delta; if (min_prob > prob) { min_prob = prob; min_state = state; } } state = state->next; } if (min_state == NULL) break; State *prev = current_state; current_state = NULL; while (current_state != min_state) { State *next = prev->next; prev->next = current_state; current_state = prev; prev = next; } Item *item = current_state->pop_item(); process(item,current_state); while (current_state != NULL) { State *next = current_state->next; current_state->next = prev; prev = current_state; current_state = next; } current_state = prev; } if (first_fetch && queue.size() == 0) { std::vector chunks; make_chunks(current_state, chunks, 0); } while (queue.size() > 0) { ExprState *estate = queue.front(); std::pop_heap(queue.begin(), queue.end(), estate_comp); queue.pop_back(); #ifdef DEBUG_EXPRS print_expr_state(m, estate); #endif PgfExpr expr = process_expr(estate, prob); if (expr != 0) return expr; } return 0; } PgfExpr PgfParser::process_expr(ExprState *estate, prob_t *prob) { if (estate->index < estate->n_args) { CCat *ccat = estate->args[estate->index]; if (ccat == NULL) { ExprState *app_state = new(estate->n_args) ExprState; app_state->expr = estate->expr ? u->eapp(estate->expr, u->emeta(0)) : u->emeta(0); app_state->prob = estate->prob; app_state->hash = estate->hash * 101 + '?'; app_state->res = estate->res; app_state->index = estate->index+1; app_state->n_args = estate->n_args; for (size_t i = 0; i < app_state->n_args; i++) { app_state->args[i] = estate->args[i]; } queue.push_back(app_state); std::push_heap(queue.begin(), queue.end(), estate_comp); } else { ccat->pending.push_back(estate); if (ccat->pending.size() == 1) { if (ccat->epsilon != 0) { for (size_t i = 0; i < ccat->epsilon->n_items; i++) { ref pitem = ccat->epsilon->items[i]; auto lin = ref::untagged(pitem->rule->container); ExprState *new_estate = new(pitem->args.size()) ExprState; new_estate->expr = u->efun(&lin->name); new_estate->prob = estate->prob-ccat->viterbi_prob+lin->absfun->prob; new_estate->hash = 0; new_estate->res = ccat; new_estate->index = 0; new_estate->n_args = pitem->args.size(); for (size_t i = 0; i < lin->name.size; i++) { new_estate->hash = new_estate->hash * 101 + lin->name.text[i]; } for (size_t i = 0; i < new_estate->n_args; i++) { new_estate->args[i] = NULL; if (pitem->args[i] != 0) { new_estate->args[i] = get_epsilon_ccat(&lin->absfun->type->hypos[i].type->name,pitem->args[i]); new_estate->prob += new_estate->args[i]->viterbi_prob; } } queue.push_back(new_estate); std::push_heap(queue.begin(), queue.end(), estate_comp); } } else { for (Production *prod : ccat->prods) { auto lin = ref::untagged(prod->rule->container); ExprState *new_estate = new(prod->args.size()) ExprState; new_estate->expr = u->efun(&lin->name); new_estate->prob = estate->prob-ccat->viterbi_prob+lin->absfun->prob; new_estate->hash = 0; new_estate->res = ccat; new_estate->index = 0; new_estate->n_args = prod->args.size(); for (size_t i = 0; i < lin->name.size; i++) { new_estate->hash = new_estate->hash * 101 + lin->name.text[i]; } for (size_t i = 0; i < new_estate->n_args; i++) { new_estate->args[i] = prod->args[i]; if (prod->args[i] != NULL) { new_estate->prob += prod->args[i]->viterbi_prob; } } queue.push_back(new_estate); std::push_heap(queue.begin(), queue.end(), estate_comp); } } } else { for (ExprProb ep : ccat->exprs) { ExprState *app_state = new(estate->n_args) ExprState; app_state->expr = estate->expr ? u->eapp(estate->expr, ep.expr) : ep.expr; app_state->prob = estate->prob-ccat->viterbi_prob+ep.prob; app_state->hash = estate->hash * 31 + ep.hash; app_state->res = estate->res; app_state->index = estate->index+1; app_state->n_args= estate->n_args; for (size_t i = 0; i < app_state->n_args; i++) { app_state->args[i] = estate->args[i]; } queue.push_back(app_state); std::push_heap(queue.begin(), queue.end(), estate_comp); } } } } else { if (estate->res == NULL) { *prob = estate->prob; return estate->expr; } prob_t prob = estate->prob - (estate->res->pending[0]->prob-estate->res->viterbi_prob); for (size_t i = estate->res->exprs.size(); i > 0; i--) { ExprProb &ep = estate->res->exprs[i-1]; if (ep.prob != prob) break; if (ep.hash == estate->hash) return 0; } estate->res->exprs.emplace_back(estate->expr, prob, estate->hash); for (ExprState *parent : estate->res->pending) { ExprState *app_state = new(parent->n_args) ExprState; app_state->expr = parent->expr ? u->eapp(parent->expr, estate->expr) : estate->expr; app_state->prob = parent->prob-estate->res->viterbi_prob+prob; app_state->hash = parent->hash * 31 + estate->hash; app_state->res = parent->res; app_state->index = parent->index+1; app_state->n_args= parent->n_args; for (size_t i = 0; i < app_state->n_args; i++) { app_state->args[i] = parent->args[i]; } queue.push_back(app_state); std::push_heap(queue.begin(), queue.end(), estate_comp); } } return 0; } PgfAbstractParser::State *PgfParser::new_state(const PgfTextSpot &start, prob_t viterbi_prob) { State **prev = ¤t_state; State *state = current_state; while (state != NULL && state->start.ptr <= start.ptr) { if (state->start.ptr == start.ptr) return state; prev = &state->next; state = state->next; } state = new State; state->start = start; state->end = start; state->viterbi_prob = viterbi_prob; state->next = *prev; *prev = state; while (state->end.ptr < end) { const uint8_t *ptr = state->end.ptr; uint32_t ucs = pgf_utf8_decode(&ptr); if (!pgf_utf8_is_space(ucs)) break; state->end.pos++; state->end.ptr = ptr; } state->needs_bind = (state->start.pos > 0 && state->start.pos == state->end.pos); return state; } void PgfParser::symbol_token(Item *item, State *state, ref symks) { PgfTextSpot next = state->end; if (text_symbol_cmp(&next,end,symks,case_sensitive) != 0) return; State *next_state = new_state(next, item->inside_prob+item->outside_prob); item->dot++; process(item, next_state); } void PgfParser::symbol_bind(Item *item, State *state, PgfSymbol sym) { if (state->needs_bind) { State *next_state = state->next; if (next_state == NULL || state->end.pos != next_state->start.pos) { next_state = new State; next_state->start = state->end; next_state->end = state->end; next_state->next = state->next; next_state->needs_bind = false; next_state->viterbi_prob = state->viterbi_prob; state->next = next_state; } item->dot++; next_state->push_item(item); } else { if (ref::get_tag(sym) == PgfSymbolBIND::tag) { delete item; } else { item->dot++; process(item, state); } } } void PgfParser::suspend(Cont *cont,Item *item,bool do_predict,ref symcat,interval_t value_i,interval_t lin_idx_i) { auto &suspended = cont->suspended[value_i][lin_idx_i]; suspended.push_back(item); size_t n_suspended = suspended.size(); if (cont->ccat == NULL) { if (n_suspended == 1) { std::function)> f = [this,item,cont](ref arg) { ref pitem = arg->items[0]; PgfSymbol sym = item->rule->syms[item->dot]; auto sym_cat = ref::untagged(sym); size_t *values1 = CLONE_VALUES(item->rule, &item->vars[0]); size_t *values2 = CLONE_VALUES(pitem->rule, &pitem->vars[0]); if (!instantiate(item->rule, values1, item->rule->args[sym_cat->d], pitem->rule, values2, pitem->rule->res)) { return; } if (!instantiate(item->rule, values1, ref::from_ptr(&sym_cat->r), pitem->rule, values2, pitem->rule->lin_idx)) { return; } CCat *&arg_ccat = epsilons[arg->fid]; if (arg_ccat == NULL) { arg_ccat = new CCat; arg_ccat->fid = arg->fid; arg_ccat->epsilon = arg; arg_ccat->cont = NULL; arg_ccat->state = NULL; arg_ccat->lin_idx = arg->lin_idx; arg_ccat->value = arg->value; arg_ccat->covered = true; arg_ccat->viterbi_prob = arg->viterbi_prob; } cont->state->completed[cont][arg_ccat->value][arg_ccat->lin_idx] = arg_ccat; }; epsilontable_iter(concr->epsilontable,cont->lincat,f); } if (do_predict) { prob_t viterbi_prob = item->inside_prob+item->outside_prob; if (cont->state->needs_bind) { bu_predict(concr->phrasetable4, cont->state, viterbi_prob); } else { bu_predict(concr->phrasetable1, cont->state, viterbi_prob, 1, sentence->size); } } } else { if (do_predict && n_suspended == 1) { if (cont->ccat->epsilon != 0) { for (size_t i = 0; i < cont->ccat->epsilon->n_items; i++) { ref pitem = cont->ccat->epsilon->items[i]; td_epsilon(cont->state,cont,pitem,item,symcat); } } else { for (Production *prod : cont->ccat->prods) { td_predict(cont->state,cont,prod,item,symcat); } } } } State *state = cont->state; while (state != NULL) { auto it1 = state->completed.find(cont); if (it1 != state->completed.end()) { for (auto it2 : it1->second.overlaps(value_i)) { for (auto it3 : it2.second.overlaps(lin_idx_i)) { Item *new_item = new (item) Item; combine(state, new_item, it3.second); } } } state = state->next; } } void PgfParser::final_item(State *state, CCat *ccat, Item *item, interval_t value, interval_t lin_idx) { if (item->cont == NULL && state->end.ptr == end) { ExprState *estate = new(item->args.size()) ExprState; estate->expr = 0; estate->prob = 0; estate->hash = 0; estate->res = ccat; estate->index = 0; estate->n_args = item->args.size(); for (size_t i = 0; i < estate->n_args; i++) { estate->args[i] = item->args[i]; estate->prob += estate->args[i]->viterbi_prob; } queue.push_back(estate); std::push_heap(queue.begin(), queue.end(), estate_comp); } else if (ccat != NULL && ccat->pending.size() > 0) { auto lin = ref::untagged(item->rule->container); ExprState *estate = new(item->args.size()) ExprState; estate->expr = u->efun(&lin->name); estate->prob = ccat->pending[0]->prob-ccat->viterbi_prob+lin->absfun->prob; estate->hash = 0; estate->res = ccat; estate->index = 0; estate->n_args = item->args.size(); for (size_t i = 0; i < lin->name.size; i++) { estate->hash = estate->hash * 101 + lin->name.text[i]; } for (size_t i = 0; i < estate->n_args; i++) { estate->args[i] = item->args[i]; estate->prob += estate->args[i]->viterbi_prob; } queue.push_back(estate); std::push_heap(queue.begin(), queue.end(), estate_comp); } } #ifdef DEBUG_EXPRS void PgfParser::print_expr_state_left(PgfPrinter *printer, PgfMarshaller *m, ExprState *estate) { if (estate->res && estate->res->pending.size() > 0) { ExprState *parent = estate->res->pending[0]; print_expr_state_left(printer, m, parent); printer->puts(" ("); } if (estate->expr) m->match_expr(printer, estate->expr); else printer->puts("::"); } void PgfParser::print_expr_state_right(PgfPrinter *printer, ExprState *estate) { for (size_t i = estate->index+1; i < estate->n_args; i++) { printer->puts(" "); if (estate->args[i] != NULL) printer->emeta(estate->args[i]->fid); else printer->puts("?"); } if (estate->res && estate->res->pending.size() > 0) { printer->puts(")"); ExprState *parent = estate->res->pending[0]; print_expr_state_right(printer, parent); } } void PgfParser::print_expr_state(PgfMarshaller *m, ExprState *estate) { PgfPrinter printer(NULL,0,m); printer.nprintf(64,"[%f] ",estate->prob); print_expr_state_left(&printer, m, estate); printer.puts(" . "); if (estate->index < estate->n_args) { if (estate->args[estate->index] != NULL) printer.emeta(estate->args[estate->index]->fid); else printer.puts("?"); } print_expr_state_right(&printer, estate); PgfText *text = printer.get_text(); fprintf(stderr, "%s\n", text->text); free(text); } #endif PgfParseTableMaker::PgfParseTableMaker(ref concr) : PgfAbstractParser(concr) { current_state = new State; current_state->start.pos = 0; current_state->start.ptr = NULL; current_state->end = current_state->start; current_state->viterbi_prob = 0; current_state->next = NULL; } ref PgfParseTableMaker::clone_item(Item *item) { size_t ex_size = sizeof(PgfMetaId) * item->args.size() + sizeof(size_t) * item->vars.size(); auto pitem = PgfDB::malloc(ex_size); pitem->res = (item->cont->ccat == NULL) ? 0 : item->cont->ccat->fid; pitem->pre_alt = item->pre_alt; pitem->pre_dot = item->pre_dot; pitem->dot = item->dot; pitem->rule = item->rule; memcpy(&pitem->vars[0],&item->vars[0],sizeof(size_t) * item->vars.size()); for (size_t i = 0; i < item->args.size(); i++) { pitem->args[i] = (item->args[i] == NULL) ? 0 : item->args[i]->fid; } return pitem; } PgfAbstractParser::State *PgfParseTableMaker::new_state(const PgfTextSpot &start, prob_t viterbi_prob) { return current_state; } void PgfParseTableMaker::symbol_token(Item *item, State *state, ref symks) { auto pitem = clone_item(item); auto phrasetable1 = phrasetable_insert(concr->phrasetable1,symks,pitem); concr->phrasetable1 = phrasetable1; delete item; } void PgfParseTableMaker::symbol_bind(Item *item, State *state, PgfSymbol sym) { auto pitem = clone_item(item); auto phrasetable4 = phrasetable_insert(concr->phrasetable4,ref(0),pitem); concr->phrasetable4 = phrasetable4; if (ref::get_tag(sym) == PgfSymbolBIND::tag) { delete item; } else { item->dot++; process(item,state); } } void PgfParseTableMaker::suspend(Cont *cont,Item *item,bool do_predict,ref symcat,interval_t value_i,interval_t lin_idx_i) { auto &suspended = cont->suspended[value_i][lin_idx_i]; suspended.push_back(item); size_t n_suspended = suspended.size(); if (cont->ccat == NULL) { auto pitem = clone_item(item); auto phrasetable2 = phrasetable_insert(concr->phrasetable2,cont->lincat,pitem); concr->phrasetable2 = phrasetable2; } else { if (do_predict && n_suspended == 1) { if (cont->ccat->epsilon != 0) { for (size_t i = 0; i < cont->ccat->epsilon->n_items; i++) { ref pitem = cont->ccat->epsilon->items[i]; td_epsilon(cont->state,cont,pitem,item,symcat); } } else { for (Production *prod : cont->ccat->prods) { td_predict(cont->state,cont,prod,item,symcat); } } } auto pitem = clone_item(item); auto phrasetable3 = phrasetable_insert(concr->phrasetable3,cont->ccat->epsilon,pitem); concr->phrasetable3 = phrasetable3; } auto it1 = cont->state->completed.find(cont); if (it1 != cont->state->completed.end()) { for (auto it2 : it1->second.overlaps(value_i)) { for (auto it3 : it2.second.overlaps(lin_idx_i)) { CCat *arg = it3.second; Item *new_item = new (item) Item; combine(cont->state, new_item, arg); } } } } void PgfParseTableMaker::final_item(State *state, CCat *ccat, Item *item, interval_t value, interval_t lin_idx) { auto pitem = clone_item(item); if (ccat->epsilon == 0) { PgfEpsilontable epsilontable = concr->epsilontable; epsilontable = epsilontable_insert(epsilontable, ccat->cont->lincat, ccat->value, ccat->lin_idx, ccat->fid, ccat->viterbi_prob, pitem, &ccat->epsilon); concr->epsilontable = epsilontable; } else { epsilontable_add(ccat->epsilon, pitem); } } void PgfParseTableMaker::bu_predict(State *state, prob_t outside_prob, CCat *ccat) { } void PgfParseTableMaker::insert_rule(ref rule) { switch (ref::get_tag(rule->container)) { case PgfConcrLin::tag: { auto lin = ref::untagged(rule->container); Cont *&cont = current_state->conts1[lin->lincat]; if (cont == NULL) { cont = new Cont; cont->ccat = NULL; cont->lincat = lin->lincat; cont->state = current_state; } Item *item = new(rule) Item; item->cont = cont; item->dot = 0; item->pre_alt = 0; item->pre_dot = 0; item->syms = rule->syms.as_vector(); item->rule = rule; item->inside_prob = lin->absfun->prob; item->outside_prob = 0; current_state->push_item(item); } } } void PgfParseTableMaker::prepare() { while (current_state->has_items()) { Item *item = current_state->pop_item(); process(item,current_state); } }