static int process_habit(DictionaryIterator *iter, struct NetworkState *state) { int rval = 0; struct NetworkCallbacks *callbacks = state->callbacks; Tuple *tuple = dict_find(iter, 1); abort_if(!tuple, "tuple is null"); int id = tuple->value->int32; tuple = dict_find(iter, 2); abort_if(!tuple, "tuple is null"); char *name = tuple->value->cstring; tuple = dict_find(iter, 3); abort_if(!tuple, "tuple is null"); int checkmark = tuple->value->int32; if(callbacks->on_habit) { void *ctx = callbacks->on_habit_context; rval = callbacks->on_habit(id, name, checkmark, ctx); abort_if(rval, "state->on_habit failed"); rval = request_next_habit(state); abort_if(rval, "request_next_habit failed"); } CLEANUP: return rval; }
static void NETWORK_on_received(DictionaryIterator *iter, void *context) { int rval = 0; struct NetworkState *state = context; abort_if(!state, "state is null"); Tuple *tuple = dict_find(iter, 0); abort_if(!tuple, "tuple is null"); char *action = tuple->value->cstring; log_debug("<-- %s", action); if(strcmp(action, "COUNT") == 0) { rval = process_count(iter, state); abort_if(rval, "process_count failed"); } else if(strcmp(action, "HABIT") == 0) { rval = process_habit(iter, state); abort_if(rval, "process_habit failed"); } else if(strcmp(action, "OK") == 0) { rval = process_ok(state); abort_if(rval, "process_ok failed"); } CLEANUP: return; }
int NETWORK_register() { int rval = 0; struct NetworkState *state = 0; state = (struct NetworkState*) malloc(sizeof(struct NetworkState)); abort_if(!state, "could not allocate state"); struct NetworkCallbacks *callbacks = 0; callbacks = (struct NetworkCallbacks*) malloc(sizeof(struct NetworkCallbacks)); abort_if(!callbacks, "could not allocate callbacks"); state->callbacks = callbacks; callbacks->on_ok = 0; callbacks->on_habit = 0; callbacks->on_count = 0; callbacks->on_ok_context = 0; callbacks->on_habit_context = 0; callbacks->on_count_context = 0; app_message_register_inbox_received(NETWORK_on_received); app_message_open(1024, 1024); app_message_set_context(state); CLEANUP: return rval; }
static int request_next_habit(struct NetworkState *state) { int rval = 0; abort_if(!state, "state is null"); if(state->habit_current >= state->habit_count) goto CLEANUP; DictionaryIterator *dict; rval = app_message_outbox_begin(&dict); abort_if(rval, "app_message_outbox_begin failed"); rval = dict_write_cstring(dict, 0, "FETCH"); abort_if(rval, "dict_write_cstring failed"); rval = dict_write_int32(dict, 1, state->habit_current); abort_if(rval, "dict_write_cstring failed"); rval = app_message_outbox_send(); abort_if(rval, "app_message_outbox_send failed"); state->habit_current++; CLEANUP: return rval; }
static int process_count(DictionaryIterator *iter, struct NetworkState *state) { int rval = 0; abort_if(!state, "state is null"); struct NetworkCallbacks *callbacks = state->callbacks; Tuple *tuple = dict_find(iter, 1); abort_if(!tuple, "tuple is null"); int count = tuple->value->int32; if(callbacks->on_count) { rval = callbacks->on_count(count, callbacks->on_count_context); abort_if(rval, "state->on_count failed"); } if(count > MAX_HABIT_COUNT) count = MAX_HABIT_COUNT; state->habit_count = count; state->habit_current = 0; rval = request_next_habit(state); abort_if(rval, "request_next_habit failed"); CLEANUP: return rval; }
int benchmark_set(int algorithm, int set_idx, const struct LFreeSet2D *set, const double *rays, const double *pre_m, const double center, int *wrong_answer) { int rval = 0; int lb[2], ub[2]; if(algorithm == ALGORITHM_NAIVE) { if (USE_FIXED_BOUNDS) { ub[0] = ub[1] = NAIVE_BIG_M; lb[0] = lb[1] = -NAIVE_BIG_M; } else { rval = LFREE_2D_get_bounding_box(set, lb, ub); abort_if(rval, "LFREE_2D_get_bounding_box failed"); ub[0] += BOUNDING_BOX_PADDING; ub[1] += BOUNDING_BOX_PADDING; lb[0] -= BOUNDING_BOX_PADDING; lb[0] -= BOUNDING_BOX_PADDING; } ub[0] = fmin(ub[0], MAX_BOX_SIZE); ub[1] = fmin(ub[1], MAX_BOX_SIZE); lb[0] = fmax(lb[0], -MAX_BOX_SIZE); lb[1] = fmax(lb[1], -MAX_BOX_SIZE); if(ub[0] == MAX_BOX_SIZE || ub[1] == MAX_BOX_SIZE || lb[0] == -MAX_BOX_SIZE || lb[1] == -MAX_BOX_SIZE) { log_info(" bounding box has been clipped\n"); } } for (int k = 0; k < N_SAMPLES_PER_SET; k ++) { rval = benchmark_set_sample(algorithm, set_idx, set, rays, pre_m, center, lb, ub, k, wrong_answer); abort_if(rval, "benchmark_set_sample failed"); } CLEANUP: return rval; }
int benchmark(int n_sets, struct LFreeSet2D *sets, double *rays, int algorithm) { int rval = 0; log_info("Running benchmark...\n"); double total_initial_time = get_user_time(); stats_printf("cpu_time:\n"); for (int j = 0; j < n_sets; j++) { log_debug("Set %d...\n", j); double set_initial_time = get_user_time(); struct LFreeSet2D *set = &sets[j]; double *pre_m = &PRE_M[j * 4]; double center = CENTER[j]; rval = LFREE_2D_print_set(set); abort_if(rval, "LFREE_2D_print_set failed"); int wrong_answer = 0; rval = benchmark_set(algorithm, j, set, rays, pre_m, center, &wrong_answer); abort_if(rval, "benchmark_set failed"); double set_duration = get_user_time() - set_initial_time; double avg = (set_duration / N_SAMPLES_PER_SET) * 1000; if(wrong_answer) avg = 1000000; stats_printf(" %d: %.8lf\n", j, avg); log_info(" %3d: %12.3lf ms\n", j, avg); } double total_duration = get_user_time() - total_initial_time; log_info(" %.3lf ms per set \n", total_duration / (n_sets * N_SAMPLES_PER_SET) * 1000); if(algorithm == ALGORITHM_MIP) { log_info(" %.3lf s spent on LP_create\n", MIP_TIME_CREATE); log_info(" %.3lf s spent on LP_optimize\n", MIP_TIME_OPTIMIZE); } CLEANUP: return rval; }
int benchmark_set(int algorithm, int set_idx, const struct LFreeSet2D *set, const double *rays, const double *pre_m, const double center, int *wrong_answer) { int rval = 0; int lb[2], ub[2]; if(algorithm == ALGORITHM_NAIVE) { if (USE_FIXED_BOUNDS) { ub[0] = ub[1] = NAIVE_BIG_M; lb[0] = lb[1] = -NAIVE_BIG_M; } else { rval = LFREE_2D_get_bounding_box(set, lb, ub); abort_if(rval, "LFREE_2D_get_bounding_box failed"); ub[0] += BOUNDING_BOX_PADDING; ub[1] += BOUNDING_BOX_PADDING; lb[0] -= BOUNDING_BOX_PADDING; lb[0] -= BOUNDING_BOX_PADDING; } int dx = ub[0] - lb[0]; int dy = ub[1] - lb[1]; if(dx >= MAX_BOX_SIZE && dy >= MAX_BOX_SIZE) { log_info(" bounding box is too large: %d by %d\n", dx, dy); *wrong_answer = 1; goto CLEANUP; } } for (int k = 0; k < N_SAMPLES_PER_SET; k ++) { rval = benchmark_set_sample(algorithm, set_idx, set, rays, pre_m, center, lb, ub, k, wrong_answer); abort_if(rval, "benchmark_set_sample failed"); } CLEANUP: return rval; }
static int process_ok(struct NetworkState *state) { int rval = 0; abort_if(!state, "state is null"); struct NetworkCallbacks *callbacks = state->callbacks; abort_if(!callbacks, "callbacks is null"); if(!callbacks->on_ok) goto CLEANUP; rval = callbacks->on_ok(callbacks->on_ok_context); abort_if(rval, "state->on_ok failed"); CLEANUP: return rval; }
int static mark_reachable_nodes( const struct Graph *graph, double *residual_caps, struct Node *from) { int rval = 0; struct Node **stack; int stack_top = 0; int *parents = 0; stack = (struct Node **) malloc(graph->node_count * sizeof(struct Node *)); abort_if(!stack, "could not allocate stack"); parents = (int *) malloc(graph->node_count * sizeof(int)); abort_if(!parents, "could not allocate parents"); stack[stack_top++] = from; from->mark = 1; while (stack_top > 0) { struct Node *n = stack[--stack_top]; for (int j = 0; j < n->degree; j++) { struct Edge *e = n->adj[j].edge; struct Node *neighbor = n->adj[j].neighbor; if (neighbor->mark) continue; if (residual_caps[e->index] <= 0) continue; stack[stack_top++] = neighbor; neighbor->mark = 1; parents[neighbor->index] = n->index; } } log_verbose("Reachable nodes:\n"); for (int i = 0; i < graph->node_count; i++) if (graph->nodes[i].mark) log_verbose(" %d from %d\n", graph->nodes[i].index, parents[i]); CLEANUP: if (parents) free(parents); if (stack) free(stack); return rval; }
static int check_short (model_t model, int group, int *src, TransitionCB cb, void *context) { abort_if (true, "Checking layer designed for algorithms using PINS long/all calls"); (void) model; (void) group; (void) src; (void) cb; (void) context; return 0; }
int NETWORK_request_list() { int rval = 0; DictionaryIterator *dict; rval = app_message_outbox_begin(&dict); abort_if(rval, "app_message_outbox_begin failed"); rval = dict_write_cstring(dict, 0, "COUNT"); abort_if(rval, "dict_write_cstring failed"); rval = app_message_outbox_send(); abort_if(rval, "app_message_outbox_send failed"); log_debug("--> %s", "COUNT"); CLEANUP: return rval; }
static void find_culprit_slot (check_ctx_t *ctx, int g) { int count; for (int i = 0; i < ctx->N; i++) { while (ctx->src2[i] == ctx->src[i]) { i++; abort_if (i >= ctx->N, "No-deterministic GBnextLong for group %d", g); } ctx->src2[i] = ctx->src[i]; // fill // retry with src2 more similar to src: ctx->idx = i; ctx->call_idx = 0; ctx->comparison_failed = false; count = GBgetTransitionsLong (ctx->parent, g, ctx->src2, find, ctx); abort_if (count != ctx->call_idx , "Wrong count returned by GBnextLong(compare): %d (Found: %d).", count, ctx->call_idx); } HREassert (false); }
int LIFTING_2D_lift_fixed(int n_halfspaces, const double *halfspaces, const double *ray, double k1, double *opt) { int rval = 0; double k0; double value; rval = LIFTING_2D_optimize_continuous(n_halfspaces, halfspaces, ray[1] + k1, &k0, &value); abort_if(rval, "LIFTING_2D_optimize_continuous failed"); double delta = k0 - ray[0]; double r_ceil[2] = { ray[0] + ceil(delta), ray[1] + k1 }; double r_floor[2] = { ray[0] + floor(delta), ray[1] + k1 }; log_debug(" delta=%.6lf value=%.6lf\n", delta, value); log_debug(" r_ceil=%12.6lf %12.6lf\n", r_ceil[0], r_ceil[1]); log_debug(" r_floor=%12.6lf %12.6lf\n", r_floor[0], r_floor[1]); double value_ceil, value_floor; rval = LIFTING_2D_psi(n_halfspaces, halfspaces, r_ceil, &value_ceil); abort_if(rval, "LIFTING_2D_psi failed"); rval = LIFTING_2D_psi(n_halfspaces, halfspaces, r_floor, &value_floor); abort_if(rval, "LIFTING_2D_psi failed"); *opt = min(value_ceil, value_floor); CLEANUP: return rval; }
static int check_long (model_t model, int g, int *src, TransitionCB cb, void *context) { check_ctx_t *ctx = GBgetContext (model); int count; int found; // collect ctx->src = src; ctx->group = g; ctx->user_cb = cb; ctx->user_ctx = context; ci_clear (ctx->check_must); isba_discard_int (ctx->stack, isba_size_int(ctx->stack)); HREassert (!ctx->reentrent, "INTERFACE ERROR: GBgetTransitions* is not re-entrant"); ctx->reentrent = 1; count = GBgetTransitionsLong (ctx->parent, g, src, collect, ctx); ctx->reentrent = 0; found = isba_size_int(ctx->stack); abort_if (count != found, "Wrong count returned by GBnextLong(collect): %d (Found: %d).", count, found); // compare ctx->src2 = copy_vec (ctx, g, src); ctx->comparison_failed = false; ctx->call_idx = 0; count = GBgetTransitionsLong (ctx->parent, g, ctx->src2, compare, ctx); abort_if (count != ctx->call_idx , "Wrong count returned by GBnextLong(compare): %d (Found: %d).", count, ctx->call_idx ); if (ctx->call_idx != found || ctx->comparison_failed) { find_culprit_slot (ctx, g); } return count; }
TEST(Greedy2DTest, test_compute_bounds_3) { int rval = 0; double bounds[100]; double f[] = {5 / 22.0, 0.0}; double rays[] = {-1 / 22.0, 0.0, 0.0, 1 / 18.0, 1 / 22.0, 0.0}; rval = GREEDY_2D_compute_bounds(rays, 3, f, bounds); abort_if(rval, "GREEDY_2D_compute_bounds failed"); EXPECT_NEAR(5.0, bounds[0], BOUNDS_EPSILON); EXPECT_NEAR(17.0, bounds[2], BOUNDS_EPSILON); EXPECT_EQ(GREEDY_BIG_E, bounds[1]); CLEANUP: if (rval) FAIL(); }
TEST(Greedy2DTest, test_compute_bounds_2) { int rval = 0; double bounds[100]; double f[] = {1 / 2.0, 1 / 2.0}; double rays[] = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 0.0}; rval = GREEDY_2D_compute_bounds(rays, 5, f, bounds); abort_if(rval, "GREEDY_2D_compute_bounds failed"); EXPECT_NEAR(0.5, bounds[0], BOUNDS_EPSILON); EXPECT_NEAR(0.5, bounds[1], BOUNDS_EPSILON); EXPECT_NEAR(0.5, bounds[2], BOUNDS_EPSILON); EXPECT_NEAR(0.5, bounds[3], BOUNDS_EPSILON); EXPECT_EQ(GREEDY_BIG_E, bounds[4]); CLEANUP: if (rval) FAIL(); }
TEST(Greedy2DTest, test_compute_bounds_1) { int rval = 0; double bounds[100]; double f[] = {1 / 4.0, 3 / 4.0}; double rays[] = {-2 / 5.0, 5 / 7.0, 0.0, 1.0, 1.0, 1.0, 4 / 5.0, -2 / 3.0, -1.0, 0.0}; rval = GREEDY_2D_compute_bounds(rays, 5, f, bounds); abort_if(rval, "GREEDY_2D_compute_bounds failed"); EXPECT_NEAR(23 / 50.0, bounds[0], BOUNDS_EPSILON); EXPECT_NEAR(23 / 42.0, bounds[1], BOUNDS_EPSILON); EXPECT_NEAR(9 / 11.0, bounds[2], BOUNDS_EPSILON); EXPECT_NEAR(9 / 11.0, bounds[3], BOUNDS_EPSILON); EXPECT_NEAR(23 / 50.0, bounds[4], BOUNDS_EPSILON); CLEANUP: if (rval) FAIL(); }
static void find (void *context, transition_info_t *ti, int *dst2, int *cpy) { check_ctx_t *ctx = (check_ctx_t *) context; abort_if (ti->group != ctx->group, "Transition info does not return correct group for group %d (found: %d)", ctx->group, ti->group); int *dst = isba_index (ctx->stack, ctx->call_idx++); int idx = find_diff (ctx, dst, dst2); ctx->comparison_failed |= ( idx != ctx->N ); int found = isba_size_int(ctx->stack); if (!ctx->comparison_failed && found == ctx->call_idx) { report ("Read dependency missing", ctx, ctx->group, ctx->idx, ctx->src2, ti); } (void) cpy; }
int LIFTING_2D_naive(int n_halfspaces, const double *halfspaces, const double *ray, const int *lb, const int *ub, double *value) { int rval = 0; *value = INFINITY; int best_k0 = 0; int best_k1 = 0; int margin = 10; for(int k0 = lb[0] - margin; k0 <= ub[0] + margin; k0++) { for(int k1 = lb[1] - margin; k1 <= ub[1] + margin; k1++) { double q[2] = { ray[0] + k0, ray[1] + k1 }; double value_q; rval = LIFTING_2D_psi(n_halfspaces, halfspaces, q, &value_q); abort_if(rval, "LIFTING_2D_ps failed"); if(value_q < *value) { best_k0 = k0; best_k1 = k1; *value = value_q; log_debug(" k=%6d %6d value=%12.6lf\n", k0, k1, *value); } } } // log_debug(" best_k=(%d %d) value=%.6lf\n", best_k0, best_k1, *value); CLEANUP: return rval; }
int RANDOMIZER_generate_triangle(double *f, double *vertices, double *lattice_points) { int rval = 0; srand((unsigned int) time(0)); f[0] = DOUBLE_random(0.0, 1.0); f[1] = DOUBLE_random(0.0, 1.0); double rays[6] = { DOUBLE_random(0, 1000.0), DOUBLE_random(0, 1000.0), DOUBLE_random(-1000.0, 0), DOUBLE_random(0, 1000.0), 0, DOUBLE_random(-1000.0, 0) }; log_verbose("r1=%12.8lf %12.8lf\n", rays[0], rays[1]); log_verbose("r2=%12.8lf %12.8lf\n", rays[2], rays[3]); log_verbose("r3=%12.8lf %12.8lf\n", rays[4], rays[5]); double bounds[6]; rval = GREEDY_2D_compute_bounds(rays, 3, f, bounds); abort_if(rval, "GREEDY_2D_compute_bounds failed"); for (int i = 0; i < 3; i++) { double *v = &vertices[2 * i]; double *r = &rays[2 * i]; v[0] = bounds[i] * r[0] + f[0]; v[1] = bounds[i] * r[1] + f[1]; } CLEANUP: return rval; }
static void compare (void *context, transition_info_t *ti, int *dst2, int *cpy) { check_ctx_t *ctx = (check_ctx_t *) context; abort_if (ti->group != ctx->group, "Transition info does not return correct group for group %d (found: %d)", ctx->group, ti->group); int *dst = isba_index (ctx->stack, ctx->call_idx++); int idx = find_diff (ctx, dst, dst2); ctx->comparison_failed |= ( idx != ctx->N ); if (ctx->comparison_failed && isba_size_int(ctx->stack) == (size_t)ctx->call_idx) { dbg_found_read_dep_error (ctx, dst, dst2, idx); } for (int *i = ci_begin (ctx->check_must); i != ci_end (ctx->check_must); i++) { if (ctx->src2[*i] != ctx->src[*i] && dst2[*i] == ctx->src2[*i]) { report ("Must write dependency violated", ctx, ctx->group, *i, ctx->src, ti); } } (void) cpy; }
static void collect (void *context, transition_info_t *ti, int *dst, int *cpy) { check_ctx_t *ctx = (check_ctx_t *) context; abort_if (ti->group != ctx->group, "Transition info does not return correct group for group %d (found: %d)", ctx->group, ti->group); for (int i = 0; i < ctx->N; i++) { if (!dm_is_set(ctx->may, ctx->group, i) && ctx->src[i] != dst[i]) { report("May write dependency missing", ctx, ctx->group, i, dst, ti); } } ctx->user_cb (ctx->user_ctx, ti, dst, cpy); ci_list *row = ctx->must[ctx->group]; for (int *i = ci_begin (row); i != ci_end (row); i++) { if (dst[*i] == ctx->src[*i]) ci_add (ctx->check_must, *i); } // in second round we recheck isba_push_int (ctx->stack, dst); }
static int parse_args(int argc, char **argv) { int rval = 0; opterr = 0; while (1) { int c = 0; int option_index = 0; c = getopt_long(argc, argv, "hb:k:s:f:o:nupew:c:a:m", options_tab, &option_index); if (c < 0) break; switch (c) { case 'l': strcpy(LOG_FILENAME, optarg); break; case 's': { int count = sscanf(optarg, "%u", &SEED); abort_if(count != 1, "invalid seed"); break; } case 'a': { int count = sscanf(optarg, "%d", &N_SAMPLES_PER_SET); abort_if(count != 1, "invalid number of samples"); abort_if(N_SAMPLES_PER_SET <= 0, "invalid number of samples"); break; } case 'f': { USE_FIXED_BOUNDS = 1; int count = sscanf(optarg, "%d", &NAIVE_BIG_M); abort_if(count != 1, "invalid fixed bound"); break; } case 'o': strcpy(STATS_FILENAME, optarg); break; case 'b': strcpy(SETS_FILENAME, optarg); break; case 'w': strcpy(ANSWERS_FILENAME, optarg); WRITE_ANSWERS = 1; break; case 'c': strcpy(ANSWERS_FILENAME, optarg); CHECK_ANSWERS = 1; break; case 'n': SELECT_NAIVE_ALGORITHM = 1; break; case 'm': SELECT_MIP_ALGORITHM = 1; break; case 'u': SELECT_BOUND_ALGORITHM = 1; break; case 'p': ENABLE_PREPROCESSING = 1; break; case 'e': ENABLE_SHEAR = 1; break; case 'h': print_usage(argv); exit(0); case ':': fprintf(stderr, "%s: option '-%c' requires an argument\n", argv[0], optopt); rval = 1; goto CLEANUP; case '?': default: fprintf(stderr, "%s: option '-%c' is invalid\n", argv[0], optopt); rval = 1; goto CLEANUP; } } if ((strlen(SETS_FILENAME) == 0)) { fprintf(stderr, "You must specify a file containing the lattice-free " "sets.\n"); rval = 1; } if (SELECT_NAIVE_ALGORITHM + SELECT_BOUND_ALGORITHM + SELECT_MIP_ALGORITHM != 1) { fprintf(stderr, "You must select exactly one algorithm.\n"); rval = 1; } if (CHECK_ANSWERS + WRITE_ANSWERS > 1) { fprintf(stderr, "Cannot write and check answers at same time.\n"); rval = 1; } CLEANUP: if (rval) fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return rval; }
int benchmark_set_sample(int algorithm, int set_idx, const struct LFreeSet2D *set, const double *rays, const double *pre_m, const double center, int *lb, int *ub, int current_sample, int *wrong_answer) { int rval = 0; for (int i = 0; i < N_RAYS; i++) { double ray[2] = { rays[2 * i], rays[2 * i + 1] }; double value; if(ENABLE_PREPROCESSING) { double r0 = ray[0], r1 = ray[1]; ray[0] = pre_m[0] * r0 + pre_m[2] * r1; ray[1] = pre_m[1] * r0 + pre_m[3] * r1; ray[0] = ray[0] - floor(set->f[0] + ray[0]); ray[1] = ray[1] + floor(center + 0.5 - set->f[1] - ray[1]); } log_debug(" Ray %d (%.6lf,%.6lf)...\n", i, ray[0], ray[1]); switch (algorithm) { case ALGORITHM_BOUND: rval = LIFTING_2D_bound(set->n_halfspaces, set->halfspaces, ray, &value); abort_if(rval, "LIFTING_2D_bound failed"); break; case ALGORITHM_NAIVE: rval = LIFTING_2D_naive(set->n_halfspaces, set->halfspaces, ray, lb, ub, &value); abort_if(rval, "LIFTING_2D_naive failed"); break; case ALGORITHM_MIP: rval = LIFTING_2D_mip(set->n_halfspaces, set->halfspaces, ray, &value); abort_if(rval, "LIFTING_2D_mip failed"); break; default: abort_if(1, "Invalid algorithm"); } if(current_sample == 0) { if(WRITE_ANSWERS) { abort_iff(!DOUBLE_geq(value, 0), "value should be non-negative (%.8lf)", value); fprintf(ANSWERS_FILE, "%d %d %.20lf\n", set_idx, i, value); } if(CHECK_ANSWERS) { int count; int expected_set_idx, expected_i; double expected_value; while(1) { count = fscanf(ANSWERS_FILE, "%d %d %lf ", &expected_set_idx, &expected_i, &expected_value); abort_if(count != 3, "error reading answer"); if(set_idx == expected_set_idx && i == expected_i) break; } double delta = fabs(value - expected_value); if(delta > 1e-3) { log_warn(" wrong answer (set=%d ray=%d answer=%.8lf" " expected=%.8lf delta=%.8lf)\n", set_idx, i, value, expected_value, delta); *wrong_answer = 1; LFREE_2D_print_set(set); } } log_verbose(" %4d %12.8lf\n", j, value); } } CLEANUP: return rval; }
int create_greedy_lp(int nrows, int nrays, const double *f, const double *rays, const double *bounds, double e, struct LP *lp) { int rval = 0; double rhs; char sense; int rmatbeg = 0; int* rmatind = 0; double *rmatval = 0; rmatind = (int *) malloc((nrows + nrays) * sizeof(int)); rmatval = (double *) malloc((nrows + nrays) * sizeof(double)); abort_if(!rmatind, "could not allocate rmatind"); abort_if(!rmatval, "could not allocate rmatval"); rval = LP_create(lp, "greedy"); abort_if(rval, "LP_create failed"); // create x (basic) variables for (int i = 0; i < nrows; i++) { rval = LP_new_col(lp, 0, -MILP_INFINITY, MILP_INFINITY, 'I'); abort_if(rval, "LP_new_col failed"); } // create s (non-basic) variables for (int i = 0; i < nrays; i++) { rval = LP_new_col(lp, 1.0, 0, MILP_INFINITY, 'C'); abort_if(rval, "LP_new_col failed"); } // add constraint \sum_{i=1}^m s_i \leq 1 sense = 'L'; rhs = 1.0; for (int i = 0; i < nrays; i++) { rmatind[i] = i + nrows; rmatval[i] = 1.0; } rval = LP_add_rows(lp, 1, nrays, &rhs, &sense, &rmatbeg, rmatind, rmatval); abort_if(rval, "LP_add_rows failed"); // add constraints x_i - \sum_{j=1}^m min{e,e_j} s_j R_ji = f_i for (int i = 0; i < nrows; i++) { int k = 0; sense = 'E'; rhs = f[i]; rmatind[k] = i; rmatval[k] = 1.0; k++; for (int j = 0; j < nrays; j++) { rmatind[k] = j + nrows; rmatval[k] = -rays[nrows * j + i] * fmin(e, bounds[j]); k++; } rval = LP_add_rows(lp, 1, nrays + 1, &rhs, &sense, &rmatbeg, rmatind, rmatval); abort_if(rval, "LP_add_rows failed"); } CLEANUP: if (rmatind) free(rmatind); if (rmatval) free(rmatval); return rval; }
int static find_augmenting_path( const struct Graph *graph, const double *residual_caps, struct Node *from, struct Node *to, int *path_length, struct Edge **path_edges, double *path_capacity) { int rval = 0; struct Node **queue = 0; int queue_start = 0; int queue_end = 0; struct Node **parents = 0; struct Edge **parent_edges = 0; int node_count = graph->node_count; queue = (struct Node **) malloc(node_count * sizeof(struct Node *)); parents = (struct Node **) malloc(node_count * sizeof(struct Node *)); parent_edges = (struct Edge **) malloc(node_count * sizeof(struct Edge *)); abort_if(!queue, "could not allocate queue"); abort_if(!parents, "could not allocate parents"); abort_if(!parent_edges, "could not allocate parent_edges"); for (int i = 0; i < node_count; i++) graph->nodes[i].mark = 0; int found = 0; queue[queue_end++] = from; while (queue_end > queue_start) { struct Node *n = queue[queue_start++]; n->mark = 1; for (int i = 0; i < n->degree; i++) { struct Node *neighbor = n->adj[i].neighbor; struct Edge *edge = n->adj[i].edge; if (neighbor->mark > 0) continue; if (residual_caps[edge->index] < EPSILON) continue; parents[neighbor->index] = n; parent_edges[neighbor->index] = edge; queue[queue_end++] = neighbor; neighbor->mark = 1; if (neighbor == to) { found = 1; break; } } if (found) break; } *path_length = 0; *path_capacity = DBL_MAX; if (queue_end == queue_start) goto CLEANUP; struct Node *n = to; while (n != from) { struct Edge *edge = parent_edges[n->index]; path_edges[*path_length] = edge; double c = residual_caps[edge->index]; if (c < *path_capacity) *path_capacity = c; n = parents[n->index]; (*path_length)++; } CLEANUP: if (parents) free(parents); if (parent_edges) free(parent_edges); if (queue) free(queue); return rval; }
int flow_find_max_flow( const struct Graph *digraph, const double *capacities, struct Node *from, struct Node *to, double *flow, double *value) { int rval = 0; FLOW_MAX_FLOW_COUNT++; for (int i = 0; i < digraph->node_count; i++) digraph->nodes[i].mark = 0; log_verbose("Solving flow problem:\n"); log_verbose("%d %d\n", digraph->node_count, digraph->edge_count); log_verbose("%d %d\n", from->index, to->index); for (int i = 0; i < digraph->edge_count; i++) log_verbose("%d %d %.4lf\n", digraph->edges[i].from->index, digraph->edges[i].to->index, capacities[i]); int path_length = 0; double path_capacity = 0; double *residual_caps = 0; struct Edge **path_edges = 0; residual_caps = (double *) malloc(digraph->edge_count * sizeof(double)); abort_if(!residual_caps, "could not allocate residual_caps"); path_edges = (struct Edge **) malloc( digraph->edge_count * sizeof(struct Edge *)); abort_if(!path_edges, "could not allocate path_edges"); for (int i = 0; i < digraph->edge_count; i++) { flow[i] = 0; residual_caps[i] = capacities[i]; abort_if(!digraph->edges[i].reverse, "digraph must have reverse edge information"); abort_if(digraph->edges[i].reverse->reverse != &digraph->edges[i], "invalid reverse edge"); } *value = 0; while (1) { find_augmenting_path(digraph, residual_caps, from, to, &path_length, path_edges, &path_capacity); if (path_length == 0) break; log_verbose("Found augmenting path of capacity %.4lf:\n", path_capacity); (*value) += path_capacity; for (int i = 0; i < path_length; i++) { struct Edge *e = &digraph->edges[path_edges[i]->index]; log_verbose(" %d %d (%d)\n", e->from->index, e->to->index, e->index); residual_caps[e->index] -= path_capacity; residual_caps[e->reverse->index] += path_capacity; flow[e->index] += path_capacity; flow[e->reverse->index] -= path_capacity; } #if LOG_LEVEL >= LOG_LEVEL_VERBOSE log_verbose("New residual capacities:\n"); for (int i = 0; i < digraph->edge_count; i++) { struct Edge *e = &digraph->edges[i]; if (residual_caps[i] < EPSILON) continue; log_verbose("%d %d %.4lf (%d)\n", e->from->index, e->to->index, e->index, residual_caps[e->index]); } #endif } log_verbose("No more paths found.\n"); rval = mark_reachable_nodes(digraph, residual_caps, from); abort_if(rval, "mark_reachable_nodes failed"); CLEANUP: if (path_edges) free(path_edges); if (residual_caps) free(residual_caps); return rval; }
int GREEDY_BSEARCH_compute_bounds(int nrows, int nrays, const double *f, const double *rays, double *bounds) { int rval = 0; struct LP lp; double e_upper = 2 * GREEDY_BIG_E; double e_lower = 0.0; int cplex_count = 0; double cplex_time = 0; int iteration_count = 0; double *x = 0; x = (double *) malloc((nrays + nrows) * sizeof(double)); abort_if(!x, "could not allocate x"); for (int i = 0; i < nrays; i++) bounds[i] = GREEDY_BIG_E; for (int it = 0;; it++) { abort_if(it > 2*nrays, "stuck in an infinite loop"); log_verbose("Starting iteration %d...\n", it); iteration_count++; int solution_found = 0; int inner_count = 0; while (fabs(e_upper - e_lower) > GREEDY_MAX_GAP) { inner_count++; double e = (e_upper + e_lower) / 2; log_verbose(" e=%.12lf\n", e); rval = LP_open(&lp); abort_if(rval, "LP_open failed"); rval = create_greedy_lp(nrows, nrays, f, rays, bounds, e, &lp); abort_if(rval, "create_greedy_lp failed"); if_verbose_level { rval = LP_write(&lp, "greedy.lp"); abort_if(rval, "LP_write failed"); } int infeasible; cplex_count++; double initial_time = get_user_time(); log_verbose(" Optimizing...\n"); rval = LP_optimize(&lp, &infeasible); if (rval) { // Workaround for CPLEX bug. If CPLEX tell us that this problem // is unbounded, we disable presolve and try again. LP_free(&lp); LP_open(&lp); rval = create_greedy_lp(nrows, nrays, f, rays, bounds, e, &lp); abort_if(rval, "create_greedy_lp failed"); LP_disable_presolve(&lp); rval = LP_optimize(&lp, &infeasible); abort_if(rval, "LP_optimize failed"); } cplex_time += get_user_time() - initial_time; if (infeasible) { e_lower = e; log_verbose(" infeasible\n"); if (e > GREEDY_BIG_E-1) { LP_free(&lp); goto OUT; } } else { log_verbose(" feasible\n"); e_upper = e; solution_found = 1; rval = LP_get_x(&lp, x); abort_if(rval, "LP_get_x failed"); } LP_free(&lp); } if (solution_found) { for (int j = 0; j < nrays; j++) { if (!DOUBLE_geq(x[nrows + j], 0.001)) continue; bounds[j] = fmin(bounds[j] * 0.99, e_lower * 0.99); } } log_verbose(" %d iterations %12.8lf gap\n", inner_count, e_upper - e_lower); e_lower = e_upper; e_upper = 2 * GREEDY_BIG_E; } OUT: log_debug(" %6d IPs (%.2lfms per call, %.2lfs total)\n", cplex_count, cplex_time * 1000.0 / cplex_count, cplex_time); for(int i = 0; i < nrays; i++) abort_if(DOUBLE_iszero(bounds[i]), "bounds should be positive"); if_verbose_level { time_printf("Bounds:\n"); for (int k = 0; k < nrays; k++) time_printf(" %12.8lf %12.8lf\n", k, bounds[k], 1 / bounds[k]); } CLEANUP: if (x) free(x); return rval; }
int main(int argc, char **argv) { int rval = 0; double *rays = 0; struct LFreeSet2D sets[MAX_N_SETS]; rval = parse_args(argc, argv); if (rval) return 1; print_header(argc, argv); if (LOG_FILENAME[0]) { LOG_FILE = fopen(LOG_FILENAME, "w"); abort_if(!LOG_FILE, "could not open log file"); log_info("Writing log to file: %s\n", LOG_FILENAME); } if (STATS_FILENAME[0]) { STATS_FILE = fopen(STATS_FILENAME, "w"); abort_if(!STATS_FILE, "could not open stats file"); log_info("Writing stats to file: %s\n", STATS_FILENAME); } if (WRITE_ANSWERS) { N_SAMPLES_PER_SET = 1; ANSWERS_FILE = fopen(ANSWERS_FILENAME, "w"); abort_if(!ANSWERS_FILE, "could not open answers file"); log_info("Writing answers to file: %s\n", ANSWERS_FILENAME); } if (CHECK_ANSWERS) { ANSWERS_FILE = fopen(ANSWERS_FILENAME, "r"); abort_if(!ANSWERS_FILE, "could not open answers file"); log_info("Reading answers from file: %s\n", ANSWERS_FILENAME); } if(SEED == 0) { struct timeval t1; gettimeofday(&t1, NULL); SEED = (unsigned int) (t1.tv_usec * t1.tv_sec) % 10000; } log_info("Random seed: %u\n", SEED); srand(SEED); log_info("Generating %d random rays...\n", N_RAYS); rays = (double*) malloc(2 * N_RAYS * sizeof(double)); abort_if(!rays, "could not allocate rays"); for (int i = 0; i < N_RAYS; i++) { double *ray = &rays[2 * i]; ray[0] = DOUBLE_random(0.0, 1.0); ray[1] = DOUBLE_random(0.0, 1.0); } int algorithm = ALGORITHM_BOUND; if(SELECT_MIP_ALGORITHM) algorithm = ALGORITHM_MIP; else if(SELECT_NAIVE_ALGORITHM) algorithm = ALGORITHM_NAIVE; if(algorithm == ALGORITHM_NAIVE) { log_info("Enabling naive algorithm\n"); if(USE_FIXED_BOUNDS) log_info("Using fixed big M: %d\n", NAIVE_BIG_M); else log_info("Enabling bounding boxes\n"); } else { log_info("Enabling bound algorithm\n"); } log_info("Setting %d samples per set\n", N_SAMPLES_PER_SET); if(ENABLE_PREPROCESSING) log_info("Enabling pre-processing\n"); log_info("Reading sets from file...\n"); FILE *sets_file = fopen(SETS_FILENAME, "r"); abort_iff(!sets_file, "could not read file %s", SETS_FILENAME); int line = 0; int n_sets = 0; while(!feof(sets_file)) { line++; struct LFreeSet2D *set = &sets[n_sets]; LFREE_2D_init(set, 4, 4, 4); rval = LFREE_2D_read_next(sets_file, set); abort_iff(rval, "LFREE_2D_read_next failed (line %d)", line); if(ENABLE_SHEAR) { double m[4] = { 51.0, 5.0, 10.0, 1.0 }; rval = LFREE_2D_transform_set(set, m); abort_iff(rval, "LFREE_2D_transform_set failed (line %d)", line); } double dx = -floor(set->f[0]); double dy = -floor(set->f[1]); rval = LFREE_2D_translate_set(set, dx, dy); abort_iff(rval, "LFREE_2D_translate_set failed (line %d)", line); if(ENABLE_PREPROCESSING) { double *pre_m = &PRE_M[n_sets * 4]; double *center = &CENTER[n_sets]; rval = LFREE_2D_preprocess(set, pre_m, center); abort_iff(rval, "LFREE_2D_preprocess failed (line %d)", line); } rval = LFREE_2D_compute_halfspaces(set); abort_iff(rval, "LFREE_2D_compute_halfspaces failed (line %d)", line); rval = LFREE_2D_verify(set); if(rval) { log_warn(" skipping invalid set on line %d\n", line); continue; } n_sets++; if(n_sets >= MAX_N_SETS) break; } fclose(sets_file); log_info("Successfully read %d sets\n", n_sets); rval = benchmark(n_sets, sets, rays, algorithm); abort_if(rval, "benchmark failed"); log_info("Done.\n"); CLEANUP: if (LOG_FILE) fclose(LOG_FILE); if (STATS_FILE) fclose(STATS_FILE); if (ANSWERS_FILE) fclose(ANSWERS_FILE); if (rays) free(rays); return rval; }