/** * 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; }
/* 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; }
/** * Remove some versions from the hint * @param h the hint in question * @param other the other set of versions to eliminate where they intersect * @return 1 if the hint is now empty, else 0 */ int hint_subtract( hint *h, bitset *other ) { bitset_and_not( h->bs, other ); return bitset_empty( h->bs ); }
/* This is a complex, recursive function to determine the cost for * calculating a condition after any still-needed variables have been * generated. Cost is measured in terms of the anticipated number of * generated new variable sets, as provided by "*float" annotations * on generator and condition lines. * * Call this with a condition and varsneeded. The soln_xxx fields will * be filled with the requested information, namely the total cost * and the generators needed to get there. The soln_generators bitset * is assumed to already exist. * * This function may not always be able to determine a solution; this * can be the case if variables are mentioned in conditions but not in * generators, for instance. In such situations, the function returns * false. It is considered a success if all variables that are needed * for a condition are resolved by at least one generator. * * This is an important function when determining the "path of least * resistence" from any generator activity; the least costly condition * will always be calculated first, then the calculations are redone, * and what is then the least will be selected, and so on. The * generators required will be inserted into the path before their * dependent conditions, in the order of least-costly ones first. * * This is a rather heavy form of analysis, but it is executed only * once, at startup of the environment. After that, the SyncRepl * updates can ripple through in great speed. Note that the complexity * and time delays of these procedures rise with the (usually modest) * degree of interrelationships between generators and conditions. */ bool cnd_get_min_total_cost (struct condition *cc, bitset_t *varsneeded, float *soln_mincost, bitset_t *soln_generators) { bool have_soln = false; float soln_mincost; varnum_t v, v_max; gennum_t g, g_max; // // Allocate bitsets that will be used while cycling, but not // across recursive uses. To that and, a pile or pool of // bitsets could come in handy... TODO: Optimisation // bitset_t *cand_varsneeded = bitset_new (varsneeded->type); bitset_t *cand_generators = bitset_new (soln_generators->type); // // If there is no need for further variables to calculate this // condition, then terminate recursion on this function. There // will be no requirement to include a generator, and so there // will be no generator-incurred expenses. There will only be // the cost of the condition itself, which must still compare // with other conditions that might be tighter. // if (bitset_isempty (varsneeded)) { /* Recursion ends, so neither generators nor their cost */ bitset_empty (out_generators); return cc->cost; } // // Iterate over the variables that will need to be generated. // For each, iterate over the generators producing it. // See how this reduces the variable need, and recurse. // v_max = bitset_max (varsneeded); for (v=0; v<v_max; v++) { // // Skip this loop iteration if v is not actually needed. // if (!bitset_test (varsneeded, v)) { continue; } // // Iterate over generators for this variable. // Note that there may be none left? // bitset_t *vargenerators; vargenerators = var_share_generators (cc->vartab, v); g_max = bitset_max (vargenerators); if (g_max = BITNUM_BAD) { // Apparently, there are no generators for v // Skip for-loop (and trouble looping to BITNUM_BAD). continue; } for (g=0; g<g_max; g++) { bitset_t *cand_generators = NULL; bitset_t *generatorvars; float cand_cost; // // Reduce the variable need. // cand_varsneeded = bitset_copy (varsneeded); generatorvars = gen_share_variables (v); bitset_subtract (cand_varsneeded, generatorvars); // // Determine the cost for generating the remainder. // if (!cnd_get_cost_total ( cc, cand_varsneeded, &cand_cost, cand_generators)) { continue; } cand_mincost *= generator_cost (g); if (have_soln && (cand_cost > soln_mincost)) { continue; } tmp_generators = soln_generators; soln_generators = cand_generators; cand_generators = tmp_generators; // Reuse in loops bitset_set (soln_generators, g); soln_mincost = cand_mincost; have_soln = true; } } // // Cleanup temporary allocations. // bitset_destroy (cand_varsneeded); bitset_destroy (cand_generators); // // Collect results. Return success only if we do indeed have // found a solution. // return have_soln; }