/** Returns TRUE if t is losing **/ static char is_losing(tuple* t, antichain* losing_PO, antichain* losing_PI) { char to_return; if(t->cf->player == P_O) { to_return = contains_element(losing_PO, t, (void*)compare_tuples_reverse); } else { to_return = contains_element(losing_PI, t, (void*)compare_tuples_reverse); } return to_return; }
/* I wanted to experiment on passing by reference in arrays... another aproach for this function would be to return the new array without the element. However, this approach has the advantage of having fewer memory leaks. */ int remove_element(int element, int **array, int length) { int i = 0; if (contains_element(element, *array, length)) { int removed = 0; int* new_array = (int*) malloc(sizeof(int) * (length - 1)); int j = 0; int current_element; for(i = 0; i < length; i++) { current_element = *(*array + i); if (element == current_element && !removed) { removed = 1; } else { new_array[j] = current_element; j++; } } if(removed) { free(*array); *array = new_array; return 1; } else { print_array(*array, length); return 0; } } else { return 0; } }
/** Returns TRUE if t has a successor in the safety game, FALSE otherwise Note that t is supposed to be an antichain of P_O -> no test is done here **/ static char has_successor_in_safety_game(tuple* t, alphabet_info* alphabet, antichain* safety_game_PI) { int i, sigma_size = alphabet->sigma_output_size; tuple* cur_succ; for(i=0; i<sigma_size; i++) { cur_succ = tuple_succ(t, i, alphabet); if(contains_element(safety_game_PI, cur_succ, (void*)compare_tuples) == TRUE) { free_tuple_full(cur_succ); return TRUE; } free_tuple_full(cur_succ); } return FALSE; }
/** Critical input signals optimization: Computes a minimal critical set of inputs signals for antichain For each element f of antichain, for each symbol s_O of the output alphabet, find a critical input signal, i.e. a signal s_I s.t. succ(succ(f, s_O), s_I) does not belong to antichain (+ privilege already added signals to try to minimize the set) Stops when the critical signals for one one-step-loosing tuple is found **/ int* compute_critical_set(antichain *a, alphabet_info *alphabet) { // Note: local cache memories optimization disabled since it seems less efficient // GHashTable *cache_lvl1 = g_hash_table_new_full(hash_key, compare_keys, (GDestroyNotify)free_hash_table_key, NULL); //cache memory used to avoid redondant computation (for the successors of t) // GHashTable *cache_lvl2 = g_hash_table_new_full(hash_key, compare_keys, (GDestroyNotify)free_hash_table_key, NULL); //cache memory used to avoid redondant computation (for the successors of the successors of t) char found, inC, is_one_step_loosing, is_in_antichain; char *info_lvl1, *info_lvl2; char *true_value = malloc(sizeof(char)); true_value[0] = TRUE; char *false_value = malloc(sizeof(char)); false_value[0] = FALSE; int i, input_size = alphabet->sigma_input_size; tuple *t, *succ_t, *succ_succ_t; antichain *min_succ; int* c = (int*)malloc((input_size+1)*sizeof(int)); //array of critical signals index in the input alphabet char* c_bool = (char*)malloc((input_size)*sizeof(char)); //array of booleans representing the critical set on a boolean format int* curC = (int*)malloc((input_size+1)*sizeof(int)); //array of signals found to be critical till here and for t (will be added to c only if t is one step loosing) char* curC_bool = (char*)malloc((input_size)*sizeof(char)); //c_bool but on a boolean format // Initialize c and c_bool c[0] = 0; for(i=0; i<input_size; i++) { c[i+1] = -1; c_bool[i] = FALSE; } GList *succ_t_link, *cur_link = a->incomparable_elements; while(cur_link != NULL) { //for each element t of the antichain t = cur_link->data; //Copy c and c_bool in curC and curC_bool curC[0] = c[0]; for(i=0; i<input_size; i++) { curC[i+1] = c[i+1]; curC_bool[i] = c_bool[i]; } is_one_step_loosing = TRUE; min_succ = (antichain*)get_from_cache(cache_min_succ, t, -1); if(min_succ == NULL) { //cache miss min_succ = minimal_tuple_succ(t, alphabet); //compute the antichain of minimal successors of t (no need of analyzing non minimal successors) add_to_cache(cache_min_succ, clone_tuple(t), -1, (void*)min_succ); //add the computed antichain to cache } succ_t_link = min_succ->incomparable_elements; while(succ_t_link != NULL) { //for all succ of t s.t. succ is minimal found = FALSE; //will be set to TRUE if a critical s_I is found for t inC = FALSE; //will be set to True if the critical signal s_I found has already been for another t or min_succ succ_t = clone_tuple(succ_t_link->data); //Seek on cache if succ_t has already been processed, i.e. if we have already checked if there exists a s_I s.t. succ(succ_t, s_I) does not belong to the antichain //info_lvl1 = get_from_cache(cache_lvl1, succ_t, -1); //attempt to retrieve data from cache_lvl1 //if(info_lvl1 == NULL) { //cache miss for(i=1; i<=curC[0]; i++) { //for s_I in c (privilege already added signals) succ_succ_t = (tuple*)get_from_cache(cache_succ, succ_t, curC[i]); if(succ_succ_t == NULL) { // cache miss succ_succ_t = tuple_succ(succ_t, curC[i], alphabet); add_to_cache(cache_succ, clone_tuple(succ_t), curC[i], (void*)succ_succ_t); //add the computed succ to cache } //Seek on cache if succ_succ_t has already been processed //info_lvl2 = get_from_cache(cache_lvl2, succ_succ_t, -1); //attempt to retrieve data from cache_lvl2 //if(info_lvl2 == NULL) { //cache miss is_in_antichain = contains_element(a, succ_succ_t, (void*)compare_tuples); /*if(is_in_antichain == TRUE) { add_to_cache(cache_lvl2, clone_tuple(succ_succ_t), -1, true_value); //add the computed result to cache_lvl2 } else { add_to_cache(cache_lvl2, clone_tuple(succ_succ_t), -1, false_value); //add the computed result to cache_lvl2 } } else { //free_tuple_full(succ_succ_t); is_in_antichain = info_lvl2[0]; }*/ if(is_in_antichain == FALSE) { inC = TRUE; break; } } if(inC == FALSE) { //if not found yet for(i=0; i<input_size; i++) { //for s_I in input alphabet if(curC_bool[i] == FALSE) { //if s_I does not belong to curC (otherwise it has already been tested) succ_succ_t = (tuple*)get_from_cache(cache_succ, succ_t, i); if(succ_succ_t == NULL) { // cache miss succ_succ_t = tuple_succ(succ_t, i, alphabet); add_to_cache(cache_succ, clone_tuple(succ_t), i, (void*)succ_succ_t); //add the computed succ to cache } //Seek on cache if succ_succ_t has already been processed //info_lvl2 = get_from_cache(cache_lvl2, succ_succ_t, -1); //attempt to retrieve data from cache_lvl2 //if(info_lvl2 == NULL) { //cache miss is_in_antichain = contains_element(a, succ_succ_t, (void*)compare_tuples); /*if(is_in_antichain == TRUE) { add_to_cache(cache_lvl2, clone_tuple(succ_succ_t), -1, true_value); //add the computed result to cache_lvl2 } else { add_to_cache(cache_lvl2, clone_tuple(succ_succ_t), -1, false_value); //add the computed result to cache_lvl2 } } else { //free_tuple_full(succ_succ_t); is_in_antichain = info_lvl2[0]; }*/ if(is_in_antichain == FALSE) { found = TRUE; //there exists a s_I s.t. succ(succ(f, s_O), s_I) does not belong to antichain curC[0] = curC[0]+1; //increment the number of critical signals curC[curC[0]] = i; //add s_I to curC curC_bool[i] = TRUE; //set the boolean of s_I to True break; } } } } if(found == FALSE && inC == FALSE) { //there exists a s_O s.t. for all s_I succ(succ(t, s_O), s,I) belongs to antichain -> t is not one step loosing is_one_step_loosing = FALSE; } /*if(is_one_step_loosing == TRUE) { add_to_cache(cache_lvl1, clone_tuple(succ_t), -1, true_value); //add the computed result to cache_lvl1 } else { add_to_cache(cache_lvl1, clone_tuple(succ_t), -1, false_value); //add the computed result to cache_lvl1 } } else { //cache hit free_tuple_full(succ_t); is_one_step_loosing = info_lvl1[0]; }*/ if(is_one_step_loosing == FALSE) { break; //not one step loosing -> skip to the next t } succ_t_link = succ_t_link->next; } //free_antichain_full(min_succ, (void*)free_tuple_full); // Not freed here because min_succ is added in cache (will be freed at the end on the fix point computation) // If f is one step loosing, add signals in curC to c if(is_one_step_loosing == TRUE) { c[0] = curC[0]; for(i=0; i<input_size; i++) { c[i+1] = curC[i+1]; c_bool[i] = curC_bool[i]; } break; //break here because we found critical signals for one one-step-loosing tuple (enough) } cur_link = cur_link->next; } free(c_bool); free(curC); free(curC_bool); free(true_value); free(false_value); // g_hash_table_destroy(cache_lvl1); // g_hash_table_destroy(cache_lvl2); return c; }
/** Adds to waiting list edges from t to each minimal (resp. maximal) successor of t, where t belongs to P_O (resp. P_I) If t belongs to P_O: computes the minimal successors of t, sorts them and adds them to succ_to_visit[t]. The first successor passed in this list is then added to waiting and remove from succ_to_visit[t] If t belongs to P_I: computes the maximal successors of t, sorts them and adds them to waiting (some of them might then be skipped if enough information is known) **/ static GList* add_to_waiting(tuple *t, alphabet_info* alphabet, antichain* safety_game_PO, antichain* safety_game_PI, antichain* losing_PO, antichain* losing_PI, GList *waiting, GHashTable *succ_to_visit, GHashTable *passed) { char player = t->cf->player; int sigma_size; if(player == P_O) { sigma_size = alphabet->sigma_output_size; } else { sigma_size = alphabet->sigma_input_size; } // Compute the successors int i; GList *succ_list = NULL; safety_game_edge *cur_edge; for(i=0; i<sigma_size; i++) { cur_edge = (safety_game_edge*)malloc(sizeof(safety_game_edge)); cur_edge->from = t; cur_edge->to = tuple_succ(t, i, alphabet); cur_edge->label_index = i; if(player == P_O) { if(contains_element(safety_game_PI, cur_edge->to, (void*)compare_tuples) == TRUE) { // succ safe? if(is_losing(cur_edge->to, losing_PO, losing_PI) == FALSE) { // succ non losing? succ_list = scan_add_or_remove_and_free(succ_list, cur_edge, (void*)compare_safety_game_edges_reverse, (void*)free_safety_game_edge); } else { free_safety_game_edge(cur_edge); } } else { free_safety_game_edge(cur_edge); } } else { succ_list = scan_add_or_remove_and_free(succ_list, cur_edge, (void*)compare_safety_game_edges, (void*)free_safety_game_edge); } } GList *sorted_succ_list = NULL; GList *curlink = succ_list; if(player == P_O) { //t belongs to P_O -> sort the successors and add them to succ_to_visit while(curlink != NULL) { //sorted_succ_list = g_list_prepend(sorted_succ_list, curlink->data); sorted_succ_list = insert_sorted(sorted_succ_list, curlink->data, (void*)compare_safety_game_edges_counters_sum_reverse); // the smallest elements will be placed at the beginning of the linked list curlink = curlink->next; } hash_table_key* key = (hash_table_key*)malloc(sizeof(hash_table_key)); key->t = t; key->sigma_index = -1; g_hash_table_insert(succ_to_visit, (gconstpointer*)key, (gconstpointer*)sorted_succ_list); // Add the first successor passed to waiting waiting = g_list_append(waiting, get_first_successor_passed_non_losing(t, succ_to_visit, passed, losing_PO, losing_PI)); } else { //t belongs to P_I -> sort the successors and add them to waiting while(curlink != NULL) { //sorted_succ_list = g_list_prepend(sorted_succ_list, curlink->data); sorted_succ_list = insert_sorted(sorted_succ_list, curlink->data, (void*)compare_safety_game_edges_counters_sum_reverse); // the largest elements will be placed at the end of the linked list -> popped first curlink = curlink->next; } // Add the successors to waiting waiting = g_list_concat(waiting, sorted_succ_list); } g_list_free(succ_list); return waiting; }
static void test_select_pivot_short_array(){ int array[2] = {6,5}; int pivot = select_pivot(array, 2); assert(contains_element(pivot, array, 2)); }
static void test_select_pivot_long_array(){ int array[10] = {6,5,1,9,4,7,5,12,8,4}; int pivot = select_pivot(array, 10); assert(contains_element(pivot, array, 10)); }
TEST fuzzy_hash_test_iterator(long size, long btree_node_size, int _commit) { INIT(); rl_btree_iterator *iterator = NULL; long *elements = malloc(sizeof(long) * size); long *nonelements = malloc(sizeof(long) * size); long *values = malloc(sizeof(long) * size); long btree_page = db->next_empty_page; RL_CALL_VERBOSE(rl_write, RL_OK, db, btree->type->btree_type, btree_page, btree); long i, element, value, *element_copy, *value_copy; long j; void *tmp; long prev_score = -1.0, score; for (i = 0; i < size; i++) { element = rand(); value = rand(); if (contains_element(element, elements, i)) { i--; continue; } else { elements[i] = element; element_copy = malloc(sizeof(long)); *element_copy = element; values[i] = value; value_copy = malloc(sizeof(long)); *value_copy = value; RL_CALL_VERBOSE(rl_btree_add_element, RL_OK, db, btree, btree_page, element_copy, value_copy); RL_CALL_VERBOSE(rl_btree_is_balanced, RL_OK, db, btree); } RL_CALL_VERBOSE(rl_btree_iterator_create, RL_OK, db, btree, &iterator); EXPECT_LONG(iterator->size, i + 1); j = 0; while (RL_OK == (retval = rl_btree_iterator_next(iterator, &tmp, NULL))) { score = *(long *)tmp; rl_free(tmp); if (j++ > 0) { if (prev_score >= score) { fprintf(stderr, "Tree is in a bad state in element %ld after adding child %ld\n", j, i); retval = RL_UNEXPECTED; goto cleanup; } } prev_score = score; } if (retval != RL_END) { rl_free(tmp); goto cleanup; } EXPECT_LONG(j, i + 1); iterator = NULL; if (_commit) { RL_CALL_VERBOSE(rl_commit, RL_OK, db); RL_CALL_VERBOSE(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_long_long, btree_page, &rl_btree_type_hash_long_long, &tmp, 1); btree = tmp; } } rl_btree_iterator_destroy(iterator); retval = 0; cleanup: free(values); free(elements); free(nonelements); rl_close(db); if (retval == 0) { PASS(); } else { FAIL(); } }
TEST fuzzy_hash_test(long size, long btree_node_size, int _commit) { INIT(); long *elements = malloc(sizeof(long) * size); long *nonelements = malloc(sizeof(long) * size); long *values = malloc(sizeof(long) * size); void **flatten_scores = malloc(sizeof(void *) * size); long btree_page = db->next_empty_page; RL_CALL_VERBOSE(rl_write, RL_OK, db, btree->type->btree_type, btree_page, btree); long i, element, value, *element_copy, *value_copy; long j, flatten_size; void *val, *tmp; for (i = 0; i < size; i++) { element = rand(); value = rand(); if (contains_element(element, elements, i)) { i--; continue; } else { RL_CALL_VERBOSE(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_long_long, btree_page, &rl_btree_type_hash_long_long, &tmp, 1); elements[i] = element; element_copy = malloc(sizeof(long)); *element_copy = element; values[i] = value; value_copy = malloc(sizeof(long)); *value_copy = value; RL_CALL_VERBOSE(rl_btree_add_element, RL_OK, db, btree, btree_page, element_copy, value_copy); RL_CALL_VERBOSE(rl_btree_is_balanced, RL_OK, db, btree); } flatten_size = 0; RL_CALL_VERBOSE(rl_flatten_btree, RL_OK, db, btree, &flatten_scores, &flatten_size); for (j = 1; j < flatten_size; j++) { if (*(long *)flatten_scores[j - 1] >= *(long *)flatten_scores[j]) { fprintf(stderr, "Tree is in a bad state in element %ld after adding child %ld\n", j, i); retval = RL_UNEXPECTED; goto cleanup; } } if (_commit) { RL_CALL_VERBOSE(rl_commit, RL_OK, db); RL_CALL_VERBOSE(rl_read, RL_FOUND, db, &rl_data_type_btree_hash_long_long, btree_page, &rl_btree_type_hash_long_long, &tmp, 1); btree = tmp; } } for (i = 0; i < size; i++) { element = rand(); if (contains_element(element, elements, size) || contains_element(element, nonelements, i)) { i--; } else { nonelements[i] = element; } } for (i = 0; i < size; i++) { RL_CALL_VERBOSE(rl_btree_find_score, RL_FOUND, db, btree, &elements[i], &val, NULL, NULL); EXPECT_LONG(*(long *)val, values[i]); RL_CALL_VERBOSE(rl_btree_find_score, RL_NOT_FOUND, db, btree, &nonelements[i], NULL, NULL, NULL); } retval = 0; cleanup: free(values); free(elements); free(nonelements); free(flatten_scores); rl_close(db); if (retval == 0) { PASS(); } else { FAIL(); } }