/** * N-queens example. * Based on work by Robert Meolic, released by him into the public domain. */ #include #include #include #include #include #include #include #ifdef HAVE_PROFILER #include #endif #include #include /* Configuration */ static int report_minterms = 0; // report minterms at every major step static int report_minor = 0; // report minor steps static int report_stats = 0; // report stats at end static int workers = 0; // autodetect number of workers by default static size_t size = 0; // will be set by caller #ifdef HAVE_PROFILER static char* profile_filename = NULL; // filename for profiling #endif /* argp configuration */ static struct argp_option options[] = { {"workers", 'w', "", 0, "Number of workers (default=0: autodetect)", 0}, #ifdef HAVE_PROFILER {"profiler", 'p', "", 0, "Filename for profiling", 0}, #endif {"report-minterms", 1, 0, 0, "Report #minterms at every major step", 1}, {"report-minor", 2, 0, 0, "Report minor steps", 1}, {"report-stats", 3, 0, 0, "Report statistics at end", 1}, {0, 0, 0, 0, 0, 0} }; static error_t parse_opt(int key, char *arg, struct argp_state *state) { switch (key) { case 'w': workers = atoi(arg); break; case 1: report_minterms = 1; break; case 2: report_minor = 1; break; case 3: report_stats = 1; break; #ifdef HAVE_PROFILER case 'p': profile_filename = arg; break; #endif case ARGP_KEY_ARG: if (state->arg_num >= 1) argp_usage(state); size = atoi(arg); break; case ARGP_KEY_END: if (state->arg_num < 1) argp_usage(state); break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp argp = { options, parse_opt, "", 0, 0, 0, 0 }; /* Obtain current wallclock time */ static double wctime() { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec + 1E-6 * tv.tv_usec); } static double t_start; #define INFO(s, ...) fprintf(stdout, "[% 8.2f] " s, wctime()-t_start, ##__VA_ARGS__) #define Abort(...) { fprintf(stderr, __VA_ARGS__); exit(-1); } VOID_TASK_0(gc_start) { if (report_minor) { printf("\n"); } INFO("(GC) Starting garbage collection...\n"); } VOID_TASK_0(gc_end) { INFO("(GC) Garbage collection done.\n"); } int main(int argc, char** argv) { argp_parse(&argp, argc, argv, 0, 0, 0); setlocale(LC_NUMERIC, "en_US.utf-8"); t_start = wctime(); // Init Lace lace_init(workers, 1000000); // auto-detect number of workers, use a 1,000,000 size task queue lace_startup(0, NULL, NULL); // auto-detect program stack, do not use a callback for startup // Lace is initialized, now set local variables LACE_ME; // Init Sylvan // Nodes table size of 1LL<<20 is 1048576 entries // Cache size of 1LL<<18 is 262144 entries // Nodes table size: 24 bytes * nodes // Cache table size: 36 bytes * cache entries // With 2^20 nodes and 2^18 cache entries, that's 33 MB // With 2^24 nodes and 2^22 cache entries, that's 528 MB sylvan_set_sizes(1LL<<20, 1LL<<24, 1LL<<18, 1LL<<22); sylvan_init_package(); sylvan_set_granularity(3); // granularity 3 is decent value for this small problem - 1 means "use cache for every operation" sylvan_init_bdd(); // Before and after garbage collection, call gc_start and gc_end sylvan_gc_hook_pregc(TASK(gc_start)); sylvan_gc_hook_postgc(TASK(gc_end)); #ifdef HAVE_PROFILER if (profile_filename != NULL) ProfilerStart(profile_filename); #endif double t1 = wctime(); BDD zero = sylvan_false; BDD one = sylvan_true; // Variables 0 ... (SIZE*SIZE-1) BDD board[size*size]; for (size_t i=0; i= 0 && j+k-i < size && k != i) if (j+k >= i && j+k < size+i && k != i) { temp = sylvan_and(temp, sylvan_not(board[k*size + (j+k-i)])); } } temp = sylvan_or(temp, sylvan_not(board[i*size+j])); // add cube to "res" res = sylvan_and(res, temp); } } if (report_minor) { printf("\n"); } if (report_minterms) { INFO("We have %.0f minterms\n", sylvan_satcount(res, vars)); } if (report_minor) { INFO("Encoding falling diagonals... "); } else { INFO("Encoding falling diagonals...\n"); } for (size_t i=0; i= 0 && j+i-k < size && k != i) if (j+i >= k && j+i < size+k && k != i) { temp = sylvan_and(temp, sylvan_not(board[k*size + (j+i-k)])); } } temp = sylvan_or(temp, sylvan_not(board[i*size + j])); // add cube to "res" res = sylvan_and(res, temp); } } if (report_minor) { printf("\n"); } if (report_minterms) { INFO("We have %.0f minterms\n", sylvan_satcount(res, vars)); } if (report_minor) { INFO("Final computation to place a queen on every row... "); } else { INFO("Final computation to place a queen on every row...\n"); } for (size_t i=0; i