void reach_sat_loop(reach_proc_t reach_proc, vset_t visited, bitvector_t *reach_groups, long *eg_count, long *next_count, long *guard_count) { bitvector_t groups[max_sat_levels]; int empty_groups[max_sat_levels]; vset_t old_vis = vset_create(domain, -1, NULL); vset_t prev_vis[nGrps]; for (int k = 0; k < max_sat_levels; k++) bitvector_create(&groups[k], nGrps); initialize_levels(groups, empty_groups, NULL, reach_groups); for (int i = 0; i < max_sat_levels; i++) prev_vis[i] = save_sat_levels?vset_create(domain, -1, NULL):NULL; while (!vset_equal(old_vis, visited)) { vset_copy(old_vis, visited); for (int k = 0; k < max_sat_levels; k++) { if (empty_groups[k]) continue; Warning(infoLong, "Saturating level: %d", k); reach_proc(visited, prev_vis[k], &groups[k], eg_count, next_count,guard_count); check_invariants(visited, -1); if (save_sat_levels) vset_copy(prev_vis[k], visited); } } for (int k = 0; k < max_sat_levels; k++) bitvector_free(&groups[k]); vset_destroy(old_vis); if (save_sat_levels) for (int i = 0; i < max_sat_levels; i++) vset_destroy(prev_vis[i]); }
void reach_sat_fix(reach_proc_t reach_proc, vset_t visited, bitvector_t *reach_groups, long *eg_count, long *next_count, long *guard_count) { (void) reach_proc; (void) guard_count; if (PINS_USE_GUARDS) Abort("guard-splitting not supported with saturation=sat-fix"); int level = 0; vset_t old_vis = vset_create(domain, -1, NULL); vset_t deadlocks = dlk_detect?vset_create(domain, -1, NULL):NULL; vset_t dlk_temp = dlk_detect?vset_create(domain, -1, NULL):NULL; LACE_ME; while (!vset_equal(visited, old_vis)) { if (trc_output != NULL) save_level(visited); vset_copy(old_vis, visited); stats_and_progress_report(NULL, visited, level); level++; for(int i = 0; i < nGrps; i++){ if (!bitvector_is_set(reach_groups, i)) continue; expand_group_next(i, visited); reach_chain_stop(); (*eg_count)++; } if (dlk_detect) vset_copy(deadlocks, visited); if (USE_PARALLELISM) vset_least_fixpoint_par(visited, visited, group_next, nGrps); else vset_least_fixpoint(visited, visited, group_next, nGrps); (*next_count)++; check_invariants(visited, level); if (dlk_detect) { for (int i = 0; i < nGrps; i++) { vset_prev(dlk_temp, visited, group_next[i],deadlocks); reduce(i, dlk_temp); vset_minus(deadlocks, dlk_temp); vset_clear(dlk_temp); } deadlock_check(deadlocks, reach_groups); } vset_reorder(domain); } vset_destroy(old_vis); if (dlk_detect) { vset_destroy(deadlocks); vset_destroy(dlk_temp); } }
void reach_sat(reach_proc_t reach_proc, vset_t visited, bitvector_t *reach_groups, long *eg_count, long *next_count, long *guard_count) { (void) reach_proc; (void) next_count; (void) guard_count; if (PINS_USE_GUARDS) Abort("guard-splitting not supported with saturation=sat"); if (act_detect != NULL && trc_output != NULL) Abort("Action detection with trace generation not supported"); for (int i = 0; i < nGrps; i++) { if (bitvector_is_set(reach_groups, i)) { struct expand_info *ctx = RTmalloc(sizeof(struct expand_info)); ctx->group = i; ctx->group_explored = group_explored[i]; ctx->eg_count = eg_count; vrel_set_expand(group_next[i], expand_group_next_projected, ctx); } } if (trc_output != NULL) save_level(visited); stats_and_progress_report(NULL, visited, 0); if (USE_PARALLELISM) vset_least_fixpoint_par(visited, visited, group_next, nGrps); else vset_least_fixpoint(visited, visited, group_next, nGrps); stats_and_progress_report(NULL, visited, 1); check_invariants(visited, -1); if (dlk_detect) { vset_t deadlocks = vset_create(domain, -1, NULL); vset_t dlk_temp = vset_create(domain, -1, NULL); vset_copy(deadlocks, visited); for (int i = 0; i < nGrps; i++) { vset_prev(dlk_temp, visited, group_next[i],deadlocks); reduce(i, dlk_temp); vset_minus(deadlocks, dlk_temp); vset_clear(dlk_temp); } deadlock_check(deadlocks, reach_groups); vset_destroy(deadlocks); vset_destroy(dlk_temp); } }
/** * \brief Adds level for player to strategy. */ void update_strategy_levels(recursive_result* result, int player, vset_t level) { if (result->strategy_levels_count[player]==result->strategy_levels_max[player]) { result->strategy_levels_max[player] += INIT_STRATEGY_MAX; result->strategy_levels[player] = RTrealloc(result->strategy_levels[player], (result->strategy_levels_max[player])*sizeof(vset_t)); } result->strategy_levels[player][result->strategy_levels_count[player]] = vset_create(result->dom, -1, NULL); vset_copy(result->strategy_levels[player][result->strategy_levels_count[player]], level); //printf("update_strategy_levels: player=%d, index=%d.\n", player, result->strategy_levels_count[player]); result->strategy_levels_count[player]++; result->strategy_boundaries[player][result->strategy_boundary_count[player]-1]++; //printf("update_strategy_levels: levels_count=%d, boundary[boundary_count-1=%d]=%d.\n", // result->strategy_levels_count[player], result->strategy_boundary_count[player]-1, // result->strategy_boundaries[player][result->strategy_boundary_count[player]-1]); assert(result->strategy_boundaries[player][result->strategy_boundary_count[player]-1] == result->strategy_levels_count[player]); }
/** * \brief Creates a symbolic parity game from the generated LTS. */ parity_game * compute_symbolic_parity_game(vset_t visited, int *src) { Print(infoShort, "Computing symbolic parity game."); debug_output_enabled = true; // num_vars and player have been pre-computed by init_pbes. parity_game* g = spg_create(domain, N, nGrps, min_priority, max_priority); for(int i=0; i < N; i++) { g->src[i] = src[i]; } vset_copy(g->v, visited); for(size_t i = 0; i < num_vars; i++) { // players Print(infoLong, "Adding nodes for var %zu (player %d).", i, player[i]); add_variable_subset(g->v_player[player[i]], g->v, g->domain, i); // priorities add_variable_subset(g->v_priority[priority[i]], g->v, g->domain, i); } if (log_active(infoLong)) { for(int p = 0; p < 2; p++) { long n_count; double elem_count; vset_count(g->v_player[p], &n_count, &elem_count); Print(infoLong, "player %d: %ld nodes, %.*g elements.", p, n_count, DBL_DIG, elem_count); } for(int p = min_priority; p <= max_priority; p++) { long n_count; double elem_count; vset_count(g->v_priority[p], &n_count, &elem_count); Print(infoLong, "priority %d: %ld nodes, %.*g elements.", p, n_count, DBL_DIG, elem_count); } } for(int i = 0; i < nGrps; i++) { g->e[i] = group_next[i]; } return g; }
/** * \brief Combines strategy levels for player. */ void concat_strategy_levels_player (int player, vdom_t domain, vset_t** dst, int* dst_count, int** dst_boundaries, int* dst_boundary_count, vset_t** src, int* src_count, int** src_boundaries, int* src_boundary_count) { //printf("concat_strategy_levels: player=%d, dst_count=%d, src_count=%d, dst_boundary_count=%d, src_boundary_count=%d.\n", // player, dst_count[player], src_count[player], dst_boundary_count[player], src_boundary_count[player]); dst[player] = RTrealloc(dst[player], (dst_count[player]+src_count[player])*sizeof(vset_t)); for (int i = 0; i < src_count[player]; i++) { dst[player][dst_count[player] + i] = vset_create(domain, -1, NULL); vset_copy(dst[player][dst_count[player] + i], src[player][i]); } dst_boundaries[player] = RTrealloc(dst_boundaries[player], (dst_boundary_count[player]+src_boundary_count[player])*sizeof(int)); for (int i = 0; i < src_boundary_count[player]; i++) { dst_boundaries[player][dst_boundary_count[player]+i] = src_boundaries[player][i] + dst_count[player]; } dst_count[player] += src_count[player]; dst_boundary_count[player] += src_boundary_count[player]; //printf("concat_strategy_levels: player=%d, dst_count=%d, dst_boundary_count=%d.\n", // player, dst_count[player], dst_boundary_count[player]); }
int main(int argc, char *argv[]){ char *files[2]; RTinitPopt(&argc,&argv,options,1,2,files,NULL,"<model> [<lts>]", "Perform an enumerative reachability analysis of <model>\n" "Run the TorX remote procedure call protocol on <model> (--torx).\n\n" "Options"); if (files[1]) { Warning(info,"Writing output to %s",files[1]); write_lts=1; } else { Warning(info,"No output, just counting the number of states"); write_lts=0; } if (application==RunTorX && write_lts) Fatal(1,error,"A TorX server does not write to a file"); Warning(info,"loading model from %s",files[0]); model_t model=GBcreateBase(); GBsetChunkMethods(model,new_string_index,NULL, (int2chunk_t)SIgetC,(chunk2int_t)SIputC,(get_count_t)SIgetCount); GBloadFile(model,files[0],&model); if (RTverbosity >=2) { fprintf(stderr,"Dependency Matrix:\n"); GBprintDependencyMatrix(stderr,model); } if (matrix) { GBprintDependencyMatrix(stdout,model); exit(0); } lts_type_t ltstype=GBgetLTStype(model); N=lts_type_get_state_length(ltstype); edge_info_t e_info=GBgetEdgeInfo(model); K=e_info->groups; Warning(info,"length is %d, there are %d groups",N,K); state_labels=lts_type_get_state_label_count(ltstype); edge_labels=lts_type_get_edge_label_count(ltstype); Warning(info,"There are %d state labels and %d edge labels",state_labels,edge_labels); if (state_labels&&write_lts&&!write_state) { Fatal(1,error,"Writing state labels, but not state vectors unsupported. " "Writing of state vector is enabled with the option --write-state"); } int src[N]; GBgetInitialState(model,src); Warning(info,"got initial state"); int level=0; switch(application){ case ReachVset: domain=vdom_create_default(N); visited_set=vset_create(domain,0,NULL); next_set=vset_create(domain,0,NULL); if (write_lts){ output=lts_output_open(files[1],model,1,0,1,"viv",NULL); lts_output_set_root_vec(output,(uint32_t*)src); lts_output_set_root_idx(output,0,0); output_handle=lts_output_begin(output,0,0,0); } vset_add(visited_set,src); vset_add(next_set,src); vset_t current_set=vset_create(domain,0,NULL); while (!vset_is_empty(next_set)){ if (RTverbosity >= 1) Warning(info,"level %d has %d states, explored %d states %d trans", level,(visited-explored),explored,trans); level++; vset_copy(current_set,next_set); vset_clear(next_set); vset_enum(current_set,explore_state_vector,model); } long long size; long nodes; vset_count(visited_set,&nodes,&size); Warning(info,"%lld reachable states represented symbolically with %ld nodes",size,nodes); break; case ReachTreeDBS: dbs=TreeDBScreate(N); if(TreeFold(dbs,src)!=0){ Fatal(1,error,"expected 0"); } if (write_lts){ output=lts_output_open(files[1],model,1,0,1,write_state?"vsi":"-ii",NULL); if (write_state) lts_output_set_root_vec(output,(uint32_t*)src); lts_output_set_root_idx(output,0,0); output_handle=lts_output_begin(output,0,0,0); } int limit=visited; while(explored<visited){ if (limit==explored){ if (RTverbosity >= 1) Warning(info,"level %d has %d states, explored %d states %d trans", level,(visited-explored),explored,trans); limit=visited; level++; } TreeUnfold(dbs,explored,src); explore_state_index(model,explored,src); } break; case RunTorX: { torx_struct_t context = { model, ltstype }; torx_ui(&context); return 0; } } if (write_lts){ lts_output_end(output,output_handle); Warning(info,"finishing the writing"); lts_output_close(&output); Warning(info,"state space has %d levels %d states %d transitions",level,visited,trans); } else { printf("state space has %d levels %d states %d transitions\n",level,visited,trans); } return 0; }
int choose_strategy_move(const parity_game* g, const recursive_result* strategy, const int player, const int* src, int* current_player, bool* strategy_play, bool* result, bool* deadlock, int* dst) { int group = -1; vset_t level = vset_create(g->domain, -1, NULL); vset_t tmp = vset_create(g->domain, -1, NULL); vset_t singleton = vset_create(g->domain, -1, NULL); vset_add(singleton, src); // Do a random run through the game, conforming to // the strategy in result. *current_player = (vset_member(g->v_player[player], src) ? player : 1-player); Print(hre_debug, "Using strategy of player %d. The position is owned by player %d.", player, *current_player); if (*current_player==player && vset_member(strategy->win[player], src)) { //printf("Player %d chooses according to his/her winning strategy.\n", player); // Choose a transition according to the strategy of player *strategy_play = true; vset_t strategy_level = vset_create(g->domain, -1, NULL); compute_strategy_level(strategy_level, src, player, strategy); vset_clear(level); for (int i=0; i < g->num_groups; i++) { vset_next(tmp, singleton, g->e[i]); vset_intersect(tmp, strategy_level); if (!vset_is_empty(tmp)) { vset_copy(level, tmp); // Choose a random element: //printf("Choosing a transition from transition group %d.\n", i); group = i; vset_random(level, dst); break; } } // Check for deadlocks if (vset_is_empty(level)) { *deadlock = true; *result = (*current_player != player); Print(infoLong, "Deadlock for player %d, player %s has won, result is %s.", *current_player, (*current_player==1) ? "0 (even / or)" : "1 (odd / and)", *result ? "true" : "false"); } } else { //Print(info, "Not player %d's turn or player %d has no winning strategy. Choosing an arbitrary move for player %d.", // player, player, *current_player); // this states belongs to (1-player) or player does not have a winning strategy *strategy_play = false; vset_t strategy_level = vset_create(g->domain, -1, NULL); /* if (vset_member(result.win[current_player], src)) { // winning move after all compute_strategy_level(strategy_level, src, current_player, result); if (vset_is_empty(strategy_level)) { Print(info, "Unexpected: src is in win[%d], but strategy_level is empty.", current_player); } else { strategy_play = true; } } */ // choose a random move vset_clear(level); for (int i=0; i < g->num_groups; i++) { vset_next(tmp, singleton, g->e[i]); if (*strategy_play && !vset_is_empty(tmp)) { vset_intersect(tmp, strategy_level); if (!vset_is_empty(tmp)) { vset_copy(level, tmp); // Choose a random element: //printf("Choosing a transition from transition group %d.\n", i); group = i; vset_random(level, dst); break; } } else { vset_union(level, tmp); } } // Check for deadlocks if (vset_is_empty(level)) { *deadlock = true; *result = (*current_player != player); Print(infoLong, "Deadlock for player %d, player %s has won, result is %s.", *current_player, (*current_player==1) ? "0 (even / or)" : "1 (odd / and)", *result ? "true" : "false"); } else if (!*strategy_play) { //Print(info, "choose randomly"); vset_random(level, dst); } } return group; }
static void actual_main(void *arg) #endif { int argc = ((struct args_t*)arg)->argc; char **argv = ((struct args_t*)arg)->argv; /* initialize HRE */ HREinitBegin(argv[0]); HREaddOptions(options,"Perform a symbolic reachability analysis of <model>\n" "The optional output of this analysis is an ETF " "representation of the input\n\nOptions"); lts_lib_setup(); // add options for LTS library HREinitStart(&argc,&argv,1,2,files,"<model> [<etf>]"); /* initialize HRE on other workers */ init_hre(HREglobal()); /* check for unsupported options */ if (PINS_POR != PINS_POR_NONE) Abort("Partial-order reduction and symbolic model checking are not compatible."); if (inhibit_matrix != NULL && sat_strategy != NO_SAT) Abort("Maximal progress is incompatibale with saturation."); if (files[1] != NULL) { char *ext = strrchr(files[1], '.'); if (ext == NULL || ext == files[1]) { Abort("Output filename has no extension!"); } if (strcasecmp(ext, ".etf") != 0) { // not ETF if (!(vset_default_domain == VSET_Sylvan && strcasecmp(ext, ".bdd") == 0) && !(vset_default_domain == VSET_LDDmc && strcasecmp(ext, ".ldd") == 0)) { Abort("Only supported output formats are ETF, BDD (with --vset=sylvan) and LDD (with --vset=lddmc)"); } if (PINS_USE_GUARDS) { Abort("Exporting symbolic state space not comptabile with " "guard-splitting"); } } } #ifdef HAVE_SYLVAN if (!USE_PARALLELISM) { if (strategy == PAR_P) { strategy = BFS_P; Print(info, "Front-end not thread-safe; using --order=bfs-prev instead of --order=par-prev."); } else if (strategy == PAR) { strategy = BFS; Print(info, "Front-end not thread-safe; using --order=bfs instead of --order=par."); } } #endif /* turn off Lace for now to speed up while not using parallelism */ lace_suspend(); /* initialize the model and PINS wrappers */ init_model(files[0]); /* initialize action detection */ act_label = lts_type_find_edge_label_prefix (ltstype, LTSMIN_EDGE_TYPE_ACTION_PREFIX); if (act_label != -1) action_typeno = lts_type_get_edge_label_typeno(ltstype, act_label); if (act_detect != NULL) init_action_detection(); bitvector_create(&state_label_used, sLbls); if (inv_detect != NULL) init_invariant_detection(); else if (PINS_USE_GUARDS) { for (int i = 0; i < nGuards; i++) { bitvector_set(&state_label_used, i); } } init_maxsum(ltstype); /* turn on Lace again (for Sylvan) */ if (vset_default_domain==VSET_Sylvan || vset_default_domain==VSET_LDDmc) { lace_resume(); } if (next_union) vset_next_fn = vset_next_union_src; init_domain(VSET_IMPL_AUTOSELECT); vset_t initial = vset_create(domain, -1, NULL); int *src = RTmalloc (sizeof(int[N])); GBgetInitialState(model, src); vset_add(initial, src); Print(infoShort, "got initial state"); /* if writing .dot files, open directory first */ if (dot_dir != NULL) { DIR* dir = opendir(dot_dir); if (dir) { closedir(dir); } else if (ENOENT == errno) { Abort("Option 'dot-dir': directory '%s' does not exist", dot_dir); } else { Abort("Option 'dot-dir': failed opening directory '%s'", dot_dir); } } if (vset_dir != NULL) { DIR *dir = opendir(vset_dir); if (dir) { closedir(dir); } else if (errno == ENOENT) { Abort("Option 'save-levels': directory '%s' does not exist", vset_dir); } else { Abort("Option 'save-levels': failed opening directory '%s'", vset_dir); } } init_mu_calculus(); /* determine if we need to generate a symbolic parity game */ #ifdef LTSMIN_PBES bool spg = true; #else bool spg = GBhaveMucalc() ? true : false; #endif /* if spg, then initialize labeling stuff before reachability */ if (spg) { Print(infoShort, "Generating a Symbolic Parity Game (SPG)."); init_spg(model); } /* create timer */ reach_timer = RTcreateTimer(); /* fix level 0 */ visited = vset_create(domain, -1, NULL); vset_copy(visited, initial); /* check the invariants at level 0 */ check_invariants(visited, 0); /* run reachability */ run_reachability(visited, files[1]); /* report states */ final_stat_reporting(visited); /* save LTS */ if (files[1] != NULL) { char *ext = strrchr(files[1], '.'); if (strcasecmp(ext, ".etf") == 0) { do_output(files[1], visited); } else { // if not .etf, then the filename ends with .bdd or .ldd, symbolic LTS do_dd_output (initial, visited, files[1]); } } compute_maxsum(visited, domain); CHECK_MU(visited, src); if (max_mu_count > 0) { Print(info, "Mu-calculus peak nodes: %ld", max_mu_count); } /* optionally print counts of all group_next and group_explored sets */ final_final_stats_reporting (); if (spg) { // converting the LTS to a symbolic parity game, save and solve. lts_to_pg_solve (visited, src); } #ifdef HAVE_SYLVAN /* in case other Lace threads were still suspended... */ if (vset_default_domain!=VSET_Sylvan && vset_default_domain!=VSET_LDDmc) { lace_resume(); } else if (SYLVAN_STATS) { sylvan_stats_report(stderr); } #endif RTfree (src); GBExit(model); }