Common Explicit-State Model Interface
=====================================

DIVINE provides an implementation for CESMI, which defines a simple common
interface between a model-checking core and a module that generates the state
space of the model in a demand-driven fashion.

CESMI does not specifically demand any concrete implementation of the
interface. DIVINE provides a C-runtime-compatible ABI conforming to the CESMI
specification, as well as C (and C++) and Haskell APIs, which can then be
translated to conform to the provided ABI using standard tools. Loading a
compiled CESMI module is facilitated by using dynamic (shared) libraries on the
target platform: ELF Shared Object files are supported on POSIX platforms, and
Dynamically Linked Libraries (DLLs) on Win32 (Win64) platforms.

DIVINE currently provides two compilers to translate models in specific
modelling formalisms to CESMI modules: a compiler for the DVE language (which
is also supported directly through an interpreter) and a compiler for the
MurPHI language, adapted from the original MurPHI model compiler.

The CESMI Specification
=======================

CESMI is a set of APIs (Application Programming Interface) to represent model
checking problems in a form independent of a specific model-checker. The API is
explicit-state (states of the model are represented discretely) and allows for
implicit (on the fly) representation of models -- local neighbourhood of a given
vertex needs to be provided. The exact semantics of vertices and edges
represented by a CESMI model depend on the model checking algorithm in
question. Multiple interpretations of a given graph are possible, and will be
discussed in detail in the section on semantics.

CESMI defines a notion of a "module" and a "loader", the role of the module
corresponding to the model, or a Kripke structure, to be examined. The "loader"
is then a part of a model checking or other model examination tool, which
treats the CESMI module as its input data.

The Module
----------

We will lay out the basic requirements for a CESMI module in this section. The
C prototypes of the individual calls exposed in the API of the module are as
follows:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

    void setup             ( cesmi_setup * );
     int get_initial       ( const cesmi_setup *, int,
                             cesmi_node * );
     int get_successor     ( const cesmi_setup *, int,
                             cesmi_node, cesmi_node * );
uint64_t get_flags         ( const cesmi_setup *, cesmi_node );
   char *show_node         ( const cesmi_setup *, cesmi_node );
   char *show_transition   ( const cesmi_setup *, cesmi_node,
                             int );

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Only `get_initial` and `get_successor` are mandatory, the rest of the
functionality is optional, and the loader must substitute suitable defaults.

The `setup` call *may* set up per-instance state, however, if it does, it
*must* keep it all through the `instance` pointer of the `cesmi_setup`
structure, which has the following C definition:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

typedef struct {
    void *loader;
    cesmi_node (*make_node)( const cesmi_setup *, int );
    cesmi_node (*clone_node)( const cesmi_setup *, cesmi_node );
    int (*add_property)( cesmi_setup *, char *, char *, int );
    void *instance; // per-instance data; never touched by DIVINE
    int property_count; /* filled in by setup */
    int property; /* filled in by loader */
    int instance_initialised;
    /* extensions at the end are ABI-compatible */
} cesmi_setup;

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For each instance of the CESMI module created by the loader, there is a unique
`cesmi_setup` value which is passed to all calls into the module. At the time of
the `setup` call, the `cesmi_setup` structure must be initialised by the loader
to its default state. The `setup` implementation of the module may change the
field `instance`, the remainder is for *reading only*. The `setup`
implementation may also modify the `cesmi_setup` structure via calls to
`add_property`.

Since the model checker might use the CESMI module in multiple threads, the
CESMI module *must not* retain any global state. All instance-specific state
*must* be managed through the `instance` pointer provided in the `cesmi_setup`
structure. The CESMI loader *may* call `setup` multiple times with a different
parameter (in the same address space), and the resulting CESMI module instances
*must* be fully isolated.

Handling State
--------------

The functions `get_initial` and `get_successor` (and by extension,
`show_transition`, see below) need to maintain state between invocations to be
able to work with reasonable efficiency. The `handle` system allows a limited
amount of state to be passed around safely (namely a single integer). To obtain
all successors of a vertex, the CESMI loader first calls `get_successor` with
`handle` value 1. The implementation of `get_successor` then returns the first
successor and a `handle` value to obtain the next successor. When there are no
further successors to return, it should give a 0 handle. When a vertex has no
successors, the response to `get_successor( setup, state, 1, result )` should
be 0, and `result` should be left untouched. The same principle applies to
`get_initial`. An example implementation of `get_successor` might look like
this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

