/* General Framework for State Space Exploration Program Module explore.c, Revision 2.0, Date 1996-08-19 */ #include #include #include #include "explore.h" #include "problem.h" /* explore.h defines the bag ADT and the types state_index_t - states are indexed by this type bag_of_state_index_t - a bag of state indexes bag_of_bag_of_state_index_t - a bag of bags of state indexes The specific details of the problem are defined in problem.h and problem.c, which must provide: NUM_SYS_STATES - we assume that the state set Q can be indexed by ints (aka state_index_t) 0 ... NUM_SYS_STATES-1 int target[NUM_SYS_STATES] - the target set for the problem, where target[q_i] = 1 if state q_i is in the target set 0 otherwise bag_of_bag_of_state_index_t sigma[NUM_SYS_STATES] - the schedular choice fuction. The scheduling demon can take any of the actions in sigma(q), where q is the current state q_i - current state index. Notationally, _i means the index of a state. sigma[q_i] is the entry corresponding to sigma(q) sigma[q_i].card - number of different scheduling choices sigma[q_i].item[j] - choice j sigma[q_i].item[j].card - number of possible sys states resulting from choice j sigma[q_i].item[j].item[k] - k'th possible result state of choice j char* state_index_to_str(state_index_t s_i) - a conversion function to convert a state index into a printable string int compute_sigma(void) - a function to compute the sigma table, returning 1 if ok, 0 if some error occurred. int compute_target(void) - a function to compute the target set, returning 1 if ok, 0 if some error occurred. This code then computes the avoidance probabilities p[q][i] is the probability that, starting in state q, the schedular can avoid the target set for at least i steps. and the path length estimates l[q] is (an estimate of) the expected length of a path, that starting at q avoids the target set. */ double p[NUM_SYS_STATES][NUM_SYS_STATES+1]; double l[NUM_SYS_STATES]; int verify_no_deadlock(void) { /* Verify that every state has at least one progress making successor, and print those that do not. Pre: sigma is well-defined Post: verify_no_deadlock() is 1 - if OK 0 - if one or more states deadlock Side Effects: prints the states that result in deadlock. */ int q_i; int no_deadlock = 1; printf("Checking for deadlock states.\n"); for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { if ( sigma[q_i].card <= 0 ) { printf("State %d deadlocks\n", q_i); no_deadlock = 0; } } if ( no_deadlock ) { printf("All states are deadlock free.\n\n"); } else { printf("NOT all states are deadlock free.\n\n"); } return no_deadlock; } void compute_avoidance_probs(void) { /* Compute avoidance probabilities and determine self-stabilization as per Prop 2.5, Prop 2.11, and Theorem 2.10 Pre: sigma is well-defined target is well-defined Post: none Side Effects: -computes p[q_i][n] for each q and for 0 <= n <= NUM_SYS_STATES -determines upper bound on expected value of the length of an avoiding path -determines whether system is self-stabilizing or not */ int q_i; int iter_num; /* initial probabilities and expected avoidance path lengths */ for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { if ( target[q_i] ) { /* in the target set, cannot avoid */ p[q_i][0] = 0.0; } else { /* outside target set, can avoid for 0 steps */ p[q_i][0] = 1.0; } l[q_i] = 0.0; } /* compute p[iter_num] for 0 ... NUM_SYS_STATES */ for ( iter_num = 0; iter_num < NUM_SYS_STATES; iter_num++ ) { for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { double max_prob = 0.0; /* compute maximum over all successors */ /* if no scheduling choices, prob is constant, equals p[q_i][0] */ if ( sigma[q_i].card == 0 ) { p[q_i][iter_num+1] = p[q_i][0]; } else { int item_num; /* sum over scheduling choices */ for (item_num=0; item_num < sigma[q_i].card; item_num++) { int sys_item_num; double succ_prob = 0; int i; /* each scheduling choice must result in at least one next state! */ assert( sigma[q_i].item[item_num].card != 0 ); /* sum over next states for the choice */ for (sys_item_num=0; sys_item_num < sigma[q_i].item[item_num].card; sys_item_num++) { i = sigma[q_i].item[item_num].item[sys_item_num]; succ_prob += p[i][iter_num]; } succ_prob = succ_prob / ( (double) sigma[q_i].item[item_num].card ); max_prob = MAX(max_prob, succ_prob); } p[q_i][iter_num+1] = max_prob; } } /* update expected length */ for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { l[q_i] += ( (double) iter_num ) * p[q_i][iter_num] * (1.0 - p[q_i][iter_num+1] ); } } /* update tail estimates */ { double pmax = 0; double exp_len_max = 0; double exp_len_sum = 0; double n = NUM_SYS_STATES; double tail; for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { pmax = MAX(pmax, p[q_i][NUM_SYS_STATES]); } tail = n * pmax * ( -1.0 - n * pmax + 3.0 * n + pmax) / (2 * (1-pmax) * (1-pmax)); for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { /* add in tail only if prob non-zero */ if ( p[q_i][NUM_SYS_STATES] > 0.0 ) { l[q_i] += tail; } exp_len_sum += l[q_i]; exp_len_max = MAX(exp_len_max, l[q_i]); } printf("Number of states, n = %d\n", (int) n); printf("Max over q of p_n(q) = %g\n", pmax); printf("Upper bound on tail of expected length, l(q) = %g\n", tail); printf("Maximum over q of l(q) = %g\n", exp_len_max); printf("Average over q of l(q) = %g\n", exp_len_sum/n); if ( pmax < 1.0 ) { printf("System is self stabilizing.\n"); } else { printf("WARNING: System is NOT self stabilizing.\n"); } } } void print_details(void) { /* Print out details of sigma expected path lengths avoiding probabilities Pre: sigma, target, p must be well-defined */ int q_i; printf("Computation details:\n"); printf("q p_n(q) l(q) sigma(q)\n"); for (q_i=0; q_i < NUM_SYS_STATES; q_i++ ) { printf("%s %8.2g %5.1f", state_index_to_str(q_i), p[q_i][NUM_SYS_STATES], l[q_i]); { int item_num; int sys_item_num; for (item_num=0; item_num < sigma[q_i].card; item_num++) { if ( sigma[q_i].item[item_num].card <= 0 ) { printf("item %d is empty!\n", item_num); } printf(" {"); for (sys_item_num=0; sys_item_num < sigma[q_i].item[item_num].card; sys_item_num++) { int qn_i; qn_i = sigma[q_i].item[item_num].item[sys_item_num]; printf("%s", state_index_to_str(qn_i)); if ( sys_item_num+1 < sigma[q_i].item[item_num].card){ printf(", "); } } printf("}"); } } printf("\n"); } printf("\n"); } void main(int argc, char* argv[]) { if ( ! compute_sigma() ) exit(0); if ( ! verify_no_deadlock() ) exit(0); if ( ! compute_target() ) exit(0); compute_avoidance_probs(); /* uncomment the following to see details of the avoidance probs */ /* print_details(); */ }