def todo(fn):
def skip(reason):
def _log(fn, message):
def canonical_cnf(be):
def current_directory(what):
    def __init__(self, testcase, location, model):
    def __enter__(self):
    def __exit__(self, type_, value, traceback):
class Configure: def init_nusmv(collecting=True):
    """
    Initialize NuSMV. Must be called only once before calling
    :func:`deinit_nusmv`.

    :param collecting: Whether or not collecting pointer wrappers to free them
                       before deiniting nusmv.

    .. warning: Deactivating the collection of pointer wrappers may provoke
                segmentation faults when deiniting nusmv without correctly
                freeing all pointer wrappers in advance.
                On the other hand, collection may blow memory.

    """
    global __collector, __collecting
    if __collector is not None:
        raise NuSMVInitError("Cannot initialize NuSMV twice.")
    else:
        __collecting = collecting
        __collector = set()
        nscinit.NuSMVCore_init_data()
        nscinit.NuSMVCore_init(None, 0)  # No addons specified
        nscinit.NuSMVCore_init_cmd_options()

        # Set NuSMV in interactive mode to avoid fast termination when errors
        # nsopt.unset_batch(nsopt.OptsHandler_get_instance())

        # Initialize option commands (set, unset)
        # to be able to set parser_is_lax
        nsopt.init_options_cmd()
        nscmd.Cmd_SecureCommandExecute("set parser_is_lax")

        return _PyNuSMVContext() def deinit_nusmv(ddinfo=False):
    """
    Quit NuSMV. Must be called only once, after calling :func:`init_nusmv`.

    :param ddinfo: Whether or not display Decision Diagrams statistics.

    """
    global __collector
    if __collector is None:
        raise NuSMVInitError(
            "Cannot deinitialize NuSMV before initialization.")
    else:
        # Apply Python garbage collection first,
        # then collect every pointer wrapper
        # that is not yet collected by Python GC
        from . import glob

        # Print statistics on stdout about DDs handled by the main DD manager.
        if ddinfo:
            try:
                manager = glob.prop_database().master.bddFsm.bddEnc.DDmanager
                nsdd.dd_print_stats(manager._ptr, nscinit.cvar.nusmv_stdout)
            except PyNuSMVError:
                pass

        glob._reset_globals()

        # First garbage collect with Python
        gc.collect()
        # Then garbage collect with PyNuSMV
        for elem in __collector:
            elem._free()
        __collector = None
        nscinit.NuSMVCore_quit() def load(*model):
    """
    Load the given model. This model can be of several forms:

    * a file path; in this case, the model is loaded from the file;
    * NuSMV modelling code; in this case, `model` is the code for the model;
    * a list of modules (list of :class:`Module <pynusmv.model.Module>`
      subclasses); in this case, the model is represented by the set of
      modules.

    """
    if len(model) == 1 and isinstance(model[0], str):
        if os.path.isfile(model[0]):
            load_from_file(model[0])
        else:
            load_from_string(model[0])
    else:  # model must be a list of modules
        load_from_modules(*model) 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 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 build_boolean_model(force=False):
    """
    Compiles the flattened hierarchy into a boolean model (SEXP) and stores it
    it a global variable.

    .. note::
        This function is subject to the following requirements:

            - hierarchy must already be flattened (:func:`flatten_hierarchy`)
            - encoding must be already built (:func:`encode_variables`)
            - boolean model must not exist yet (or the force flag must be on)

    :param force: a flag telling whether or not the boolean model must be built
       even though the cone of influence option is turned on.

    :raises NuSMVNeedFlatHierarchyError: if the hierarchy wasn't flattened yet.
    :raises NuSMVNeedVariablesEncodedError: if the variables are not yet encoded
    :raises NuSMVModelAlreadyBuiltError: if the boolean model is already built and force=False
    """
    global __bool_sexp_fsm

    # check the preconditions
    if not nscompile.cmp_struct_get_encode_variables(global_compile_cmps()):
        raise NuSMVNeedVariablesEncodedError("Need variables encoded.")
    if nscompile.cmp_struct_get_build_bool_model(global_compile_cmps()) and not force:
        raise NuSMVModelAlreadyBuiltError("The boolean model is already built and the force flag is off")

    # create the flat model if need be.
    if not nscompile.cmp_struct_get_build_flat_model(global_compile_cmps()):
        build_flat_model()

    # Create the boolean model proper (CompileCmd.c/compile_create_boolean_model)
    propdb        = nsprop.PropPkg_get_prop_database()
    bool_sexp_fsm = nsprop.PropDb_master_get_bool_sexp_fsm(propdb)

    # even though the force flag is on, a call to this method will have no effect
    # if the bool sexp_fsm already exists in the propdb (reproduces the behavior
    # of CompileCmd.c/compile_create_boolean_model() )
    if bool_sexp_fsm is None:
        benc = __bdd_encoding
        symb = benc.symbTable
        mgr  = benc.DDmanager

        # Temporarily disable reordering (if needed)
        reord= nsdd.wrap_dd_reordering_status(mgr._ptr)
        if reord.status == 1:
            nsdd.dd_autodyn_disable(mgr._ptr)

        # add 'determ' to the default and Artifact classes
        determ = symb.create_layer("determ", nssymb_table.SYMB_LAYER_POS_BOTTOM)
        nssymb_table.SymbTable_layer_add_to_class(symb._ptr, "determ", None)
        nssymb_table.SymbTable_layer_add_to_class(symb._ptr, "determ", "Artifacts Class")

        # THIS IS THE REAL CREATION !!
        scalar_sexp_fsm = nsprop.PropDb_master_get_scalar_sexp_fsm(propdb)
        bool_sexp_fsm   = nssexp.BoolSexpFsm_create_from_scalar_fsm(
                                        scalar_sexp_fsm, benc._ptr, determ);

        __bool_sexp_fsm = BoolSexpFsm(bool_sexp_fsm, freeit=False)
        nsprop.PropDb_master_set_bool_sexp_fsm(propdb, bool_sexp_fsm)
        # unfortunately, if the C malloc fails, the C assertion will also fail
        # and result in a program crash.

        boolenc = nsboolenc.boolenc2baseenc(nsenc.Enc_get_bool_encoding())
        nsbaseenc.BaseEnc_commit_layer(boolenc,"determ")

        bddenc  = nsbddenc.bddenc2baseenc(nsenc.Enc_get_bdd_encoding())
        nsbaseenc.BaseEnc_commit_layer(bddenc, "determ")

        # Re-enable reordering if it had been disabled
        if reord.status == 1:
            nsdd.dd_autodyn_enable(mgr._ptr, reord.method);

    # Tell NuSMV that the boolean model was built
    nscompile.cmp_struct_set_build_bool_model(global_compile_cmps()) def bmc_setup(force=False):
