static inline int on_stack_accepting_up (wctx_t *ctx, int *accepting) { cndfs_alg_local_t *cloc = (cndfs_alg_local_t *) ctx->local; size_t *depth; int on_stack; on_stack = fset_find (cloc->pink, NULL, &ctx->state->ref, (void**)&depth, true); HREassert (on_stack != FSET_FULL); if (!on_stack) { *accepting = pins_state_is_accepting(ctx->model, state_info_state(ctx->state)) != 0; Debug ("Added state %zu %s with depth %zu accepting depth", ctx->state->ref, (*accepting ? "(accepting)" : ""), cloc->accepting_depth); *depth = cloc->accepting_depth; // write currect accepting depth cloc->accepting_depth += *accepting; } return on_stack; }
int cndfs_state_seen (void *ptr, transition_info_t *ti, ref_t ref, int seen) { wctx_t *ctx = (wctx_t *) ptr; cndfs_alg_local_t *cloc = (cndfs_alg_local_t *) ctx->local; void *level; if (!seen) { seen = fset_find (cloc->pink, NULL, &ref, &level, false); HREassert (seen != FSET_FULL); } if (seen) return 1; uint32_t old = state_store_get_colors (ref) & 3; return -(old == CCYAN); (void) ti; }
static void tarjan_handle (void *arg, state_info_t *successor, transition_info_t *ti, int seen) { // parent state is ctx->state wctx_t *ctx = (wctx_t *) arg; alg_local_t *loc = ctx->local; raw_data_t *addr; hash32_t hash; int found; ctx->counters->trans++; // self-loop if (ctx->state->ref == successor->ref) return; // completed SCC if (state_store_has_color (successor->ref, SCC_STATE, 0)) return; hash = ref_hash (successor->ref); found = fset_find (loc->visited_states, &hash, &successor->ref, (void **)&addr, false); if (found) { // previously visited state ==> update lowlink state_info_deserialize (loc->target, *addr); if (loc->state_tarjan.lowlink > loc->target_tarjan.lowlink) loc->state_tarjan.lowlink = loc->target_tarjan.lowlink; } else { // unseen state ==> push to search_stack raw_data_t stack_loc = dfs_stack_push (loc->search_stack, NULL); state_info_serialize (successor, stack_loc); } (void) ti; (void) seen; }
static void endfs_handle_red (void *arg, state_info_t *successor, transition_info_t *ti, int seen) { wctx_t *ctx = (wctx_t *) arg; alg_local_t *loc = ctx->local; cndfs_alg_local_t *cloc = (cndfs_alg_local_t *) ctx->local; int onstack; /* Find cycle back to the seed */ HREassert (cloc->accepting_depth > 0); size_t *level; onstack = ctx->state->ref == loc->seed->ref; if (!onstack) { onstack = fset_find (cloc->pink, NULL, &successor->ref, (void**)&level, false); HREassert (onstack != FSET_FULL); } if ( onstack && *level < cloc->accepting_depth ) ndfs_report_cycle (ctx, ctx->model, loc->stack, successor); /* Mark states dangerous if necessary */ if ( Strat_ENDFS == loc->strat && pins_state_is_accepting(ctx->model, state_info_state(successor)) && state_store_get_colors (successor->ref) != CRED ) state_store_try_color(successor->ref, GDANGEROUS, loc->rec_bits); if ( !onstack && state_store_get_colors (successor->ref) != CRED ) { raw_data_t stack_loc = dfs_stack_push (loc->stack, NULL); state_info_serialize (successor, stack_loc); } // check proviso if (PINS_POR && proviso == Proviso_CNDFS && cloc->successors == NONEC) { if (ti->por_proviso != 0) { // state already fully expanded cloc->successors = SRCINV; } else if (onstack) { // cycle check if (onstack) cloc->successors = CYCLE; } // avoid full exploration (proviso is enforced later in backtrack) ti->por_proviso = 1; // avoid full exploration } (void) seen; }
/** * move a search_stack state to the tarjan_stack */ static void move_tarjan (wctx_t *ctx, state_info_t *state, raw_data_t state_data) { alg_local_t *loc = ctx->local; raw_data_t *addr; hash32_t hash; int found; // add state to tarjan_stack raw_data_t tarjan_loc = dfs_stack_push (loc->tarjan_stack, NULL); state_info_serialize (state, tarjan_loc); // Update reference to the new stack hash = ref_hash (state->ref); found = fset_find (loc->visited_states, &hash, &state->ref, (void**) &addr, false); HREassert (*addr == state_data, "Wrong addr?"); HREassert (found, "Could not find key in set"); *addr = tarjan_loc; }
static void endfs_handle_blue (void *arg, state_info_t *successor, transition_info_t *ti, int seen) { wctx_t *ctx = (wctx_t *) arg; alg_local_t *loc = ctx->local; cndfs_alg_local_t *cloc = (cndfs_alg_local_t *) ctx->local; size_t *level; int onstack = fset_find (cloc->pink, NULL, &successor->ref, (void**)&level, false); HREassert (onstack != FSET_FULL); /** * The following lines bear little resemblance to the algorithms in the * respective papers (Evangelista et al./ Laarman et al.), but we must * store all non-red states on the stack in order to calculate * all-red correctly later. Red states are also stored as optimization. */ if ( ecd && onstack && *level < cloc->accepting_depth) { /* Found cycle in blue search */ ndfs_report_cycle (ctx, ctx->model, loc->stack, successor); } else if ( all_red || (!onstack && state_store_get_colors (successor->ref) != CBLUE) ) { raw_data_t stack_loc = dfs_stack_push (loc->stack, NULL); state_info_serialize (successor, stack_loc); } // check proviso if (PINS_POR && proviso == Proviso_CNDFS && cloc->successors == NONEC) { if (ti->por_proviso != 0) { // state already fully expanded cloc->successors = SRCINV; } else if (onstack) { // check cycle cloc->successors = CYCLE; } // avoid full exploration (proviso is enforced later in backtrack) ti->por_proviso = 1; } (void) seen; }
static int resize (fset_t *dbs, fset_resize_t mode) { void *key, *data; bool res; if (dbs->resizing) return true; dbs->resizing = 1; size_t old_size = dbs->size; switch (mode) { case GROW: if (dbs->size == dbs->size_max) { dbs->resizing = 0; return false; } memset (dbs->hash + dbs->size, 0, sizeof (mem_hash_t[dbs->size])); dbs->size <<= 1; dbs->size3 <<= 1; break; case SHRINK: if (dbs->size == dbs->init_size) { dbs->resizing = 0; return true; } dbs->size >>= 1; dbs->size3 >>= 1; break; case REHASH: break; } dbs->mask = dbs->size - 1; Debug ("%s %zu to %zu", fset_resize_names[mode], old_size, dbs->size); //RTstartTimer (dbs->timer); size_t tombs = 0; size_t todos = 0; for (size_t i = 0; i < old_size; i++) { mem_hash_t h = *memoized(dbs,i); if (TOMB == h) { tombs++; *memoized(dbs, i) = EMPTY; } else if (h != EMPTY) {// && home_loc(h) & dbs->mask != i) { dbs->todo[todos] = *memoized(dbs,i); void *tdata = bucket(dbs, dbs->todo_data, todos); void *data = bucket(dbs, dbs->data, i); memcpy (tdata, data, dbs->total_length); todos++; *memoized(dbs, i) = EMPTY; } } dbs->tombs -= tombs; dbs->load -= todos; HREassert (dbs->tombs == 0); for (size_t i = 0; i < todos; i++) { mem_hash_t h = dbs->todo[i]; key = bucket(dbs, dbs->todo_data, i); res = fset_find (dbs, &h, key, &data, true); // load++ HREassert (!res); memcpy (data, key + dbs->key_length, dbs->data_length); } //RTstopTimer (dbs->timer); Debug ("%s %zu to %zu took %zu/%zu todos and cleaned %zu/%zu tombstones in %.2f sec", fset_resize_names[mode], old_size, dbs->size, todos, dbs->load, tombs, dbs->load + tombs, RTrealTime(dbs->timer)); dbs->max_todos = max (todos, dbs->max_todos); dbs->max_grow = max (dbs->max_grow, dbs->size); dbs->resizes++; dbs->resizing = 0; return true; }
void tarjan_run (run_t *run, wctx_t *ctx) { alg_local_t *loc = ctx->local; raw_data_t *addr; raw_data_t state_data; bool on_stack; hash32_t hash; #ifdef HAVE_PROFILER Warning (info, "Using the profiler"); ProfilerStart ("tarjan.perf"); #endif #ifdef SEARCH_COMPLETE_GRAPH int init_state = dlopen_get_worker_initial_state (ctx->id, W); int inits = 0; // loop until every state of the graph has been visited while ( 1 ) { inits ++; // use loc->target as a dummy for the initial state loc->target->ref = init_state; #endif tarjan_init (ctx); // continue until we are done exploring the graph while ( !run_is_stopped (run) ) { state_data = dfs_stack_top (loc->search_stack); if (state_data != NULL) { // there is a state on the current stackframe ==> explore it state_info_deserialize (ctx->state, state_data); // pop the state and continue if it is part of a completed SCC if (state_store_has_color (ctx->state->ref, SCC_STATE, 0)) { dfs_stack_pop (loc->search_stack); continue; } hash = ref_hash (ctx->state->ref); on_stack = fset_find (loc->visited_states, &hash, &ctx->state->ref, (void **) &addr, true); if (!on_stack) { // unseen state ==> initialize and explore HREassert (loc->cnt.tarjan_counter != UINT32_MAX); loc->cnt.tarjan_counter ++; loc->state_tarjan.index = loc->cnt.tarjan_counter; loc->state_tarjan.lowlink = loc->cnt.tarjan_counter; // point visited_states data to stack *addr = state_data; explore_state (ctx); state_info_serialize (ctx->state, state_data); } else { // previously visited state ==> update parent // NB: state is on tarjan_stack state_info_deserialize (ctx->state, *addr); update_parent (ctx, loc->state_tarjan.lowlink); dfs_stack_pop (loc->search_stack); } } else { // there is no state on the current stackframe ==> backtrack // we are done if we backtrack from the initial state if (0 == dfs_stack_nframes (loc->search_stack)) break; // leave the stackframe dfs_stack_leave (loc->search_stack); ctx->counters->level_cur--; // retrieve the parent state from search_stack (to be removed) state_data = dfs_stack_top (loc->search_stack); state_info_deserialize (ctx->state, state_data); Debug ("Backtracking %zu (%d, %d)", ctx->state->ref, loc->state_tarjan.index, loc->state_tarjan.lowlink); if (loc->state_tarjan.index == loc->state_tarjan.lowlink) { // index == lowlink ==> root of the SCC ==> report the SCC pop_scc (ctx, ctx->state->ref, loc->state_tarjan.lowlink); } else { // lowlink < index ==> LIVE SCC ==> move to tarjan_stack move_tarjan (ctx, ctx->state, state_data); update_parent (ctx, loc->state_tarjan.lowlink); } dfs_stack_pop (loc->search_stack); } } #ifdef SEARCH_COMPLETE_GRAPH init_state = dlopen_get_new_initial_state (init_state); if (init_state == -1) { Warning(info, "Number of inits : %d", inits); break; } } #endif #ifdef HAVE_PROFILER Warning(info, "Done profiling"); ProfilerStop(); #endif if (!run_is_stopped(run) && dfs_stack_size(loc->tarjan_stack) != 0) Warning (info, "Tarjan stack not empty: %zu (stack %zu)", dfs_stack_size(loc->tarjan_stack), dfs_stack_size(loc->search_stack)); if (!run_is_stopped(run) && fset_count(loc->visited_states) != 0) Warning (info, "Stack-set not empty: %zu", fset_count(loc->visited_states)); }
/* ENDFS dfs_red */ static void endfs_red (wctx_t *ctx) { alg_local_t *loc = ctx->local; cndfs_alg_local_t *cloc = (cndfs_alg_local_t *) ctx->local; size_t seed_level = dfs_stack_nframes (loc->stack); int accepting = 0; int on_stack; size_t count = fset_count(cloc->pink); size_t *level; while ( !run_is_stopped(ctx->run) ) { raw_data_t state_data = dfs_stack_top (loc->stack); if (NULL != state_data) { state_info_deserialize (ctx->state, state_data); // seed is only state on both cyan and pink stack on_stack = ctx->state->ref == loc->seed->ref; if (!on_stack) { on_stack = fset_find (cloc->pink, NULL, &ctx->state->ref, (void**)&level, false); HREassert (on_stack != FSET_FULL); } if (!on_stack && state_store_get_colors(ctx->state->ref) != CRED) { on_stack_accepting_up (ctx, &accepting); //add to stack bitvector_unset (&loc->stackbits, cur(ctx,INVOL)); dfs_stack_push (cloc->in_stack, state_data); if ( Strat_CNDFS == loc->strat && ctx->state->ref != loc->seed->ref && accepting) dfs_stack_push (cloc->out_stack, state_data); endfs_explore_state_red (ctx); } else { if (seed_level == dfs_stack_nframes (loc->stack)) break; dfs_stack_pop (loc->stack); } } else { //backtrack dfs_stack_leave (loc->stack); ctx->counters->level_cur--; /* exit search if backtrack hits seed, leave stack the way it was */ if (seed_level == dfs_stack_nframes(loc->stack)) break; state_data = dfs_stack_top (loc->stack); state_info_deserialize (ctx->state, state_data); if (check_cndfs_proviso(ctx)) { reach_explore_all (ctx, ctx->state); continue; } accepting = pins_state_is_accepting (ctx->model, state_info_state(ctx->state)) != 0; accepting_down (ctx, ctx->state, accepting); dfs_stack_pop (loc->stack); } } if (!run_is_stopped(ctx->run)) { HREassert (fset_count(cloc->pink) == count); } }