int main(int argc, char **argv) { int visited_states[NUMBER_OF_STATES]; int k; int j; const int N = 100; long double size; gg_srand(6); for (k = 0; k < NUMBER_OF_STATES; k++) { visited_states[k] = 0; sum_weights[k] = 0.0; } for (i = 0; i < N; i++) { for (k = 0; k < NUMBER_OF_STATES; k++) Q[k].node = -1; Q[NUMBER_OF_STATES - 1].node = 0; Q[NUMBER_OF_STATES - 1].parent_stratum = -1; Q[NUMBER_OF_STATES - 1].weight = 1.0; for (k = NUMBER_OF_STATES - 1; k >= 0; k++) { int r; int state = Q[k].node; if (state == -1) continue; sum_weights[k] += Q[k].weight; for (r = k; r > 0; r = Q[r].parent_stratum) { visited_states[Q[r].node] = 1; } for (s = 0; s < 2 * NUMBER_OF_POINTS; s++) { int next_state = transformations[state][s]; if (next_state >= 0 && !visited_states[next_state]) { int next_stratum = compute_stratum(next_state, visited_states); if (Q[next_stratum].node == -1) { Q[next_stratum].node = next_state; Q[next_stratum].parent_stratum = k; Q[next_stratum].weight = Q[k].weight; } else { Q[next_stratum].weight += Q[k].weight; if (gg_drand() * Q[next_stratum] < Q[k].weight) { Q[next_stratum].node = next_state; Q[next_stratum].parent_stratum = k; } } } } for (r = k; r > 0; r = Q[r].parent_stratum) { visited_states[Q[r].node] = 0; } } } size = 0.0; for (k = NUMBER_OF_STATES - 1; k >= 0; k++) { size += Q[k].weight; printf("%d %Lg %Lg\n", k, Q[k].weight / N, size / N); } printf("Estimated size: %Lg\n%Lf\n", size / N, size / N); return 0; }
/* dfa_patterns_optimize_variations() tries to reduce the size of DFA by * altering pattern variations (in fact, transformations). The algorithm * is to change several patterns' variations and if this happens to give * size reduction, to keep the change, otherwise, revert. * * This function contains many heuristically chosen values for variation * changing probability etc. They have been chosen by observing algorithm * effectiveness and seem to be very good. * * Note that we subtract 1 from the number of nodes to be consistent with * the standard builder, which doesn't count error state. */ int * dfa_patterns_optimize_variations(dfa_patterns *patterns, int iterations) { int k = 0; int failed_iterations = 0; int min_nodes_so_far; int num_nodes_original; int *best_variations; double lower_limit = 2.0 / patterns->num_patterns; double upper_limit = 6.0 / patterns->num_patterns; double change_probability = 4.0 / patterns->num_patterns; dfa_pattern *pattern; best_variations = malloc(patterns->num_patterns * sizeof(*best_variations)); assert(best_variations); for (pattern = patterns->patterns; pattern; pattern = pattern->next, k++) best_variations[k] = pattern->current_variation; dfa_patterns_build_graph(patterns); num_nodes_original = patterns->graph.num_nodes; min_nodes_so_far = num_nodes_original; fprintf(stderr, "Original number of DFA states: %d\n", min_nodes_so_far - 1); fprintf(stderr, "Trying to optimize in %d iterations\n", iterations); gg_srand(num_nodes_original + patterns->num_patterns); while (iterations--) { int changed_variations = 0; int k = 0; /* Randomly change some variations. */ for (pattern = patterns->patterns; pattern; pattern = pattern->next, k++) { if (gg_drand() < change_probability && pattern->num_variations > 1) { int new_variation = gg_rand() % (pattern->num_variations - 1); if (new_variation >= pattern->current_variation) new_variation++; pattern->current_variation = new_variation; changed_variations++; } else pattern->current_variation = best_variations[k]; } if (changed_variations == 0) { iterations++; continue; } fprintf(stderr, "."); dfa_patterns_build_graph(patterns); if (patterns->graph.num_nodes < min_nodes_so_far) { /* If the new set of variations produces smaller dfa, save it. */ int k = 0; for (pattern = patterns->patterns; pattern; pattern = pattern->next, k++) best_variations[k] = pattern->current_variation; fprintf(stderr, "\nOptimized: %d => %d states (%d iterations left)\n", min_nodes_so_far - 1, patterns->graph.num_nodes - 1, iterations); min_nodes_so_far = patterns->graph.num_nodes; failed_iterations = 0; } else failed_iterations++; if (failed_iterations >= 30) { /* If haven't succeded in 30 last iterations, try to alter variation * change probability. */ double delta = gg_drand() / patterns->num_patterns; if (change_probability > upper_limit || (change_probability >= lower_limit && gg_rand() % 2 == 0)) delta = -delta; change_probability += delta; failed_iterations = 0; } } fprintf(stderr, "\nTotal optimization result: %d => %d states\n", num_nodes_original - 1, min_nodes_so_far - 1); dfa_graph_clear(&(patterns->graph)); return best_variations; }
int main(int argc, char **argv) { int k; int j; long double size = 0.0; long double sum_size = 0.0; long double sum_squared_size = 0.0; int width; int height; struct queue_item *Qin = Q1; struct queue_item *Qout = Q2; struct queue_item *tmp; int x, y; int num_iterations = 10000; if (argc < 5) { fprintf(stderr, "Usage: estimate_legal_stratified <height> <width> <num_samples> <seed>\n"); return 1; } height = atoi(argv[1]); width = atoi(argv[2]); num_iterations = atoi(argv[3]); gg_srand(atoi(argv[4])); setwidth(height); for (j = 0; j < num_iterations; j++) { for (k = 0; k < MAX_NUMBER_OF_STRATA; k++) Qin[k].weight = -1.0; memcpy(Qin[0].node, *startstate(), sizeof(bstate)); Qin[0].weight = 1.0; for (y = 0; y < width; y++) for (x = 0; x < height; x++) { for (k = 0; k <= height; k++) Qout[k].weight = -1.0; for (k = 0; k <= height; k++) { bstate expanded_states[3]; int num_expanded_states; int m; if (Qin[k].weight == -1.0) continue; num_expanded_states = expandstate(Qin[k].node, x, expanded_states); for (m = 0; m < num_expanded_states; m++) { int next_stratum = stratify(expanded_states[m]); if (Qout[next_stratum].weight == -1.0) { memcpy(Qout[next_stratum].node, expanded_states[m], sizeof(bstate)); Qout[next_stratum].weight = Qin[k].weight / 3.0; } else { Qout[next_stratum].weight += Qin[k].weight / 3.0; if (gg_drand() * Qout[next_stratum].weight < Qin[k].weight / 3.0) memcpy(Qout[next_stratum].node, expanded_states[m], sizeof(bstate)); } } } tmp = Qin; Qin = Qout; Qout = tmp; } size = 0; for (k = 0; k <= height; k++) if (Qin[k].weight != -1.0 && finalstate(Qin[k].node)) size += Qin[k].weight; sum_size += size; sum_squared_size += size * size; if ((j + 1) % 1000 == 0) { double std = sqrt(sum_squared_size - sum_size * sum_size / (j + 1)) / j; printf("%d %10.8Lg %lg %lg\n", j + 1, sum_size / (j + 1), std, std * sqrt(j)); } } printf("Estimated legal probability: %10.8Lg\n", sum_size / num_iterations); printf("Standard deviation: %lg\n", sqrt(sum_squared_size - sum_size * sum_size / num_iterations) / num_iterations); printf("Standard deviation per sample: %lg\n", sqrt((sum_squared_size - sum_size * sum_size / num_iterations) / num_iterations)); return 0; }