def bmc_exit():
def build_master_be_fsm():
def master_be_fsm():
def go_bmc(force=False):
    def __enter__(self):
    def __exit__(self, typ, value, traceback):
class BmcSupport: class NuSMVNeedBooleanModelError(PyNuSMVError):

    """
    Exception raised when the boolean model must be created.

    """
    pass class NuSMVBmcAlreadyInitializedError(PyNuSMVError):

    """
    Exception raised when the bmc sub system is already initialized

    """
    pass class NuSMVNoReadModelError(PyNuSMVError):

    """
    Exception raised when no SMV model has been read yet.

    """
    pass class BeFsm(PointerWrapper):
    """
    This class wraps the public interface of a BE FSM as defined in NuSMV
    with the BeFsm_ptr type.
    
    Its role is to give an access to the properties of FSM as represented with
    boolean expressions (BE). For instance, it gives access to the initial states
    the invariants and the transition relation encoded in terms of BE. Moreover
    it gives the possibility to compute the synchronous product of two FSMs.  
    """
    
    def __init__(self, ptr, freeit=False):
        """
        Creates an instance of the BeFsm, using the NuSMV pointer. 
        :param ptr: the NuSMV pointer of type BeFsm_ptr
        :param freeit: a flag indicating whether or not the system resources 
          should be freed upon garbage collection.
        """
        super().__init__(ptr, freeit)
        
    def _free(self):
        """Frees the system resources associated with this object"""
        if self._freeit and self._ptr is not None:
            _be.BeFsm_destroy(self._ptr)
            self._freeit = False
            self._ptr    = None
    
    @staticmethod
    def global_master_instance():
        """
        :return: the boolean FSM in BE stored in the master prop. 
        :raises NuSMVBeFsmMasterInstanceNotInitializedError:
             when the global BE FSM is null in the global properties database 
             (ie when coi is enabled).
        """
        _pd  = _prop.PropPkg_get_prop_database()
        _fsm = _prop.PropDb_master_get_be_fsm(_pd)
        if _fsm is None:
            raise NuSMVBeFsmMasterInstanceNotInitializedError("""
                            BE fsm stored in master prop is not initialized.
                            You must either initialize the BE model (ie. go_bmc)
                            or disable COI.
                            """)
        return BeFsm(_fsm)
    
    @staticmethod
    def create(enc, init, invar, trans, fairness, freeit=False):
        """
        Creates a new BeFsm instance using the given encoder, initial states, 
        invariants, transition relation and list of fairness.
        
        :param enc: the encoder used to represent the variables of the model.
        :param init: the boolean expression representing the initial states of 
          the FSM
        :param invar: the boolean expression representing the invariants of the 
          model encoded in this FSM
        :pqram trans: the boolean expression representing the transition relation
          of the model encoded in this FSM
        :param fairness: a list of boolean expression representing the fairness
          constraints of the model. 
        :param freeit: a flag indicating whether or not the system resources 
          should be freed upon garbage collection.
          
        :return: a new instance of BeFsm that gets its init, invar, transition 
          relation and the list of fairness in Boolean Expression format
        """
        # very unlikely to be used directly
        return BeFsm(_be.BeFsm_create(enc._ptr, 
                                      init._ptr, 
                                      invar._ptr,
                                      trans._ptr,
                                      fairness._ptr))
    
    @staticmethod
    def create_from_sexp(enc, sexp_fsm):
        """
        Creates a new instance of BeFsm extracting the necessary information
        from the given `sexp_fsm` of type :class:`BoolSexpFsm <pynusmv.sexp.BoolSexpFsm>`
        
        :param enc: the encoder used to represent the variables of the model.
        :param sexp_fsm: the BoolSexpFsm which contains the automaton information
        """
        return BeFsm(_be.BeFsm_create_from_sexp_fsm(enc._ptr, sexp_fsm._ptr)) 
    
    def copy(self, freeit=True):
        """
        Creates a new independent copy of the FSM.
        :param freeit: a flag indicating whether or not the system resources 
        should be freed upon garbage collection.
        """
        return BeFsm(_be.BeFsm_copy(self._ptr), freeit=freeit)
    
    def __copy__(self):
        """Creates a new independent copy of the FSM"""
        return self.copy()
    
    @property
    def encoding(self):
        """The BE encoding of this FSM"""
        if not hasattr(self, "__encoding"):
            setattr(self, '__encoding', BeEnc(_be.BeFsm_get_be_encoding(self._ptr), freeit=False))
        return getattr(self, '__encoding')
    
    @property
    def init(self):
        """The BE representing the initial states of this FSM"""
        _expr = _be.BeFsm_get_init(self._ptr)
        return Be(_expr, self.encoding.manager) if _expr is not None else None
    
    @property
    def invariants(self):
        """The boolean expression representing the invariants of this FSM"""
        _expr = _be.BeFsm_get_invar(self._ptr)
        return Be(_expr, self.encoding.manager) if _expr is not None else None
    
    @property
    def trans(self):
        """
        The boolean expression representing the transition relation of the FSM
        
        .. note::
        
            Transition expression shifted at time zero is what brings you to 
            state one. Hence::
            
                shift_to_time(init, 0) & shift_to_time(trans, 0) == STATE_1 
        """
        _expr = _be.BeFsm_get_trans(self._ptr)
        return Be(_expr, self.encoding.manager) if _expr is not None else None
    
    @property
    def fairness_list(self):
        """
        The list of fairness constraints of this model encoded in BE format.
        
        .. note:: accessing this property is not free: use fairness_iterator
           instead if you don't need to manipulate the list as a list.
        """
        return [ i for i in self.fairness_iterator() ]
    
    def fairness_iterator(self):
        """:return: an iterator to iterate over the fairness list"""
        _ptr  = _be.BeFsm_get_fairness_list(self._ptr)
        _iter = NodeIterator.from_pointer(_ptr)
        for fairness in _iter:
            yield self._fairness_conversion(fairness)
    
    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 apply_synchronous_product(self, other):
        """
        Apply the synchronous product between self and other modifying self.
        :param other: the other to compute the synchronous product with
        """
        _be.BeFsm_apply_synchronous_product(self._ptr, other._ptr)
        
    def __mul__(self, other):
        """
        :return: a new fsm corresponding to the synchronous product of self and
        other.
        :param other: the other to compute the synchronous product with
        """
        cpy = self.copy()
        cpy.apply_synchronous_product(other)
        return cpy
    
    def __imul__(self, other):
        """
        Apply the synchronous product between self and other modifying self.
        :param other: the other to compute the synchronous product with
        """
        self.apply_synchronous_product(other)
import unittest
from tests              import utils as tests 
from pynusmv.init       import init_nusmv, deinit_nusmv
from pynusmv.glob       import (load, 
                                flatten_hierarchy, 
                                encode_variables,
                                build_boolean_model)
from pynusmv.bmc        import glob as bmcglob
from pynusmv.exception  import (NuSMVNeedBooleanModelError,
                                NuSMVBmcAlreadyInitializedError,
                                NuSMVNoReadModelError)
from pynusmv.be.fsm import BeFsm



class TestBmcGlob(unittest.TestCase):
    
    def setUp(self):
        init_nusmv()
        
    def tearDown(self):
        deinit_nusmv()
    
    def model(self):

        return tests.current_directory(__file__)+"/models/flipflops.smv"