#define PROG_NAME "tmaze_bb_stats" #define PROG_DESC "analysis of the Blip-Blop maze" #define PROG_VERS "1.0" #define tmaze_bb_stats_C_COPYRIGHT \ "Copyright © 2009 by the State University of Campinas (UNICAMP)" /* Last edited on 2009-11-08 21:17:44 by stolfi */ #define PROG_HELP \ " " PROG_NAME " \\\n" \ " -size {NX} {NY} \\\n" \ " [ -topology { open | torus} } ] \\\n" \ " [ -seed {SEED} ] \\\n" \ " [ -plot {TILESIZE} ] \\\n" \ " [ -cells ] [ -grid ] \\\n" \ " [ -style { straight | curved } ] \\\n" \ " [ -dump ] \\\n" \ " " argparser_help_info_HELP #define PROG_INFO \ "NAME\n" \ " " PROG_NAME " - " PROG_DESC "\n" \ "\n" \ "SYNOPSIS\n" \ PROG_HELP "\n" \ "\n" \ "DESCRIPTION\n" \ " The program prints to standard output an" \ " analysis of the components of random instances" \ " of the Blip-Blop maze family.\n" \ "\n" \ "OPTIONS\n" \ " -size {NX} {NY}\n" \ " This mandatory parameter specifies the number of cell columns {NX} and" \ " cell rows {NY} in the maze, respectively.\n" \ "\n" \ " -trials {NTR}\n" \ " This optional parameter specifies the number of" \ " instances that should be generated and analyzed. The" \ " default is a single instance.\n" \ "\n" \ " -topology { open | torus }\n" \ " This optional parameter specifies what happens at the edges of the" \ " cell array. The \"open\" option specifies that" \ " paths cannot cross those edges, so that cells along them" \ " have no neighbors. The \"torus\"option specifies that" \ " opposite edges of the maze are implicltly" \ " connected with toroidal topology, so that" \ " every cell has four neighbors. The default is \"-topology open\".\n" \ "\n" \ " -seed {SEED}\n" \ " This optional parameter specifies the (integer) seed for the random" \ " number generator for the first instance. For subsequent" \ " instances, the seed is incremented by a fixed constant. The" \ " default is \"-seed 1\".\n" \ "\n" \ " -plot {CELLSIZE}\n" \ " This optional parameter requests an Encapsulated Postscript plot of the" \ " first maze, which is written to a file \"out/{NX}-{NY}-{SEED}.eps\". Each" \ " cell will be plotted as a square with {CELLSIZE} by {CELLSIZE}" \ " millimeters.\n" \ "\n" \ " -cells\n" \ " This optional parameter requests that the cell backgrounds be painted. The" \ " default is to leave them transparent.\n" \ "\n" \ " -grid\n" \ " This optional parameter requests that the cell outlines be stroked. The" \ " default is not to stroke the cell outlines.\n" \ "\n" \ " -style { straight | curved }\n" \ " This optional parameter requests that the roads be plotted" \ " with either straight or curved sides. The default is curved.\n" \ "\n" \ " -dump\n" \ " This optional parameter requests the program to write the underlying" \ " graph of the first maze to the file \"out/{NX}-{NY}-{SEED}.grf\".\n" \ "\n" \ "DOCUMENTATION OPTIONS\n" \ argparser_help_info_HELP_INFO "\n" \ "\n" \ "SEE ALSO\n" \ " mirrormaze(1).\n" \ "\n" \ "AUTHOR\n" \ " Created 2009-11-07 by Jorge Stolfi, IC-UNICAMP, based" \ " on {tmaze_bb_stats.c} of 2009-02-04 by the same author.\n" \ "\n" \ "MODIFICATION HISTORY\n" \ " 2009-11-08 Added \"-trials\" option. [J.Stolfi]\n" \ "\n" \ "WARRANTY\n" \ argparser_help_info_NO_WARRANTY "\n" \ "\n" \ "RIGHTS\n" \ " " tmaze_bb_stats_C_COPYRIGHT ".\n" \ "\n" \ argparser_help_info_STANDARD_RIGHTS #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include /* COMMAND-LINE OPTIONS */ typedef struct options_t { int nx; /* Number of cell columns in maze. */ int ny; /* Number of cell rows in maze. */ bool_t torus; /* TRUE use toroidal topology. */ int trials; /* Number of instances to generate and analyze. */ int seed; /* A string-valued argument. */ double plot_cell_size; /* Size of each cell in plot (mm), or 0 if no plot. */ bool_t plot_cells; /* TRUE to paint the cell backgrounds. */ bool_t plot_grid; /* TRUE to stroke the cell outlines. */ bool_t style_curved; /* TRUE to draw curved roads in plot. */ bool_t dump; /* TRUE requests a dump of the graph. */ } options_t; options_t *parse_options(int argc, char **argv); /* Parses the command line arguments and packs them as an {options_t}. */ void show_options(options_t *o); /* Prints the options {o} to {stderr}. */ int main(int argc,char** argv); /* IMPLEMENTATIONS */ int main(int argc, char** argv) { options_t *o = parse_options(argc, argv); show_options(o); /* Make sure that directories exist: */ mkdir("out", 0777); /* Create a maze with the requested size and topology: */ tmaze_t M = tmaze_bb_make(o->nx, o->ny, o->torus); /* Initialize the seed for tile randomization: */ int seed = o->seed; /* Global counts: */ double *ct_tot = NULL; /* Count components by size over all trials. */ double *ct_exp = NULL; /* Predicted counts for one trial. */ int it; for (it = 0; it < o->trials; it++) { /* Fill the maze with random tiles: */ tmaze_bb_random(&M, seed); /* Get its graph: */ dgraph_t G = tmaze_bb_graph_make(&M); assert(G.rows == G.cols); dgraph_vertex_count_t nv = G.rows; /* Tot num of vertices. */ dgraph_vertex_count_t size; if (it == 0) { /* First trial, output what the user requested. */ /* Print out the maze if small enough: */ if ((M.nx <= 70) && (M.ny <= 70)) { tmaze_bb_print(stderr, &M); } /* Plot the maze if so requested: */ if (o->plot_cell_size > 0) { char *fig_name = NULL; char *fig_name = jsprintf("%06d-%06d-%010d", M.nx, M.ny, o->seed); tmaze_bb_plot_maze("out", fig_name, &M, o->plot_cells, o->plot_grid, o->plot_cell_size, o->style_curved); free(fig_name); } /* Allocate the total count table: */ ct_tot = notnull(malloc((nv+1)*sizeof(double)), "no mem"); ct_exp = notnull(malloc((nv+1)*sizeof(double)), "no mem"); for (size = 0; size <= nv; size++) { ct_tot[size] = 0; ct_exp[size] = tmaze_bb_predicted_comp_count(&M, size); } /* Dump the graph, if so requested: */ if (o->dump) { char *gfile_name = NULL; char *gfile_name = jsprintf("out/%06d-%06d-%010d.grf", M.nx, M.ny, o->seed); FILE *gfile = open_write(gfile_name, TRUE); dgraph_write(gfile, &G); fclose(gfile); free(gfile_name); } } /* Get the connected components as a function of size: */ dgraph_vertex_count_t mv; /* Max size of a component. */ dgraph_vertex_count_t *ct; /* Count cmponents by size. */ tmaze_bb_graph_count_components_by_size (&G, &M, &mv, &ct); assert(mv < nv); /* Accumulate them to the total count: */ for (size = 0; size <= mv; size++) { /* Consistency checks: */ if (size <= 1) { /* Blip-Blop maze graphs have no 0-vertex or 1-vertex components. */ assert(ct[size] == 0); } else if ((size % 2) == 1) { /* Odd-size components are expected only along edges or wrapping the torus: */ if (M.torus && ((M.nx % 2) == 0) && ((M.ny % 2) == 0)) { assert(ct[size] == 0); } } else if (size == 2) { /* There are no 2-vertex components in the torus: */ if (M.torus) { assert(ct[size] == 0); } } else if (size == 6) { /* There should be no plain components with 6 vertices: */ if (M.torus && (M.nx > 3) && (M.ny > 3)) { assert(ct[size] == 0); } } else if (size == 10) { /* There should be no plain components with 10 vertices: */ if (M.torus && (M.nx > 5) && (M.ny > 5)) { assert(ct[size] == 0); } } /* Accumulate counts: */ ct_tot[size] += ct[size]; } /* Free storage for one instance: */ free(ct); dgraph_trim(&G, 0); /* Prepare for the next one: */ seed += 17; } /* Print the distribution to stdout: */ print_distr(stdout, &G, &M, mv, ct_tot); /* Free storage (good manners): */ free(M.tile); return 0; } #define MIN_MAZE_SIZE (2) #define MAX_MAZE_SIZE (65535) /* Maze size range in both dimensions. The minimum width and minimum height are defined as 2, since the graph of a 1-wide or 1-tall maze has parallel edges, which are not well-supported by the representation. */ #define MAX_SEED (1073741823L) #define MAX_TRIALS (1000000) options_t *parse_options(int argc, char **argv) { /* Initialize argument parser: */ argparser_t *pp = argparser_new(stderr, argc, argv); argparser_set_help(pp, PROG_NAME " version " PROG_VERS ", usage:\n" PROG_HELP); argparser_set_info(pp, PROG_INFO); argparser_process_help_info_options(pp); /* Allocate the command line argument record: */ options_t *o = (options_t *)malloc(sizeof(options_t)); /* Parse the keyword parameters: */ argparser_get_keyword(pp, "-size"); o->nx = argparser_get_next_int(pp, MIN_MAZE_SIZE, MAX_MAZE_SIZE); o->ny = argparser_get_next_int(pp, MIN_MAZE_SIZE, MAX_MAZE_SIZE); if (argparser_keyword_present(pp, "-topology")) { if (argparser_keyword_present_next(pp, "torus")) { o->torus = TRUE; } else if (argparser_keyword_present_next(pp, "open")) { o->torus = FALSE; } else { argparser_error(pp, "unknown option"); } } else { o->torus = TRUE; } if (argparser_keyword_present(pp, "-seed")) { o->seed = argparser_get_next_int(pp, 0, MAX_SEED); } else { o->seed = 1; } if (argparser_keyword_present(pp, "-trials")) { o->trials = argparser_get_next_int(pp, 1, MAX_TRIALS); } else { o->trials = 1; } if (argparser_keyword_present(pp, "-plot")) { o->plot_cell_size = argparser_get_next_double(pp, 0, 100.0); } else { o->plot_cell_size = 0; } if (argparser_keyword_present(pp, "-style")) { if (argparser_keyword_present_next(pp, "straight")) { o->style_curved = FALSE; } else if (argparser_keyword_present_next(pp, "curved")) { o->style_curved = TRUE; } else { argparser_error(pp, "unrecognized \"-style\" option"); } } else { o->style_curved = TRUE; } o->dump = argparser_keyword_present(pp, "-dump"); /* Parse the positional parameters: */ argparser_skip_parsed(pp); /* Check for spurious arguments: */ argparser_finish(pp); return o; } void show_options(options_t *o) { fprintf(stderr, "-- command line arguments --------------------------------\n"); fprintf(stderr, "maze dimensions = %d x %d\n", o->nx, o->ny); fprintf(stderr, "total cells = %d\n", o->nx * o->ny); char *topology_name[2] = { "open", "torus" }; fprintf(stderr, "topology = %s\n", topology_name[o->torus]); fprintf(stderr, "seed = %d\n", o->seed); if (o->plot_cell_size > 0) { fprintf(stderr, "plot cell size = %.3f mm\n", o->plot_cell_size); } fprintf(stderr, "dump the graph = %c\n", "NY"[o->dump]); fprintf(stderr, "----------------------------------------------------------\n"); }