def test_create_trans(self): fsm = self.model() p = eval_simple_expression(fsm, "p") new_trans = BddTrans.from_string(fsm.bddEnc.symbTable, "next(p) = !p") self.assertEqual(new_trans.post(p), ~p) with self.assertRaises(NuSMVFlatteningError): new_trans = BddTrans.from_string(fsm.bddEnc.symbTable, "next(p) = !p", strcontext="main")
def test_create_trans_counters_assign(self): fsm = self.model("tests/pynusmv/models/counters-assign.smv") c1c0bdd = evalSexp(fsm, "c1.c = 0") c2c0bdd = evalSexp(fsm, "c2.c = 0") c1c1bdd = evalSexp(fsm, "c1.c = 1") c2c1bdd = evalSexp(fsm, "c2.c = 1") self.assertEqual(c1c0bdd & c2c0bdd, fsm.init) self.assertEqual(c1c0bdd & c2c1bdd | c1c1bdd & c2c0bdd, fsm.post(fsm.init)) fsmbuilder = nscompile.Compile_get_global_fsm_builder() enc = nsenc.Enc_get_bdd_encoding() ddmanager = nsbddenc.BddEnc_get_dd_manager(enc) base_enc = nsbddenc.bddenc2baseenc(enc) symb_table = nsbaseenc.BaseEnc_get_symb_table(base_enc) propDb = glob.prop_database() master = propDb.master sexpfsm_ptr = nsprop.Prop_get_scalar_sexp_fsm(master._ptr) # Create a new expr trans c2c = self.get_variable_from_string(sexpfsm_ptr, "c2.c") self.assertIsNotNone(c2c) # trans = next(c2c) = (c2.c + 1) % 4 nextc2c = nssexp.Expr_next(c2c, symb_table) one = nsnode.create_node(parser.NUMBER, None, None) one.left.nodetype = nsnode.int2node(1) self.assertEqual(nsnode.sprint_node(one), "1") four = nsnode.create_node(parser.NUMBER, None, None) four.left.nodetype = nsnode.int2node(4) self.assertEqual(nsnode.sprint_node(four), "4") c2cp1 = nssexp.Expr_plus(c2c, one) c2cp1m4 = nssexp.Expr_mod(c2cp1, four) trans = nssexp.Expr_equal(nextc2c, c2cp1m4, symb_table) clusters = nsfsm.FsmBuilder_clusterize_expr(fsmbuilder, enc, trans) cluster_options = nsbddtrans.ClusterOptions_create( nsopt.OptsHandler_get_instance()) bddTrans = BddTrans( nsbddtrans.BddTrans_create( ddmanager, clusters, nsbddenc.BddEnc_get_state_vars_cube(enc), nsbddenc.BddEnc_get_input_vars_cube(enc), nsbddenc.BddEnc_get_next_state_vars_cube(enc), nsopt.get_partition_method(nsopt.OptsHandler_get_instance()), cluster_options)) fsm.trans = bddTrans self.assertEqual(c1c0bdd & c2c0bdd, fsm.init) self.assertEqual(c2c1bdd, fsm.post(fsm.init))
def _compute_epistemic_trans(self, agents): from .glob import symb_table trans = None for agent in agents: if agent not in self._epistemic: raise UnknownAgentError( str(agents) + " are an unknown agents names.") trans = nsnode.find_node(nsparser.AND, self._epistemic[agent], trans) self._epistemic_trans[frozenset(agents)] = BddTrans.from_trans( symb_table(), trans)
def _compute_epistemic_trans(self, agents): from .glob import symb_table trans = None for agent in agents: if agent not in self._epistemic: raise UnknownAgentError(str(agents) + " are an unknown agents names.") trans = nsnode.find_node(nsparser.AND, self._epistemic[agent], trans) self._epistemic_trans[agents] = BddTrans.from_trans(symb_table(), trans)
def encode_strategies(mas, agents, formula, filtered): """ Encode the strategies for agents, to check formula, given the filtered moves. mas -- a multi-agents system; agents -- a subset of agents of mas; formula -- an ATLK_irF strategic formula where the group is agents; filtered -- either the complete protocol of the agents, or the filtered moves for agents, for the given formula. The result is the presence, in mas.transitions[formula], of three relations under the "jump", "equiv", and "follow" keys, to perform the model checking: * the "jump" relation encode the fact that the original state stays the same and all strategies can change; * the "equiv" relation encode the fact that the states are equivalent for some agent in the group of formula, and the strategies of these agents are kept the same; * the "follow" relation encode the original transition relation with each agent of the group of formula following his strategy encoded in the current state (and that these strategies are kept the same). Note: mas.encoded is populated with intermediate cached information: * mas.encoded[(agent, filtered)] gives two (model-based) relations: + the relation encoding the fact that the encoded strategies of agent from filtered are kept the same; + the relation encoding the fact that the encoded strategies of agent are followed; they only depends on the agent and the filtered moves, thus if two sub-formulas have the same filtered moves (e.g., pre-filtering is not used), the relations are the same; * mas.encoded[agent] gives the relation encoding the equivalence for agent; it only depends on agent, since it only depends on what he observes; THIS RELATION DOES NOT ENCODE THE FACT THAT THE STRATEGIES DO NOT CHANGE; * mas.encoded["jump"] gives the relation encoding the fact that the state is the same but the strategies can change; it only depends on the MAS, since all strategies are free and only the state is kept identical. """ if not hasattr(mas, "transitions"): mas.transitions = {} if not hasattr(mas, "encoded"): mas.encoded = {} # if mas.encoded["jump"] does not exist, # encode it, based on the original state variables of the model if "jump" not in mas.encoded: jump = jump_relation(mas) mas.encoded["jump"] = jump # Encode each agent variables and relations if needed # for each agent in agents, # if (agent, filtered) is not in mas.encoded, # compute them for agent in agents: if (agent, filtered) not in mas.encoded: relations = strategy_relations(mas, agents, agent, filtered) mas.encoded[(agent, filtered)] = relations # for each agent in agents, # if mas.encoded[agent] is not present, # compute it for agent in agents: if agent not in mas.encoded: relation = equivalence_relation(mas, agent) mas.encoded[agent] = relation # Encode the transition relations if formula not in mas.transitions: mas.transitions[formula] = {} # the "jump" relation is just mas.encoded["jump"] if "jump" not in mas.transitions[formula]: jump = mas.encoded["jump"] trans = BddTrans.from_string(mas.bddEnc.symbTable, str(jump)) mas.transitions[formula]["jump"] = trans # the "equiv" relation is based on # * the "equiv" relations of each agent in agents # (disjunction, for group knowledge) # * the strategies of the agents are the same # (based on the variables of each agent, stored in # mas.encoded[(agent, filtered)]) if "equiv" not in mas.transitions[formula]: equiv = reduce(operator.or_, (mas.encoded[agent] for agent in agents), model.Falseexp()) equiv = reduce(operator.and_, (mas.encoded[(agent, filtered)][0] for agent in agents), equiv) trans = BddTrans.from_string(mas.bddEnc.symbTable, str(equiv)) mas.transitions[formula]["equiv"] = trans # the "follow" relation is based on # * the original transition relation of the MAS; # * the fact that the strategies of the agents are the same, # and that the strategies for agents are followed by these agents, # given by the variables in mas.encoded[(agent, filtered)] if "follow" not in mas.transitions[formula]: flat = glob.flat_hierarchy() follow = reduce(operator.and_, (mas.encoded[(agent, filtered)][0] & mas.encoded[(agent, filtered)][1] for agent in agents), flat.trans) trans = BddTrans.from_string(mas.bddEnc.symbTable, str(follow)) mas.transitions[formula]["follow"] = trans
def test_get_trans_counters_assign(self): fsm = self.model("tests/pynusmv/models/counters-assign.smv") c1c0bdd = evalSexp(fsm, "c1.c = 0") c2c0bdd = evalSexp(fsm, "c2.c = 0") c1c1bdd = evalSexp(fsm, "c1.c = 1") c2c1bdd = evalSexp(fsm, "c2.c = 1") self.assertEqual(c1c0bdd & c2c0bdd, fsm.init) self.assertEqual(c1c0bdd & c2c1bdd | c1c1bdd & c2c0bdd, fsm.post(fsm.init)) fsmbuilder = nscompile.Compile_get_global_fsm_builder() enc = nsenc.Enc_get_bdd_encoding() ddmanager = nsbddenc.BddEnc_get_dd_manager(enc) propDb = glob.prop_database() master = propDb.master sexpfsm_ptr = nsprop.Prop_get_scalar_sexp_fsm(master._ptr) trans = self.trans_for_module(sexpfsm_ptr, "c2") # ANALYSE THE TRANS TO UNDERSTAND HOW TO CREATE NUMBERS #car = nsnode.car #cdr = nsnode.cdr #print("TRANS--------------------------------") #print(nsnode.sprint_node(cdr(trans))) #print("TRANS--------------------------------") # cdr(trans) = #case #run = rc2 : case #c2.c + 1 >= stop : start; #c2.c + 1 < stop : c2.c + 1; #esac; #!(run = rc2) : c2.c; #esac # car(cdr(trans)) = #run = rc2 : case #c2.c + 1 >= stop : start; #c2.c + 1 < stop : c2.c + 1; #esac; # cdr(car(cdr(trans))) = #case #c2.c + 1 >= stop : start; #c2.c + 1 < stop : c2.c + 1; #esac # car(cdr(car(cdr(trans)))) = #c2.c + 1 >= stop : start # car(car(cdr(car(cdr(trans))))) = #c2.c + 1 >= stop # car(car(car(cdr(car(cdr(trans)))))) = #c2.c + 1 # car(car(car(car(cdr(car(cdr(trans))))))) = #c2.c # car(car(car(car(car(cdr(car(cdr(trans)))))))) = #c2 # cdr(car(car(car(car(cdr(car(cdr(trans)))))))) = #c # cdr(car(car(car(cdr(car(cdr(trans))))))) = #1 #print(cdr(cdr(car(car(car(car(cdr(car(cdr(trans)))))))))) #print(nsnode.sprint_node(cdr(car(car(car(car(cdr(car(cdr(trans)))))))))) clusters = nsfsm.FsmBuilder_clusterize_expr(fsmbuilder, enc, trans) cluster_options = nsbddtrans.ClusterOptions_create( nsopt.OptsHandler_get_instance()) bddTrans = BddTrans( nsbddtrans.BddTrans_create( ddmanager, clusters, nsbddenc.BddEnc_get_state_vars_cube(enc), nsbddenc.BddEnc_get_input_vars_cube(enc), nsbddenc.BddEnc_get_next_state_vars_cube(enc), nsopt.get_partition_method(nsopt.OptsHandler_get_instance()), cluster_options)) fsm.trans = bddTrans self.assertEqual(c1c0bdd & c2c0bdd, fsm.init) self.assertEqual(c2c1bdd | c2c0bdd, fsm.post(fsm.init))
spec = prop.expr print(spec) bdd = pynusmv.mc.eval_ctl_spec(fsm, spec) & fsm.reachable_states bdd print("BDD Manipulation\n") print("reachable states from initial states :") #init print(fsm.count_states(fsm.init)) for state in fsm.pick_all_states(fsm.init): print(state.get_str_values()) print("\ntransition relations pre or post-images :") #transition relation for state in fsm.pick_all_states(fsm.post(fsm.init)): print(state.get_str_values()) print("\nspecial case of transition relations co-exist :") #next from pynusmv.fsm import BddTrans trans = BddTrans.from_string(fsm.bddEnc.symbTable,"next(F_operon) = 0") for state in fsm.pick_all_states(trans.post(fsm.init)): print(state.get_str_values()) print("\nFrom the BDD-encoded FSM fsm and the specification spec, we call the eval_ctl_spec function to get all the states of fsm satisfying spec. Conjuncted with the set of reachables states of the model, we get bdd, a BDD representing all the reachable states of fsm satisfying spec. Finally, from this BDD we extract all the single states and display them, that is, we display, for each of them, the value of each state variable of the model :") satstates = fsm.pick_all_states(bdd) for state in satstates: print(state.get_str_values())