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 test_smv_incorrect_file(self): car = nsnode.car cdr = nsnode.cdr f = "tests/pynusmv/models/counter-syntax-error.smv" nsopt.set_input_file(nsopt.OptsHandler_get_instance(), f) ret = nsparser.Parser_ReadSMVFromFile(f) # When parsing a model with parser_is_lax enabled, the parser gets # as many correct parts of the model as possible and build a partial # model with it. # In this example, a partial model is built, this is why the command # returns 0. self.assertEqual(ret, 0) errors = nsparser.Parser_get_syntax_errors_list() self.assertIsNotNone(errors) while errors is not None: error = car(errors) err = nsparser.Parser_get_syntax_error(error) self.assertIsNotNone(err) self.assertEqual(len(err), 4) errors = cdr(errors)
def flatten_hierarchy(keep_single_enum=False): """ Flatten the read model and store it in global data structures. :param keep_single_enum: whether or not enumerations with single values should be converted into defines :type keep_single_enum: bool :raise: a :exc:`NuSMVNoReadModelError <pynusmv.exception.NuSMVNoReadModelError>` if no model is read yet :raise: a :exc:`NuSMVCannotFlattenError <pynusmv.exception.NuSMVCannotFlattenError>` if an error occurred during flattening :raise: a :exc:`NuSMVModelAlreadyFlattenedError <pynusmv.exception.NuSMVModelAlreadyFlattenedError>` if the model is already flattened .. warning:: In case of type checking errors, a message is printed at stderr and a :exc:`NuSMVCannotFlattenError <pynusmv.exception.NuSMVCannotFlattenError>` is raised. """ # Check cmps if not nscompile.cmp_struct_get_read_model(global_compile_cmps()): raise NuSMVNoReadModelError("Cannot flatten; no read model.") if nscompile.cmp_struct_get_flatten_hrc(global_compile_cmps()): raise NuSMVModelAlreadyFlattenedError("Model already flattened.") # Update options to reflect keep_single_enum if keep_single_enum: nsopt.set_keep_single_value_vars(nsopt.OptsHandler_get_instance()) else: nsopt.unset_keep_single_value_vars(nsopt.OptsHandler_get_instance()) # Flatten hierarchy ret = nscompile.flatten_hierarchy() if ret != 0: raise NuSMVCannotFlattenError("Cannot flatten the model.") global __symb_table __symb_table = SymbTable(nscompile.Compile_get_global_symb_table())
def is_cone_of_influence_enabled(): """ This function returns true iff the cone of influence (coi) option is enabled. :return: true iff the cone of influence (coi) option is enabled """ opthandler = nsopt.OptsHandler_get_instance() is_coi_enabled = nsopt.OptsHandler_get_bool_option_value( opthandler, "cone_of_influence") return is_coi_enabled
def check_ltl_spec(spec): """ Return whether the loaded SMV model satisfies or not the LTL given `spec`. That is, return whether all initial states of le model satisfies `spec` or not. :param spec: a specification :type spec: :class:`Spec <pynusmv.prop.Spec>` :rtype: bool """ # Check that a model has been compiled assert(glob.prop_database().master is not None) # Create a property from the given spec prop = nsprop.Prop_create_partial(spec._ptr, propTypes["LTL"]) # Save settings o = nsopt.OptsHandler_get_enum_option_value( nsopt.OptsHandler_get_instance(), "oreg_justice_emptiness_bdd_algorithm") if (nscompile. FlatHierarchy_get_compassion(glob. global_compile_flathierarchy()) is None and o == nsfsmbdd.BDD_OREG_JUSTICE_EMPTINESS_BDD_ALGORITHM_EL_FWD): saved_options = nsfsmbdd.Bdd_elfwd_check_set_and_save_options( nsfsmbdd.BDD_ELFWD_OPT_ALL) else: saved_options = None # Create, build and check the structure for LTL model checking ltl_struct = nsltl.Ltl_StructCheckLtlSpec_create(prop) nsltl.Ltl_StructCheckLtlSpec_build(ltl_struct) nsltl.Ltl_StructCheckLtlSpec_check(ltl_struct) # Get the result result = nsprop.Prop_get_status(prop) == nsprop.Prop_True # Destroy the intermediate structure nsltl.Ltl_StructCheckLtlSpec_destroy(ltl_struct) # Restore settings if saved_options is not None: nsfsmbdd.Bdd_elfwd_restore_options(nsfsmbdd.BDD_ELFWD_OPT_ALL, saved_options) # Destroy prop nsprop.Prop_destroy(prop) return result
def build_model(): """ Build the BDD FSM of the current model and store it in global data structures. :raise: a :exc:`NuSMVNeedFlatModelError <pynusmv.exception.NuSMVNeedFlatModelError>` if the Sexp FSM of the model is not built yet :raise: a :exc:`NuSMVNeedVariablesEncodedError <pynusmv.exception.NuSMVNeedVariablesEncodedError>` if the variables of the model are not encoded yet :raise: a :exc:`NuSMVModelAlreadyBuiltError <pynusmv.exception.NuSMVModelAlreadyBuiltError>` if the BDD FSM of the model is already built """ # Check cmps if not nscompile.cmp_struct_get_build_flat_model(global_compile_cmps()): raise NuSMVNeedFlatModelError("Need flat model.") if not nscompile.cmp_struct_get_encode_variables(global_compile_cmps()): raise NuSMVNeedVariablesEncodedError("Need variables encoded.") if nscompile.cmp_struct_get_build_model(global_compile_cmps()): raise NuSMVModelAlreadyBuiltError("The model is already built.") # Build the model pd = nsprop.PropPkg_get_prop_database() sexp_fsm = nsprop.PropDb_master_get_scalar_sexp_fsm(pd) bdd_fsm = nsfsm.FsmBuilder_create_bdd_fsm( nscompile.Compile_get_global_fsm_builder(), nsenc.Enc_get_bdd_encoding(), sexp_fsm, nsopt.get_partition_method(nsopt.OptsHandler_get_instance())) nsprop.PropDb_master_set_bdd_fsm(pd, bdd_fsm) # Register executors enc = nsbddfsm.BddFsm_get_bdd_encoding(bdd_fsm) nstrace.TraceManager_register_complete_trace_executor( nstrace.TracePkg_get_global_trace_manager(), "bdd", "BDD partial trace execution", nstraceexec.bddCompleteTraceExecutor2completeTraceExecutor( nstraceexec.BDDCompleteTraceExecutor_create(bdd_fsm, enc))) nstrace.TraceManager_register_partial_trace_executor( nstrace.TracePkg_get_global_trace_manager(), "bdd", "BDD complete trace execution", nstraceexec.bddPartialTraceExecutor2partialTraceExecutor( nstraceexec.BDDPartialTraceExecutor_create(bdd_fsm, enc))) # Update cmps nscompile.cmp_struct_set_build_model(global_compile_cmps())
def test_namecheR1(self): # activate bdd dynamic reordering nsopt.set_dynamic_reorder(nsopt.OptsHandler_get_instance()) fsm = self.nameche_model() # AG (T_04BM.st = o & TRP_CM.krc = s -> AX (!R1.L_CS)) to = prop.atom("T_04BM.st = o") trps = prop.atom("TRP_CM.krc = s") nr1lcs = prop.atom("!R1.L_CS") p = prop.imply(to & trps, prop.ax(nr1lcs)) self.assertTrue(fsm.reachable_states <= eval_ctl(fsm, p)) # AG (EF R1.L_CS) r1lcs = prop.atom("R1.L_CS") p = prop.ef(r1lcs) self.assertTrue(fsm.reachable_states <= eval_ctl(fsm, p))
def enable_dynamic_reordering(DDmanager=None, method="sift"): """ Enable dynamic reordering of BDD variables under control of `DDmanager` with the given `method`. :param DDmanager: the concerned DD manager; if None, the global DD manager is used instead. :type DDmanager: :class:`DDManager` :param method: the method to use for reordering: `sift (default method)`, `random`, `random_pivot`, `sift_converge`, `symmetry_sift`, `symmetry_sift_converge`, `window{2, 3, 4}`, `window{2, 3, 4}_converge`, `group_sift`, `group_sift_converge`, `annealing`, `genetic`, `exact`, `linear`, `linear_converge`, `same` (the previously chosen method) :type method: :class:`str` :raise: a :exc:`MissingManagerError <pynusmv.exception.MissingManagerError>` if the manager is missing .. note:: For more information on reordering methods, see NuSMV manual. """ if DDmanager is None: DDmanager_ptr = nscinit.cvar.dd_manager else: DDmanager_ptr = DDmanager._ptr if DDmanager_ptr is None: raise MissingManagerError("Missing manager") method = nsdd.StringConvertToDynOrderType(method) if method == nsdd.CUDD_REORDER_NONE: method = nsdd.CUDD_REORDER_SIFT nsopt.set_dynamic_reorder(nsopt.OptsHandler_get_instance()) nsdd.dd_autodyn_enable(DDmanager_ptr, method)
def encode_variables(layers=None, variables_ordering=None): """ Encode the BDD variables of the current model and store it in global data structures. If variables_ordering is provided, use this ordering to encode the variables; otherwise, the default ordering method is used. :param layers: the set of layers variables to encode :type layers: :class:`set` :param variables_ordering: the file containing a custom ordering :type variables_ordering: path to file :raise: a :exc:`NuSMVNeedFlatHierarchyError <pynusmv.exception.NuSMVNeedFlatHierarchyError>` if the model is not flattened :raise: a :exc:`NuSMVModelAlreadyEncodedError <pynusmv.exception.NuSMVModelAlreadyEncodedError>` if the variables are already encoded """ # Check cmps if not nscompile.cmp_struct_get_flatten_hrc(global_compile_cmps()): raise NuSMVNeedFlatHierarchyError("Need flat hierarchy.") if nscompile.cmp_struct_get_encode_variables(global_compile_cmps()): raise NuSMVModelAlreadyEncodedError( "The variables are already encoded.") # See to understand why setting a default set value is not a good idea # http://pylint-messages.wikidot.com/messages:w0102 layers = layers or {"model"} if variables_ordering is not None: nsopt.set_input_order_file(nsopt.OptsHandler_get_instance(), variables_ordering) encode_variables_for_layers(layers, init=True) # Update cmps nscompile.cmp_struct_set_encode_variables(global_compile_cmps()) # Get global encoding global __bdd_encoding __bdd_encoding = BddEnc(nsenc.Enc_get_bdd_encoding())
def disable_dynamic_reordering(DDmanager=None): """ Disable dynamic reordering of BDD variables under control of `DDmanager`. :param DDmanager: the concerned DD manager; if None, the global DD manager is used instead. :type DDmanager: :class:`DDManager` :raise: a :exc:`MissingManagerError <pynusmv.exception.MissingManagerError>` if the manager is missing """ if DDmanager is None: DDmanager_ptr = nscinit.cvar.dd_manager else: DDmanager_ptr = DDmanager._ptr if DDmanager_ptr is None: raise MissingManagerError("Missing manager") nsopt.unset_dynamic_reorder(nsopt.OptsHandler_get_instance()) nsdd.dd_autodyn_disable(DDmanager_ptr)
def load_from_file(filepath): """ Load a model from an SMV file and store it in global data structures. :param filepath: the path to the SMV file :type filepath: str """ # Check file if not os.path.exists(filepath): raise IOError("File {} does not exist".format(filepath)) # Check cmps. Need reset_nusmv if a model is already read if nscompile.cmp_struct_get_read_model(global_compile_cmps()): raise NuSMVModelAlreadyReadError("A model is already read.") # Set the input file nsopt.set_input_file(nsopt.OptsHandler_get_instance(), filepath) # Call the parser # ret = 0 => OK # ret = 1 => syntax error (and there are registered syntax errors) # ret = 2 => lexer error ret = nsparser.Parser_ReadSMVFromFile(filepath) if ret == 2: # ret = 2 means lexer error raise NuSMVLexerError("An error with NuSMV lexer occured.") # When parsing a model with parser_is_lax enabled (this is the case # since this is enabled in init_nusmv), the parser gets # as many correct parts of the model as possible and build a partial # model with it. # Raise exceptions if needed errors = nsparser.Parser_get_syntax_errors_list() if errors is not None: raise NuSMVParsingError.from_nusmv_errors_list(errors) # Update cmps nscompile.cmp_struct_set_read_model(global_compile_cmps())
def check_explain_ltl_spec(spec): """ Return whether the loaded SMV model satisfies or not the LTL given `spec`, that is, whether all initial states of le model satisfies `spec` or not. Return also an explanation for why the model does not satisfy `spec`, if it is the case, or `None` otherwise. The result is a tuple where the first element is a boolean telling whether `spec` is satisfied, and the second element is either `None` if the first element is `True`, or a path of the SMV model violating `spec` otherwise. The explanation is a tuple of alternating states and inputs, starting and ennding with a state. The path is looping if the last state is somewhere else in the sequence. States and inputs are represented by dictionaries where keys are state and inputs variable of the loaded SMV model, and values are their value. :param spec: a specification :type spec: :class:`Spec <pynusmv.prop.Spec>` :rtype: tuple """ # Check that a model has been compiled assert(glob.prop_database().master is not None) # Create a property from the given spec prop = nsprop.Prop_create_partial(spec._ptr, propTypes["LTL"]) # Save settings o = nsopt.OptsHandler_get_enum_option_value( nsopt.OptsHandler_get_instance(), "oreg_justice_emptiness_bdd_algorithm") if (nscompile. FlatHierarchy_get_compassion(glob. global_compile_flathierarchy()) is None and o == nsfsmbdd.BDD_OREG_JUSTICE_EMPTINESS_BDD_ALGORITHM_EL_FWD): saved_options = nsfsmbdd.Bdd_elfwd_check_set_and_save_options( nsfsmbdd.BDD_ELFWD_OPT_ALL) else: saved_options = None # Create, build and check the structure for LTL model checking ltl_struct = nsltl.Ltl_StructCheckLtlSpec_create(prop) nsltl.Ltl_StructCheckLtlSpec_build(ltl_struct) nsltl.Ltl_StructCheckLtlSpec_check(ltl_struct) # Get the result result = nsprop.Prop_get_status(prop) == nsprop.Prop_True # explain if not result: # Extract explanation bdd_fsm = BddFsm(ltl_struct.fsm) full_fairness = (not nsfsmbdd.FairnessList_is_empty( nsfsmbdd.compassionList2fairnessList( nsfsmbdd.BddFsm_get_compassion(bdd_fsm._ptr)))) # Counterexample construction for forward Emerson-Lei not yet # implemented assert(full_fairness or not o) tmp = BDD(nsencbdd.BddEnc_pick_one_state(ltl_struct.bdd_enc, ltl_struct.s0), dd_manager=DDManager(nsencbdd.BddEnc_get_dd_manager( ltl_struct.bdd_enc))) if full_fairness: exp = BDDList(nsltl.witness(bdd_fsm._ptr, ltl_struct.bdd_enc, tmp._ptr), ddmanager=tmp._manager) else: path = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(tmp._ptr)), None) exp = BDDList(nsnode.reverse( nsmc.explain(bdd_fsm._ptr, ltl_struct.bdd_enc, path, ltl_struct.spec_formula, None)), ddmanager=tmp._manager) if exp is None: # The counterexample consists of one initial state exp = BDDList(nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(tmp._ptr)), None), ddmanager=tmp._manager) exp = exp.to_tuple() # removes all the tableau variables from the result before # building the resulting trace. This will make simulation # working, but may show unexistent loops in the shown trace def clean(bdd): tableau_cube = Cube(nsencbdd.BddEnc_get_layer_vars_cube( ltl_struct.bdd_enc, ltl_struct.tableau_layer, nssymb_table.VFT_ALL), dd_manager=bdd._manager) return bdd.forsome(tableau_cube) # exp has at least one element explanation = [bdd_fsm.pick_one_state(clean(exp[0])).get_str_values()] for inputs_bdd, state_bdd in zip(exp[1::2], exp[2::2]): explanation.append(bdd_fsm.pick_one_inputs( clean(inputs_bdd)) .get_str_values()) explanation.append(bdd_fsm.pick_one_state( clean(state_bdd)) .get_str_values()) else: explanation = None # Destroy the intermediate structure nsltl.Ltl_StructCheckLtlSpec_destroy(ltl_struct) # Restore settings if saved_options is not None: nsfsmbdd.Bdd_elfwd_restore_options(nsfsmbdd.BDD_ELFWD_OPT_ALL, saved_options) # Destroy prop nsprop.Prop_destroy(prop) return (result, explanation if explanation is None else tuple(explanation))