/* 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; }
// this is slower, because each call needs to malloc, but it is reentrant float dselip(unsigned long k, unsigned long n, const float *arr) { float* sorted_data = malloc(sizeof(float) * n); memcpy(sorted_data, arr, sizeof(float)*n); QSORT_R(sorted_data, n, sizeof(float), NULL, compare_floats_asc_r); float kth_item = sorted_data[k]; free(sorted_data); return kth_item; }
int* permuted_sort(const void* realarray, int array_stride, int (*compare)(const void*, const void*), int* perm, int N) { permsort_t ps; if (!perm) perm = permutation_init(perm, N); ps.compare = compare; ps.data_array = realarray; ps.data_array_stride = array_stride; QSORT_R(perm, N, sizeof(int), &ps, compare_permuted); return perm; }
static void bl_sort_rec(bl* list, void* pivot, int (*compare)(const void* v1, const void* v2, void* userdata), void* userdata) { bl* less; bl* equal; bl* greater; int i; bl_node* node; // Empty case if (!list->head) return; // Base case: list with only one block. if (list->head == list->tail) { bl_node* node; struct funcandtoken ft; ft.compare = compare; ft.userdata = userdata; node = list->head; QSORT_R(NODE_DATA(node), node->N, list->datasize, &ft, qcompare); return; } less = bl_new(list->blocksize, list->datasize); equal = bl_new(list->blocksize, list->datasize); greater = bl_new(list->blocksize, list->datasize); for (node=list->head; node; node=node->next) { char* data = NODE_CHARDATA(node); for (i=0; i<node->N; i++) { int val = compare(data, pivot, userdata); if (val < 0) bl_append(less, data); else if (val > 0) bl_append(greater, data); else bl_append(equal, data); data += list->datasize; } } // recurse before freeing anything... bl_sort_with_userdata(less, compare, userdata); bl_sort_with_userdata(greater, compare, userdata); for (node=list->head; node;) { bl_node* next; next = node->next; bl_free_node(node); node = next; } list->head = NULL; list->tail = NULL; list->N = 0; list->last_access = NULL; list->last_access_n = 0; if (less->N) { list->head = less->head; list->tail = less->tail; list->N = less->N; } if (equal->N) { if (list->N) { list->tail->next = equal->head; list->tail = equal->tail; } else { list->head = equal->head; list->tail = equal->tail; } list->N += equal->N; } if (greater->N) { if (list->N) { list->tail->next = greater->head; list->tail = greater->tail; } else { list->head = greater->head; list->tail = greater->tail; } list->N += greater->N; } // note, these are supposed to be "free", not "bl_free"; we've stolen // the blocks, we're just freeing the headers. free(less); free(equal); free(greater); }
// solve vp problem using Permutation Pack or Choose Pack vp_solution_t solve_hvp_problem_MCB(vp_problem_t vp_prob, int args[], qsort_cmp_func *cmp_item_idxs, qsort_cmp_func *cmp_bin_idxs) { int i, j; int isCP = args[0]; int w = MIN(args[1], vp_prob->num_dims); int dims[vp_prob->num_dims]; int vector_dims[vp_prob->num_items][w]; int unmapped_vectors[vp_prob->num_items]; int num_unmapped_vectors = vp_prob->num_items; int b, v, best_v, best_v_idx, cmp_val; int bin_dim_ranks[vp_prob->num_dims]; int *v_perm, *best_perm, *tmp_perm; int bin_idxs[vp_prob->num_bins]; int *open_bins = bin_idxs; int num_open_bins = vp_prob->num_bins; vp_solution_t vp_soln = new_vp_solution(vp_prob); // initialize dims for (j = 0; j < vp_prob->num_dims; j++) dims[j] = j; // initialize unmapped vectors and vector dims for (i = 0; i < vp_prob->num_items; i++) { unmapped_vectors[i] = i; QSORT_R(dims, vp_prob->num_dims, sizeof(int), vp_prob->items[i]->totals, rcmp_double_array_idxs); for (j = 0; j < w; j++) vector_dims[i][j] = dims[j]; } // initialize open bins for (i = 0; i < vp_prob->num_bins; i++) open_bins[i] = i; if (cmp_bin_idxs) QSORT_R(open_bins, num_open_bins, sizeof(int), vp_prob->bins, cmp_bin_idxs); // initialize pointers to v_perm and best_perm v_perm = (int *)calloc(w, sizeof(int)); best_perm = (int *)calloc(w, sizeof(int)); while (num_open_bins > 0 && num_unmapped_vectors > 0) { b = *open_bins; best_v = -1; best_v_idx = -1; // Find the first vector that can be put in the bin for (i = 0; i < num_unmapped_vectors; i++) { v = unmapped_vectors[i]; if (vp_item_can_fit_in_bin(vp_soln, v, b)) { best_v = v; best_v_idx = i; break; } } // This probably over-complicates things, but check and make sure that // there are at least 2 vectors before doing all the PP/CP stuff for (i++; i < num_unmapped_vectors; i++) { v = unmapped_vectors[i]; if (vp_item_can_fit_in_bin(vp_soln, v, b)) { break; } } if (i < num_unmapped_vectors) { // compute bin permutation QSORT_R(dims, vp_prob->num_dims, sizeof(int), vp_soln->capacities[b], rcmp_double_array_idxs); // compute bin dim positions bin_dim_ranks[dims[0]] = 0; // make sure j > 0 j = 1; // CP treats first w positions as the same... if (isCP) for (; j < w; j++) bin_dim_ranks[dims[j]] = 0; // we assume j > 0 from above... for (; j < vp_prob->num_dims; j++) { if (vp_soln->capacities[b][dims[j-1]] == vp_soln->capacities[b][dims[j]]) { bin_dim_ranks[dims[j]] = bin_dim_ranks[dims[j-1]]; } else { bin_dim_ranks[dims[j]] = bin_dim_ranks[dims[j-1]]+1; } } // apply bin key inverse to best vector key to get how it permutes // the bin key in the first w elements... for (j = 0; j < w; j++) best_perm[j] = bin_dim_ranks[vector_dims[best_v][j]]; // CP ignores position if (isCP) qsort(best_perm, w, sizeof(int), cmp_ints); // start with the current vector and look for the "best" one by the // CP/PP and secondary criteria... for (; i < num_unmapped_vectors; i++) { v = unmapped_vectors[i]; if (!vp_item_can_fit_in_bin(vp_soln, v, b)) continue; // apply bin key inverse to vector keys to get how they permute // the bin key in the first w elements... for (j = 0; j < w; j++) v_perm[j] = bin_dim_ranks[vector_dims[v][j]]; // CP ignores position of the first w if (isCP) qsort(v_perm, w, sizeof(int), cmp_ints); cmp_val = cmp_int_arrays_lex(w, v_perm, best_perm); if (cmp_val < 0 || (0 == cmp_val && cmp_item_idxs && QSORT_CMP_CALL(cmp_item_idxs, vp_prob->items, &v, &best_v) < 0)) { best_v = v; best_v_idx = i; tmp_perm = best_perm; best_perm = v_perm; v_perm = tmp_perm; } } } // if we found a vector put it in the bin and delete from the list of // unmapped vectors -- otherwise advance to the next bin if (best_v > -1) { vp_put_item_in_bin(vp_soln, best_v, b); num_unmapped_vectors--; unmapped_vectors[best_v_idx] = unmapped_vectors[num_unmapped_vectors]; } else { open_bins++; num_open_bins--; } } free(v_perm); free(best_perm); if (!num_unmapped_vectors) return vp_soln; free_vp_solution(vp_soln); return NULL; }
vp_solution_t solve_hvp_problem_FITD(vp_problem_t vp_prob, int args[], qsort_cmp_func *cmp_item_idxs, qsort_cmp_func *cmp_bin_idxs) { int fit_type = args[0]; int i, j, k; int v, b; int item_sortmap[vp_prob->num_items]; int bin_sortmap[vp_prob->num_bins]; double sumcapacities[vp_prob->num_bins]; vp_solution_t vp_soln = new_vp_solution(vp_prob); // set up vector sort map for (i = 0; i < vp_prob->num_items; i++) item_sortmap[i] = i; if (cmp_item_idxs) QSORT_R(item_sortmap, vp_prob->num_items, sizeof(int), vp_prob->items, cmp_item_idxs); // set up bin sort map for (j = 0; j < vp_prob->num_bins; j++) bin_sortmap[j] = j; if (cmp_bin_idxs) QSORT_R(bin_sortmap, vp_prob->num_bins, sizeof(int), vp_prob->bins, cmp_bin_idxs); // Place vectors into bins switch(fit_type) { case FIRST_FIT: for (i = 0; i < vp_prob->num_items; i++) { v = item_sortmap[i]; for (j = 0; j < vp_prob->num_bins; j++) { b = bin_sortmap[j]; if (!vp_put_item_in_bin_safe(vp_soln, v, b)) break; } if (j >= vp_prob->num_bins) { free_vp_solution(vp_soln); return NULL; } } break; case BEST_FIT: for (i = 0; i < vp_prob->num_items; i++) { v = item_sortmap[i]; for (j = 0; j < vp_prob->num_bins; j++) { b = bin_sortmap[j]; if (vp_item_can_fit_in_bin(vp_soln, v, b)) { sumcapacities[b] = 0.0; for (k = 0; k < vp_prob->num_dims; k++) { sumcapacities[b] += vp_soln->capacities[b][k]; } } else { sumcapacities[b] = 2.0 * vp_prob->num_dims + 1.0; } } b = double_array_argmin(sumcapacities, vp_prob->num_bins); if (sumcapacities[j] > 2.0 * vp_prob->num_dims || vp_put_item_in_bin_safe(vp_soln, v, b)) { free_vp_solution(vp_soln); return NULL; } } break; default: fprintf(stderr,"Invalid VP fit type '%d'\n", fit_type); exit(1); } return vp_soln; }
// solve vp problem using Permutation Pack or Choose Pack vp_solution_t solve_hvp_problem_MinCD(vp_problem_t vp_prob, int args[], qsort_cmp_func *cmp_item_idxs, qsort_cmp_func *cmp_bin_idxs) { int i, j; int unmapped_vectors[vp_prob->num_items]; int num_unmapped_vectors = vp_prob->num_items; int b, v, best_v, best_v_idx; double best_val, val; int bin_idxs[vp_prob->num_bins]; int *open_bins = bin_idxs; int num_open_bins = vp_prob->num_bins; vp_solution_t vp_soln = new_vp_solution(vp_prob); // initialize unmapped vectors and vector dims for (i = 0; i < vp_prob->num_items; i++) unmapped_vectors[i] = i; // initialize open bins for (i = 0; i < vp_prob->num_bins; i++) open_bins[i] = i; if (cmp_bin_idxs) QSORT_R(open_bins, num_open_bins, sizeof(int), vp_prob->bins, cmp_bin_idxs); while (num_open_bins > 0 && num_unmapped_vectors > 0) { b = *open_bins; best_v = -1; best_v_idx = -1; // Find the first vector that can be put in the bin for (i = 0; i < num_unmapped_vectors; i++) { v = unmapped_vectors[i]; if (vp_item_can_fit_in_bin(vp_soln, v, b)) { best_v = v; best_v_idx = i; best_val = pairwise_distance(vp_soln, b, v); break; } } for (i++; i < num_unmapped_vectors; i++) { v = unmapped_vectors[i]; if (!vp_item_can_fit_in_bin(vp_soln, v, b)) continue; val = pairwise_distance(vp_soln, b, v); // FIXME: pick the one that minimizes pairwise distance... if (val < best_val || (val == best_val && cmp_item_idxs && QSORT_CMP_CALL(cmp_item_idxs, vp_prob->items, &v, &best_v) < 0)) { best_v = v; best_v_idx = i; best_val = val; } } // if we found a vector put it in the bin and delete from the list of // unmapped vectors -- otherwise advance to the next bin if (best_v > -1) { vp_put_item_in_bin(vp_soln, best_v, b); num_unmapped_vectors--; unmapped_vectors[best_v_idx] = unmapped_vectors[num_unmapped_vectors]; } else { open_bins++; num_open_bins--; } } if (!num_unmapped_vectors) return vp_soln; free_vp_solution(vp_soln); return NULL; }