#ifdef USE_VALUE #error "does not work with USE_VALUE (yet)" #endif #include #include #include #include // for sysconf() #include #include #include "fdc_int.h" #include "store.h" #include "variables.h" #include "values.h" #include "bound.h" #if STEAL_WORK > 0 #include #endif static int _fd_dsearch_(fd_int[]); // XXX #ifdef STORE_LIST #error "STORE_LIST deprecated" #endif static __thread int agent; static int nagents; // how many agents there are // says whether we are counting or looking for solutions int _fd_counting_solutions; #ifdef NEW_ENTRANCE # if STEAL_WORK < 1 # error "NEW_ENTRANCE only makes sense with STEAL_WORK" # else static pthread_spinlock_t entrance_lock; static volatile int agents_searching = 0, agents_failed = 0; # endif #endif extern int tid; // XXX: team ID, just for debugging #include "pool.c" void _fd_epoch_forward() { } void _fd_epoch_rewind() { #ifdef CONSTRAINT_TEMPS fd__constraint_data_reset(); #endif } int _fd_dsearch(fd_int variables[], int agent_no) { #if STEAL_WORK > 0 struct timespec tsettle = { 0, 1000000 }; // 1ms #ifdef NEW_ENTRANCE bool failed_initially = false; #endif #endif agent = agent_no; #if defined(NEW_ENTRANCE) && defined(DEBUG_SPLITGO) _fd_debug("[%d.%d] agents_searching = %d, agents_failed = %d\n", tid, agent, agents_searching, agents_failed); #endif _fd_init_local_depository(); #if DEBUG_SPLITGO > 1 _fd_output("[%d.%d] ", tid, agent); _fd_cprint2(variables); #endif if (_fd_filter_domains() == FD_NOSOLUTION) { fd_int variable = NULL; _fd_debug("[%d.%d] failed before beginning\n", tid, agent); #if STEAL_WORK > 0 #ifdef NEW_ENTRANCE failed_initially = true; pthread_spin_lock(&entrance_lock); ++agents_failed; pthread_spin_unlock(&entrance_lock); while (agents_searching == 0 && agents_failed < nagents) ; if (agents_searching == 0) return FD_NOSOLUTION; #endif /* NEW_ENTRANCE */ #if RANDOM_VICTIM >= 2 // XXX: to check if this is needed/useful // give the other agents time to start searching nanosleep(&tsettle, NULL); #endif do { #ifndef INDEX_IN_POOL if (!_fd_steal_store(store, agent_no, 7)) #else if (!_fd_steal_store(store, &variable, agent_no, 7)) #endif { _fd_debug("[%d.%d] giving up\n", tid, agent); return FD_NOSOLUTION; } #ifdef CONSTRAINT_TEMPS fd__constraint_data_reset(); // XXX: this doesn't belong here! #endif } while (_fd_revise_wrt_variable(variable) == FD_NOSOLUTION); #else /* STEAL_WORK > 0 */ return FD_NOSOLUTION; #endif /* STEAL_WORK > 0 */ } #if DEBUG_SPLITGO > 1 _fd_output("[%d.%d] ", tid, agent); _fd_cprint2(variables); #endif #ifdef NEW_ENTRANCE pthread_spin_lock(&entrance_lock); if (failed_initially) --agents_failed; ++agents_searching; pthread_spin_unlock(&entrance_lock); #endif _fd_debug("[%d.%d] about to start searching\n", tid, agent); return _fd_dsearch_(variables); } static int _fd_dsearch_(fd_int _fd_variables[]) { #ifndef STORE_IN_POOL _fd_store alt_store; #endif fd_int variable; int instantiations = 0, backtrack = 0; #ifdef DEBUG_SEARCH printf("* before search\n"); _fd_cprint2(_fd_variables); #endif // start by selecting a variable while (variable = _fd_var_select2(fd__label_vars)) { // clone store _fd_start_saving_store(&alt_store); // split domain _fd_val_split(DOMAIN_REF(variable), (DOMAIN_REF_T()) (alt_store + variable->index)); // XXX _fd_epoch_forward(); instantiations++; #ifdef DEBUG_PROGRESS if (instantiations % 100000 == 0) _fd_debug("[%d.%d] still alive (%d stores)\n", tid, agent, next_split_index - base_split_index); #endif #ifndef INLINE_DOMAINS assert(!_fd_val_empty((DOMAIN_REF_T()) (alt_store + variable->index))); #else assert(!_fd_val_empty(alt_store[variable->index])); #endif _fd_end_saving_store(variable); while (_fd_revise_wrt_variable(variable) == FD_NOSOLUTION) { #ifdef DEBUG_SEARCH printf("* fail\n"); _fd_cprint2(_fd_variables); #endif // check whether this thread has been cancelled // XXX: is there a better place to put this? if (!_fd_counting_solutions) pthread_testcancel(); _fd_epoch_rewind(); do { // try to ``restore'' the store if (!_fd_restore_store(&variable)) { if (!_fd_counting_solutions) { _fd_debug("[%d.%d] performed %d instantiations and %d backtracks\n", tid, agent, instantiations, backtrack); _fd_statistics_pool(); } return FD_NOSOLUTION; } backtrack++; } while (_fd_optimising && fd__bound_and_revise() == FD_NOSOLUTION); if (_fd_optimising && variable == _fd_bound_variable()) break; if (variable && !fd_var_single(variable, NULL)) break; } } #ifdef DEBUG_SEARCH printf("* succeed\n"); _fd_cprint2(_fd_variables); #endif if (!_fd_counting_solutions) { _fd_debug("[%d.%d] performed %d instantiations and %d backtracks\n", tid, agent, instantiations, backtrack); _fd_debug("[%d.%d] %d stores in store\n", tid, agent, next_split_index - base_split_index); _fd_statistics_pool(); } #ifdef STORE_IN_POOL memcpy(main_store, store, STORE_SIZE); #endif return FD_OK; // found a solution: all domains are singletons } int _fd_dsearch_again(fd_int _fd_variables[]) { fd_int variable; do { // try to restore the state to the previous store _fd_epoch_rewind(); if (!_fd_restore_store(&variable)) return FD_NOSOLUTION; } while (// force the propagation of the new bound when optimising _fd_optimising && fd__bound_and_revise() == FD_NOSOLUTION || (!_fd_optimising || variable != _fd_bound_variable()) && (!variable || fd_var_single(variable, NULL)) && _fd_revise_wrt_variable(variable) == FD_NOSOLUTION); return _fd_dsearch_(_fd_variables); } unsigned long long _fd_count_solutions(fd_int variables[], int agent_no) { unsigned long long solutions = 0; if (_fd_dsearch(variables, agent_no) == FD_OK) { solutions = 1; while (_fd_dsearch_again(variables) == FD_OK) solutions++; } _fd_statistics_pool(); return solutions; }