int get_successor( const cesmi_setup *setup, int handle,
                   cesmi_node from, cesmi_node *to )
{
    struct state *in = (struct state *) from.memory;

    if (in->a < 4 && in->b < 4 && handle < 3) {
        *to = setup->make_node( setup, sizeof( struct state ) );
        struct state *out = (struct state *) to->memory;
        *out = *in;
        switch (handle) {
        case 1: out->a ++; return 2;
        case 2: out->b ++; return 3;
        }
    }
    return 0;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Memory Management
-----------------

The module is responsible for allocating memory for new states, and it must use
the `make_node` or `clone_node` functions provided in the `cesmi_setup`
structure it is given, passing the `setup` as their first parameter, and either
the size of the bit vector it requires (`make_node`) or a state to be cloned
(`clone_node`). The loader might need to store additional data with the state,
hence it returns a structure with two pointers in it.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

typedef struct {
    void *handle;
    char *memory;
} cesmi_node;

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The `memory` field of the returned structure is for use by the CESMI module to
store state information. The module *must not* alter the `handle` -- it must be
retained in the result of the respective `get_initial` or `get_successor` call.
The `memory` pointer *must not* be passed to `free`. The module should only
call `make_node`/`clone_node` at a point where it is known that a state will be
generated, along with its size, otherwise it will cause undesirable memory
leaks.

Human-readable Labels
---------------------

To aid in reading counterexamples or when exploring the state space, it is
often very useful to have human-readable labels assigned to system states
and/or transitions. To this end, CESMI specifies (optional) functions
`show_node` and `show_transition`. Both should return a heap-allocated (with
`malloc`) string. The case of `show_node` is straightforward, it only gets the
state itself. For `show_transition`, the origin state of the transition is
given, plus a handle. The handle is treated the same way as in `get_successor`:
`show_transition` must give the description of the first **enabled** transition
in the given origin state, or, if no such transition exists, return a `NULL`
pointer.

Building CESMI Modules with DIVINE
==================================

The CESMI module more or less represents a generic oriented graph. It is
intentionally kept as simple as reasonably possible: apart from the graph
itself and human-readable descriptions of edges and vertices, the only further
information exposed in the interface about the graph is a set of per-state
flags, which are used to encode the vertex properties interesting for model
checking: whether the state is a goal state, or whether it is an accepting
state of a Büchi automaton. This means that for the purpose of LTL model
checking, the CESMI module must expose a product automaton of the negative
claim Büchi translation of the LTL formula and of the system.

While this makes the specification and the loader much simpler, it also adds
substantial amount of work for the module authors. What more, this task is
repetitive, since large part of the work is the same from model to model:
constructing the Büchi automaton from an LTL formula and synchronising its
guards with the system, based on values of atomic propositions of the formula.

To this end, DIVINE provides a small framework to help you build CESMI modules
suitable for LTL model checking out of a system description and a set of LTL
formulas, exposed via the `divine compile --cesmi` sub-command.

When using `divine compile --cesmi`, you should always `#include "cesmi.h"` --
this will allow the C/C++ compiler to check your function prototypes against
those mandated by the CESMI specification. It will also give you access to the
`struct` types `cesmi_setup` and `cesmi_node` and the `cesmi_flags` /
`cesmi_property_type` enums.

To add LTL formula(s) to your CESMI module, you should additionally `#include
"cesmi-ltl.h"` which provides a number of helper functions to make your job
easier. To get access to `cesmi-ltl.h`, you must provide a file with LTL
formulas on the commandline, say `divine compile --cesmi mymodule.c
mymodule.ltl`. In this case, `divine` will generate code for traversing the
Büchi automaton from each LTL formula and links it to your module. To use this
generated code, you should use the following APIs:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

uint64_t buchi_flags( cesmi_setup *setup, cesmi_node n );

int buchi_get_initial( const cesmi_setup *setup,
                       int handle, cesmi_node *to,
                       get_initial_t next );
int buchi_get_successor( const cesmi_setup *setup, int handle,
                         cesmi_node from,
                         cesmi_node *to, get_successor_t next );
char *buchi_show_node( const cesmi_setup *setup, cesmi_node from,
                       show_node_t next );
char *buchi_show_transition( const cesmi_setup *setup,
                             cesmi_node from,
                             int handle, show_transition_t next );

void buchi_setup( cesmi_setup *setup );

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Each of the `buchi_` functions corresponds to one of the CESMI functions:
`buchi_get_initial` to `get_initial`, etc. When implementing your CESMI module,
you should implement a CESMI-compatible function under a different name, say
`_get_initial` and implement the CESMI `get_initial` like this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

int get_initial( const cesmi_setup *s, int h, cesmi_node *n ) {
    return buchi_get_initial( s, h, n, _get_initial );
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The `buchi_setup` is different as it is supposed to be called at the end of
the `setup` function like this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.C}

void setup( cesmi_setup *s ) {
    s->add_property( s, NULL, NULL, cesmi_pt_goal );
    s->add_property( s, NULL, NULL, cesmi_pt_deadlock );
    buchi_setup( s );
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For a full example, please refer to `examples/cesmi/withltl.c` shipped in
DIVINE source tarballs. Compile and test it like this:

    $ divine compile --cesmi examples/cesmi/withltl.c \
                             examples/cesmi/withltl.ltl
    $ divine metrics withltl.so --property=p_3
