/** * Pop a previous match state back into the match * @param m the match state * @return 1 if the pop was possible else 0 */ int match_pop( match *m ) { if ( m->queue == NULL ) return 0; else { match *n = match_deepest_queued( m ); match_state *ms = n->queue; n->queue = match_state_next( ms ); n->start = match_state_start(ms); n->end = match_state_end(ms); n->prev = match_state_prev(ms); n->maximal = match_state_maximal(ms); match_state_loc( ms, &n->loc ); n->text_off = match_state_text_off( ms ); n->len = match_state_len( ms ); if ( n->bs != NULL ) { bitset_dispose( n->bs ); n->bs = NULL; } if ( match_state_bs(ms) != NULL ) n->bs = bitset_clone( match_state_bs(ms) ); if ( n->prev_bs != NULL ) { bitset_dispose( n->prev_bs ); n->prev_bs = NULL; } if ( match_state_prev_bs(ms) != NULL ) n->prev_bs = bitset_clone( match_state_prev_bs(ms) ); n->freq = 0; match_state_dispose( ms ); return 1; } }
/** * Make an exact deep copy of a match * @param mt the match to copy * @param log the log to report errors to * @return a copy of mt or NULL on failure */ match *match_copy( match *mt, plugin_log *log ) { match *mt2 = calloc( 1, sizeof(match) ); if ( mt2 != NULL ) { mt2->start = mt->start; mt2->end = mt->end; mt2->prev = mt->prev; if ( mt->prev_bs != NULL ) mt2->prev_bs = bitset_clone( mt->prev_bs ); if ( mt->bs != NULL ) mt2->bs = bitset_clone( mt->bs ); mt2->st_off = mt->st_off; //mt2->text_off = 0; mt2->text_off = mt->text_off; mt2->len = mt->len; mt2->maximal = mt->maximal; mt2->freq = mt->freq; mt2->cards = mt->cards; mt2->st = mt->st; if ( mt->next != NULL ) mt2->next = match_copy( mt->next, log ); if ( mt->queue != NULL ) mt2->queue = match_state_copy(mt->queue,log); mt2->loc = mt->loc; } else plugin_log_add( log, "match: failed to duplicate match object\n"); return mt2; }
/** * Add a card AFTER a node. c->right will be displaced by one * card. Although this will increase the node's overhang, the increase * is exactly that of the displaced card's versions, which will reattach * via the overhang, instead of the forced rule. * @param c the incoming pair of a node * @param after the card to add into lp's node. must intersect with lp. * @param verify if 1 then check that the resulting node is OK * @return 1 if the new node is a bona fide node */ int card_add_at_node( card *c, card *after, int verify ) { int res = 0; int dispose = 0; bitset *bs1 = pair_versions(c->p); if ( pair_is_hint(card_pair(c->right)) ) { bs1 = bitset_clone(bs1); if ( bs1 != NULL ) { c = c->right; dispose = 1; // bs1 is the amalgam of leading pair+hint bitset_or( bs1, pair_versions(c->p) ); } } if ( bs1 != NULL ) { after->right = c->right; after->left = c; if ( c->right != NULL ) c->right->left = after; c->right = after; res = (verify)?bitset_intersects(bs1,pair_versions(after->p)):1; if ( dispose ) bitset_dispose( bs1 ); } return res; }
/* Make an estimate of the total cost of determining the given condition * with the given set of still-needed variables. Return true on success, * and then also set soln_mincost with the cost of running all generators * and the condition, and set soln_generators (which must be allocated) * to the set of generators used to get to this point. * * This cost estimator assumes that vartab_analyse_cheapest_generators() * has already been run, and it only succeeds when all varsneeded have * a generator assigned to them (which should be caught out by that prior * phase, but it nonetheless returns an OK as a boolean). * * The soln_mincost represents the minimum cost estimation for setting up * all the variables. The soln_generators provides the generators that * need to run before the varsneeded have been generated, ordered by * ascending weight. The soln_generator_count provides the number of * entries filled into this table; the assumption made is that at least * as many entries are available as the number of elements in varsneeded. * Room up to this point may be overwritten by this routine, even if this * exceeds the impression given by a lower soln_generator_count. */ bool cnd_estimate_total_cost (struct cndtab *cctab, cndnum_t cndnum, bitset_t *varsneeded, float *soln_mincost, struct gentab *gentab, unsigned int *soln_generator_count, gennum_t soln_generators []) { bitset_iter_t v; bitset_t *vneeded; *soln_generator_count = 0; // // Find the cheapest generator for each of the varsneeded bitset_iterator_init (&v, varsneeded); while (bitset_iterator_next_one (&v, NULL)) { gennum_t unit_gen; bitset_t *genvars; unsigned int gi = bitset_iterator_bitnum (&v); // // The first step generates a list with the cheapest generators; // this could actually return an ordered _list_ of generators // and would cut off the most expensive ones when varsneeded // are generated as by-products in other generators. // This leads to more accurate estimates, and more efficiency. if (!var_get_cheapest_generator ( vartab_from_type (cctab->vartype), gi, &unit_gen, NULL)) { return false; } soln_generators [*soln_generator_count++] = unit_gen; } // // Now sort the soln_generators by their weight. // // This is a sort for optimisation purposes; if it returns an error, // then the cause is normally memory shortage, in which case the // lost efficiency here is less vital than other things going awry. QSORT_R(soln_generators, *soln_generator_count, sizeof (struct generator *), gentab, _qsort_gen_cmp_weight); // // From the sorted soln_generators list, subtract generated variables // from varsneeded until all are done. Cut off the output list at // that point by returning a possibly lower soln_generator_count. // //TODO// Might be able to skip generators that add nothing of interest *soln_generator_count = 0; *soln_mincost = cnd_get_weight (cctab, cndnum); vneeded = bitset_clone (varsneeded); while (!bitset_isempty (vneeded)) { gennum_t g = soln_generators [*soln_generator_count++]; *soln_mincost *= gen_get_weight (gentab, g); bitset_t *genvars = gen_share_variables (gentab, g); bitset_subtract (vneeded, genvars); } bitset_destroy (vneeded); return true; }
static void match_push_versions( match *m ) { if ( m->prev_bs != NULL ) { bitset_clear( m->prev_bs ); bitset_or( m->prev_bs, m->bs ); } else m->prev_bs = bitset_clone( m->bs ); }
/** * Compute the overlap between the versions of this card and another * @param c the current card * @param bs the versions of the other card that may overlap those in c * @return an allocated set of bits in bs that not in c, or NULL if none */ bitset *card_overlap( card *c, bitset *bs ) { bitset *overlap = NULL; bitset *p_versions = pair_versions( c->p ); if ( !bitset_equals(bs,p_versions) ) { overlap = bitset_clone( bs ); bitset_and_not( overlap, p_versions ); if ( bitset_empty(overlap) ) { bitset_dispose( overlap ); overlap = NULL; } } return overlap; }
/** * Create a hint object * @param versions the versions to clone * @return a finished hint or NULL */ hint *hint_create( bitset *versions, vgnode *n ) { hint *h = calloc( 1, sizeof(hint) ); if ( h != NULL ) { h->n = n; h->bs = bitset_clone( versions ); if ( h->bs == NULL ) { hint_dispose( h ); h = NULL; } } else fprintf(stderr,"hint: failed to crate object\n"); return h; }
/* Make an estimate of the total cost of determining the given condition * with the given set of still-needed variables. Return true on success, * and then also set soln_mincost with the cost of running all generators * and the condition, and set soln_generators (which must be allocated) * to the set of generators used to get to this point. */ bool DEPRECATED_cnd_estimate_total_cost (struct condition *cc, bitset_t *varsneeded, float *soln_mincost, bitset_t *soln_generators) { // // First, for all varsneeded, determine their cheapest generator // struct iter_var_gen ivg; ivg.okay = true; ivg.vartab = cc->vartab; ivg.total_cost = cc->weight; ivg.varneed = bitset_clone (varsneeded); ivg.generate = soln_generators; bitset_empty (ivg.generate); bitset_iterate (varsneeded, var_cheap_generator_it, &ivg); bitset_destroy (ivg.varneed); *soln_mincost = ivg.total_cost; return ivg.okay; }
/** * Complete a single match between the pairs list and the suffixtree * @param m the match all ready to go * @param text the text of the new version * @param v the new version id * @param log the log to save errors in * @return 1 if the match was at least 1 char long else 0 */ int match_single( match *m, UChar *text, int v, plugin_log *log, int popped ) { UChar c; // go to the deepest match if not the first one (as usual) while ( m->next != NULL ) m = m->next; pos *loc = &m->loc; // preserve popped location in suffix tree if ( !popped ) { loc->v = suffixtree_root( m->st ); loc->loc = node_start(loc->v)-1; m->maximal = 0; } do { UChar *data = pair_data(card_pair(m->end.current)); c = data[m->end.pos]; if ( suffixtree_advance_pos(m->st,loc,c) ) { if ( m->bs == NULL ) m->bs = bitset_clone( pair_versions(card_pair(m->end.current)) ); if ( !m->maximal && node_is_leaf(loc->v) ) { m->text_off = m->st_off + node_start(loc->v)-m->len; if ( !is_maximal(m,text) ) break; else m->maximal = 1; } // we are already matched, so increase length m->len++; if ( !match_advance(m,loc,v,log) ) break; } else break; } while ( 1 ); return m->maximal; }