def get_instances_for_module(self, modtree): """ Return the list of variables that are instances of modules in module modtree. modtree is a part of the AST of the SMV model. modtree.type = MODULE """ # MODULE(MODTYPE(...), declarationlist) varlist = [] declarations = nsnode.cdr(modtree) while declarations is not None: decl = nsnode.car(declarations) if decl.type == nsparser.VAR: decl = nsnode.car(decl) while decl is not None: var = nsnode.car(decl) # var_id : type => COLON(ATOM, type) if nsnode.cdr(var).type == nsparser.MODTYPE: varlist.append(var) decl = nsnode.cdr(decl) declarations = nsnode.cdr(declarations) return varlist
def test_equal_atoms(self): test = parse_next_expression("test") test = nsnode.find_node(test.type, nsnode.car(test), nsnode.cdr(test)) same = parse_next_expression("test") same = nsnode.find_node(same.type, nsnode.car(same), nsnode.cdr(same)) other = parse_next_expression("testx") other = nsnode.find_node(other.type, nsnode.car(other), nsnode.cdr(other)) self.assertTrue(nsnode.node_equal(test, same) != 0) self.assertTrue(nsnode.node_equal(test, other) == 0)
def __getitem__(self, val): """ Return the BDD stored at val. :param val: the index requested OR a slice. .. note:: cannot access elements with negative indices. """ if isinstance(val, int): if val < 0: raise IndexError("BDDList index out of range") ptr = self._ptr while val > 0: if ptr is None: raise IndexError("BDDList index out of range") val -= 1 ptr = nsnode.cdr(ptr) if ptr is None: raise IndexError("BDDList index out of range") bdd_ptr = nsnode.node2bdd(nsnode.car(ptr)) if bdd_ptr is not None: return BDD(nsdd.bdd_dup(bdd_ptr), self._manager, freeit=True) else: return None elif isinstance(val, slice): # TODO Implement slicing raise NotImplementedError("BDDList slice not implemented") else: raise IndexError("BDDList index wrong type")
def get_str_values(self, layers=None): """ Return a dictionary of the (variable, value) pairs of these Inputs. :param layers: if not `None`, the set of names of the layers from which picking the string values :rtype: a dictionary of pairs of strings. """ enc = self._fsm.bddEnc # Get symb table from enc (BaseEnc) table = enc.symbTable # Get symbols (SymbTable) for inputs if layers is None: layers = nssymb_table.SymbTable_get_class_layer_names( table._ptr, None) symbols = nssymb_table.SymbTable_get_layers_i_symbols( table._ptr, layers) layers_array = None else: layers_array = nsutils.array_alloc_strings(len(layers)) for i, layer in enumerate(layers): nsutils.array_insert_strings(layers_array, i, layer) symbols = nssymb_table.SymbTable_get_layers_i_symbols( table._ptr, layers_array) # Get assign symbols (BddEnc) assign_list = nsbddEnc.BddEnc_assign_symbols(enc._ptr, self._ptr, symbols, 0, None) values = {} # Traverse the symbols to print variables of the state assign_list_ptr = assign_list while assign_list_ptr: assignment = nsnode.car(assign_list_ptr) var = nsnode.car(assignment) val = nsnode.cdr(assignment) values[nsnode.sprint_node(var)] = nsnode.sprint_node(val) assign_list_ptr = nsnode.cdr(assign_list_ptr) nsnode.free_list(assign_list) nsutils.NodeList_destroy(symbols) if layers_array: nsutils.array_free(layers_array) return values
def show_types(self, node, indent=""): if node is not None: if node.type not in {nsparser.NUMBER, nsparser.ATOM}: print(indent + str(node.type)) self.show_types(nsnode.car(node), indent + " ") self.show_types(nsnode.cdr(node), indent + " ") else: print(indent + str(node.type), ":", nsnode.sprint_node(node)) else: print(indent + "None")
def __iter__(self): ptr = self._ptr while ptr: # Yield BDD copy bdd_ptr = nsnode.node2bdd(nsnode.car(ptr)) if bdd_ptr is not None: yield BDD(nsdd.bdd_dup(bdd_ptr), self._manager, freeit=True) else: yield None ptr = nsnode.cdr(ptr)
def car(this_node): """ Returns the lhs branch of this node. .. note:: This is a simple workaround of `Node.car` which does not behave as expected. :param this_node: the node whose lhs (car) is wanted. :return: the lhs member of this node. """ return Node.from_ptr(_node.car(this_node._ptr))
def from_nusmv_errors_list(errors): """ Create a new NuSMVParsingError from the given list of NuSMV errors. :param errors: the list of errors from NuSMV """ errlist = [] while errors is not None: error = nsnode.car(errors) err = nsparser.Parser_get_syntax_error(error) errlist.append(_Error(*err[1:])) errors = nsnode.cdr(errors) return NuSMVParsingError(tuple(errlist))
def get_str_values(self): """ Return a dictionary of the (variable, value) pairs of this StateInputs. :rtype: a dictionary of pairs of strings. """ enc = self._fsm.bddEnc # Get symb table from enc (BaseEnc) table = enc.symbTable # Get symbols (SymbTable) for states layers = nssymb_table.SymbTable_get_class_layer_names(table._ptr, None) symbols = nssymb_table.SymbTable_get_layers_sf_symbols( table._ptr, layers) isymbols = nssymb_table.SymbTable_get_layers_i_symbols( table._ptr, layers) nsutils.NodeList_concat(symbols, isymbols) nsutils.NodeList_destroy(isymbols) # Get assign symbols (BddEnc) assign_list = nsbddEnc.BddEnc_assign_symbols(enc._ptr, self._ptr, symbols, 0, None) values = {} # Traverse the symbols to print variables of the state assign_list_ptr = assign_list while assign_list_ptr: assignment = nsnode.car(assign_list_ptr) var = nsnode.car(assignment) val = nsnode.cdr(assignment) values[nsnode.sprint_node(var)] = nsnode.sprint_node(val) assign_list_ptr = nsnode.cdr(assign_list_ptr) nsnode.free_list(assign_list) nsutils.NodeList_destroy(symbols) return values
def _get_instances_args_for_module(modtree): """ Return a dictionary of instance name -> list of instance arguments pairs, with instances of modules in module modtree. modtree is a part of the AST of the SMV model. modtree.type = MODULE """ # MODULE(MODTYPE(...), declarationlist) varlist = {} declarations = nsnode.cdr(modtree) while declarations is not None: decl = nsnode.car(declarations) if decl.type == nsparser.VAR: decl = nsnode.car(decl) while decl is not None: var = nsnode.car(decl) # var_id : type => COLON(ATOM, type) if nsnode.cdr(var).type == nsparser.MODTYPE: varid = nsnode.sprint_node(nsnode.car(var)) if varid in varlist: pass # TODO Variable already defined else: # Compute args list argslist = [] args = nsnode.cdr(nsnode.cdr(var)) while args is not None: arg = nsnode.car(args) argslist.append(arg) args = nsnode.cdr(args) varlist[varid] = argslist decl = nsnode.cdr(decl) declarations = nsnode.cdr(declarations) return varlist
def car(self): """ The left child of this specification. :rtype: :class:`Spec` """ if self._car == "undefined": left = nsnode.car(self._ptr) if left: self._car = Spec(left, freeit=self._freeit) else: self._car = None return self._car
def _free(self): if self._freeit and self._ptr is not None: # Free content ptr = self._ptr while ptr: # Free BDD bdd_ptr = nsnode.node2bdd(nsnode.car(ptr)) if bdd_ptr is not None: nsdd.bdd_free(self._manager._ptr, bdd_ptr) ptr = nsnode.cdr(ptr) # Free list nsnode.free_list(self._ptr) self._freeit = False
def test_run_checkctlspec(self): ret = cmd.Cmd_SecureCommandExecute("read_model -i" " tests/pynusmv/models/admin.smv") self.assertEqual(ret, 0) ret = cmd.Cmd_SecureCommandExecute("go") self.assertEqual(ret, 0) node, err = nsparser.ReadSimpExprFromString("admin = alice") self.assertIsNotNone(node) node = nsnode.car(node) self.assertIsNotNone(node) node = Spec(node) self.assertIsNotNone(node)
def _fairness_conversion(self, fairness): """ Converts the given `fairness` into a Be representation. .. note:: This function is present for purely technical reason: under the hood, NuSMV encodes the fairness list as a NodeList however the 'car' (value) of these nodes is nothing that can be understood AST-wise. Indeed, the values are opaque pointers (be_ptr that is to say void*) to a structure representing a Be. """ beptr = _be.node_ptr_to_be_ptr(_node.car(fairness._ptr)) bexpr = Be(beptr, self.encoding.manager) return bexpr
def parse_ltl_spec(spec): """ Parse a LTL specification :param string spec: the specification to parse :raise: a :exc:`NuSMVParsingError <pynusmv.exception.NuSMVParsingError>` if a parsing error occurs .. warning:: Returned value is a SWIG wrapper for the NuSMV node_ptr. It is the responsibility of the caller to manage it. """ node, err = nsparser.ReadCmdFromString("LTLWFF " + spec) if err: errors = nsparser.Parser_get_syntax_errors_list() raise NuSMVParsingError.from_nusmv_errors_list(errors) else: node = nsnode.car(node) # Get rid of the top CTLWFF node if node.type is nsparser.CONTEXT and nsnode.car(node) is None: # Get rid of the top empty context if any return nsnode.cdr(node) else: return node
def parse_next_expression(expression): """ Parse a "next" expression. :param string expression: the expression to parse :raise: a :exc:`NuSMVParsingError <pynusmv.exception.NuSMVParsingError>` if a parsing error occurs .. warning:: Returned value is a SWIG wrapper for the NuSMV node_ptr. It is the responsibility of the caller to manage it. """ node, err = nsparser.ReadNextExprFromString(expression) if err: errors = nsparser.Parser_get_syntax_errors_list() raise NuSMVParsingError.from_nusmv_errors_list(errors) else: node = nsnode.car(node) # Get rid of the top NEXTWFF node if node.type is nsparser.CONTEXT and nsnode.car(node) is None: # Get rid of the top empty context if any return nsnode.cdr(node) else: return node
def mas(agents=None, initial_ordering=None): """ Return (and compute if needed) the multi-agent system represented by the currently read SMV model. If agents is not None, the set of agents (and groups) of the MAS is determined by agents. Otherwise, every top-level module instantiation is considered an agent where - her actions are the inputs variables prefixed by her name; - her observable variables are composed of * the state variables of the system prefixed by her name; * the state variables provided as an argument to the module instantiation. If initial_ordering is not None, it must be the path to a variables ordering file. It is used as the initial ordering for variables of the model. Note: if the MAS is already computed, agents and initial_ordering arguments have no effect. agents -- a set of agents. """ global __mas if __mas is None: # Check cmps if not nscompile.cmp_struct_get_read_model(nscompile.cvar.cmps): raise NuSMVNoReadModelError("Cannot build MAS; no read file.") if agents is None: # Get agents names tree = nsparser.cvar.parsed_tree main = None while tree is not None: module = nsnode.car(tree) if (nsnode.sprint_node(nsnode.car( nsnode.car(module))) == "main"): main = module tree = nsnode.cdr(tree) if main is None: print("[ERROR] No main module.") return # TODO Error, cannot find main module arguments = _get_instances_args_for_module(main) # arguments is a dict instancename(str)->listofargs(node) agents = arguments.keys() # Compute the model _compute_model(variables_ordering=initial_ordering) st = symb_table() # Flatten arguments and filter on variables argvars = _flatten_and_filter_variable_args(arguments) # Get agents observable variables (locals + module parameters) localvars = _get_variables_by_instances(agents) #localvars is a dict instancename(str)->listofvars(node) inputvars = _get_input_vars_by_instances(agents) # Merge instance variable arguments and local variables variables = { key: ((key in argvars and argvars[key] or []) + (key in localvars and localvars[key] or [])) for key in list(argvars.keys()) + list(localvars.keys()) } # Compute epistemic relation singletrans = {} for agent in variables: transexpr = None for var in variables[agent]: var = nsnode.sprint_node(var) transexpr = nsnode.find_node(nsparser.AND, _get_epistemic_trans(var), transexpr) singletrans[agent] = transexpr # Process variables to get strings instead of nodes observedvars = { ag: {nsnode.sprint_node(v) for v in variables[ag]} for ag in variables.keys() } inputvars = { ag: {nsnode.sprint_node(v) for v in inputvars[ag]} for ag in inputvars.keys() } groups = None else: _compute_model(variables_ordering=initial_ordering) # observedvars: a dictionary of agent name -> set of observed vars observedvars = { str(agent.name): [str(var) for var in agent.observables] for agent in agents } # inputsvars: a dictionary of agent name -> set of inputs vars inputvars = { str(agent.name): [str(ivar) for ivar in agent.actions] for agent in agents } # groups: # a dictionary of group name -> names of agents of the group groups = { str(group.name): [str(agent.name) for agent in group.agents] for group in agents if isinstance(group, Group) } # singletrans: a dictionary of agent name -> epistemic transition singletrans = {} for agent in agents: name = str(agent.name) transexpr = None for var in observedvars[name]: transexpr = nsnode.find_node(nsparser.AND, _get_epistemic_trans(var), transexpr) singletrans[name] = transexpr # Create the MAS fsm = _prop_database().master.bddFsm __mas = MAS(fsm._ptr, observedvars, inputvars, singletrans, groups=groups, freeit=False) return __mas