#!/usr/bin/python

import sys

def genFiles (dir):
    ############################################################
    f = open (dir + "/" + "bfs.h", "w")
    f.write ("\
/**\n\
 * @file bfs.h\n\
 * @brief Implementation of BFS based algorithms: BFS, DBFS (distributed BFS)\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_BFS\n\
#define LIB_BFS\n\
\n\
#include \"includes.h\"\n\
#include \"context.h\"\n\
#include \"state.h\"\n\
#include \"event.h\"\n\
\n\
\n\
/**\n\
 * @brief Launch the BFS based algorithm.\n\
 */\n\
void bfs\n\
();\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "bfs.c", "w")
    f.write ("\
#include \"bfs.h\"\n\
#include \"list.h\"\n\
#include \"bfs_queue.h\"\n\
#include \"config.h\"\n\
#include \"context.h\"\n\
#include \"dbfs_comm.h\"\n\
#include \"htbl.h\"\n\
#include \"prop.h\"\n\
#include \"reduction.h\"\n\
#include \"workers.h\"\n\
#include \"state.h\"\n\
\n\
#if CFG_ALGO_BFS == 0 && CFG_ALGO_DBFS == 0\n\
\n\
void bfs() { assert(0); }\n\
\n\
#else\n\
\n\
struct timespec BFS_WAIT_TIME[CFG_NO_WORKERS];\n\
\n\
htbl_t H = NULL;\n\
bfs_queue_t Q = NULL;\n\
pthread_barrier_t BFS_BARRIER;\n\
\n\
\n\
worker_id_t bfs_thread_owner\n\
(hash_key_t h) {\n\
  uint8_t result = 0;\n\
  int i;\n\
  \n\
  for(i = 0; i < sizeof(hash_key_t); i++) {\n\
    result += (h >> (i * 8)) & 0xff;\n\
  }\n\
  return result % CFG_NO_WORKERS;\n\
}\n\
\n\
void bfs_wait_barrier\n\
() {\n\
  if(CFG_PARALLEL) {\n\
    context_barrier_wait(&BFS_BARRIER);\n\
  }\n\
}\n\
\n\
void bfs_init_queue\n\
() {\n\
  bool_t levels = CFG_ALGO_DBFS ? 1 : 2;\n\
  bool_t events_in_queue = CFG_EDGE_LEAN;\n\
  uint16_t no_workers = CFG_NO_WORKERS + (CFG_ALGO_DBFS ? 1 : 0);\n\
  bool_t states_in_queue = CFG_HASH_COMPACTION;\n\
  \n\
  Q = bfs_queue_new(no_workers, CFG_BFS_QUEUE_BLOCK_SIZE,\n\
                    states_in_queue, events_in_queue, levels);\n\
}\n\
\n\
bool_t bfs_check_termination\n\
(worker_id_t w) {\n\
  bool_t result = FALSE;\n\
  uint16_t trials = 0;\n\
  \n\
  if(CFG_ALGO_DBFS) {\n\
    dbfs_comm_send_all_pending_states(w);\n\
    while(!(result = dbfs_comm_termination())\n\
          && bfs_queue_local_is_empty(Q, w)) {\n\
      context_sleep(BFS_WAIT_TIME[w]);\n\
      trials ++;\n\
    }\n\
    if(trials == 1) {\n\
      BFS_WAIT_TIME[w].tv_nsec /= 2;\n\
    }    \n\
  } else {\n\
    bfs_wait_barrier();\n\
    bfs_queue_switch_level(Q, w);\n\
    bfs_wait_barrier();\n\
    result = !context_keep_searching() || bfs_queue_is_empty(Q);\n\
    bfs_wait_barrier();\n\
  }\n\
  return result;\n\
}\n\
\n\
void bfs_report_trace\n\
(htbl_id_t id) {\n\
  list_t trace = list_new(SYSTEM_HEAP, sizeof(event_t), event_free_void);\n\
  list_t trace_id = htbl_get_trace(H, id);\n\
  list_iter_t it;\n\
  state_t s = state_initial();\n\
  event_t e;\n\
  \n\
  for(it = list_get_iter(trace_id);\n\
      !list_iter_at_end(it);\n\
      it = list_iter_next(it)) {\n\
    e = state_event(s, * ((event_id_t *) list_iter_item(it)));\n\
    event_exec(e, s);\n\
    list_append(trace, &e);\n\
  }\n\
  state_free(s);\n\
  list_free(trace_id);\n\
  context_set_trace(trace);\n\
}\n\
\n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
#define bfs_back_to_s() {event_undo(e, s);}\n\
#else\n\
#define bfs_back_to_s() {state_free(succ);}\n\
#endif\n\
\n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
#define bfs_goto_succ() {event_exec(e, s); succ = s;}\n\
#else\n\
#define bfs_goto_succ() {succ = state_succ_mem(s, e, heap);}\n\
#endif\n\
\n\
void * bfs_worker\n\
(void * arg) {\n\
  const worker_id_t w = (worker_id_t) (unsigned long int) arg;\n\
  const bool_t states_in_queue = bfs_queue_states_stored(Q);\n\
  const bool_t por = CFG_POR;\n\
  const bool_t proviso = CFG_PROVISO;\n\
  const bool_t edge_lean = CFG_EDGE_LEAN;\n\
  const bool_t with_trace = CFG_ACTION_CHECK_SAFETY && CFG_ALGO_BFS;\n\
  uint32_t levels = 0;\n\
  state_t s, succ;\n\
  htbl_id_t id_succ;\n\
  event_list_t en;\n\
  worker_id_t x, y;\n\
  unsigned int arcs;\n\
  heap_t heap = local_heap_new();\n\
  hash_key_t h;\n\
  bfs_queue_item_t item, succ_item;\n\
  event_t e;\n\
  bool_t is_new, reduced, termination = FALSE;\n\
  \n\
  while(!termination) {\n\
    for(x = 0; x < bfs_queue_no_workers(Q) && context_keep_searching(); x ++) {\n\
      while(!bfs_queue_slot_is_empty(Q, x, w) && context_keep_searching()) {\n\
 \n\
        /**\n\
         *  get the next state sent by thread x, get its successors\n\
         *  and a valid reduced set.  if the states are not stored in\n\
         *  the queue we get it from the hash table\n\
         */\n\
        item = bfs_queue_next(Q, x, w);\n\
        heap_reset(heap);\n\
        if(states_in_queue) {\n\
          s = item.s;\n\
        } else {\n\
          s = htbl_get_mem(H, item.id, heap);\n\
        }\n\
\n\
        /**\n\
         *  compute enabled events and apply POR\n\
         */\n\
        if(por) {\n\
          en = state_events_reduced_mem(s, &reduced, heap);\n\
          if(reduced) {\n\
            context_incr_stat(STAT_STATES_REDUCED, w, 1);\n\
          }\n\
        } else {\n\
          en = state_events_mem(s, heap);\n\
        }\n\
\n\
\n\
        /**\n\
         *  check the state property\n\
         */\n\
        if(CFG_ACTION_CHECK_SAFETY && state_check_property(s, en)) {\n\
          context_faulty_state(s);\n\
          if(with_trace) {\n\
            bfs_report_trace(item.id);\n\
          }\n\
        }\n\
        \n\
        /**\n\
         *  apply edge lean reduction after checking state property\n\
         *  (EDGE-LEAN may remove all enabled events)\n\
         */\n\
        if(edge_lean && item.e_set) {\n\
          edge_lean_reduction(en, item.e);\n\
        }\n\
\n\
        /**\n\
         *  expand the current state and put its unprocessed\n\
         *  successors in the queue\n\
         */\n\
      state_expansion:\n\
        arcs = 0;\n\
        while(!list_is_empty(en)) {\n\
          arcs ++;\n\
          list_pick_first(en, &e);\n\
          bfs_goto_succ();\n\
          if(!CFG_ALGO_DBFS) {\n\
            htbl_insert(H, succ, &is_new, &id_succ, &h);\n\
          } else {\n\
            h = state_hash(succ);\n\
            if(!dbfs_comm_state_owned(h)) {\n\
              dbfs_comm_process_state(w, succ, h);\n\
              bfs_back_to_s();\n\
              continue;\n\
            }\n\
            htbl_insert_hashed(H, succ, h, &is_new, &id_succ);\n\
          }\n\
\n\
          /**\n\
           *  if new, enqueue the successor\n\
           */\n\
          if(is_new) {\n\
            y = bfs_thread_owner(h);\n\
            htbl_set_worker_attr(H, id_succ, ATTR_CYAN, y, TRUE);\n\
            succ_item.id = id_succ;\n\
            succ_item.s = succ;\n\
            succ_item.e_set = TRUE;\n\
            succ_item.e = e;\n\
            bfs_queue_enqueue(Q, succ_item, w, y);\n\
            if(with_trace) {\n\
              htbl_set_attr(H, succ_item.id, ATTR_PRED, item.id);\n\
              htbl_set_attr(H, succ_item.id, ATTR_EVT, event_id(e));\n\
            }\n\
            context_incr_stat(STAT_STATES_STORED, w, 1);\n\
          } else {\n\
\n\
            /**\n\
             *  if the successor state is not new and if the current\n\
             *  state is reduced then the successor must be in the\n\
             *  queue (i.e., cyan for some worker)\n\
             */\n\
            if(por && proviso && reduced && !htbl_get_any_cyan(H, id_succ)) {\n\
              reduced = FALSE;\n\
              list_free(en);\n\
              bfs_back_to_s();\n\
              en = state_events_mem(s, heap);\n\
              context_incr_stat(STAT_STATES_REDUCED, w, -1);\n\
              goto state_expansion;\n\
            }\n\
          }\n\
          bfs_back_to_s();\n\
        }\n\
        state_free(s);\n\
        list_free(en);\n\
\n\
        /**\n\
         *  update some statistics\n\
         */\n\
        if(0 == arcs) {\n\
          context_incr_stat(STAT_STATES_DEADLOCK, w, 1);\n\
        }\n\
        context_incr_stat(STAT_ARCS, w, arcs);\n\
        context_incr_stat(STAT_STATES_PROCESSED, w, 1);\n\
        context_incr_stat(STAT_EVENT_EXEC, w, arcs);\n\
\n\
        /**\n\
         *  the state leaves the queue => we unset its cyan bit\n\
         */\n\
        bfs_queue_dequeue(Q, x, w);\n\
        htbl_set_worker_attr(H, item.id, ATTR_CYAN, w, FALSE);\n\
      }\n\
    }\n\
\n\
    /**\n\
     *  all states in the queue have been processed => check for termination\n\
     */\n\
    termination = bfs_check_termination(w);\n\
    levels ++;\n\
  }\n\
  heap_free(heap);\n\
  context_set_stat(STAT_BFS_LEVELS, 0, levels);\n\
}\n\
\n\
void bfs\n\
() {\n\
  const bool_t with_trace = CFG_ACTION_CHECK_SAFETY && CFG_ALGO_BFS;\n\
  state_t s = state_initial();\n\
  bool_t is_new;\n\
  htbl_id_t id;\n\
  worker_id_t w;\n\
  hash_key_t h;\n\
  bool_t enqueue = TRUE;\n\
  bfs_queue_item_t item;\n\
  \n\
  H = htbl_default_new();\n\
  bfs_init_queue();\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    BFS_WAIT_TIME[w].tv_sec = 0;\n\
    BFS_WAIT_TIME[w].tv_nsec = 1000;\n\
  }\n\
\n\
  if(CFG_ALGO_DBFS) {\n\
    dbfs_comm_start(H, Q);\n\
  }\n\
\n\
  pthread_barrier_init(&BFS_BARRIER, NULL, CFG_NO_WORKERS);\n\
  \n\
  if(CFG_ALGO_DBFS) {\n\
    h = state_hash(s);\n\
    enqueue = dbfs_comm_state_owned(h);\n\
  }\n\
  \n\
  if(enqueue) {\n\
    htbl_insert(H, s, &is_new, &id, &h);\n\
    w = h % CFG_NO_WORKERS;\n\
    item.id = id;\n\
    item.s = s;\n\
    item.e_set = FALSE;\n\
    if(with_trace) {\n\
      htbl_set_attr(H, id, ATTR_PRED, id);\n\
      htbl_set_attr(H, id, ATTR_EVT, 0);\n\
    }\n\
    bfs_queue_enqueue(Q, item, w, w);\n\
    bfs_queue_switch_level(Q, w);\n\
    context_incr_stat(STAT_STATES_STORED, w, 1);\n\
  }\n\
  state_free(s);\n\
\n\
  launch_and_wait_workers(&bfs_worker);\n\
\n\
  if(CFG_ALGO_DBFS) {\n\
    context_stop_search();\n\
    dbfs_comm_end();\n\
  }\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "bfs_queue.h", "w")
    f.write ("\
/**\n\
 * @file bfs_queue.h\n\
 * @brief Implementation of the queue used by BFS based algorithm.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 *\n\
 * The queue is decomposed in levels.  States to be processed are\n\
 * dequeued from level 0 and sucessor states are enqueued in level (1\n\
 * % levels).  Once a BFS level terminated, each queue of level l is\n\
 * replaced by the queue of level l + 1.  Each of these queues is a\n\
 * W*W array (with W = number of working threads).  Each slot (w_from,\n\
 * w_to) of this array contains states enqueued by worker w_from and\n\
 * destinated (i.e., that must be processed) by worker w_to.\n\
 */\n\
\n\
#ifndef LIB_BFS_QUEUE\n\
#define LIB_BFS_QUEUE\n\
\n\
#include \"bfs.h\"\n\
#include \"htbl.h\"\n\
\n\
\n\
/**\n\
 * @struct bfs_queue_item_t\n\
 * @brief  items of the BFS queue\n\
 *\n\
 * The queue stores state identifiers.  If states cannot be recovered\n\
 * from the hash table (e.g., if hash-compaction is one) we also need\n\
 * to save the full state descriptor.  In some case (e.g. edge-lean\n\
 * reduction, we also store the event that generated the state from\n\
 * the successor).  e_set = TRUE if and only if the event e is\n\
 * relevant.  Otherwise it is false, e.g. for the initial state.\n\
 */\n\
typedef struct {\n\
  htbl_id_t id;\n\
  state_t s;\n\
  event_t e;\n\
  bool_t e_set;\n\
} bfs_queue_item_t;\n\
\n\
\n\
/**\n\
 * @typedef bfs_queue_t\n\
 * @brief the BFS queue type\n\
 */\n\
typedef struct struct_bfs_queue_t * bfs_queue_t;\n\
\n\
\n\
/**\n\
 * @brief BFS queue constructor.\n\
 * @param no_workers - number of workers that will access the queue\n\
 * @param slot_size - number of states in each block of a slot\n\
 * @param states_stored - do we store full states in the queue?\n\
 * @param events_stored - do we store events in the queue?\n\
 */\n\
bfs_queue_t bfs_queue_new\n\
(uint16_t no_workers,\n\
 uint32_t slot_size,\n\
 bool_t states_stored,\n\
 bool_t events_stored,\n\
 uint8_t levels);\n\
\n\
\n\
/**\n\
 * @brief Check if full states are stored in the queue.\n\
 */\n\
bool_t bfs_queue_states_stored\n\
(bfs_queue_t q);\n\
\n\
\n\
/**\n\
 * @brief Check if queue q is empty.\n\
 */\n\
bool_t bfs_queue_is_empty\n\
(bfs_queue_t q);\n\
\n\
\n\
/**\n\
 * @brief Check if local queue q of worker w is empty.\n\
 */\n\
bool_t bfs_queue_local_is_empty\n\
(bfs_queue_t q,\n\
 worker_id_t w);\n\
\n\
\n\
/**\n\
 * @brief Free queue q.\n\
 */\n\
void bfs_queue_free\n\
(bfs_queue_t q);\n\
\n\
\n\
/**\n\
 * @brief Return the number of threads having access to the queue.\n\
 */\n\
uint16_t bfs_queue_no_workers\n\
(bfs_queue_t q);\n\
\n\
\n\
/**\n\
 * @brief Check if the next slot (from, to) is empty.\n\
 */\n\
bool_t bfs_queue_slot_is_empty\n\
(bfs_queue_t q,\n\
 worker_id_t from,\n\
 worker_id_t to);\n\
\n\
\n\
/**\n\
 * @brief Enqueue item in the next slot (from, to).\n\
 */\n\
void bfs_queue_enqueue\n\
(bfs_queue_t  q,\n\
 bfs_queue_item_t item,\n\
 worker_id_t from,\n\
 worker_id_t to);\n\
\n\
\n\
/**\n\
 * @brief Dequeue an item from slot (from, to).\n\
 */\n\
bfs_queue_item_t bfs_queue_dequeue\n\
(bfs_queue_t q,\n\
 worker_id_t from,\n\
 worker_id_t to);\n\
\n\
\n\
/**\n\
 * @brief Get the next item from slot (from, to) but leave it in the\n\
 *        queue.\n\
 */\n\
bfs_queue_item_t bfs_queue_next\n\
(bfs_queue_t q,\n\
 worker_id_t from,\n\
 worker_id_t to);\n\
\n\
\n\
/**\n\
 * @brief Swap all next slots (from, w) by next slots (from, w).  This\n\
 *        has to be call by all workers.\n\
 */\n\
void bfs_queue_switch_level\n\
(bfs_queue_t q,\n\
 worker_id_t w);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "bfs_queue.c", "w")
    f.write ("\
#include \"bfs_queue.h\"\n\
#include \"config.h\"\n\
\n\
struct struct_bfs_queue_block_t {\n\
  bfs_queue_item_t * items;\n\
  heap_t heap;\n\
  struct struct_bfs_queue_block_t * prev;\n\
  struct struct_bfs_queue_block_t * next;\n\
};\n\
\n\
typedef struct struct_bfs_queue_block_t struct_bfs_queue_block_t;\n\
\n\
typedef struct_bfs_queue_block_t * bfs_queue_block_t;\n\
\n\
typedef struct {\n\
  bfs_queue_block_t first;\n\
  bfs_queue_block_t last;\n\
  uint64_t first_index;\n\
  uint64_t last_index;\n\
} struct_bfs_queue_slot_t;\n\
\n\
typedef struct_bfs_queue_slot_t * bfs_queue_slot_t;\n\
\n\
struct struct_bfs_queue_t {\n\
  bfs_queue_slot_t *** slots;\n\
  uint16_t no_workers;\n\
  uint32_t slot_size;\n\
  bool_t states_stored;\n\
  bool_t events_stored;\n\
  uint8_t levels;\n\
};\n\
\n\
typedef struct struct_bfs_queue_t struct_bfs_queue_t;\n\
\n\
bfs_queue_block_t bfs_queue_block_new\n\
(uint32_t slot_size,\n\
 bool_t allocate_heap) {\n\
  bfs_queue_block_t result;\n\
  \n\
  result = mem_alloc(SYSTEM_HEAP, sizeof(struct_bfs_queue_block_t));\n\
  result->items = mem_alloc(SYSTEM_HEAP, sizeof(bfs_queue_item_t) * slot_size);\n\
  if(allocate_heap) {\n\
    result->heap = local_heap_new();\n\
  } else {\n\
    result->heap = NULL;\n\
  }\n\
  return result;\n\
}\n\
\n\
void bfs_queue_block_free\n\
(bfs_queue_block_t n,\n\
 bool_t free_next) {  \n\
  if(n) {\n\
    if(free_next && n->next) {\n\
      bfs_queue_block_free(n->next, free_next);\n\
    }\n\
    heap_free(n->heap);\n\
    mem_free(SYSTEM_HEAP, n->items);\n\
    mem_free(SYSTEM_HEAP, n);\n\
  }\n\
}\n\
\n\
bfs_queue_slot_t bfs_queue_slot_new\n\
() {\n\
  bfs_queue_slot_t result;\n\
\n\
  result = mem_alloc(SYSTEM_HEAP, sizeof (struct_bfs_queue_slot_t));\n\
  result->first = NULL;\n\
  result->last = NULL;\n\
  result->first_index = 0;\n\
  result->last_index = 0;\n\
  return result;\n\
}\n\
\n\
void bfs_queue_slot_free\n\
(bfs_queue_slot_t q) {\n\
  bfs_queue_block_free(q->first, TRUE);\n\
  mem_free(SYSTEM_HEAP, q);\n\
}\n\
\n\
bfs_queue_t bfs_queue_new\n\
(uint16_t no_workers,\n\
 uint32_t slot_size,\n\
 bool_t states_stored,\n\
 bool_t events_stored,\n\
 uint8_t levels) {\n\
  worker_id_t w, x;\n\
  bfs_queue_t result;\n\
  uint8_t l;\n\
  \n\
  result = mem_alloc(SYSTEM_HEAP, sizeof(struct_bfs_queue_t));\n\
  result->no_workers = no_workers;\n\
  result->slot_size = slot_size;\n\
  result->levels = levels;\n\
  result->states_stored = states_stored;\n\
  result->events_stored = events_stored;\n\
  result->slots = mem_alloc(SYSTEM_HEAP, sizeof(bfs_queue_slot_t **) * levels);\n\
  for(l = 0; l < levels; l ++) {\n\
    result->slots[l] = mem_alloc(SYSTEM_HEAP,\n\
				 sizeof(bfs_queue_slot_t *) * no_workers);\n\
    for(w = 0; w < no_workers; w ++) {\n\
      result->slots[l][w] = mem_alloc(SYSTEM_HEAP,\n\
				      sizeof(bfs_queue_slot_t) * no_workers);\n\
      for(x = 0; x < no_workers; x ++) {\n\
	result->slots[l][w][x] = bfs_queue_slot_new(slot_size);\n\
      }\n\
    }\n\
  }\n\
  return result;\n\
}\n\
\n\
void bfs_queue_free\n\
(bfs_queue_t q) {\n\
  worker_id_t w, x;\n\
  uint8_t l;\n\
\n\
  for(l = 0; l < q->levels; l ++) {\n\
    for(w = 0; w < q->no_workers; w ++) {\n\
      for(x = 0; x < q->no_workers; x ++) {\n\
	bfs_queue_slot_free(q->slots[l][w][x]);\n\
      }\n\
      mem_free(SYSTEM_HEAP, q->slots[l][w]);\n\
    }\n\
    mem_free(SYSTEM_HEAP, q->slots[l]);\n\
  }\n\
  mem_free(SYSTEM_HEAP, q->slots);\n\
  mem_free(SYSTEM_HEAP, q);\n\
}\n\
\n\
bool_t bfs_queue_states_stored\n\
(bfs_queue_t q) {\n\
  return q->states_stored;\n\
}\n\
\n\
uint16_t bfs_queue_no_workers\n\
(bfs_queue_t q) {\n\
  return q->no_workers;\n\
}\n\
\n\
bool_t bfs_queue_slot_is_empty_real\n\
(bfs_queue_t q,\n\
 uint8_t level,\n\
 worker_id_t from,\n\
 worker_id_t to) {\n\
  bfs_queue_slot_t slot = q->slots[level][to][from];\n\
  \n\
  return ((NULL == slot->first) ||\n\
	  (slot->first == slot->last &&\n\
	   slot->first_index == slot->last_index)) ?\n\
    TRUE : FALSE;\n\
}\n\
\n\
bool_t bfs_queue_slot_is_empty\n\
(bfs_queue_t q,\n\
 worker_id_t from,\n\
 worker_id_t to) {\n\
  return bfs_queue_slot_is_empty_real(q, 0, from, to);\n\
}\n\
\n\
bool_t bfs_queue_local_is_empty\n\
(bfs_queue_t q,\n\
 worker_id_t w) {\n\
  worker_id_t x;\n\
  uint8_t l;\n\
  \n\
  for(l = 0; l < q->levels; l ++) {\n\
    for(x = 0; x < q->no_workers; x ++) {\n\
      if(!bfs_queue_slot_is_empty_real(q, l, x, w)) {\n\
	return FALSE;\n\
      }\n\
    }\n\
  }\n\
  return TRUE;\n\
}\n\
\n\
bool_t bfs_queue_is_empty\n\
(bfs_queue_t q) {\n\
  worker_id_t w;\n\
  \n\
  for(w = 0; w < q->no_workers; w ++) {\n\
    if(!bfs_queue_local_is_empty(q, w)) {\n\
      return FALSE;\n\
    }\n\
  }\n\
  return TRUE;\n\
}\n\
\n\
void bfs_queue_enqueue\n\
(bfs_queue_t q,\n\
 bfs_queue_item_t item,\n\
 worker_id_t from,\n\
 worker_id_t to) {\n\
  bfs_queue_slot_t slot = q->slots[1 % q->levels][to][from];\n\
  \n\
  if(!slot->first) {\n\
    slot->last = bfs_queue_block_new(q->slot_size, q->states_stored);\n\
    slot->last_index = 0;\n\
    slot->first = slot->last;\n\
    slot->first->next = NULL;\n\
    slot->first->prev = NULL;\n\
  }\n\
  else if(q->slot_size == slot->last_index) {\n\
    slot->last->next = bfs_queue_block_new(q->slot_size, q->states_stored);\n\
    slot->last_index = 0;\n\
    slot->last->next->next = NULL;\n\
    slot->last->next->prev = slot->last;\n\
    slot->last = slot->last->next;\n\
  }\n\
  if(q->states_stored) {\n\
    item.s = state_copy_mem(item.s, slot->last->heap);\n\
  }\n\
  if(q->events_stored && item.e_set) {\n\
    item.e = event_copy_mem(item.e, slot->last->heap);\n\
  }\n\
  slot->last->items[slot->last_index] = item;\n\
  slot->last_index ++;\n\
}\n\
\n\
bfs_queue_item_t bfs_queue_dequeue\n\
(bfs_queue_t q,\n\
 worker_id_t from,\n\
 worker_id_t to) {\n\
  bfs_queue_item_t result;\n\
  bfs_queue_block_t tmp;\n\
  bfs_queue_slot_t slot = q->slots[0][to][from];\n\
\n\
  result = bfs_queue_next(q, from, to);\n\
  slot->first_index ++;\n\
  if(q->slot_size == slot->first_index) {\n\
    tmp = slot->first->next;\n\
    bfs_queue_block_free(slot->first, FALSE);\n\
    slot->first = tmp;\n\
    slot->first_index = 0;\n\
  }\n\
  return result;\n\
}\n\
\n\
bfs_queue_item_t bfs_queue_next\n\
(bfs_queue_t q,\n\
 worker_id_t from,\n\
 worker_id_t to) {\n\
  bfs_queue_item_t result;\n\
  bfs_queue_slot_t slot = q->slots[0][to][from];\n\
\n\
  assert(slot->first && slot->first_index < q->slot_size);\n\
  result = slot->first->items[slot->first_index];\n\
  return result;\n\
}\n\
\n\
void bfs_queue_switch_level\n\
(bfs_queue_t q,\n\
 worker_id_t w) {\n\
  uint8_t l;\n\
  worker_id_t x;\n\
\n\
  for(l = q->levels - 1; l; l --) {\n\
    for(x = 0; x < q->no_workers; x ++) {\n\
      bfs_queue_slot_free(q->slots[l - 1][w][x]);\n\
      q->slots[l - 1][w][x] = q->slots[l][w][x];\n\
      q->slots[l][w][x] = bfs_queue_slot_new();\n\
    }\n\
  }\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "buchi.h", "w")
    f.write ("\
/**\n\
 * @file buchi.h\n\
 * @brief Description of Buchi automata for LTL verification algorithms.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 *\n\
 * The implementation of the Buchi automaton (buchi.c) is generated by\n\
 * ltl2ba.\n\
 */\n\
\n\
#ifndef LIB_BUCHI\n\
#define LIB_BUCHI\n\
\n\
#include \"common.h\"\n\
#include \"includes.h\"\n\
#include \"model.h\"\n\
\n\
\n\
/**\n\
 * @typedef a state of a Buchi automaton\n\
 */\n\
typedef int bstate_t;\n\
\n\
\n\
/**\n\
 * @struct an event of a Buchi automaton is identified by its source\n\
 *         and destination states\n\
 */\n\
typedef struct {\n\
  bstate_t from;\n\
  bstate_t to;\n\
} bevent_t;\n\
\n\
\n\
/**\n\
 * @brief Return the initial state of the Buchi automaton.\n\
 */\n\
bstate_t bstate_initial\n\
();\n\
\n\
\n\
/**\n\
 * @brief Check if the state is accepting.\n\
 */\n\
bool_t bstate_accepting\n\
(bstate_t b);\n\
\n\
\n\
/**\n\
 * @brief Get successors of state b synchronised with the model state\n\
 *        s.  Return in succs the list of successors and in no_succs\n\
 *        the number of successors.\n\
 */\n\
void bstate_succs\n\
(bstate_t b,\n\
 mstate_t s,\n\
 bstate_t * succs,\n\
 unsigned int * no_succs);\n\
\n\
\n\
/**\n\
 * @brief Compares two events.\n\
 */\n\
order_t bevent_cmp\n\
(bevent_t e,\n\
 bevent_t f);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "common.h", "w")
    f.write ("\
/**\n\
 * @file common.h\n\
 * @brief Some common declarations.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_COMMON\n\
#define LIB_COMMON\n\
\n\
#include \"includes.h\"\n\
\n\
\n\
/**\n\
 * @typedef bit_vector_t\n\
 * @brief a bit vector\n\
 */\n\
typedef char * bit_vector_t;\n\
\n\
\n\
/**\n\
 * @typedef hash_key_t\n\
 * @brief a hash value\n\
 */\n\
typedef uint64_t hash_key_t;\n\
\n\
\n\
/**\n\
 * @typedef worker_id_t\n\
 * @brief identifier of a worker thread\n\
 */\n\
typedef uint8_t worker_id_t;\n\
\n\
\n\
/**\n\
 * @typedef bool_t\n\
 * @brief a boolean value\n\
 */\n\
typedef uint8_t bool_t;\n\
#define FALSE 0\n\
#define TRUE  1\n\
\n\
\n\
/**\n\
 * @typedef rseed_t\n\
 * @brief a seed to generate random numbers\n\
 */\n\
typedef uint32_t rseed_t;\n\
\n\
\n\
/**\n\
 * @typedef order_t\n\
 * @brief an order value\n\
 */\n\
typedef uint8_t order_t; \n\
#define LESS    1\n\
#define EQUAL   2\n\
#define GREATER 3\n\
\n\
\n\
/**\n\
 * @struct lna_timer_t\n\
 * @brief a timer used to measure time flow\n\
 */\n\
typedef struct {\n\
  struct timeval start;\n\
  uint64_t value;\n\
} lna_timer_t;\n\
\n\
\n\
/**\n\
 * @brief atomic compare-and-swap\n\
 */\n\
#define CAS(val, old, new) (__sync_bool_compare_and_swap((val), (old), (new)))\n\
\n\
\n\
/**\n\
 * @brief Return a seed to generate random numbers.\n\
 */\n\
rseed_t random_seed\n\
(worker_id_t w);\n\
\n\
\n\
/**\n\
 * @brief Return a random integer and update the seed.\n\
 */\n\
uint32_t random_int\n\
(rseed_t * seed);\n\
\n\
\n\
/**\n\
 * @brief Initialise an helena timer.\n\
 */\n\
void lna_timer_init\n\
(lna_timer_t * t);\n\
\n\
\n\
/**\n\
 * @brief Start the helena timer.\n\
 */\n\
void lna_timer_start\n\
(lna_timer_t * t);\n\
\n\
\n\
/**\n\
 * @brief Stop the helena timer.\n\
 */\n\
void lna_timer_stop\n\
(lna_timer_t * t);\n\
\n\
\n\
/**\n\
 * @brief Get the timer value, i.e., # of micro-seconds between the\n\
 *        start and stop of the timer.\n\
 */\n\
uint64_t lna_timer_value\n\
(lna_timer_t t);\n\
\n\
\n\
/**\n\
 * @brief Get the duration in micro-seconds between two time values.\n\
 */\n\
uint64_t duration\n\
(struct timeval t0,\n\
 struct timeval t1);\n\
\n\
\n\
/**\n\
 * @brief Return a hash value for vector v of length len.\n\
 */\n\
hash_key_t bit_vector_hash\n\
(bit_vector_t v,\n\
 unsigned int len);\n\
\n\
\n\
/**\n\
 * @brief Return memory usage of the current process as a % of\n\
 *        available memory.\n\
 */\n\
float mem_usage\n\
();\n\
\n\
\n\
/**\n\
 * @brief Return CPU usage of the current process as a %.\n\
 */\n\
float cpu_usage\n\
(unsigned long * total,\n\
 unsigned long * utime,\n\
 unsigned long * stime);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "common.c", "w")
    f.write ("\
#include \"common.h\"\n\
\n\
const uint64_t crc64_tab[256] = {\n\
  0x0000000000000000, 0x7ad870c830358979, 0xf5b0e190606b12f2,\n\
  0x8f689158505e9b8b, 0xc038e5739841b68f, 0xbae095bba8743ff6,\n\
  0x358804e3f82aa47d, 0x4f50742bc81f2d04, 0xab28ecb46814fe75,\n\
  0xd1f09c7c5821770c, 0x5e980d24087fec87, 0x24407dec384a65fe,\n\
  0x6b1009c7f05548fa, 0x11c8790fc060c183, 0x9ea0e857903e5a08,\n\
  0xe478989fa00bd371, 0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8,\n\
  0x88b81eabe8d57d73, 0xf2606e63d8e0f40a, 0xbd301a4810ffd90e,\n\
  0xc7e86a8020ca5077, 0x4880fbd87094cbfc, 0x32588b1040a14285,\n\
  0xd620138fe0aa91f4, 0xacf86347d09f188d, 0x2390f21f80c18306,\n\
  0x594882d7b0f40a7f, 0x1618f6fc78eb277b, 0x6cc0863448deae02,\n\
  0xe3a8176c18803589, 0x997067a428b5bcf0, 0xfa11fe77117cdf02,\n\
  0x80c98ebf2149567b, 0x0fa11fe77117cdf0, 0x75796f2f41224489,\n\
  0x3a291b04893d698d, 0x40f16bccb908e0f4, 0xcf99fa94e9567b7f,\n\
  0xb5418a5cd963f206, 0x513912c379682177, 0x2be1620b495da80e,\n\
  0xa489f35319033385, 0xde51839b2936bafc, 0x9101f7b0e12997f8,\n\
  0xebd98778d11c1e81, 0x64b116208142850a, 0x1e6966e8b1770c73,\n\
  0x8719014c99c2b083, 0xfdc17184a9f739fa, 0x72a9e0dcf9a9a271,\n\
  0x08719014c99c2b08, 0x4721e43f0183060c, 0x3df994f731b68f75,\n\
  0xb29105af61e814fe, 0xc849756751dd9d87, 0x2c31edf8f1d64ef6,\n\
  0x56e99d30c1e3c78f, 0xd9810c6891bd5c04, 0xa3597ca0a188d57d,\n\
  0xec09088b6997f879, 0x96d1784359a27100, 0x19b9e91b09fcea8b,\n\
  0x636199d339c963f2, 0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416,\n\
  0x2aca3b2d1a053f9d, 0x50124be52a30b6e4, 0x1f423fcee22f9be0,\n\
  0x659a4f06d21a1299, 0xeaf2de5e82448912, 0x902aae96b271006b,\n\
  0x74523609127ad31a, 0x0e8a46c1224f5a63, 0x81e2d7997211c1e8,\n\
  0xfb3aa75142244891, 0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec,\n\
  0x41da32eaea507767, 0x3b024222da65fe1e, 0xa2722586f2d042ee,\n\
  0xd8aa554ec2e5cb97, 0x57c2c41692bb501c, 0x2d1ab4dea28ed965,\n\
  0x624ac0f56a91f461, 0x1892b03d5aa47d18, 0x97fa21650afae693,\n\
  0xed2251ad3acf6fea, 0x095ac9329ac4bc9b, 0x7382b9faaaf135e2,\n\
  0xfcea28a2faafae69, 0x8632586aca9a2710, 0xc9622c4102850a14,\n\
  0xb3ba5c8932b0836d, 0x3cd2cdd162ee18e6, 0x460abd1952db919f,\n\
  0x256b24ca6b12f26d, 0x5fb354025b277b14, 0xd0dbc55a0b79e09f,\n\
  0xaa03b5923b4c69e6, 0xe553c1b9f35344e2, 0x9f8bb171c366cd9b,\n\
  0x10e3202993385610, 0x6a3b50e1a30ddf69, 0x8e43c87e03060c18,\n\
  0xf49bb8b633338561, 0x7bf329ee636d1eea, 0x012b592653589793,\n\
  0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee, 0xbbcbcc9dfb2ca865,\n\
  0xc113bc55cb19211c, 0x5863dbf1e3ac9dec, 0x22bbab39d3991495,\n\
  0xadd33a6183c78f1e, 0xd70b4aa9b3f20667, 0x985b3e827bed2b63,\n\
  0xe2834e4a4bd8a21a, 0x6debdf121b863991, 0x1733afda2bb3b0e8,\n\
  0xf34b37458bb86399, 0x8993478dbb8deae0, 0x06fbd6d5ebd3716b,\n\
  0x7c23a61ddbe6f812, 0x3373d23613f9d516, 0x49aba2fe23cc5c6f,\n\
  0xc6c333a67392c7e4, 0xbc1b436e43a74e9d, 0x95ac9329ac4bc9b5,\n\
  0xef74e3e19c7e40cc, 0x601c72b9cc20db47, 0x1ac40271fc15523e,\n\
  0x5594765a340a7f3a, 0x2f4c0692043ff643, 0xa02497ca54616dc8,\n\
  0xdafce7026454e4b1, 0x3e847f9dc45f37c0, 0x445c0f55f46abeb9,\n\
  0xcb349e0da4342532, 0xb1eceec59401ac4b, 0xfebc9aee5c1e814f,\n\
  0x8464ea266c2b0836, 0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4,\n\
  0xe8a46c1224f5a634, 0x927c1cda14c02f4d, 0x1d148d82449eb4c6,\n\
  0x67ccfd4a74ab3dbf, 0x289c8961bcb410bb, 0x5244f9a98c8199c2,\n\
  0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30, 0x438c80a64ce15841,\n\
  0x3954f06e7cd4d138, 0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca,\n\
  0x83b465d5d4a0eece, 0xf96c151de49567b7, 0x76048445b4cbfc3c,\n\
  0x0cdcf48d84fe7545, 0x6fbd6d5ebd3716b7, 0x15651d968d029fce,\n\
  0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c, 0xaf85882d2576a038,\n\
  0xd55df8e515432941, 0x5a3569bd451db2ca, 0x20ed197575283bb3,\n\
  0xc49581ead523e8c2, 0xbe4df122e51661bb, 0x3125607ab548fa30,\n\
  0x4bfd10b2857d7349, 0x04ad64994d625e4d, 0x7e7514517d57d734,\n\
  0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6, 0x12b5926535897936,\n\
  0x686de2ad05bcf04f, 0xe70573f555e26bc4, 0x9ddd033d65d7e2bd,\n\
  0xd28d7716adc8cfb9, 0xa85507de9dfd46c0, 0x273d9686cda3dd4b,\n\
  0x5de5e64efd965432, 0xb99d7ed15d9d8743, 0xc3450e196da80e3a,\n\
  0x4c2d9f413df695b1, 0x36f5ef890dc31cc8, 0x79a59ba2c5dc31cc,\n\
  0x037deb6af5e9b8b5, 0x8c157a32a5b7233e, 0xf6cd0afa9582aa47,\n\
  0x4ad64994d625e4da, 0x300e395ce6106da3, 0xbf66a804b64ef628,\n\
  0xc5bed8cc867b7f51, 0x8aeeace74e645255, 0xf036dc2f7e51db2c,\n\
  0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de, 0xe1fea520be311aaf,\n\
  0x9b26d5e88e0493d6, 0x144e44b0de5a085d, 0x6e963478ee6f8124,\n\
  0x21c640532670ac20, 0x5b1e309b16452559, 0xd476a1c3461bbed2,\n\
  0xaeaed10b762e37ab, 0x37deb6af5e9b8b5b, 0x4d06c6676eae0222,\n\
  0xc26e573f3ef099a9, 0xb8b627f70ec510d0, 0xf7e653dcc6da3dd4,\n\
  0x8d3e2314f6efb4ad, 0x0256b24ca6b12f26, 0x788ec2849684a65f,\n\
  0x9cf65a1b368f752e, 0xe62e2ad306bafc57, 0x6946bb8b56e467dc,\n\
  0x139ecb4366d1eea5, 0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8,\n\
  0xa97e5ef8cea5d153, 0xd3a62e30fe90582a, 0xb0c7b7e3c7593bd8,\n\
  0xca1fc72bf76cb2a1, 0x45775673a732292a, 0x3faf26bb9707a053,\n\
  0x70ff52905f188d57, 0x0a2722586f2d042e, 0x854fb3003f739fa5,\n\
  0xff97c3c80f4616dc, 0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4,\n\
  0xee5fbac7cf26d75f, 0x9487ca0fff135e26, 0xdbd7be24370c7322,\n\
  0xa10fceec0739fa5b, 0x2e675fb4576761d0, 0x54bf2f7c6752e8a9,\n\
  0xcdcf48d84fe75459, 0xb71738107fd2dd20, 0x387fa9482f8c46ab,\n\
  0x42a7d9801fb9cfd2, 0x0df7adabd7a6e2d6, 0x772fdd63e7936baf,\n\
  0xf8474c3bb7cdf024, 0x829f3cf387f8795d, 0x66e7a46c27f3aa2c,\n\
  0x1c3fd4a417c62355, 0x935745fc4798b8de, 0xe98f353477ad31a7,\n\
  0xa6df411fbfb21ca3, 0xdc0731d78f8795da, 0x536fa08fdfd90e51,\n\
  0x29b7d047efec8728\n\
};\n\
\n\
hash_key_t bit_vector_hash\n\
(bit_vector_t v,\n\
 unsigned int len) {\n\
    unsigned int i;\n\
    uint64_t result = 0;\n\
\n\
    for(i = 0; i < len; i++) {\n\
      result = crc64_tab[(uint8_t) (result ^ v[i])] ^ (result >> 8);\n\
    }\n\
    return result;\n\
}\n\
\n\
void lna_timer_init\n\
(lna_timer_t * t) {\n\
  t->value = 0;\n\
}\n\
\n\
void lna_timer_start\n\
(lna_timer_t * t) {\n\
  gettimeofday(&t->start, NULL);\n\
}\n\
\n\
void lna_timer_stop\n\
(lna_timer_t * t) {\n\
  struct timeval end;\n\
  gettimeofday(&end, NULL);\n\
  t->value += (uint64_t)\n\
    (end.tv_sec * 1000000 + end.tv_usec) -\n\
    (t->start.tv_sec * 1000000 + t->start.tv_usec);\n\
}\n\
\n\
uint64_t lna_timer_value\n\
(lna_timer_t t) {\n\
  return t.value;\n\
}\n\
\n\
uint64_t duration\n\
(struct timeval t0,\n\
 struct timeval t1) {\n\
  uint64_t t0_time = t0.tv_sec * 1000000 + t0.tv_usec;\n\
  uint64_t t1_time = t1.tv_sec * 1000000 + t1.tv_usec;\n\
  return (uint64_t) t1_time - t0_time;\n\
}\n\
\n\
rseed_t random_seed\n\
(worker_id_t w) {\n\
  struct timeval t;\n\
  \n\
  gettimeofday(&t, NULL);\n\
  return t.tv_sec * 1000000 + t.tv_usec + w;\n\
}\n\
\n\
#define RANDOM_MULT 1664525\n\
#define RANDOM_CONS 1\n\
#define RANDOM_MASK 0xFFFF\n\
#define RANDOM_LOW(X) (X&RANDOM_MASK)\n\
#define RANDOM_HIGH(X) ((X>>16)&RANDOM_MASK)\n\
\n\
uint32_t random_int\n\
(uint32_t * seed) {\n\
  uint32_t lo, hi;\n\
  uint32_t s = *seed;\n\
  lo = RANDOM_LOW(RANDOM_LOW(s) * RANDOM_LOW(RANDOM_MULT) + RANDOM_CONS);\n\
  hi = RANDOM_LOW(RANDOM_HIGH(s) * RANDOM_LOW(RANDOM_MULT))\n\
    + RANDOM_LOW(RANDOM_HIGH(RANDOM_MULT) * RANDOM_LOW(s))\n\
    + RANDOM_HIGH(RANDOM_LOW(s) * RANDOM_LOW(RANDOM_MULT) + RANDOM_CONS);\n\
  *seed = (hi << 16 | lo);\n\
  return *seed;\n\
}\n\
\n\
float mem_usage() {\n\
  float result = 0.0;\n\
  FILE * f;\n\
  unsigned int size = 0;\n\
  \n\
  f = fopen(\"/proc/self/statm\", \"r\");\n\
  if(f) {\n\
    fscanf(f, \"%u\", &size);\n\
  }\n\
  fclose(f);\n\
  return (float) size / 1000.0;\n\
}\n\
\n\
unsigned long cpu_total\n\
() {\n\
  FILE * file;\n\
  long unsigned int n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, result;\n\
  \n\
  file = fopen(\"/proc/stat\", \"r\");\n\
  if(file) {\n\
    fscanf(file, \"%*s %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\",\n\
           &n0, &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &n9);\n\
    result = n0 + n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9;\n\
    \n\
  }\n\
  fclose(file);\n\
  return result;\n\
}\n\
\n\
float cpu_usage\n\
(unsigned long * total,\n\
 unsigned long * utime,\n\
 unsigned long * stime) {\n\
  const unsigned long total_before = *total;\n\
  const unsigned long utime_before = *utime;\n\
  const unsigned long stime_before = *stime;\n\
  float result = 0.0;\n\
  FILE * file;\n\
  char name[30];\n\
  \n\
  snprintf(name, 30, \"/proc/%u/stat\", (unsigned) getpid());\n\
  *total = cpu_total();\n\
  file = fopen(name, \"r\");\n\
  if(file) {\n\
    fscanf(file, \"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u\");\n\
    fscanf(file, \"%lu %lu\", utime, stime);\n\
  }\n\
  fclose(file);\n\
  result = 100.0 *\n\
    ((float) ((*utime) + (*stime) - utime_before - stime_before)) /\n\
    ((float) ((*total) - total_before));\n\
  return result * sysconf(_SC_NPROCESSORS_ONLN);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "comm_shmem.h", "w")
    f.write ("\
/**\n\
 * @file comm_shmem.h\n\
 * @brief Various stuffs for shmem communication\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_COMM_SHMEM\n\
#define LIB_COMM_SHMEM\n\
\n\
#include \"includes.h\"\n\
#include \"common.h\"\n\
\n\
/**\n\
 * @brief init_comm_shmem\n\
 */\n\
void init_comm_shmem\n\
();\n\
\n\
\n\
/**\n\
 * @brief finalise_comm_shmem\n\
 */\n\
void finalise_comm_shmem\n\
();\n\
\n\
\n\
/**\n\
 * @brief comm_shmem_barrier\n\
 */\n\
void comm_shmem_barrier\n\
();\n\
\n\
\n\
/**\n\
 * @brief comm_shmem_put\n\
 */\n\
void comm_shmem_put\n\
(uint32_t pos,\n\
 void * src,\n\
 int size,\n\
 int pe);\n\
\n\
\n\
/**\n\
 * @brief comm_shmem_get\n\
 */\n\
void comm_shmem_get\n\
(void * dst,\n\
 uint32_t pos, \n\
 int size,\n\
 int pe);\n\
\n\
\n\
/**\n\
 * @brief comm_shmem_me\n\
 */\n\
int comm_shmem_me\n\
();\n\
\n\
\n\
/**\n\
 * @brief comm_shmem_pes\n\
 */\n\
int comm_shmem_pes\n\
();\n\
\n\
\n\
/**\n\
 * @brief comm_shmem_malloc\n\
 */\n\
void * comm_shmem_malloc\n\
(int size);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "comm_shmem.c", "w")
    f.write ("\
#include \"comm_shmem.h\"\n\
#include \"config.h\"\n\
#include \"context.h\"\n\
\n\
#if CFG_DISTRIBUTED == 1\n\
#include \"shmem.h\"\n\
#endif\n\
\n\
#define COMM_SHMEM_CHUNK_SIZE 10000\n\
#define COMM_SHMEM_DEBUG_XXX\n\
\n\
pthread_mutex_t COMM_SHMEM_MUTEX;\n\
void * COMM_SHMEM_HEAP;\n\
\n\
void init_comm_shmem\n\
() {\n\
#if CFG_DISTRIBUTED == 0\n\
  assert(0);\n\
#else\n\
  shmem_init();\n\
  COMM_SHMEM_HEAP = shmem_malloc(CFG_SHMEM_HEAP_SIZE);\n\
  pthread_mutex_init(&COMM_SHMEM_MUTEX, NULL);\n\
#endif\n\
}\n\
\n\
void finalise_comm_shmem\n\
() {\n\
#if CFG_DISTRIBUTED == 0\n\
  assert(0);\n\
#else\n\
  shmem_free(COMM_SHMEM_HEAP);\n\
  shmem_finalize();\n\
  pthread_mutex_destroy(&COMM_SHMEM_MUTEX);\n\
#endif\n\
}\n\
\n\
void comm_shmem_barrier\n\
() {\n\
#if CFG_DISTRIBUTED == 0\n\
  assert(0);\n\
#else\n\
  shmem_barrier_all();\n\
#endif\n\
}\n\
\n\
void comm_shmem_put\n\
(uint32_t pos,\n\
 void * src,\n\
 int size,\n\
 int pe) {\n\
  \n\
#if CFG_DISTRIBUTED == 0\n\
  assert(0);\n\
#else\n\
  /**\n\
   * NOTE: shmem_put fails on local PE in some cases.  we do memcpy\n\
   * instead which seems equivalent.\n\
   */\n\
  if(pe == shmem_my_pe()) {\n\
    memcpy(COMM_SHMEM_HEAP + pos, src, size);\n\
  } else {\n\
#if defined(COMM_SHMEM_DEBUG)\n\
    printf(\"%d put %d bytes at %d to %d\\n\", shmem_my_pe(), size, pos, pe);\n\
#endif\n\
    context_incr_stat(STAT_BYTES_SENT, 0, size);\n\
    pthread_mutex_lock(&COMM_SHMEM_MUTEX);\n\
    while(size) {\n\
      if(size < COMM_SHMEM_CHUNK_SIZE) {\n\
	shmem_putmem(COMM_SHMEM_HEAP + pos, src, size, pe);\n\
	size = 0;\n\
      } else {\n\
	shmem_putmem(COMM_SHMEM_HEAP + pos, src, COMM_SHMEM_CHUNK_SIZE, pe);\n\
	size -= COMM_SHMEM_CHUNK_SIZE;\n\
	pos += COMM_SHMEM_CHUNK_SIZE;\n\
	src += COMM_SHMEM_CHUNK_SIZE;\n\
      }\n\
    }\n\
    pthread_mutex_unlock(&COMM_SHMEM_MUTEX);\n\
#if defined(COMM_SHMEM_DEBUG)\n\
    printf(\"%d put done\\n\", shmem_my_pe());\n\
#endif\n\
  }\n\
#endif\n\
}\n\
\n\
void comm_shmem_get\n\
(void * dst,\n\
 uint32_t pos,\n\
 int size,\n\
 int pe) {\n\
#if CFG_DISTRIBUTED == 0\n\
  assert(0);\n\
#else\n\
  if(pe == shmem_my_pe()) {\n\
    memcpy(dst, COMM_SHMEM_HEAP + pos, size);\n\
  } else {\n\
#if defined(COMM_SHMEM_DEBUG)\n\
    printf(\"%d get %d bytes at %d from %d\\n\", shmem_my_pe(), size, pos, pe);\n\
#endif\n\
    context_incr_stat(STAT_BYTES_SENT, 0, size);\n\
    pthread_mutex_lock(&COMM_SHMEM_MUTEX);\n\
    shmem_getmem(dst, COMM_SHMEM_HEAP + pos, size, pe);\n\
    pthread_mutex_unlock(&COMM_SHMEM_MUTEX);\n\
#if defined(COMM_SHMEM_DEBUG)\n\
    printf(\"%d get done\\n\", shmem_my_pe());\n\
#endif\n\
  }\n\
#endif\n\
}\n\
\n\
int comm_shmem_me\n\
() {\n\
#if CFG_DISTRIBUTED == 0\n\
  return 0;\n\
#else\n\
  return shmem_my_pe();\n\
#endif\n\
}\n\
\n\
int comm_shmem_pes\n\
() {\n\
#if CFG_DISTRIBUTED == 0\n\
  return 1;\n\
#else\n\
  return shmem_n_pes();\n\
#endif\n\
}\n\
\n\
void * comm_shmem_malloc\n\
(int size) {\n\
#if CFG_DISTRIBUTED == 0\n\
  assert(0);\n\
#else\n\
  return shmem_malloc(size);\n\
#endif\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "context.h", "w")
    f.write ("\
/**\n\
 * @file context.h\n\
 * @brief Implementation of the context of a search.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_CONTEXT\n\
#define LIB_CONTEXT\n\
\n\
#include \"includes.h\"\n\
#include \"model.h\"\n\
#include \"state.h\"\n\
#include \"event.h\"\n\
\n\
\n\
/**\n\
 * @typedef termination_state_t\n\
 * @brief possible termination states of helena\n\
 */\n\
typedef enum {\n\
  TERM_SUCCESS,\n\
  TERM_ERROR,\n\
  TERM_INTERRUPTION,\n\
  TERM_SEARCH_TERMINATED,\n\
  TERM_NO_ERROR,\n\
  TERM_MEMORY_EXHAUSTED,\n\
  TERM_TIME_ELAPSED,\n\
  TERM_STATE_LIMIT_REACHED,\n\
  TERM_FAILURE\n\
} term_state_t;\n\
\n\
\n\
/**\n\
 * @typedef stat_t\n\
 * @brief available statistics\n\
 */\n\
typedef enum {\n\
  STAT_STATES_STORED,\n\
  STAT_STATES_ACCEPTING,\n\
  STAT_STATES_DEADLOCK,\n\
  STAT_STATES_PROCESSED,\n\
  STAT_STATES_REDUCED,\n\
  STAT_STATES_UNSAFE,\n\
  STAT_ARCS,\n\
  STAT_MAX_DFS_STACK_SIZE,\n\
  STAT_AVG_CPU_USAGE,\n\
  STAT_BARRIER_TIME,\n\
  STAT_BFS_LEVELS,\n\
  STAT_BYTES_SENT,\n\
  STAT_COMP_TIME,\n\
  STAT_DDD_TIME,\n\
  STAT_EVENT_EXEC,\n\
  STAT_EVENT_EXEC_DDD,\n\
  STAT_MAX_MEM_USED,\n\
  STAT_SEARCH_TIME,\n\
  STAT_SLEEP_TIME\n\
} stat_t;\n\
\n\
\n\
/**\n\
 * @brief Context initialisation.\n\
 */\n\
void init_context\n\
();\n\
\n\
\n\
/**\n\
 * @brief Context finalisation.\n\
 */\n\
void finalise_context\n\
();\n\
\n\
\n\
/**\n\
 * @brief Raise an error: stop the search and set the termination\n\
 *        state.  This does not apply for simulation mode.  No effect\n\
 *        if an error has already been raised.\n\
 */\n\
void context_error\n\
(char * msg);\n\
\n\
\n\
/**\n\
 * @brief Check if an error has been raised.\n\
 */\n\
bool_t context_error_raised\n\
();\n\
\n\
\n\
/**\n\
 * @brief Return the error message of the error raised, NULL if no\n\
 *        error raised.\n\
 */\n\
char * context_error_msg\n\
();\n\
\n\
\n\
/**\n\
 * @brief Cancel the last error raised.\n\
 */\n\
void context_flush_error\n\
();\n\
\n\
void context_interruption_handler\n\
(int signal);\n\
\n\
void context_stop_search\n\
();\n\
\n\
void context_faulty_state\n\
(state_t s);\n\
\n\
bool_t context_keep_searching\n\
();\n\
\n\
uint16_t context_no_workers\n\
();\n\
\n\
pthread_t * context_workers\n\
();\n\
\n\
void context_set_termination_state\n\
(term_state_t state);\n\
\n\
void context_set_trace\n\
(event_list_t trace);\n\
\n\
float context_cpu_usage\n\
();\n\
\n\
struct timeval context_start_time\n\
();\n\
\n\
FILE * context_open_graph_file\n\
();\n\
\n\
FILE * context_graph_file\n\
();\n\
\n\
void context_close_graph_file\n\
();\n\
\n\
uint32_t context_global_worker_id\n\
(worker_id_t w);\n\
\n\
uint32_t context_proc_id\n\
();\n\
\n\
void context_barrier_wait\n\
(pthread_barrier_t * b);\n\
\n\
void context_sleep\n\
(struct timespec t);\n\
\n\
term_state_t context_termination_state\n\
();\n\
\n\
void context_incr_stat\n\
(stat_t stat,\n\
 worker_id_t w,\n\
 double val);\n\
\n\
void context_set_max_stat\n\
(stat_t stat,\n\
 worker_id_t w,\n\
 double val);\n\
\n\
double context_get_stat\n\
(stat_t stat);\n\
\n\
void context_set_stat\n\
(stat_t stat,\n\
 worker_id_t w,\n\
 double val);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "context.c", "w")
    f.write ("\
#include \"context.h\"\n\
#include \"observer.h\"\n\
#include \"config.h\"\n\
#include \"comm_shmem.h\"\n\
#include \"papi_stats.h\"\n\
\n\
#define NO_STATS 19\n\
\n\
typedef enum {\n\
  STAT_TYPE_TIME,\n\
  STAT_TYPE_GRAPH,\n\
  STAT_TYPE_OTHERS\n\
} stat_type_t;\n\
\n\
typedef struct {\n\
  struct timeval start_time;\n\
  struct timeval end_time;\n\
  unsigned int no_workers;\n\
  unsigned long cpu_total;\n\
  unsigned long utime;\n\
  unsigned long stime;\n\
  bool_t keep_searching;\n\
  bool_t error_raised;\n\
  FILE * graph_file;\n\
  char * error_msg;\n\
  term_state_t term_state;\n\
\n\
  /*  for the trace context  */\n\
  bool_t faulty_state_found;\n\
  state_t faulty_state;\n\
  event_list_t trace;\n\
  pthread_mutex_t ctx_mutex;\n\
\n\
  /*  statistics field  */\n\
  uint64_t * stat[NO_STATS];\n\
  bool_t stat_set[NO_STATS];\n\
\n\
  /*  threads  */\n\
  pthread_t observer;\n\
  pthread_t * workers;\n\
} struct_context_t;\n\
\n\
typedef struct_context_t * context_t;\n\
\n\
context_t CTX;\n\
\n\
void init_context\n\
() {\n\
  worker_id_t w;\n\
  unsigned int i;\n\
  unsigned int no_workers = CFG_NO_WORKERS;\n\
  \n\
  CTX = mem_alloc(SYSTEM_HEAP, sizeof(struct_context_t));\n\
  \n\
  CTX->error_msg = NULL;\n\
  CTX->error_raised = FALSE;\n\
\n\
  if(CFG_ACTION_SIMULATE) {\n\
    return;\n\
  }\n\
  \n\
  /*\n\
   * initialisation of statistic related fields\n\
   */\n\
  for(i = 0; i < NO_STATS; i ++) {\n\
    CTX->stat_set[i] = FALSE;\n\
    CTX->stat[i] = mem_alloc(SYSTEM_HEAP, (no_workers + 1) * sizeof(double));\n\
    for(w = 0; w < no_workers + 1; w ++) {\n\
      CTX->stat[i][w] = 0.0;\n\
    }\n\
  }\n\
\n\
  /*\n\
   * statistics that must be outputed must be set to 0 to appear in\n\
   * the report\n\
   */\n\
  context_set_stat(STAT_STATES_STORED, 0, 0);\n\
  context_set_stat(STAT_STATES_DEADLOCK, 0, 0);\n\
  if(CFG_ACTION_CHECK_LTL) {\n\
    context_set_stat(STAT_STATES_ACCEPTING, 0, 0);\n\
  }\n\
  \n\
  CTX->no_workers = no_workers;\n\
  CTX->faulty_state_found = FALSE;\n\
  CTX->trace = NULL;\n\
  CTX->keep_searching = TRUE;\n\
  gettimeofday(&CTX->start_time, NULL);\n\
  CTX->graph_file = NULL;\n\
  if(!CFG_ACTION_CHECK) {\n\
    CTX->term_state = TERM_SEARCH_TERMINATED;\n\
  } else {\n\
    if(CFG_HASH_COMPACTION) {\n\
      CTX->term_state = TERM_NO_ERROR;\n\
    } else {\n\
      CTX->term_state = TERM_SUCCESS;\n\
    }\n\
  }\n\
  CTX->cpu_total = 0;\n\
  CTX->utime = 0;\n\
  CTX->stime = 0;\n\
  cpu_usage(&CTX->cpu_total, &CTX->utime, &CTX->stime);\n\
  \n\
  /*\n\
   * launch the observer thread\n\
   */\n\
  pthread_create(&CTX->observer, NULL, &observer_worker, (void *) CTX);\n\
  CTX->workers = mem_alloc(SYSTEM_HEAP, sizeof(pthread_t) * CTX->no_workers);\n\
  pthread_mutex_init(&CTX->ctx_mutex, NULL);\n\
}\n\
\n\
#define context_state_to_xml(s, out) {          \\\n\
    fprintf(out, \"<state>\\n\");                  \\\n\
    state_to_xml(s, out);                       \\\n\
    fprintf(out, \"</state>\\n\");                 \\\n\
  }\n\
\n\
#define context_event_to_xml(e, out) {          \\\n\
    fprintf(out, \"<event>\\n\");                  \\\n\
    event_to_xml(e, out);                       \\\n\
    fprintf(out, \"</event>\\n\");                 \\\n\
  }\n\
\n\
void context_output_trace\n\
(FILE * out) {\n\
  event_t e;\n\
  state_t s = state_initial();\n\
  list_iter_t it;\n\
\n\
  if(CTX->trace) {\n\
    if(list_size(CTX->trace) > CFG_MAX_TRACE_LENGTH) {\n\
      fprintf(out, \"<traceTooLong/>\\n\");\n\
    } else {\n\
      context_state_to_xml(s, out);\n\
      for(it = list_get_iter(CTX->trace);\n\
          !list_iter_at_end(it);\n\
          it = list_iter_next(it)) {\n\
        e = * ((event_t *) list_iter_item(it));\n\
        if(!event_is_dummy(e)) {\n\
          context_event_to_xml(e, out);\n\
          event_exec(e, s);\n\
          if(CFG_TRACE_FULL) {\n\
            context_state_to_xml(s, out);\n\
          }\n\
        }\n\
      }\n\
      if(CFG_TRACE_EVENTS && !list_is_empty(CTX->trace) > 0) {\n\
        context_state_to_xml(s, out);\n\
      }\n\
    }\n\
  }\n\
  state_free(s);\n\
}\n\
\n\
bool_t context_stat_do_average\n\
(stat_t stat) {\n\
  switch(stat) {\n\
  case STAT_STATES_PROCESSED: return TRUE;\n\
  default:                    return FALSE;\n\
  }\n\
}\n\
\n\
char * context_stat_xml_name\n\
(stat_t stat) {\n\
  switch(stat) {\n\
  case STAT_STATES_STORED:      return \"statesStored\";\n\
  case STAT_STATES_PROCESSED:   return \"statesProcessed\";\n\
  case STAT_STATES_DEADLOCK:    return \"statesTerminal\";\n\
  case STAT_STATES_ACCEPTING:   return \"statesAccepting\";\n\
  case STAT_STATES_REDUCED:     return \"statesReduced\";\n\
  case STAT_STATES_UNSAFE:      return \"statesUnsafe\";\n\
  case STAT_ARCS:               return \"arcs\";\n\
  case STAT_MAX_DFS_STACK_SIZE: return \"maxDFSStackSize\";\n\
  case STAT_BFS_LEVELS:         return \"bfsLevels\";\n\
  case STAT_EVENT_EXEC:         return \"eventsExecuted\";\n\
  case STAT_EVENT_EXEC_DDD:     return \"eventsExecutedDDD\";\n\
  case STAT_BYTES_SENT:         return \"bytesSent\";\n\
  case STAT_MAX_MEM_USED:       return \"maxMemoryUsed\";\n\
  case STAT_AVG_CPU_USAGE:      return \"avgCPUUsage\";\n\
  case STAT_SEARCH_TIME:        return \"searchTime\";\n\
  case STAT_SLEEP_TIME:         return \"sleepTime\";\n\
  case STAT_BARRIER_TIME:       return \"barrierTime\";\n\
  case STAT_DDD_TIME:           return \"duplicateDetectionTime\";\n\
  case STAT_COMP_TIME:          return \"compilationTime\";\n\
  default:\n\
    assert(FALSE);\n\
  }\n\
}\n\
\n\
stat_type_t context_stat_type\n\
(stat_t stat) {\n\
  switch(stat) {\n\
  case STAT_STATES_STORED:      return STAT_TYPE_GRAPH;\n\
  case STAT_STATES_PROCESSED:   return STAT_TYPE_GRAPH;\n\
  case STAT_STATES_DEADLOCK:    return STAT_TYPE_GRAPH;\n\
  case STAT_STATES_ACCEPTING:   return STAT_TYPE_GRAPH;\n\
  case STAT_STATES_REDUCED:     return STAT_TYPE_GRAPH;\n\
  case STAT_STATES_UNSAFE:      return STAT_TYPE_GRAPH;\n\
  case STAT_ARCS:               return STAT_TYPE_GRAPH;\n\
  case STAT_BFS_LEVELS:         return STAT_TYPE_GRAPH;\n\
  case STAT_MAX_DFS_STACK_SIZE: return STAT_TYPE_GRAPH;\n\
  case STAT_EVENT_EXEC:         return STAT_TYPE_OTHERS;\n\
  case STAT_EVENT_EXEC_DDD:     return STAT_TYPE_OTHERS;\n\
  case STAT_BYTES_SENT:         return STAT_TYPE_OTHERS;\n\
  case STAT_MAX_MEM_USED:       return STAT_TYPE_OTHERS;\n\
  case STAT_AVG_CPU_USAGE:      return STAT_TYPE_OTHERS;\n\
  case STAT_SEARCH_TIME:        return STAT_TYPE_TIME;\n\
  case STAT_SLEEP_TIME:         return STAT_TYPE_TIME;\n\
  case STAT_BARRIER_TIME:       return STAT_TYPE_TIME;\n\
  case STAT_COMP_TIME:          return STAT_TYPE_TIME;\n\
  case STAT_DDD_TIME:           return STAT_TYPE_TIME;\n\
  default:\n\
    assert(FALSE);\n\
  }\n\
}\n\
\n\
void context_stat_format\n\
(uint8_t stat,\n\
 double val,\n\
 FILE * out) {\n\
  if(STAT_MAX_MEM_USED == stat ||\n\
     STAT_AVG_CPU_USAGE == stat) {\n\
    fprintf(out, \"%.2lf\", val);\n\
  } else if(STAT_TYPE_TIME == context_stat_type(stat)) {\n\
    fprintf(out, \"%.2lf\", val / 1000000.0);\n\
  } else {\n\
    fprintf(out, \"%llu\", (uint64_t) val);\n\
  }\n\
}\n\
\n\
void context_stat_to_xml\n\
(uint8_t stat,\n\
 FILE * out) {\n\
  int i;\n\
  char * name = context_stat_xml_name(stat);\n\
  double sum = context_get_stat(stat), min, max, avg, dev;\n\
  worker_id_t w;\n\
  \n\
  fprintf(out, \"<%s>\", name);\n\
  context_stat_format(stat, sum, out);\n\
  fprintf(out, \"</%s>\\n\", name);\n\
  if(context_stat_do_average(stat) && CTX->no_workers > 1) {\n\
    min = max = CTX->stat[stat][0];\n\
    avg = sum / CFG_NO_WORKERS;\n\
    dev = 0;\n\
    for(w = 1; w < CTX->no_workers + 1; w ++) {\n\
      if(CTX->stat[stat][w] > max) {\n\
        max = CTX->stat[stat][w];\n\
      } else if(CTX->stat[stat][w] < min) {\n\
        min = CTX->stat[stat][w];\n\
      }\n\
      dev += (CTX->stat[stat][w] - avg) * (CTX->stat[stat][w] - avg);\n\
    }\n\
    dev = sqrt(dev / CTX->no_workers);\n\
    fprintf(out, \"<%sMin>\", name);\n\
    context_stat_format(stat, min, out);\n\
    fprintf(out, \"</%sMin>\\n\", name);\n\
    fprintf(out, \"<%sMax>\", name);\n\
    context_stat_format(stat, max, out);\n\
    fprintf(out, \"</%sMax>\\n\", name);\n\
    fprintf(out, \"<%sDev>\", name);\n\
    context_stat_format(stat, dev, out);\n\
    fprintf(out, \"</%sDev>\\n\", name);\n\
  }\n\
}\n\
\n\
void context_stats_to_xml\n\
(stat_type_t stat_type,\n\
 FILE * out) {\n\
  int i;\n\
\n\
  for(i = 0; i < NO_STATS; i ++) {\n\
    if(CTX->stat_set[i] && context_stat_type(i) == stat_type) {\n\
      context_stat_to_xml(i, out);\n\
    }\n\
  }\n\
}\n\
\n\
void finalise_context\n\
() {\n\
  FILE * out;\n\
  void * dummy;\n\
  worker_id_t w;\n\
  char name[1024], file_name[1024];\n\
  char * buf = NULL;\n\
  size_t n = 0;\n\
  int i;\n\
\n\
  if(!CFG_ACTION_SIMULATE) {\n\
    gettimeofday(&CTX->end_time, NULL);\n\
    context_set_stat(STAT_SEARCH_TIME, 0,\n\
                     duration(CTX->start_time, CTX->end_time));\n\
    CTX->keep_searching = FALSE;\n\
    pthread_join(CTX->observer, &dummy);\n\
    if(NULL != CTX->graph_file) {\n\
      fclose(CTX->graph_file);\n\
    }\n\
\n\
    /**\n\
     *  make the report\n\
     */\n\
    if(CFG_DISTRIBUTED) {\n\
      sprintf(file_name, \"%s.%d\", CFG_REPORT_FILE, context_proc_id());\n\
      out = fopen(file_name, \"w\");\n\
    } else {\n\
      out = fopen(CFG_REPORT_FILE, \"w\");\n\
    }\n\
    fprintf(out, \"<helenaReport>\\n\");\n\
    fprintf(out, \"<infoReport>\\n\");\n\
    fprintf(out, \"<model>%s</model>\\n\", model_name());\n\
#if defined(MODEL_HAS_XML_PARAMETERS)\n\
    model_xml_parameters(out);\n\
#endif\n\
    fprintf(out, \"<language>%s</language>\\n\", CFG_LANGUAGE);\n\
    fprintf(out, \"<date>%s</date>\\n\", CFG_DATE);\n\
    fprintf(out, \"<filePath>%s</filePath>\\n\", CFG_FILE_PATH);\n\
    gethostname(name, 1024);\n\
    fprintf(out, \"<host>%s (pid = %d)</host>\\n\", name, getpid());\n\
    fprintf(out, \"</infoReport>\\n\");\n\
    fprintf(out, \"<searchReport>\\n\");\n\
    if(strcmp(\"\", CFG_PROPERTY)) {\n\
      fprintf(out, \"<property>%s</property>\\n\", CFG_PROPERTY);\n\
    }\n\
    fprintf(out, \"<searchResult>\");\n\
    switch(CTX->term_state) {\n\
    case TERM_STATE_LIMIT_REACHED:\n\
      fprintf(out, \"stateLimitReached\"); break;\n\
    case TERM_MEMORY_EXHAUSTED:\n\
      fprintf(out, \"memoryExhausted\"); break;\n\
    case TERM_TIME_ELAPSED:\n\
      fprintf(out, \"timeElapsed\"); break;\n\
    case TERM_INTERRUPTION:\n\
      fprintf(out, \"interruption\"); break;\n\
    case TERM_SEARCH_TERMINATED:\n\
      fprintf(out, \"searchTerminated\"); break;\n\
    case TERM_NO_ERROR:\n\
      fprintf(out, \"noCounterExample\"); break;\n\
    case TERM_SUCCESS:\n\
      fprintf(out, \"propertyHolds\"); break;\n\
    case TERM_FAILURE:\n\
      fprintf(out, \"propertyViolated\"); break;\n\
    case TERM_ERROR:\n\
      fprintf(out, \"error\"); break;\n\
    }\n\
    fprintf(out, \"</searchResult>\\n\");\n\
    if(CTX->term_state == TERM_ERROR && CTX->error_raised && CTX->error_msg) {\n\
      fprintf(out, \"<errorMessage>%s</errorMessage>\\n\", CTX->error_msg);\n\
    }\n\
    fprintf(out, \"<searchOptions>\\n\");\n\
    fprintf(out, \"<searchAlgorithm>\");\n\
    if(CFG_ALGO_DFS || CFG_ALGO_TARJAN) {\n\
      fprintf(out, \"depthSearch\");\n\
    } else if(CFG_ALGO_BFS) {\n\
      fprintf(out, \"breadthSearch\");\n\
    } else if(CFG_ALGO_DDFS) {\n\
      fprintf(out, \"distributedDepthSearch\");\n\
    } else if(CFG_ALGO_DBFS) {\n\
      fprintf(out, \"distributedBreadthSearch\");\n\
    } else if(CFG_ALGO_RWALK) {\n\
      fprintf(out, \"randomWalk\");\n\
    } else if(CFG_ALGO_DELTA_DDD) {\n\
      fprintf(out, \"deltaDDD\");\n\
    }\n\
    fprintf(out, \"</searchAlgorithm>\\n\");\n\
    if(CFG_HASH_STORAGE || CFG_DELTA_DDD_STORAGE) {\n\
      fprintf(out, \"<hashTableSize>%d</hashTableSize>\\n\", CFG_HASH_SIZE);\n\
    }\n\
    fprintf(out, \"<workers>%d</workers>\\n\", CTX->no_workers);\n\
    if(CFG_DISTRIBUTED) {\n\
      fprintf(out, \"<shmemHeapSize>%d</shmemHeapSize>\\n\", CFG_SHMEM_HEAP_SIZE);\n\
    }\n\
    if(CFG_POR) {\n\
      fprintf(out, \"<partialOrder/>\\n\");\n\
    }\n\
    if(CFG_HASH_COMPACTION) {\n\
      fprintf(out, \"<hashCompaction/>\\n\");\n\
    }\n\
    if(CFG_RANDOM_SUCCS) {\n\
      fprintf(out, \"<randomSuccs/>\\n\");\n\
    }\n\
    if(CFG_EDGE_LEAN) {\n\
      fprintf(out, \"<edgeLean/>\\n\");\n\
    }\n\
    if(CFG_ALGO_DELTA_DDD) {\n\
      fprintf(out, \"<candidateSetSize>%d</candidateSetSize>\\n\",\n\
	      CFG_DELTA_DDD_CAND_SET_SIZE);\n\
    }\n\
    fprintf(out, \"</searchOptions>\\n\");\n\
    fprintf(out, \"</searchReport>\\n\");\n\
    fprintf(out, \"<statisticsReport>\\n\");\n\
    model_xml_statistics(out);\n\
    fprintf(out, \"<timeStatistics>\\n\");\n\
    context_stats_to_xml(STAT_TYPE_TIME, out);\n\
    fprintf(out, \"</timeStatistics>\\n\");\n\
    fprintf(out, \"<graphStatistics>\\n\");\n\
    context_stats_to_xml(STAT_TYPE_GRAPH, out);\n\
    fprintf(out, \"</graphStatistics>\\n\");\n\
    if(CFG_WITH_PAPI) {\n\
      papi_stats_output(out);\n\
    }\n\
    fprintf(out, \"<otherStatistics>\\n\");\n\
    context_stats_to_xml(STAT_TYPE_OTHERS, out);\n\
    fprintf(out, \"</otherStatistics>\\n\");\n\
    fprintf(out, \"</statisticsReport>\\n\");\n\
    if(CTX->term_state == TERM_FAILURE) {\n\
      fprintf(out, \"<traceReport>\\n\");\n\
      if(CFG_TRACE_STATE) {\n\
	fprintf(out, \"<traceState>\\n\");\n\
	context_state_to_xml(CTX->faulty_state, out);\n\
	fprintf(out, \"</traceState>\\n\");\n\
      } else if(CFG_TRACE_FULL) {\n\
	fprintf(out, \"<traceFull>\\n\");\n\
	context_output_trace(out);\n\
	fprintf(out, \"</traceFull>\\n\");\n\
      } else if(CFG_TRACE_EVENTS) {\n\
	fprintf(out, \"<traceEvents>\\n\");\n\
	context_output_trace(out);\n\
	fprintf(out, \"</traceEvents>\\n\");\n\
      }\n\
      fprintf(out, \"</traceReport>\\n\");  \n\
    }\n\
    fprintf(out, \"</helenaReport>\\n\");\n\
    fclose(out);\n\
\n\
    /**\n\
     *  in distributed mode the report file must be printed to the\n\
     *  standard output so that it can be sent to the main process.  we\n\
     *  prefix each line with [xml-PID]\n\
     */\n\
    if(CFG_DISTRIBUTED) {\n\
      out = fopen(file_name, \"r\");\n\
      while(getline(&buf, &n, out) != -1) {\n\
	printf(\"[xml-%d] %s\", context_proc_id(), buf);\n\
      }\n\
      free(buf);\n\
      fclose(out);\n\
    }\n\
\n\
    /**\n\
     *  free everything\n\
     */\n\
    free(CTX->workers);\n\
    if(CTX->trace) {\n\
      list_free(CTX->trace);\n\
    }\n\
    if(CTX->faulty_state_found) {\n\
      state_free(CTX->faulty_state);\n\
    }\n\
    for(i = 0; i < NO_STATS; i ++) {\n\
      free(CTX->stat[i]);\n\
    }\n\
    pthread_mutex_destroy(&CTX->ctx_mutex);\n\
  }\n\
  if(CTX->error_raised) {\n\
    free(CTX->error_msg);\n\
  }\n\
  free(CTX);\n\
}\n\
\n\
void context_interruption_handler\n\
(int signal) {\n\
  CTX->term_state = TERM_INTERRUPTION;\n\
  CTX->keep_searching = FALSE;\n\
}\n\
\n\
void context_stop_search\n\
() {\n\
  CTX->keep_searching = FALSE;\n\
}\n\
\n\
void context_faulty_state\n\
(state_t s) {\n\
  pthread_mutex_lock(&CTX->ctx_mutex);\n\
  if(CTX->faulty_state) {\n\
    state_free(CTX->faulty_state);\n\
  }\n\
  CTX->faulty_state = state_copy(s);\n\
  CTX->keep_searching = FALSE;\n\
  CTX->term_state = TERM_FAILURE;\n\
  CTX->faulty_state_found = TRUE;\n\
  pthread_mutex_unlock(&CTX->ctx_mutex);\n\
}\n\
\n\
void context_set_trace\n\
(event_list_t trace) {\n\
  pthread_mutex_lock(&CTX->ctx_mutex);\n\
  if(CTX->trace) {\n\
    list_free(CTX->trace);\n\
  }\n\
  CTX->trace = trace;\n\
  CTX->keep_searching = FALSE;\n\
  CTX->term_state = TERM_FAILURE;\n\
  pthread_mutex_unlock(&CTX->ctx_mutex);\n\
}\n\
\n\
bool_t context_keep_searching\n\
() {\n\
  return CTX->keep_searching;\n\
}\n\
\n\
uint16_t context_no_workers\n\
() {\n\
  return CTX->no_workers;\n\
}\n\
\n\
pthread_t * context_workers\n\
() {\n\
  return CTX->workers;\n\
}\n\
\n\
void context_set_termination_state\n\
(term_state_t term_state) {\n\
  CTX->term_state = term_state;\n\
  CTX->keep_searching = FALSE;\n\
}\n\
\n\
struct timeval context_start_time\n\
() {\n\
  return CTX->start_time;\n\
}\n\
\n\
FILE * context_open_graph_file\n\
() {\n\
  FILE * result = NULL;\n\
  if(CFG_ACTION_BUILD_GRAPH) {\n\
    CTX->graph_file = fopen(CFG_GRAPH_FILE, \"w\");\n\
    result = CTX->graph_file;\n\
  }\n\
  return result;\n\
}\n\
\n\
FILE * context_graph_file\n\
() {\n\
  return CTX->graph_file;\n\
}\n\
\n\
void context_close_graph_file\n\
() {\n\
  if(CTX->graph_file) {\n\
    fclose(CTX->graph_file);\n\
    CTX->graph_file = NULL;\n\
  }\n\
}\n\
\n\
term_state_t context_termination_state\n\
() {\n\
  return CTX->term_state;\n\
}\n\
\n\
void context_error\n\
(char * msg) {\n\
  pthread_mutex_lock(&CTX->ctx_mutex);\n\
  if(CTX->error_raised) {\n\
    free(CTX->error_msg);\n\
  }\n\
  CTX->error_msg = mem_alloc(SYSTEM_HEAP, sizeof(char) * strlen(msg) + 1);\n\
  strcpy(CTX->error_msg, msg);\n\
  if(!CFG_ACTION_SIMULATE) {\n\
    CTX->term_state = TERM_ERROR;\n\
    CTX->keep_searching = FALSE;\n\
  }\n\
  CTX->error_raised = TRUE;\n\
  pthread_mutex_unlock(&CTX->ctx_mutex);\n\
}\n\
\n\
void context_flush_error\n\
() {\n\
  if(CFG_ACTION_SIMULATE) {\n\
    if(CTX->error_raised) {\n\
      mem_free(SYSTEM_HEAP, CTX->error_msg);\n\
    }\n\
    CTX->error_msg = NULL;\n\
  }\n\
  CTX->error_raised = FALSE;\n\
}\n\
\n\
bool_t context_error_raised\n\
() {\n\
  return CTX->error_raised;\n\
}\n\
\n\
char * context_error_msg\n\
() {\n\
  return CTX->error_msg;\n\
}\n\
\n\
uint32_t context_global_worker_id\n\
(worker_id_t w) {\n\
  return context_proc_id() * CTX->no_workers + w;\n\
}\n\
\n\
uint32_t context_proc_id\n\
() {\n\
  return comm_shmem_me();\n\
}\n\
\n\
float context_cpu_usage\n\
() {\n\
  return cpu_usage(&CTX->cpu_total, &CTX->utime, &CTX->stime);\n\
}\n\
\n\
void context_barrier_wait\n\
(pthread_barrier_t * b) {\n\
  lna_timer_t t;\n\
  \n\
  lna_timer_init(&t);\n\
  lna_timer_start(&t);\n\
  pthread_barrier_wait(b);\n\
  lna_timer_stop(&t);\n\
  context_incr_stat(STAT_BARRIER_TIME, 0, lna_timer_value(t));\n\
}\n\
\n\
void context_sleep\n\
(struct timespec t) {\n\
  nanosleep(&t, NULL);\n\
  context_incr_stat(STAT_SLEEP_TIME, 0, t.tv_nsec);\n\
}\n\
\n\
void context_incr_stat\n\
(stat_t stat,\n\
 worker_id_t w,\n\
 double val) {\n\
  CTX->stat[stat][w] += val;\n\
  CTX->stat_set[stat] = TRUE;\n\
}\n\
\n\
void context_set_stat\n\
(stat_t stat,\n\
 worker_id_t w,\n\
 double val) {\n\
  CTX->stat[stat][w] = val;\n\
  CTX->stat_set[stat] = TRUE;\n\
}\n\
\n\
double context_get_stat\n\
(stat_t stat) {\n\
  worker_id_t w;\n\
  double result = 0;\n\
\n\
  for(w = 0; w < CTX->no_workers + 1; w ++) {\n\
    result += CTX->stat[stat][w];\n\
  }\n\
  return result;\n\
}\n\
\n\
void context_set_max_stat\n\
(stat_t stat,\n\
 worker_id_t w,\n\
 double val) {\n\
  if(val > CTX->stat[stat][w]) {\n\
    CTX->stat[stat][w] = val;\n\
  }\n\
  CTX->stat_set[stat] = TRUE;\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "darray.h", "w")
    f.write ("\
/**\n\
 * @file darray.h\n\
 * @brief Implementation of dynamic arrays.\n\
 * @date 6 nov 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_DARRAY\n\
#define LIB_DARRAY\n\
\n\
#include \"heap.h\"\n\
\n\
typedef uint32_t darray_size_t;\n\
\n\
typedef uint32_t darray_index_t;\n\
\n\
typedef struct struct_darray_t * darray_t;\n\
\n\
\n\
/**\n\
 * @brief darray_new\n\
 */\n\
darray_t darray_new\n\
(heap_t heap,\n\
 uint32_t sizeof_item);\n\
\n\
\n\
/**\n\
 * @brief darray_free\n\
 */\n\
void darray_free\n\
(darray_t darray);\n\
\n\
\n\
/**\n\
 * @brief darray_size\n\
 */\n\
darray_size_t darray_size\n\
(darray_t darray);\n\
\n\
\n\
\n\
/**\n\
 * @brief darray_reset\n\
 */\n\
void darray_reset\n\
(darray_t darray);\n\
\n\
\n\
/**\n\
 * @brief darray_push\n\
 */\n\
void darray_push\n\
(darray_t darray,\n\
 void * item);\n\
\n\
\n\
/**\n\
 * @brief darray_pop\n\
 */\n\
void * darray_pop\n\
(darray_t darray);\n\
\n\
\n\
/**\n\
 * @brief darray_top\n\
 */\n\
void * darray_top\n\
(darray_t darray);\n\
\n\
\n\
/**\n\
 * @brief darray_get\n\
 */\n\
void * darray_get\n\
(darray_t darray,\n\
 darray_index_t i);\n\
\n\
\n\
/**\n\
 * @brief darray_set\n\
 */\n\
void darray_set\n\
(darray_t darray,\n\
 darray_index_t i,\n\
 void * item);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "darray.c", "w")
    f.write ("\
#include \"darray.h\"\n\
\n\
struct struct_darray_t {\n\
  void * items;\n\
  darray_size_t items_size;\n\
  darray_size_t no_items;\n\
  heap_t heap;\n\
  uint32_t sizeof_item;\n\
};\n\
typedef struct struct_darray_t struct_darray_t;\n\
\n\
#define darray_item(darray, i) \\\n\
  ((darray)->items + (i) * (darray)->sizeof_item)\n\
\n\
darray_t darray_new\n\
(heap_t heap,\n\
 uint32_t sizeof_item) {\n\
  darray_t result;\n\
\n\
  result = mem_alloc(heap, sizeof(struct_darray_t));\n\
  result->heap = heap;\n\
  result->no_items = 0;\n\
  result->items_size = 0;\n\
  result->sizeof_item = sizeof_item;\n\
  result->items = NULL;\n\
  return result;\n\
}\n\
\n\
\n\
void darray_free\n\
(darray_t darray) {\n\
  if(heap_has_mem_free(darray->heap)) {\n\
    if(darray->items) {\n\
      mem_free(darray->heap, darray->items);\n\
    }\n\
    mem_free(darray->heap, darray);\n\
  }\n\
}\n\
\n\
\n\
darray_size_t darray_size\n\
(darray_t darray) {\n\
  return darray->no_items;\n\
}\n\
\n\
\n\
void darray_reset\n\
(darray_t darray) {\n\
  darray->no_items = 0;\n\
}\n\
\n\
\n\
void darray_push\n\
(darray_t darray,\n\
 void * item) {\n\
  void * new_items;\n\
  uint32_t i;\n\
  \n\
  if(darray->no_items == darray->items_size) {\n\
    if(0 == darray->items_size) {\n\
      darray->items_size = 1;\n\
    } else {\n\
      darray->items_size *= 2;\n\
    }\n\
    new_items = mem_alloc(darray->heap,\n\
                          darray->items_size * darray->sizeof_item);\n\
    for(i = 0; i < darray->no_items; i ++) {\n\
      memcpy(new_items + i * darray->sizeof_item,\n\
             darray_item(darray, i),\n\
             darray->sizeof_item);\n\
    }\n\
    mem_free(darray->heap, darray->items);\n\
    darray->items = new_items;\n\
  }\n\
  memcpy(darray_item(darray, darray->no_items), item, darray->sizeof_item);\n\
  darray->no_items ++;\n\
}\n\
\n\
\n\
void * darray_pop\n\
(darray_t darray) {\n\
  void * result;\n\
\n\
  assert(darray->no_items);\n\
  result = darray_item(darray, darray->no_items - 1);\n\
  darray->no_items --;\n\
  return result;\n\
}\n\
\n\
\n\
void * darray_top\n\
(darray_t darray) {\n\
  void * result;\n\
\n\
  assert(darray->no_items);\n\
  result = darray_item(darray, darray->no_items - 1);\n\
  return result;\n\
}\n\
\n\
\n\
void * darray_get\n\
(darray_t darray,\n\
 darray_index_t i) {\n\
  assert(i >= 0 && i < darray->no_items);\n\
  return darray_item(darray, i);\n\
}\n\
\n\
\n\
void darray_set\n\
(darray_t darray,\n\
 darray_index_t i,\n\
 void * item) {\n\
  assert(i <= darray->no_items);\n\
  if(i == darray->no_items) {\n\
    darray_push(darray, item);\n\
  } else {\n\
    memcpy(darray_item(darray, i), item, darray->sizeof_item);\n\
  }\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "dbfs_comm.h", "w")
    f.write ("\
/**\n\
 * @file dbfs_comm.h\n\
 * @brief Communication library used by the DBFS algorithm\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_DBFS_COMM\n\
#define LIB_DBFS_COMM\n\
\n\
#include \"includes.h\"\n\
#include \"bfs_queue.h\"\n\
#include \"htbl.h\"\n\
\n\
\n\
/**\n\
 * @brief dbfs_comm_start\n\
 */\n\
void dbfs_comm_start\n\
(htbl_t h,\n\
 bfs_queue_t q);\n\
\n\
\n\
/**\n\
 * @brief dbfs_comm_end\n\
 */\n\
void dbfs_comm_end\n\
();\n\
\n\
\n\
/**\n\
 * @brief dbfs_comm_process_state\n\
 */\n\
void dbfs_comm_process_state\n\
(worker_id_t w,\n\
 state_t s,\n\
 hash_key_t h);\n\
\n\
\n\
/**\n\
 *  @brief dbfs_comm_termination\n\
 */\n\
bool_t dbfs_comm_termination\n\
();\n\
\n\
\n\
/**\n\
 * @brief dbfs_comm_send_all_pending_states\n\
 */\n\
void dbfs_comm_send_all_pending_states\n\
(worker_id_t w);\n\
\n\
\n\
/**\n\
 * @brief dbfs_comm_state_owned\n\
 */\n\
bool_t dbfs_comm_state_owned\n\
(hash_key_t h);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "dbfs_comm.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"dbfs_comm.h\"\n\
#include \"comm_shmem.h\"\n\
\n\
#if CFG_ALGO_BFS == 1 || CFG_ALGO_DBFS == 1\n\
\n\
#define COMM_WAIT_TIME_MUS      2\n\
#define WORKER_WAIT_TIME_MUS    1\n\
#define WORKER_STATE_BUFFER_LEN 10000\n\
#define MAX_PES                 100\n\
\n\
typedef enum {\n\
  TOKEN_NONE,\n\
  TOKEN_BLACK,\n\
  TOKEN_WHITE\n\
} dbfs_token_t;\n\
\n\
#define DBFS_COMM_DEBUG_XXX\n\
\n\
typedef struct {\n\
  uint32_t no_states;\n\
  uint32_t len;\n\
} buffer_data_t;\n\
\n\
typedef struct {\n\
  heap_t * heaps[CFG_NO_WORKERS];\n\
  htbl_t * states[CFG_NO_WORKERS];\n\
  uint32_t * no_states[CFG_NO_WORKERS];\n\
  uint32_t * len[CFG_NO_WORKERS];\n\
  uint32_t * remote_pos[CFG_NO_WORKERS];\n\
  htbl_id_t ** ids[CFG_NO_WORKERS];\n\
} worker_buffers_t;\n\
\n\
const struct timespec COMM_WAIT_TIME = { 0, COMM_WAIT_TIME_MUS * 1000 };\n\
const struct timespec WORKER_WAIT_TIME = { 0, WORKER_WAIT_TIME_MUS * 1000 };\n\
\n\
htbl_t H;\n\
bfs_queue_t Q;\n\
pthread_t CW;\n\
heap_t COMM_HEAPS;\n\
worker_buffers_t BUF;\n\
uint32_t DBFS_HEAP_SIZE;\n\
uint32_t DBFS_HEAP_SIZE_WORKER;\n\
uint32_t DBFS_HEAP_SIZE_PE;\n\
int PES;\n\
int ME;\n\
\n\
/* termination detection variables */\n\
bool_t TERM = FALSE;\n\
dbfs_token_t TERM_COLOR = TOKEN_WHITE;\n\
bool_t TOKEN_SENT = FALSE;\n\
\n\
#define POS_TOKEN 0\n\
#define POS_TERM sizeof(dbfs_token_t)\n\
#define POS_DATA                                        \\\n\
  (sizeof(dbfs_token_t) + sizeof(bool_t) +                   \\\n\
   sizeof(buffer_data_t) * CFG_NO_WORKERS * PES)\n\
#define POS_BUFFER(w, pe)                               \\\n\
  (sizeof(dbfs_token_t) + sizeof(bool_t) +                   \\\n\
   sizeof(buffer_data_t) * (w + pe * CFG_NO_WORKERS))\n\
\n\
\n\
\n\
bool_t dbfs_comm_termination\n\
() {\n\
  return TERM;\n\
}\n\
\n\
\n\
uint8_t dbfs_comm_state_owner\n\
(hash_key_t h) {\n\
  int i = 0;\n\
  uint8_t result = 0;\n\
\n\
  for(i = 0; i < sizeof(hash_key_t); i ++) {\n\
    result += h >> (i * 8);\n\
  }\n\
  return result % PES;\n\
}\n\
\n\
\n\
bool_t dbfs_comm_state_owned\n\
(hash_key_t h) {\n\
  return dbfs_comm_state_owner(h) == ME;\n\
}\n\
\n\
\n\
void dbfs_comm_reinit_buffer\n\
(worker_id_t w,\n\
 int pe) {\n\
  uint32_t i;\n\
\n\
  for(i = 0; i < BUF.no_states[w][pe]; i ++) {\n\
    htbl_erase(BUF.states[w][pe], BUF.ids[w][pe][i]);\n\
  }\n\
  htbl_reset(BUF.states[w][pe]);\n\
  BUF.len[w][pe] = 0;\n\
  BUF.no_states[w][pe] = 0;\n\
}\n\
\n\
\n\
void dbfs_comm_poll_remote_pe\n\
(worker_id_t w,\n\
 int pe) {\n\
  buffer_data_t data;\n\
  \n\
  do {\n\
    comm_shmem_get(&data, POS_BUFFER(w, ME), sizeof(buffer_data_t), pe);\n\
    if(data.no_states > 0) {\n\
      context_sleep(WORKER_WAIT_TIME);\n\
    }\n\
  } while(data.no_states > 0);\n\
}\n\
\n\
\n\
void dbfs_comm_send_buffer\n\
(worker_id_t w,\n\
 int pe) {\n\
  buffer_data_t data;\n\
  char buffer[DBFS_HEAP_SIZE_WORKER];\n\
  uint32_t i, pos;\n\
  bit_vector_t s;\n\
  uint16_t size;\n\
  hash_key_t h;\n\
\n\
#if defined(DBFS_COMM_DEBUG)\n\
  assert(BUF.no_states[w][pe] <= WORKER_STATE_BUFFER_LEN);\n\
  assert(pe != ME);\n\
  assert(BUF.len[w][pe] <= DBFS_HEAP_SIZE_WORKER);\n\
#endif\n\
  \n\
  /**\n\
   * poll the remote PE to see if I can send my states\n\
   */\n\
  dbfs_comm_poll_remote_pe(w, pe);\n\
\n\
  /**\n\
   * send my states to the remote PE\n\
   */\n\
  memset(buffer, 0, DBFS_HEAP_SIZE_WORKER);\n\
  pos = 0;\n\
  for(i = 0; i < BUF.no_states[w][pe]; i ++) {\n\
    htbl_get_serialised(BUF.states[w][pe], BUF.ids[w][pe][i],\n\
			    &s, &size, &h);\n\
    memcpy(buffer + pos, &h, sizeof(hash_key_t));\n\
    memcpy(buffer + pos + sizeof(hash_key_t), &size, sizeof(uint16_t));\n\
    memcpy(buffer + pos + sizeof(hash_key_t) + sizeof(uint16_t), s, size);\n\
    pos += sizeof(hash_key_t) + sizeof(uint16_t) + size;\n\
  }\n\
#if defined(DBFS_COMM_DEBUG)\n\
  assert(pos == BUF.len[w][pe]);\n\
#endif\n\
  comm_shmem_put(BUF.remote_pos[w][pe], buffer, pos, pe);\n\
\n\
  /**\n\
   * send my data to the remote PE\n\
   */\n\
  data.no_states = BUF.no_states[w][pe];\n\
  data.len = pos;\n\
#if defined(DBFS_COMM_DEBUG)\n\
  assert(data.len > 0);\n\
  assert(data.no_states > 0);\n\
#endif  \n\
  comm_shmem_put(POS_BUFFER(w, ME), &data, sizeof(buffer_data_t), pe);\n\
\n\
  if(pe < ME) {\n\
    TERM_COLOR = TOKEN_BLACK;\n\
  }\n\
\n\
  dbfs_comm_poll_remote_pe(w, pe);\n\
  dbfs_comm_reinit_buffer(w, pe);\n\
}\n\
\n\
\n\
void dbfs_comm_send_all_pending_states\n\
(worker_id_t w) {\n\
  int pe;\n\
  buffer_data_t data;\n\
\n\
  /**\n\
   * send all buffers content\n\
   */\n\
  for(pe = 0; pe < PES; pe ++) {\n\
    if(pe != ME && BUF.no_states[w][pe] > 0) {\n\
      dbfs_comm_send_buffer(w, pe);\n\
    }\n\
  }\n\
}\n\
\n\
\n\
void dbfs_comm_process_state\n\
(worker_id_t w,\n\
 state_t s,\n\
 hash_key_t h) {\n\
  const uint16_t len = state_char_size(s);\n\
  const int pe = dbfs_comm_state_owner(h);\n\
  htbl_id_t id;\n\
  uint32_t no;\n\
  bool_t is_new;\n\
\n\
#if defined(DBFS_COMM_DEBUG)\n\
  assert(ME != pe);\n\
  assert(BUF.no_states[w][pe] <= WORKER_STATE_BUFFER_LEN);\n\
#endif\n\
\n\
  /**\n\
   * not enough space to put the state in the buffer => we first send\n\
   * the buffer content to the remote pe\n\
   */\n\
  if((BUF.len[w][pe] + sizeof(hash_key_t) + sizeof(uint16_t) + len >\n\
      DBFS_HEAP_SIZE_WORKER)\n\
     || (BUF.no_states[w][pe] == WORKER_STATE_BUFFER_LEN)) {\n\
    dbfs_comm_send_buffer(w, pe);\n\
  }\n\
\n\
  /**\n\
   * insert the state in table\n\
   */\n\
  htbl_insert_hashed(BUF.states[w][pe], s, h, &is_new, &id);\n\
  if(is_new) {\n\
    BUF.len[w][pe] += sizeof(hash_key_t) + sizeof(uint16_t) + len;\n\
    BUF.ids[w][pe][BUF.no_states[w][pe]] = id;\n\
    BUF.no_states[w][pe] ++;\n\
  }\n\
}\n\
\n\
\n\
bool_t dbfs_comm_worker_process_incoming_states\n\
() {\n\
  const worker_id_t w = CFG_NO_WORKERS;\n\
  worker_id_t x, d;\n\
  uint32_t pos, tmp_pos, no_states;\n\
  uint16_t s_len;\n\
  bool_t states_received = TRUE, is_new;\n\
  hash_key_t h;\n\
  buffer_data_t data;\n\
  char buffer[DBFS_HEAP_SIZE_WORKER];\n\
  htbl_id_t sid;\n\
  bfs_queue_item_t item;\n\
  state_t s;\n\
  int pe;\n\
  bool_t result = FALSE;\n\
\n\
  while(states_received) {\n\
    states_received = FALSE;\n\
    pos = 0;\n\
    for(pe = 0; pe < PES; pe ++) {\n\
      if(pe != ME) {\n\
        for(x = 0; x < CFG_NO_WORKERS; x ++, pos += DBFS_HEAP_SIZE_WORKER) {\n\
          comm_shmem_get(&data, POS_BUFFER(x, pe), sizeof(buffer_data_t), ME);\n\
	  if(0 != data.no_states) {\n\
	    result = TRUE;\n\
	    states_received = TRUE;\n\
            comm_shmem_get(buffer, POS_DATA + pos, data.len, ME);\n\
            no_states = data.no_states;\n\
            data.no_states = 0;\n\
            data.len = 0;\n\
            comm_shmem_put(POS_BUFFER(x, pe), &data,\n\
                           sizeof(buffer_data_t), ME);\n\
	    tmp_pos = 0;\n\
            while((no_states --) > 0) {\n\
\n\
              /**\n\
               * read the state from the buffer and insert it in the\n\
               * hash table\n\
               */\n\
\n\
              /* hash value */\n\
              memcpy(&h, buffer + tmp_pos, sizeof(hash_key_t));\n\
              tmp_pos += sizeof(hash_key_t);\n\
          \n\
              /* state char length */\n\
              memcpy(&s_len, buffer + tmp_pos, sizeof(uint16_t));\n\
              tmp_pos += sizeof(uint16_t);\n\
          \n\
              /* insert the state */\n\
              htbl_insert_serialised(H, buffer + tmp_pos, s_len,\n\
                                     h, &is_new, &sid);\n\
              tmp_pos += s_len;\n\
\n\
              /**\n\
               * state is new => put it in the queue.  if the queue\n\
               * contains full states we have to unserialise it\n\
               */\n\
              if(is_new) {\n\
                item.id = sid;\n\
		d = h % CFG_NO_WORKERS;\n\
		if(CFG_HASH_COMPACTION) {\n\
		  heap_reset(COMM_HEAPS);\n\
		  s = state_unserialise_mem(buffer + tmp_pos - s_len,\n\
                                            COMM_HEAPS);\n\
		  item.s = s;\n\
		}\n\
                bfs_queue_enqueue(Q, item, w, d);\n\
		if(CFG_HASH_COMPACTION) {\n\
		  state_free(item.s);\n\
		}\n\
                context_incr_stat(STAT_STATES_STORED, w, 1);\n\
              }\n\
            }\n\
          }\n\
        }\n\
      }\n\
    }\n\
  }\n\
  return result;\n\
}\n\
\n\
\n\
bool_t dbfs_comm_all_buffers_empty\n\
() {\n\
  int pe;\n\
  worker_id_t w;\n\
\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    for(pe = 0; pe < PES; pe ++) {\n\
      if(BUF.len[w][pe] != 0) {\n\
	return FALSE;\n\
      }\n\
    }\n\
  }\n\
  return TRUE;\n\
}\n\
\n\
\n\
void dbfs_comm_send_token\n\
(dbfs_token_t token,\n\
 int pe) {\n\
  comm_shmem_put(POS_TOKEN, &token, sizeof(dbfs_token_t), pe);\n\
}\n\
\n\
\n\
void dbfs_comm_send_term\n\
(int pe) {\n\
  bool_t term = TRUE;\n\
  \n\
  comm_shmem_put(POS_TERM, &term, sizeof(bool_t), pe);\n\
}\n\
\n\
\n\
dbfs_token_t dbfs_comm_recv_token\n\
() {\n\
  dbfs_token_t result;\n\
  \n\
  comm_shmem_get(&result, POS_TOKEN, sizeof(dbfs_token_t), ME);\n\
  return result;\n\
}\n\
\n\
\n\
bool_t dbfs_comm_recv_term\n\
() {\n\
  bool_t result;\n\
  \n\
  comm_shmem_get(&result, POS_TERM, sizeof(bool_t), ME);\n\
  return result;\n\
}\n\
\n\
\n\
void dbfs_comm_check_termination\n\
() {\n\
  int next;\n\
  dbfs_token_t to_send, token;\n\
  bool_t term;\n\
\n\
  if(bfs_queue_is_empty(Q) && dbfs_comm_all_buffers_empty()) {\n\
    next = (ME + 1) % PES;\n\
    token = dbfs_comm_recv_token();\n\
    term = dbfs_comm_recv_term();\n\
    if(0 == ME) {\n\
      if(!TOKEN_SENT || TOKEN_BLACK == token) {\n\
	TOKEN_SENT = TRUE;\n\
	dbfs_comm_send_token(TOKEN_NONE, ME);\n\
	dbfs_comm_send_token(TOKEN_WHITE, next);\n\
      } else if(TOKEN_WHITE == token) {\n\
	TERM = TRUE;\n\
        dbfs_comm_send_term(next);\n\
      }\n\
    } else if(term) {\n\
      TERM = TRUE;\n\
      dbfs_comm_send_term(next);\n\
    } else if(token != TOKEN_NONE) {\n\
      dbfs_comm_send_token(TOKEN_NONE, ME);\n\
      if(TOKEN_BLACK == token) {\n\
	to_send = TOKEN_BLACK;\n\
      } else if(TOKEN_WHITE == token) {\n\
	to_send = TERM_COLOR;\n\
        TERM_COLOR = TOKEN_WHITE;\n\
      } else {\n\
	assert(0);\n\
      }    \n\
      dbfs_comm_send_token(to_send, next);\n\
    }\n\
  }\n\
}\n\
\n\
\n\
void * dbfs_comm_worker\n\
(void * arg) {\n\
      \n\
  /**\n\
   * sleep a bit and process incoming states.  communicator 0 checks\n\
   * for termination if it did not receive any states\n\
   */\n\
  while(!TERM) {\n\
    context_sleep(COMM_WAIT_TIME);\n\
    if(!dbfs_comm_worker_process_incoming_states()) {\n\
      dbfs_comm_check_termination();\n\
    }\n\
  }\n\
}\n\
\n\
\n\
void dbfs_comm_start\n\
(htbl_t h,\n\
 bfs_queue_t q) {\n\
  int pe, remote_pos;\n\
  worker_id_t w;\n\
  buffer_data_t data;\n\
  dbfs_token_t token = TOKEN_NONE;\n\
  \n\
  /* shmem initialisation */\n\
  PES = comm_shmem_pes();\n\
  ME = comm_shmem_me();\n\
  DBFS_HEAP_SIZE_WORKER =\n\
    (CFG_SHMEM_HEAP_SIZE - POS_DATA) / ((PES - 1) * CFG_NO_WORKERS);\n\
  DBFS_HEAP_SIZE_PE = CFG_NO_WORKERS * DBFS_HEAP_SIZE_WORKER;\n\
  DBFS_HEAP_SIZE = DBFS_HEAP_SIZE_PE * (PES - 1);\n\
  assert(PES <= MAX_PES);\n\
  TERM = FALSE;\n\
  comm_shmem_put(POS_TERM, &TERM, sizeof(bool_t), ME);\n\
  comm_shmem_put(POS_TOKEN, &token, sizeof(dbfs_token_t), ME);\n\
\n\
  /* initialise global variables */\n\
  Q = q;\n\
  H = h;\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    BUF.heaps[w] = mem_alloc(SYSTEM_HEAP, sizeof(heap_t) * PES);\n\
    BUF.ids[w] = mem_alloc(SYSTEM_HEAP, sizeof(htbl_id_t *) * PES);\n\
    BUF.len[w] = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * PES);\n\
    BUF.no_states[w] = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * PES);\n\
    BUF.remote_pos[w] = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * PES);\n\
    BUF.states[w] = mem_alloc(SYSTEM_HEAP, sizeof(htbl_t) * PES);\n\
  }\n\
  for(pe = 0; pe < PES; pe ++) {\n\
    remote_pos = POS_DATA + ME * DBFS_HEAP_SIZE_PE;\n\
    if(ME > pe) {\n\
      remote_pos -= DBFS_HEAP_SIZE_PE;\n\
    }\n\
    for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
      data.len = 0;\n\
      data.no_states = 0;\n\
      comm_shmem_put(POS_BUFFER(w, pe), &data, sizeof(buffer_data_t), ME);\n\
      BUF.no_states[w][pe] = 0;\n\
      BUF.len[w][pe] = 0;\n\
      if(ME == pe) {\n\
        BUF.remote_pos[w][pe] = 0;\n\
      } else {\n\
        BUF.remote_pos[w][pe] = remote_pos;\n\
        BUF.ids[w][pe] = mem_alloc(SYSTEM_HEAP, sizeof(htbl_id_t) *\n\
                                   WORKER_STATE_BUFFER_LEN);\n\
        BUF.heaps[w][pe] = local_heap_new();\n\
        BUF.states[w][pe] = htbl_new(FALSE, WORKER_STATE_BUFFER_LEN * 2,\n\
                                     1, FALSE, 0);\n\
        dbfs_comm_reinit_buffer(w, pe);\n\
        remote_pos += DBFS_HEAP_SIZE_WORKER;\n\
      }\n\
    }\n\
  }\n\
  \n\
  /* launch the communicator threads */\n\
  COMM_HEAPS = local_heap_new();\n\
  pthread_create(&CW, NULL, &dbfs_comm_worker, NULL);\n\
}\n\
\n\
\n\
void dbfs_comm_end\n\
() {\n\
  void * dummy;\n\
  int pe;\n\
  worker_id_t w;\n\
  \n\
  pthread_join(CW, &dummy);\n\
  heap_free(COMM_HEAPS);\n\
  \n\
#if defined(DBFS_COMM_DEBUG)\n\
  printf(\"[%d] all communicators terminated\\n\", ME);\n\
#endif\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    for(pe = 0; pe < PES; pe ++) {\n\
      if(ME != pe) {\n\
        htbl_free(BUF.states[w][pe]);\n\
        heap_free(BUF.heaps[w][pe]);\n\
	mem_free(SYSTEM_HEAP, BUF.ids[w][pe]);\n\
      }\n\
    }\n\
    mem_free(SYSTEM_HEAP, BUF.heaps[w]);\n\
    mem_free(SYSTEM_HEAP, BUF.ids[w]);\n\
    mem_free(SYSTEM_HEAP, BUF.len[w]);\n\
    mem_free(SYSTEM_HEAP, BUF.no_states[w]);\n\
    mem_free(SYSTEM_HEAP, BUF.remote_pos[w]);\n\
    mem_free(SYSTEM_HEAP, BUF.states[w]);\n\
  }\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "ddfs_comm.h", "w")
    f.write ("\
/**\n\
 * @file ddfs_comm.h\n\
 * @brief Communication library used by the DDFS algorithm\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_DDFS_COMM\n\
#define LIB_DDFS_COMM\n\
\n\
#include \"includes.h\"\n\
#include \"context.h\"\n\
#include \"htbl.h\"\n\
\n\
\n\
/**\n\
 * @brief ddfs_comm_start\n\
 */\n\
void ddfs_comm_start\n\
(htbl_t h);\n\
\n\
\n\
/**\n\
 * @brief ddfs_comm_end\n\
 */\n\
void ddfs_comm_end\n\
();\n\
\n\
\n\
/**\n\
 * @brief ddfs_comm_process_explored_state\n\
 */\n\
void ddfs_comm_process_explored_state\n\
(worker_id_t w,\n\
 htbl_id_t id);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "ddfs_comm.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"ddfs_comm.h\"\n\
#include \"comm_shmem.h\"\n\
\n\
#if CFG_ALGO_DDFS == 1 || CFG_ALGO_DFS == 1 || CFG_ALGO_TARJAN == 1\n\
\n\
#define MAX_PES            100\n\
#define PRODUCE_PERIOD_MS  20\n\
#define CONSUME_PERIOD_MS  5\n\
#define CONSUME_WAIT_MS    1\n\
\n\
#define BUFFER_WORKER_SIZE (CFG_SHMEM_HEAP_SIZE / CFG_NO_WORKERS)\n\
#define BUCKET_OK          1\n\
#define BUCKET_WRITE       2\n\
\n\
\n\
typedef struct {\n\
  uint8_t status[CFG_NO_WORKERS];\n\
  uint32_t size[CFG_NO_WORKERS];\n\
  uint32_t char_len[CFG_NO_WORKERS];\n\
  bool_t full[CFG_NO_WORKERS];\n\
  char buffer[CFG_NO_WORKERS][BUFFER_WORKER_SIZE];\n\
} ddfs_comm_buffers_t;\n\
\n\
const struct timespec PRODUCE_PERIOD = { 0, PRODUCE_PERIOD_MS * 1000000 };\n\
const struct timespec CONSUME_PERIOD = { 0, CONSUME_PERIOD_MS * 1000000 };\n\
const struct timespec CONSUME_WAIT_TIME = { 0, CONSUME_WAIT_MS * 1000000 };\n\
const struct timespec WAIT_TIME = { 0, 10 };\n\
\n\
ddfs_comm_buffers_t BUF;\n\
htbl_t H;\n\
uint16_t BASE_LEN;\n\
pthread_t PROD;\n\
pthread_t CONS;\n\
int PES;\n\
int ME;\n\
\n\
typedef struct {\n\
  bool_t produced[MAX_PES];\n\
  uint32_t size;\n\
  uint32_t char_len;\n\
} pub_data_t;\n\
\n\
#define DDFS_COMM_DATA_POS sizeof(pub_data_t)\n\
\n\
\n\
void ddfs_comm_process_explored_state\n\
(worker_id_t w,\n\
 htbl_id_t id) {\n\
  uint16_t s_char_len, len;\n\
  bit_vector_t s;\n\
  bool_t red = FALSE, blue = FALSE;\n\
  hash_key_t h;\n\
  void * pos;\n\
\n\
  /**\n\
   *  put the state of worker w in its buffer\n\
   */\n\
  if(!BUF.full[w] && CAS(&BUF.status[w], BUCKET_OK, BUCKET_WRITE)) {\n\
    if(CFG_HASH_COMPACTION) {\n\
      h = htbl_get_hash(H, id);\n\
    } else {\n\
      htbl_get_serialised(H, id, &s, &s_char_len, &h);\n\
    }\n\
    len = BASE_LEN;\n\
    if(!CFG_HASH_COMPACTION) {\n\
      len += sizeof(uint16_t) + s_char_len;\n\
    }\n\
    if(len + BUF.char_len[w] > BUFFER_WORKER_SIZE) {\n\
      BUF.full[w] = TRUE;\n\
    } else {\n\
      if(BUF.size[w] == 0) {\n\
        memset(BUF.buffer[w], 0, BUFFER_WORKER_SIZE);\n\
      }\n\
      BUF.size[w] ++;\n\
      pos = BUF.buffer[w] + BUF.char_len[w];\n\
      BUF.char_len[w] += len;\n\
      \n\
      /*  hash value  */\n\
      memcpy(pos, &h, sizeof(hash_key_t));\n\
      pos += sizeof(hash_key_t);\n\
     \n\
      /*  blue attribute  */\n\
      if(htbl_has_attr(H, ATTR_BLUE)) {\n\
        blue = htbl_get_attr(H, id, ATTR_BLUE);\n\
        memcpy(pos, &blue, sizeof(bool_t));\n\
        pos += sizeof(bool_t);\n\
      }\n\
          \n\
      /*  red attribute  */\n\
      if(htbl_has_attr(H, ATTR_RED)) {\n\
        red = htbl_get_attr(H, id, ATTR_RED);\n\
        memcpy(pos, &red, sizeof(bool_t));\n\
        pos += sizeof(bool_t);\n\
      }\n\
\n\
      /*  char length and state vector */\n\
      if(!CFG_HASH_COMPACTION) {\n\
	memcpy(pos, &s_char_len, sizeof(uint16_t));\n\
	pos += sizeof(uint16_t);\n\
	memcpy(pos, s, s_char_len);\n\
	pos += s_char_len;\n\
      }\n\
    }\n\
    BUF.status[w] = BUCKET_OK;\n\
  }\n\
}\n\
\n\
void * ddfs_comm_producer\n\
(void * arg) {\n\
  int pe;\n\
  worker_id_t w;\n\
  uint64_t size = 0, char_len = 0;\n\
  pub_data_t data;\n\
  const worker_id_t my_worker_id = CFG_NO_WORKERS;\n\
  \n\
  while(context_keep_searching()) {\n\
    context_sleep(PRODUCE_PERIOD);\n\
\n\
    /**\n\
     *  wait that all other pes have consumed my states\n\
     */\n\
  wait_for_states_consumed:\n\
    comm_shmem_get(&data, 0, sizeof(pub_data_t), ME);\n\
    for(pe = 0; pe < PES && context_keep_searching(); pe ++) {\n\
      if(pe != ME && data.produced[pe]) {\n\
        context_sleep(CONSUME_PERIOD);\n\
        goto wait_for_states_consumed;\n\
      }\n\
    }\n\
\n\
    /**\n\
     *  put in my local heap states produced by my workers\n\
     */\n\
    char_len = DDFS_COMM_DATA_POS;\n\
    size = 0;\n\
    for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
      \n\
      /*  wait for the bucket of thread w to be ready  */\n\
      while(!CAS(&BUF.status[w], BUCKET_OK, BUCKET_WRITE)) {\n\
	context_sleep(WAIT_TIME);\n\
      }\n\
\n\
      /*  copy the buffer of worker w to my local  heap  */\n\
      comm_shmem_put(char_len, BUF.buffer[w], BUF.char_len[w], ME);\n\
      char_len += BUF.char_len[w];\n\
      size += BUF.size[w];\n\
\n\
      /*  reset the buffer of worker w and make it available  */\n\
      BUF.char_len[w] = 0;\n\
      BUF.size[w] = 0;\n\
      BUF.full[w] = FALSE;\n\
      BUF.status[w] = BUCKET_OK;\n\
    }\n\
    \n\
    /*  notify other PEs that I have produced some states  */\n\
    data.size = size;\n\
    data.char_len = char_len;\n\
    for(pe = 0; pe < PES; pe ++) {\n\
      if(pe != ME) {\n\
        data.produced[pe] = TRUE;\n\
      }\n\
    }\n\
    comm_shmem_put(0, &data, sizeof(pub_data_t), ME);\n\
  }\n\
}\n\
\n\
void * ddfs_comm_consumer\n\
(void * arg) {\n\
  const worker_id_t w = CFG_NO_WORKERS;\n\
  bool_t f = FALSE;\n\
  int pe;\n\
  void * pos;\n\
  uint16_t s_char_len, len;\n\
  htbl_id_t sid;\n\
  bit_vector_t s;\n\
  bool_t red = FALSE, blue = FALSE, is_new;\n\
  char buffer[CFG_SHMEM_HEAP_SIZE];\n\
  hash_key_t h;\n\
  pub_data_t remote_data;\n\
  \n\
  while(context_keep_searching()) {\n\
    \n\
    context_sleep(CONSUME_PERIOD);\n\
\n\
    /**\n\
     * get states put by remote PEs in their heap and put these in my\n\
     * local hash table\n\
     */\n\
    for(pe = 0; pe < PES; pe ++) {\n\
      if(ME != pe) {\n\
	comm_shmem_get(&remote_data, 0, sizeof(pub_data_t), pe);\n\
        if(remote_data.produced[ME]) {\n\
          comm_shmem_get(buffer, DDFS_COMM_DATA_POS, remote_data.char_len, pe);\n\
          comm_shmem_put(sizeof(bool_t) * ME, &f, sizeof(bool_t), pe);\n\
          pos = buffer;\n\
          while(remote_data.size --) {\n\
\n\
            /*  get hash value  */\n\
            memcpy(&h, pos, sizeof(hash_key_t));\n\
            pos += sizeof(hash_key_t);\n\
                    \n\
            /*  get blue attribute  */\n\
            if(htbl_has_attr(H, ATTR_BLUE)) {\n\
              memcpy(&blue, pos, sizeof(bool_t));\n\
              pos += sizeof(bool_t);\n\
            }\n\
          \n\
            /*  get red attribute  */\n\
            if(htbl_has_attr(H, ATTR_RED)) {\n\
              memcpy(&red, pos, sizeof(bool_t));\n\
              pos += sizeof(bool_t);\n\
            }\n\
       \n\
	    if(CFG_HASH_COMPACTION) {\n\
	      htbl_insert_serialised(H, pos, s_char_len,\n\
                                     h, &is_new, &sid);\n\
	    } else {\n\
              \n\
	      /*  get state vector char length  */\n\
	      memcpy(&s_char_len, pos, sizeof(uint16_t));\n\
	      pos += sizeof(uint16_t);\n\
              \n\
	      /*  get state vector and insert it  */\n\
	      htbl_insert_serialised(H, pos, s_char_len, h, &is_new, &sid);\n\
	      pos += s_char_len;\n\
	    }\n\
\n\
            if(is_new) {\n\
              context_incr_stat(STAT_STATES_STORED, w, 1);\n\
            }\n\
\n\
            /*  set the blue and red attribute of the state  */\n\
            if(blue && htbl_has_attr(H, ATTR_BLUE)) {\n\
              htbl_set_attr(H, sid, ATTR_BLUE, TRUE);\n\
            }\n\
            if(red && htbl_has_attr(H, ATTR_RED)) {\n\
              htbl_set_attr(H, sid, ATTR_BLUE, TRUE);\n\
            }\n\
          }\n\
        }\n\
      }\n\
    }\n\
  }\n\
  return NULL;\n\
}\n\
\n\
void ddfs_comm_start\n\
(htbl_t h) {\n\
  worker_id_t w;\n\
  int i = 0;\n\
  pub_data_t data;\n\
  \n\
  /*  shmem and symmetrical heap initialisation  */\n\
  PES = comm_shmem_pes();\n\
  ME = comm_shmem_me();\n\
  assert(PES <= MAX_PES);\n\
  \n\
  H = h;\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    BUF.status[w] = BUCKET_OK;\n\
    BUF.size[w] = 0;\n\
    BUF.char_len[w] = 0;\n\
    BUF.full[w] = FALSE;\n\
  }\n\
  BASE_LEN = sizeof(hash_key_t)\n\
    + (htbl_has_attr(H, ATTR_BLUE) ? sizeof(bool_t) : 0)\n\
    + (htbl_has_attr(H, ATTR_RED) ? sizeof(bool_t) : 0);\n\
  for(i = 0; i < MAX_PES; i ++) {\n\
    data.produced[i] = FALSE;\n\
  }\n\
  comm_shmem_put(0, &data, sizeof(pub_data_t), ME);\n\
\n\
  /*  launch the producer and consumer threads  */\n\
  pthread_create(&PROD, NULL, &ddfs_comm_producer, NULL);\n\
  pthread_create(&CONS, NULL, &ddfs_comm_consumer, NULL);\n\
}\n\
\n\
void ddfs_comm_end\n\
() {\n\
  void * dummy;\n\
\n\
  pthread_join(PROD, &dummy);\n\
  pthread_join(CONS, &dummy);\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "delta_ddd.h", "w")
    f.write ("\
/**\n\
 * @file delta_ddd.h\n\
 * @brief Implementation of the delta DDD algorithm.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_DELTA_DDD\n\
#define LIB_DELTA_DDD\n\
\n\
#include \"includes.h\"\n\
#include \"common.h\"\n\
#include \"state.h\"\n\
#include \"event.h\"\n\
\n\
\n\
/**\n\
 * @brief delta_ddd\n\
 */\n\
void delta_ddd\n\
();\n\
\n\
\n\
/**\n\
 * @brief Report on the delta-ddd search progress.\n\
 */\n\
void delta_ddd_progress_report\n\
(uint64_t * states_stored);\n\
\n\
\n\
/**\n\
 * @brief Finalisation of the DELTA-DDD.  Used to free data allocated\n\
 *        by delta_ddd.\n\
 */\n\
void delta_ddd_finalise\n\
();\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "delta_ddd.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"delta_ddd.h\"\n\
#include \"prop.h\"\n\
#include \"graph.h\"\n\
#include \"workers.h\"\n\
#include \"context.h\"\n\
\n\
#if CFG_ALGO_DELTA_DDD != 1\n\
\n\
void delta_ddd() { assert(0); }\n\
\n\
#else\n\
\n\
typedef uint32_t delta_ddd_storage_id_t;\n\
\n\
typedef struct struct_delta_ddd_storage_t * delta_ddd_storage_t;\n\
\n\
typedef struct {\n\
  delta_ddd_storage_id_t fst_child;\n\
  delta_ddd_storage_id_t next;\n\
  bool_t father;\n\
  bool_t dd;\n\
  bool_t dd_visit;\n\
  bool_t recons[2];\n\
  event_id_t e;\n\
  hash_key_t h;\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
  uint32_t num;\n\
#endif\n\
} delta_ddd_state_t;\n\
\n\
typedef struct {\n\
  unsigned char content;\n\
  delta_ddd_storage_id_t id;\n\
  delta_ddd_storage_id_t pred;\n\
  event_id_t e;\n\
  bit_vector_t s;\n\
  hash_key_t h;\n\
  uint16_t width;\n\
} delta_ddd_candidate_t;\n\
\n\
struct struct_delta_ddd_storage_t {\n\
  delta_ddd_storage_id_t root;\n\
  delta_ddd_state_t ST[CFG_HASH_SIZE];\n\
  int32_t size[CFG_NO_WORKERS];\n\
  uint64_t dd_time;\n\
};\n\
\n\
typedef struct struct_delta_ddd_storage_t struct_delta_ddd_storage_t;\n\
\n\
delta_ddd_storage_t S;\n\
uint32_t next_num;\n\
\n\
/*  mail boxes used during expansion  */\n\
delta_ddd_candidate_t * BOX[CFG_NO_WORKERS][CFG_NO_WORKERS];\n\
uint32_t BOX_size[CFG_NO_WORKERS][CFG_NO_WORKERS];\n\
uint32_t BOX_tot_size[CFG_NO_WORKERS];\n\
uint32_t BOX_max_size;\n\
\n\
/*  candidate set (obtained from boxes after merging)  */\n\
delta_ddd_candidate_t * CS[CFG_NO_WORKERS];\n\
uint32_t CS_size[CFG_NO_WORKERS];\n\
uint32_t * NCS[CFG_NO_WORKERS];\n\
uint32_t CS_max_size;\n\
\n\
/*  state table  */\n\
delta_ddd_state_t * ST;\n\
\n\
/*  heaps used to store candidates, to reconstruct states and\n\
 *  perform duplicate detection  */\n\
heap_t candidates_heaps[CFG_NO_WORKERS];\n\
heap_t expand_heaps[CFG_NO_WORKERS];\n\
heap_t detect_heaps[CFG_NO_WORKERS];\n\
heap_t expand_evts_heaps[CFG_NO_WORKERS];\n\
heap_t detect_evts_heaps[CFG_NO_WORKERS];\n\
\n\
/*  random seeds  */\n\
rseed_t seeds[CFG_NO_WORKERS];\n\
\n\
/*  synchronisation variables  */\n\
bool_t LVL_TERMINATED[CFG_NO_WORKERS];\n\
pthread_barrier_t BARRIER;\n\
uint32_t NEXT_LVL;\n\
uint32_t NEXT_LVLS[CFG_NO_WORKERS];\n\
bool_t error_reported;\n\
\n\
/*  alternating bit to know which states to expand  */\n\
uint8_t RECONS_ID;\n\
\n\
#define MAX_LOCAL_HEAP_SIZE 100000\n\
\n\
#define DELTA_DDD_CAND_NEW  1\n\
#define DELTA_DDD_CAND_DEL  2\n\
#define DELTA_DDD_CAND_NONE 3\n\
\n\
#define DELTA_DDD_OWNER(h) (((h) & CFG_HASH_SIZE_M) % CFG_NO_WORKERS)\n\
\n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
#define DELTA_DDD_VISIT_PRE_HEAP_PROCESS() {    \\\n\
    if(heap_size(heap) > MAX_LOCAL_HEAP_SIZE) {	\\\n\
      state_t copy = state_copy(s);		\\\n\
      heap_reset(heap);                         \\\n\
      s = state_copy_mem(copy, heap);		\\\n\
      state_free(copy);                         \\\n\
    }						\\\n\
    heap_pos = heap_get_position(heap_evts);	\\\n\
  }\n\
#define DELTA_DDD_VISIT_POST_HEAP_PROCESS() {   \\\n\
    heap_set_position(heap_evts, heap_pos);	\\\n\
  }\n\
#define DELTA_DDD_VISIT_HANDLE_EVENT(func) {            \\\n\
    e = state_event_mem(s, ST[curr].e, heap_evts);	\\\n\
    event_exec(e, s);                                   \\\n\
    s = func(w, curr, s, depth - 1);                    \\\n\
    event_undo(e, s);                                   \\\n\
  }\n\
#else  /*  !defined(MODEL_EVENT_UNDOABLE)  */\n\
#define DELTA_DDD_VISIT_PRE_HEAP_PROCESS() {    \\\n\
    heap_pos = heap_get_position(heap);         \\\n\
  }\n\
#define DELTA_DDD_VISIT_POST_HEAP_PROCESS() {   \\\n\
    heap_set_position(heap, heap_pos);		\\\n\
  }\n\
#define DELTA_DDD_VISIT_HANDLE_EVENT(func) {    \\\n\
    e = state_event(s, ST[curr].e);             \\\n\
    t = state_succ_mem(s, e, heap);             \\\n\
    func(w, curr, t, depth - 1);                \\\n\
  }\n\
#endif\n\
\n\
#define DELTA_DDD_PICK_RANDOM_NODE(w, now, start)	{       \\\n\
    unsigned int rnd;						\\\n\
    delta_ddd_storage_id_t fst = ST[now].fst_child;             \\\n\
    start = fst;						\\\n\
    rnd = random_int(&seeds[w]) % (ST[now].father >> 1);	\\\n\
    while(rnd --) {						\\\n\
      if((start = ST[start].next) == now) {			\\\n\
	start = fst;						\\\n\
      }								\\\n\
    }								\\\n\
  }\n\
\n\
void delta_ddd_barrier\n\
(worker_id_t w) {\n\
  if(CFG_PARALLEL) {\n\
    context_barrier_wait(&BARRIER);\n\
  }\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_storage_new\n\
 *\n\
 *****/\n\
delta_ddd_storage_t delta_ddd_storage_new\n\
() {\n\
  worker_id_t w, x;\n\
  unsigned int i, fst, last, s;\n\
  delta_ddd_storage_t result;\n\
\n\
  result = mem_alloc(SYSTEM_HEAP, sizeof(struct_delta_ddd_storage_t));\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    result->size[w] = 0;\n\
  }\n\
\n\
  /*\n\
   *  initialisation of the state table\n\
   */\n\
  for(i = 0; i < CFG_HASH_SIZE; i ++) {\n\
    result->ST[i].fst_child = UINT_MAX;\n\
    result->ST[i].recons[0] = FALSE;\n\
    result->ST[i].recons[1] = FALSE;\n\
  }\n\
\n\
  result->dd_time = 0;\n\
  return result;\n\
}\n\
\n\
void delta_ddd_storage_free\n\
(delta_ddd_storage_t storage) {\n\
  worker_id_t w, x;\n\
  unsigned int i;\n\
  mem_free(SYSTEM_HEAP, storage);\n\
}\n\
\n\
uint64_t delta_ddd_storage_size\n\
(delta_ddd_storage_t storage) {\n\
  uint64_t result = 0;\n\
  worker_id_t w;\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    result += storage->size[w];\n\
  }\n\
  return result;\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_create_trace\n\
 *\n\
 *****/\n\
void delta_ddd_create_trace\n\
(delta_ddd_storage_id_t id) {\n\
  event_list_t trace = list_new(SYSTEM_HEAP, sizeof(event_t), event_free_void);\n\
  state_t s = state_initial();\n\
  list_t trace_ids = list_new(SYSTEM_HEAP, sizeof(event_id_t), NULL);\n\
  event_id_t eid;\n\
  event_t e;\n\
  delta_ddd_storage_id_t curr;\n\
\n\
  curr = id;\n\
  while(curr != S->root) {\n\
    list_append(trace_ids, &ST[curr].e);\n\
    while(!(ST[curr].father & 1)) { curr = ST[curr].next; }\n\
    curr = ST[curr].next;\n\
  }\n\
  while(!list_is_empty(trace_ids)) {\n\
    list_pick_last(trace_ids, &eid);\n\
    e = state_event(s, eid);\n\
    event_exec(e, s);\n\
    list_append(trace, &e);\n\
  }\n\
  list_free(trace_ids);\n\
  state_free(s);\n\
  context_set_trace(trace);\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_send_candidate\n\
 *\n\
 *****/\n\
bool_t delta_ddd_send_candidate\n\
(worker_id_t w,\n\
 delta_ddd_storage_id_t pred,\n\
 event_id_t e,\n\
 state_t s) {\n\
  delta_ddd_candidate_t c;\n\
  worker_id_t x;\n\
  \n\
  c.content = DELTA_DDD_CAND_NEW;\n\
  c.pred = pred;\n\
  c.e = e;\n\
  c.width = state_char_size(s);\n\
  c.s = mem_alloc0(candidates_heaps[w], c.width);\n\
  state_serialise(s, c.s);\n\
  c.h = state_hash(s);\n\
  x = DELTA_DDD_OWNER(c.h);\n\
  BOX[w][x][BOX_size[w][x]] = c;  \n\
  BOX_size[w][x] ++;\n\
  BOX_tot_size[w] ++;\n\
  return BOX_size[w][x] == BOX_max_size;\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_merge_candidate_set\n\
 *\n\
 *  merge the mailboxes of workers into the candidate set before\n\
 *  performing duplicate detection\n\
 *\n\
 *****/\n\
bool_t delta_ddd_cmp_vector\n\
(uint16_t width,\n\
 bit_vector_t v,\n\
 bit_vector_t w) {\n\
  uint16_t i;\n\
  for(i = 0; i < width; i ++) {\n\
    if(v[i] != w[i]) {\n\
      return FALSE;\n\
    }\n\
  }\n\
  return TRUE;\n\
}\n\
\n\
bool_t delta_ddd_merge_candidate_set\n\
(worker_id_t w) {\n\
  delta_ddd_candidate_t * C = CS[w];\n\
  unsigned int i, pos, fst, slot;\n\
  delta_ddd_storage_id_t id;\n\
  worker_id_t x;\n\
  bool_t loop;\n\
\n\
  CS_size[w] = 0;\n\
  for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
    for(i = 0; i < BOX_size[x][w]; i ++) {\n\
      delta_ddd_candidate_t c = BOX[x][w][i];\n\
      fst = pos = c.h % CS_max_size;\n\
      loop = TRUE;\n\
      while(loop) {\n\
	switch(C[pos].content) {\n\
	case DELTA_DDD_CAND_NONE :\n\
	  C[pos] = c;\n\
	  NCS[w][CS_size[w] ++] = pos;\n\
	  loop = FALSE;\n\
	  slot = C[pos].h & CFG_HASH_SIZE_M;\n\
\n\
	  /*  mark for reconstruction states in conflict with the candidate  */\n\
	  while(ST[slot].fst_child != UINT_MAX) {\n\
            if(ST[slot].h == c.h) {\n\
              ST[slot].dd = TRUE;\n\
              id = slot;\n\
              while(id != S->root) {\n\
                while(!(ST[id].father & 1)) {\n\
                  id = ST[id].next;\n\
                }\n\
                id = ST[id].next;\n\
                if(ST[id].dd_visit) {\n\
                  break;\n\
                } else {\n\
                  ST[id].dd_visit = TRUE;\n\
                }\n\
              }\n\
            }\n\
            slot = (slot + CFG_NO_WORKERS) & CFG_HASH_SIZE_M;\n\
	  }\n\
	  break;\n\
	case DELTA_DDD_CAND_NEW :\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
	  pos = (pos + 1) % CS_max_size;\n\
	  assert (pos != fst);\n\
#else\n\
	  if(c.h == C[pos].h\n\
             && c.width == C[pos].width\n\
             && delta_ddd_cmp_vector(c.width, c.s, C[pos].s)) {\n\
	    loop = FALSE;\n\
	  } else {\n\
	    pos = (pos + 1) % CS_max_size;\n\
	    assert (pos != fst);\n\
	  }\n\
#endif\n\
	  break;\n\
	case DELTA_DDD_CAND_DEL :\n\
	  assert(FALSE);\n\
	}\n\
      }\n\
    }\n\
  }\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_duplicate_detection_dfs\n\
 *\n\
 *****/\n\
void delta_ddd_storage_delete_candidate\n\
(worker_id_t w,\n\
 state_t s,\n\
 delta_ddd_storage_id_t id) {\n\
  hash_key_t h = state_hash(s);\n\
  unsigned int fst, i = h % CS_max_size;\n\
  worker_id_t x = DELTA_DDD_OWNER(h);\n\
  \n\
  fst = i;\n\
  do {\n\
    switch(CS[x][i].content) {\n\
    case DELTA_DDD_CAND_NONE : return;\n\
    case DELTA_DDD_CAND_NEW  :\n\
      if(state_cmp_vector(s, CS[x][i].s)) {\n\
	CS[x][i].content = DELTA_DDD_CAND_DEL;\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
	CS[x][i].id = id;\n\
	break;\n\
#else\n\
	return;\n\
#endif\n\
      }\n\
    }\n\
    i = (i + 1) % CS_max_size;\n\
  } while(fst != i);\n\
}\n\
\n\
state_t delta_ddd_duplicate_detection_dfs\n\
(worker_id_t w,\n\
 delta_ddd_storage_id_t now,\n\
 state_t s,\n\
 unsigned int depth) {\n\
  heap_t heap = detect_heaps[w];\n\
  heap_t heap_evts = detect_evts_heaps[w];\n\
  state_t t;\n\
  event_t e;\n\
  mem_size_t heap_pos;\n\
  delta_ddd_storage_id_t start, curr;\n\
\n\
  DELTA_DDD_VISIT_PRE_HEAP_PROCESS();\n\
\n\
  /*\n\
   *  remove state now from the candidate set\n\
   */\n\
  if(ST[now].dd) {\n\
    ST[now].dd = FALSE;\n\
    delta_ddd_storage_delete_candidate(w, s, now);\n\
  }\n\
\n\
  /*\n\
   *  state now must be visited by the duplicate detection procedure\n\
   */\n\
  if(ST[now].dd_visit) {\n\
    \n\
    /*\n\
     *  we start expanding now from a randomly picked successor\n\
     */\n\
    DELTA_DDD_PICK_RANDOM_NODE(w, now, start);\n\
    curr = start;\n\
    do {\n\
      if(ST[curr].dd || ST[curr].dd_visit) {\n\
        context_incr_stat(STAT_EVENT_EXEC, w, 1);\n\
        context_incr_stat(STAT_EVENT_EXEC_DDD, w, 1);\n\
	DELTA_DDD_VISIT_HANDLE_EVENT(delta_ddd_duplicate_detection_dfs);\n\
      }\n\
      if(ST[curr].father & 1) {\n\
	curr = ST[ST[curr].next].fst_child;\n\
      } else {\n\
	curr = ST[curr].next;\n\
      }\n\
    } while(curr != start);\n\
  }\n\
  ST[now].dd = FALSE;\n\
  ST[now].dd_visit = FALSE;\n\
  DELTA_DDD_VISIT_POST_HEAP_PROCESS();\n\
  return s;\n\
}\n\
\n\
\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
void delta_ddd_remove_duplicates_around\n\
(delta_ddd_candidate_t * C,\n\
 unsigned int i) {\n\
  int j, k, m, moves[2] = { 1, -1};\n\
  for(k = 0; k < 2; k ++) {\n\
    j = i;\n\
    m = moves[k];\n\
    while(TRUE) {\n\
      j += m;\n\
      if(j == -1) { j = CS_max_size - 1; }\n\
      if(j == CS_max_size) { j = 0; }\n\
      if(C[j].content == DELTA_DDD_CAND_NONE) { break; }\n\
      if(C[j].width == C[i].width\n\
         && delta_ddd_cmp_vector(C[j].width, C[j].s, C[i].s)) {\n\
	C[j].content = DELTA_DDD_CAND_DEL;\n\
	C[j].id = C[i].id;\n\
      }\n\
    }\n\
  }\n\
}\n\
\n\
void delta_ddd_write_nodes_graph\n\
(worker_id_t w) {\n\
  delta_ddd_candidate_t * C = CS[w];\n\
  unsigned int i = 0;\n\
  uint8_t t, succs = 0;\n\
  FILE * gf = context_graph_file();\n\
  for(i = 0; i < CS_max_size; i ++) {\n\
    if(DELTA_DDD_CAND_NEW == C[i].content) {\n\
      t = GT_NODE;\n\
      fwrite(&t, sizeof(uint8_t), 1, gf);\n\
      fwrite(&ST[C[i].id].num, sizeof(node_t), 1, gf);\n\
      fwrite(&succs, sizeof(uint8_t), 1, gf);\n\
    }\n\
  }\n\
  for(i = 0; i < CS_max_size; i ++) {\n\
    if(DELTA_DDD_CAND_NONE != C[i].content) {\n\
      t = GT_EDGE;\n\
      fwrite(&t, sizeof(uint8_t), 1, gf);\n\
      fwrite(&ST[C[i].pred].num, sizeof(node_t), 1, gf);\n\
      fwrite(&C[i].e, sizeof(edge_num_t), 1, gf);\n\
      fwrite(&ST[C[i].id].num, sizeof(node_t), 1, gf);\n\
    }\n\
  }\n\
}\n\
#endif\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_insert_new_states\n\
 *\n\
 *  insert in the state tree states that are still in the candidate\n\
 *  set after duplicate detection\n\
 *\n\
 *****/\n\
delta_ddd_storage_id_t delta_ddd_insert_new_state\n\
(worker_id_t w,\n\
 hash_key_t h,\n\
 delta_ddd_state_t s,\n\
 delta_ddd_storage_id_t pred) {\n\
  uint8_t r = (RECONS_ID + 1) & 1;\n\
  unsigned int id, fst = h & CFG_HASH_SIZE_M, slot = fst;\n\
\n\
  context_incr_stat(STAT_STATES_STORED, w, 1);\n\
  \n\
  while(ST[slot].fst_child != UINT_MAX) {\n\
    assert((slot = (slot + CFG_NO_WORKERS) & CFG_HASH_SIZE_M) != fst);\n\
  }\n\
  s.next = s.fst_child = slot;\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
  s.num = next_num ++;\n\
#endif\n\
  ST[slot] = s;\n\
\n\
  /*  mark the state for the next expansion step  */\n\
  do {\n\
    ST[pred].recons[r] = TRUE;\n\
    while(!(ST[pred].father & 1)) {\n\
      pred = ST[pred].next;\n\
    }\n\
    pred = ST[pred].next;\n\
  } while(pred != S->root && !ST[pred].recons[r]);\n\
  return slot;\n\
}\n\
\n\
void delta_ddd_insert_new_states\n\
(worker_id_t w) {\n\
  worker_id_t x;\n\
  unsigned int i = 0;\n\
  delta_ddd_candidate_t c, * C = CS[w];\n\
  delta_ddd_state_t ns;\n\
  unsigned int no_new = 0;\n\
\n\
  ns.dd = ns.dd_visit = ns.recons[RECONS_ID] = FALSE;\n\
  ns.recons[(RECONS_ID + 1) & 1] = TRUE;\n\
  for(i = 0; i < CS_size[w]; i ++) {\n\
    c = C[NCS[w][i]];\n\
    if(DELTA_DDD_CAND_NEW == c.content) {\n\
      no_new ++;\n\
      ns.e = c.e;\n\
      ns.father = 0;\n\
      ns.h = c.h;\n\
      C[NCS[w][i]].id = delta_ddd_insert_new_state(w, c.h, ns, c.pred);\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
      delta_ddd_remove_duplicates_around(C, NCS[w][i]);\n\
#endif\n\
    }\n\
  }\n\
  S->size[w] += no_new;\n\
  NEXT_LVLS[w] += no_new;\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
  delta_ddd_write_nodes_graph(w);\n\
#endif\n\
\n\
  delta_ddd_barrier(w);\n\
\n\
  if(0 == w) {\n\
    for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
      for(i = 0; i < CS_size[x]; i ++) {\n\
	c = CS[x][NCS[x][i]];\n\
	if(DELTA_DDD_CAND_NEW == c.content) {\n\
	  if(ST[c.pred].fst_child == c.pred) {\n\
	    ST[c.id].next = c.pred;\n\
	    ST[c.id].father += 1;\n\
	  } else {\n\
	    ST[c.id].next = ST[c.pred].fst_child;\n\
	  }\n\
	  ST[c.pred].fst_child = c.id;\n\
	  ST[c.pred].father += 2;\n\
	}\n\
	CS[x][NCS[x][i]].content = DELTA_DDD_CAND_NONE;\n\
      }\n\
    }\n\
  }\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_duplicate_detection\n\
 *\n\
 *****/\n\
bool_t delta_ddd_duplicate_detection\n\
(worker_id_t w) {\n\
  state_t s;\n\
  worker_id_t x;\n\
  bool_t all_terminated = TRUE;\n\
  lna_timer_t t;\n\
\n\
  if(0 == w) {\n\
    lna_timer_init(&t);\n\
    lna_timer_start(&t);\n\
  }\n\
\n\
  /*\n\
   *  initialize heaps for duplicate detection\n\
   */\n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
  heap_reset(detect_evts_heaps[w]);\n\
#endif\n\
  heap_reset(detect_heaps[w]);\n\
  s = state_initial_mem(detect_heaps[w]);\n\
\n\
  /*\n\
   *  merge the candidate set and mark states to reconstruct\n\
   */\n\
  delta_ddd_barrier(w);\n\
  if(delta_ddd_storage_size(S) >= 0.9 * CFG_HASH_SIZE) {\n\
    context_error(\"state table too small (increase --hash-size and rerun)\");\n\
  }\n\
  if(!context_keep_searching()) {\n\
    pthread_exit(NULL);\n\
  }\n\
  delta_ddd_merge_candidate_set(w);\n\
\n\
  /*\n\
   *  reconstruct states and perform duplicate detection\n\
   */\n\
  delta_ddd_barrier(w);\n\
  delta_ddd_duplicate_detection_dfs(w, S->root, s, 0);\n\
\n\
  /*\n\
   *  insert these new states in the tree\n\
   */\n\
  delta_ddd_barrier(w);\n\
  delta_ddd_insert_new_states(w);\n\
\n\
  /*\n\
   *  reinitialise my mail boxes and candidate heaps\n\
   */\n\
  heap_reset(candidates_heaps[w]);\n\
  BOX_tot_size[w] = 0;\n\
  for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
    BOX_size[w][x] = 0;\n\
    all_terminated = all_terminated && LVL_TERMINATED[x];\n\
  }\n\
  if(0 == w) {\n\
    lna_timer_stop(&t);\n\
    S->dd_time += lna_timer_value(t);\n\
  }\n\
  delta_ddd_barrier(w);\n\
  return all_terminated ? FALSE : TRUE;\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_expand_dfs\n\
 *\n\
 *  recursive function called by delta_ddd_expand to explore state now\n\
 *\n\
 *****/\n\
state_t delta_ddd_expand_dfs\n\
(worker_id_t w,\n\
 delta_ddd_storage_id_t now,\n\
 state_t s,\n\
 unsigned int depth) {\n\
  heap_t heap = expand_heaps[w];\n\
  heap_t heap_evts = expand_evts_heaps[w];\n\
  mem_size_t heap_pos;\n\
  delta_ddd_storage_id_t start, curr;\n\
  state_t t;\n\
  event_t e;\n\
  event_id_t e_id;\n\
  event_list_t en;\n\
  unsigned int en_size, i;\n\
  worker_id_t x, y;\n\
  uint32_t size;\n\
\n\
  DELTA_DDD_VISIT_PRE_HEAP_PROCESS();\n\
\n\
  if(0 == depth) {\n\
    \n\
    /*\n\
     *  we have reached a leaf => we expand it\n\
     */\n\
    en = state_events_mem(s, heap);\n\
    if(CFG_ACTION_CHECK_SAFETY && state_check_property(s, en)) {\n\
      if(!error_reported) {\n\
	error_reported = TRUE;\n\
	context_faulty_state(s);\n\
	delta_ddd_create_trace(now);\n\
      }\n\
    }\n\
    en_size = list_size(en);\n\
    if(0 == en_size) {\n\
      context_incr_stat(STAT_STATES_DEADLOCK, w, 1);\n\
    }\n\
    for(i = 0; i < en_size; i ++) {\n\
      e = * ((event_t *) list_nth(en, i));\n\
      e_id = event_id(e);\n\
      t = state_succ_mem(s, e, heap);\n\
      if(delta_ddd_send_candidate(w, now, e_id, t)) {\n\
	delta_ddd_duplicate_detection(w);\n\
      }\n\
    }\n\
    context_incr_stat(STAT_ARCS, w, en_size);\n\
    context_incr_stat(STAT_EVENT_EXEC, w, en_size);\n\
    context_incr_stat(STAT_STATES_PROCESSED, w, 1);\n\
\n\
    /*\n\
     *  perform duplicate detection if the candidate set is full\n\
     */\n\
    size = 0;\n\
    for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
      size += BOX_tot_size[x];\n\
    }\n\
    if(size >= CFG_DELTA_DDD_CAND_SET_SIZE) {\n\
      delta_ddd_duplicate_detection(w);\n\
    }\n\
  } else {\n\
\n\
    /*\n\
     *  we start expanding now from a randomly picked successor\n\
     */\n\
    DELTA_DDD_PICK_RANDOM_NODE(w, now, start);\n\
    curr = start;\n\
    do {\n\
      if(ST[curr].recons[RECONS_ID]) {\n\
        context_incr_stat(STAT_EVENT_EXEC, w, 1);\n\
	DELTA_DDD_VISIT_HANDLE_EVENT(delta_ddd_expand_dfs);\n\
      }\n\
      if(ST[curr].father & 1) {\n\
	curr = ST[ST[curr].next].fst_child;\n\
      } else {\n\
	curr = ST[curr].next;\n\
      }\n\
    } while(curr != start);\n\
  }\n\
\n\
  ST[now].recons[RECONS_ID] = FALSE;\n\
  DELTA_DDD_VISIT_POST_HEAP_PROCESS();\n\
  return s;\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_expand\n\
 *\n\
 *****/\n\
void delta_ddd_expand\n\
(worker_id_t w,\n\
 unsigned int depth) {\n\
  state_t s;\n\
\n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
  heap_reset(expand_evts_heaps[w]);\n\
#endif\n\
  heap_reset(expand_heaps[w]);\n\
  s = state_initial_mem(expand_heaps[w]);\n\
  delta_ddd_expand_dfs(w, S->root, s, depth);\n\
  LVL_TERMINATED[w] = TRUE;\n\
  while(delta_ddd_duplicate_detection(w));\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd_worker\n\
 *\n\
 *****/\n\
void * delta_ddd_worker\n\
(void * arg) {\n\
  worker_id_t x, w = (worker_id_t) (unsigned long int) arg;\n\
  unsigned int depth = 0;\n\
  FILE * gf;\n\
  \n\
  if(0 == w) {\n\
    delta_ddd_state_t ns;\n\
    state_t s = state_initial();\n\
    hash_key_t h = state_hash(s);\n\
    delta_ddd_storage_id_t slot = h & CFG_HASH_SIZE_M;\n\
    uint8_t t = GT_NODE, succs = 0;\n\
\n\
    ns.dd = ns.dd_visit = ns.recons[0] = FALSE;\n\
    ns.recons[1] = ns.father = 1;\n\
    ns.next = ns.fst_child = slot;\n\
    ns.h = h;\n\
#if CFG_ACTION_BUILD_GRAPH == 1\n\
    gf = context_graph_file();\n\
    ns.num = next_num ++;\n\
    fwrite(&t, sizeof(uint8_t), 1, gf);\n\
    fwrite(&ns.num, sizeof(node_t), 1, gf);\n\
    fwrite(&succs, sizeof(uint8_t), 1, gf);\n\
#endif\n\
    ST[slot] = ns;\n\
    S->root = slot;\n\
    S->size[0] = 1;\n\
    state_free(s);\n\
    RECONS_ID = 0;\n\
    NEXT_LVL = 1;\n\
    context_incr_stat(STAT_STATES_STORED, w, 1);\n\
  }\n\
  delta_ddd_barrier(w);\n\
  while(NEXT_LVL != 0) {\n\
\n\
    /*\n\
     *  initialise some data for the next level\n\
     */\n\
    delta_ddd_barrier(w);\n\
    LVL_TERMINATED[w] = FALSE;\n\
    NEXT_LVLS[w] = 0;\n\
    if(0 == w) {\n\
      NEXT_LVL = 0;\n\
      RECONS_ID = (RECONS_ID + 1) & 1;\n\
    }\n\
\n\
    /*\n\
     *  all workers expand the current level\n\
     */\n\
    delta_ddd_barrier(w);\n\
    delta_ddd_expand(w, depth);\n\
    depth ++;\n\
    if(0 == w) {\n\
      for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
	NEXT_LVL += NEXT_LVLS[x];\n\
      }\n\
      context_set_stat(STAT_BFS_LEVELS, 0, depth);\n\
    }\n\
    delta_ddd_barrier(w);\n\
  }\n\
  return NULL;\n\
}\n\
\n\
\n\
\n\
/*****\n\
 *\n\
 *  Function: delta_ddd\n\
 *\n\
 *****/\n\
void delta_ddd\n\
() {  \n\
  worker_id_t w, x;\n\
  void * dummy;\n\
  unsigned int i, s;\n\
  FILE * gf;\n\
\n\
  S = delta_ddd_storage_new();\n\
  ST = S->ST;\n\
  pthread_barrier_init(&BARRIER, NULL, CFG_NO_WORKERS);\n\
  error_reported = FALSE;\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    seeds[w] = random_seed(w);\n\
  }\n\
  next_num = 0;\n\
  gf = context_open_graph_file();\n\
\n\
  /*\n\
   *  initialisation of the heaps\n\
   */\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    expand_heaps[w] = local_heap_new();\n\
    detect_heaps[w] = local_heap_new();\n\
    candidates_heaps[w] = local_heap_new();\n\
    expand_evts_heaps[w] = local_heap_new();\n\
    detect_evts_heaps[w] = local_heap_new();\n\
  }\n\
\n\
  /*\n\
   *  initialisation of the mailboxes of workers\n\
   */\n\
  BOX_max_size = (CFG_DELTA_DDD_CAND_SET_SIZE /\n\
                  (CFG_NO_WORKERS * CFG_NO_WORKERS)) << 2;\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
      s = BOX_max_size * sizeof(delta_ddd_candidate_t);\n\
      BOX[w][x] = mem_alloc(SYSTEM_HEAP, s);\n\
      for(i = 0; i < BOX_max_size; i ++) {\n\
	BOX[w][x][i].content = DELTA_DDD_CAND_NONE;\n\
	BOX[w][x][i].h = 0;\n\
	BOX_size[w][x] = 0;\n\
      }\n\
    }\n\
    BOX_tot_size[w] = 0;\n\
  }\n\
\n\
  /*\n\
   *  initialisation of the candidate set\n\
   */\n\
  CS_max_size = (CFG_DELTA_DDD_CAND_SET_SIZE / CFG_NO_WORKERS) << 1;\n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    CS[w] = mem_alloc(SYSTEM_HEAP, CS_max_size *\n\
                      sizeof(delta_ddd_candidate_t));\n\
    NCS[w] = mem_alloc(SYSTEM_HEAP, CS_max_size * sizeof(uint32_t));\n\
    for(i = 0; i < CS_max_size; i ++) {\n\
      CS[w][i].content = DELTA_DDD_CAND_NONE;\n\
    }\n\
    CS_size[w] = 0;\n\
  }\n\
\n\
  launch_and_wait_workers(&delta_ddd_worker);\n\
\n\
  /*\n\
   * free everything\n\
   */  \n\
  for(w = 0; w < CFG_NO_WORKERS; w ++) {\n\
    mem_free(SYSTEM_HEAP, CS[w]);\n\
    mem_free(SYSTEM_HEAP, NCS[w]);\n\
    for(x = 0; x < CFG_NO_WORKERS; x ++) {\n\
      mem_free(SYSTEM_HEAP, BOX[w][x]);\n\
    }\n\
    heap_free(candidates_heaps[w]);\n\
    heap_free(expand_heaps[w]);\n\
    heap_free(detect_heaps[w]);\n\
    heap_free(expand_evts_heaps[w]);\n\
    heap_free(detect_evts_heaps[w]);\n\
  }\n\
\n\
  context_close_graph_file();\n\
  context_set_stat(STAT_DDD_TIME, 0, S->dd_time);\n\
  \n\
  delta_ddd_storage_free(S);\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "dfs.h", "w")
    f.write ("\
/**\n\
 * @file dfs.h\n\
 * @brief Implementation of DFS based algorithms: DFS, DDFS (distributed DFS).\n\
 *        Nested DFS algorithms for LTL verification (sequential or multi-core)\n\
 *        are also implemented here.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_DFS\n\
#define LIB_DFS\n\
\n\
#include \"includes.h\"\n\
#include \"context.h\"\n\
\n\
\n\
/**\n\
 * @brief Launch the DFS based algorithm.\n\
 */\n\
void dfs\n\
();\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "dfs.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"darray.h\"\n\
#include \"dfs.h\"\n\
#include \"model.h\"\n\
#include \"dfs_stack.h\"\n\
#include \"ddfs_comm.h\"\n\
#include \"prop.h\"\n\
#include \"reduction.h\"\n\
#include \"workers.h\"\n\
#include \"por_analysis.h\"\n\
\n\
/*\n\
 * TODO:\n\
 *\n\
 * if edge-lean is turned on, DFS may report a deadlock whereas it's\n\
 * just edge-lean that removed all enabled transitions\n\
 *\n\
 * possible deadlocks when combining hash-compaction and cndfs\n\
 *\n\
 */\n\
\n\
#if CFG_ALGO_DDFS == 0 && CFG_ALGO_DFS == 0 && CFG_ALGO_TARJAN == 0\n\
\n\
void dfs() { assert(0); }\n\
\n\
#else\n\
\n\
#define DFS_MAX_HEAP_SIZE 100000\n\
\n\
const struct timespec DFS_WAIT_RED_SLEEP_TIME = { 0, 10 };\n\
\n\
typedef struct {\n\
  bool_t accepting;\n\
  htbl_id_t id;  \n\
} red_processed_t;\n\
\n\
htbl_t H = NULL;\n\
\n\
state_t dfs_recover_state\n\
(dfs_stack_t stack,\n\
 state_t now,\n\
 worker_id_t w,\n\
 heap_t heap) {\n\
  htbl_id_t id;\n\
\n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
  dfs_stack_event_undo(stack, now);\n\
#else\n\
  if(CFG_HASH_COMPACTION) {\n\
    now = dfs_stack_top_state(stack, heap);\n\
  } else {\n\
    id = dfs_stack_top(stack);\n\
    now = htbl_get_mem(H, id, heap);\n\
  }\n\
#endif\n\
  return now;\n\
}\n\
\n\
#define dfs_push_new_state(id, is_s0) {                                 \\\n\
    dfs_stack_push(stack, id, now);                                     \\\n\
    e_ref = is_s0 && edge_lean ? &e : NULL;                             \\\n\
    en = dfs_stack_compute_events(stack, now, por, e_ref);              \\\n\
    if(blue) {                                                          \\\n\
      htbl_set_worker_attr(H, id, ATTR_CYAN, w, TRUE);                  \\\n\
    } else {                                                            \\\n\
      htbl_set_worker_attr(H, id, ATTR_PINK, w, TRUE);                  \\\n\
      red_stack_size ++;                                                \\\n\
    }                                                                   \\\n\
    if(htbl_has_attr(H, ATTR_SAFE) &&                                   \\\n\
       dfs_stack_fully_expanded(stack)) {                               \\\n\
      htbl_set_attr(H, id, ATTR_SAFE, TRUE);                            \\\n\
    }                                                                   \\\n\
    if(tarjan) {                                                        \\\n\
      darray_push(scc_stack, &id);                                      \\\n\
      htbl_set_attr(H, id, ATTR_INDEX, index);                          \\\n\
      htbl_set_attr(H, id, ATTR_LOWLINK, index);                        \\\n\
      htbl_set_attr(H, id, ATTR_LIVE, TRUE);                            \\\n\
      index ++;                                                         \\\n\
    }                                                                   \\\n\
    if(is_new) {                                                        \\\n\
      context_incr_stat(STAT_STATES_STORED, w, 1);                      \\\n\
    }                                                                   \\\n\
    if(!dfs_stack_fully_expanded(stack)) {                              \\\n\
      context_incr_stat(STAT_STATES_REDUCED, w, 1);                     \\\n\
    }                                                                   \\\n\
    if(is_new && blue && (0 == list_size(en))) {                        \\\n\
      context_incr_stat(STAT_STATES_DEADLOCK, w, 1);                    \\\n\
    }                                                                   \\\n\
    context_set_max_stat(STAT_MAX_DFS_STACK_SIZE, 0,                    \\\n\
                         dfs_stack_size(stack));                        \\\n\
    if(check_safety && state_check_property(now, en)) {                 \\\n\
      context_faulty_state(now);                                        \\\n\
      dfs_stack_create_trace(stack);                                    \\\n\
    }                                                                   \\\n\
  }\n\
    \n\
\n\
void * dfs_worker\n\
(void * arg) {\n\
  const worker_id_t w = (worker_id_t) (unsigned long int) arg;\n\
  const uint32_t wid = context_global_worker_id(w);\n\
  const bool_t check_ltl = CFG_ACTION_CHECK_LTL;\n\
  const bool_t check_safety = CFG_ACTION_CHECK_SAFETY;\n\
  const bool_t por = CFG_POR;\n\
  const bool_t proviso = CFG_POR && CFG_PROVISO;\n\
  const bool_t edge_lean = CFG_EDGE_LEAN;\n\
  const bool_t shuffle = CFG_PARALLEL || CFG_ALGO_DDFS || CFG_RANDOM_SUCCS;\n\
  const bool_t ddfs = CFG_ALGO_DDFS;\n\
  const bool_t ndfs = check_ltl\n\
    && CFG_ALGO_DFS && !CFG_PARALLEL;\n\
  const bool_t cndfs = check_ltl\n\
    && CFG_ALGO_DDFS || (CFG_ALGO_DFS && CFG_PARALLEL);\n\
  const bool_t tarjan = CFG_ALGO_TARJAN;\n\
  const bool_t states_stored = \n\
#if defined(MODEL_EVENT_UNDOABLE)\n\
    FALSE\n\
#else\n\
    CFG_HASH_COMPACTION\n\
#endif\n\
    ;\n\
  uint32_t i;\n\
  hash_key_t h;\n\
  heap_t heap = local_heap_new();\n\
  state_t copy, now = state_initial_mem(heap);\n\
  dfs_stack_t stack = dfs_stack_new(wid, CFG_DFS_STACK_BLOCK_SIZE,\n\
                                    shuffle, states_stored);\n\
  htbl_id_t id, id_seed, id_succ, id_popped;\n\
  bool_t push, blue = TRUE, is_new, state_popped = FALSE, on_stack;\n\
  event_t e;\n\
  event_t * e_ref;\n\
  event_list_t en;\n\
  uint64_t red_stack_size = 0, index = 0, index_other, lowlink, lowlink_popped;\n\
  red_processed_t proc;\n\
  darray_t red_states = cndfs ?\n\
    darray_new(SYSTEM_HEAP, sizeof(red_processed_t)) : NULL;\n\
  darray_t scc_stack = tarjan ?\n\
    darray_new(SYSTEM_HEAP, sizeof(htbl_id_t)) : NULL;\n\
  darray_t scc = tarjan ?\n\
    darray_new(SYSTEM_HEAP, sizeof(htbl_id_t)) : NULL;\n\
  \n\
  /*\n\
   * insert the initial state and push it on the stack\n\
   */\n\
  htbl_insert(H, now, &is_new, &id, &h);\n\
  dfs_push_new_state(id, TRUE);\n\
\n\
  /*\n\
   * search loop\n\
   */\n\
  while(dfs_stack_size(stack) && context_keep_searching()) {\n\
  loop_start:\n\
\n\
    /*\n\
     * reinitialise the heap if its current size exceeds\n\
     * DFS_MAX_HEAP_SIZE\n\
     */\n\
    if(heap_size(heap) >= DFS_MAX_HEAP_SIZE) {\n\
      copy = state_copy(now);\n\
      heap_reset(heap);\n\
      now = state_copy_mem(copy, heap);\n\
      state_free(copy);\n\
    }\n\
\n\
    id = dfs_stack_top(stack);\n\
\n\
    /**\n\
     * before handling the state on top of the stack we look at the\n\
     * state that has just been popped, if any\n\
     */\n\
    if(state_popped) {\n\
      state_popped = FALSE;\n\
\n\
      /*\n\
       * in tarjan we update the lowlink of the current state\n\
       */\n\
      if(tarjan) {\n\
        lowlink_popped = htbl_get_attr(H, id_popped, ATTR_LOWLINK);\n\
        if(lowlink_popped < htbl_get_attr(H, id, ATTR_LOWLINK)) {\n\
          htbl_set_attr(H, id, ATTR_LOWLINK, lowlink_popped);\n\
        }\n\
      }\n\
\n\
      /*\n\
       * proviso is on: if the current state and its popped successor\n\
       * are unsafe, we set the unsafe-sucessor bit of the current\n\
       * state\n\
       */\n\
      if(proviso &&\n\
         !htbl_get_attr(H, id, ATTR_SAFE) &&\n\
         !htbl_get_attr(H, id_popped, ATTR_SAFE)) {\n\
        htbl_set_attr(H, id, ATTR_UNSAFE_SUCC, TRUE);\n\
      }\n\
    }\n\
\n\
    /**\n\
     * 1st case for the state on top of the stack: all its events have\n\
     * been executed => it must be popped\n\
     **/\n\
    if(dfs_stack_top_expanded(stack)) {\n\
\n\
      /*\n\
       * proviso is on: if the state to pop does not have unsafe\n\
       * successors, it become safe.  else if it is marked for revisit\n\
       * it also become safe and we reexpand it\n\
       */\n\
      if(proviso && !htbl_get_attr(H, id, ATTR_SAFE)) {\n\
        if(!htbl_get_attr(H, id, ATTR_UNSAFE_SUCC)) {\n\
          htbl_set_attr(H, id, ATTR_SAFE, TRUE);\n\
        } else if(htbl_get_attr(H, id, ATTR_TO_REVISIT)) {\n\
          htbl_set_attr(H, id, ATTR_SAFE, TRUE);\n\
          dfs_stack_compute_events(stack, now, FALSE, NULL);\n\
          context_incr_stat(STAT_STATES_REDUCED, w, - 1);\n\
          goto loop_start;\n\
        }\n\
      }\n\
\n\
      /*\n\
       * we check an ltl property => launch the red search if the\n\
       * state is accepting\n\
       */\n\
      if(check_ltl && blue && state_accepting(now)) {\n\
        context_incr_stat(STAT_STATES_ACCEPTING, w, 1);\n\
        id_seed = dfs_stack_top(stack);\n\
        blue = FALSE;\n\
        red_stack_size = 1;\n\
        dfs_stack_compute_events(stack, now, por, NULL);\n\
        if(cndfs) {\n\
          darray_reset(red_states);\n\
        }\n\
        goto loop_start;\n\
      }\n\
\n\
      /* \n\
       * put new colors on the popped state as it leaves the stack\n\
       */\n\
      if(blue) {\n\
	htbl_set_worker_attr(H, id, ATTR_CYAN, w, FALSE);\n\
        htbl_set_attr(H, id, ATTR_BLUE, TRUE);\n\
      } else {  /* nested search of ndfs or cndfs */\n\
        \n\
        /*\n\
         * in cdnfs we put the popped state in red_states.  in\n\
         * sequential ndfs we can directly mark it as red.\n\
         */\n\
        if(cndfs) {\n\
          proc.accepting = state_accepting(now);\n\
          proc.id = id;\n\
          darray_push(red_states, &proc);\n\
        } else {\n\
          htbl_set_attr(H, id, ATTR_RED, TRUE);\n\
        }\n\
        red_stack_size --;\n\
        \n\
        /*\n\
         * termination of the red DFS.  in cndfs we wait for all\n\
         * accepting states of the red_states set to become red and\n\
         * then mark all states of this set as red\n\
         */\n\
        if(0 == red_stack_size) {\n\
          blue = TRUE;\n\
          if(cndfs) {\n\
            for(i = 0; i < darray_size(red_states); i ++) {\n\
              proc = * ((red_processed_t *) darray_get(red_states, i));\n\
              if(proc.accepting && proc.id != id) {\n\
                while(!htbl_get_attr(H, proc.id, ATTR_RED)\n\
                      && context_keep_searching()) {\n\
                  context_sleep(DFS_WAIT_RED_SLEEP_TIME);\n\
                }\n\
              }\n\
            }\n\
            for(i = 0; i < darray_size(red_states); i ++) {\n\
              proc = * ((red_processed_t *) darray_get(red_states, i));\n\
              htbl_set_attr(H, proc.id, ATTR_RED, TRUE);\n\
            }\n\
          }\n\
        }\n\
      }\n\
\n\
      /*\n\
       * in distributed DFS we process the state to be later sent\n\
       */\n\
      if(ddfs) {\n\
	ddfs_comm_process_explored_state(w, id);\n\
      }\n\
\n\
      /*\n\
       * in tarjan we check the state popped if the root of an SCC in\n\
       * which case we pop this SCC\n\
       */\n\
      if(tarjan) {\n\
        if(htbl_get_attr(H, id, ATTR_INDEX) ==\n\
           htbl_get_attr(H, id, ATTR_LOWLINK)) {\n\
          darray_reset(scc);\n\
          do {\n\
            id_succ = * ((htbl_id_t *) darray_pop(scc_stack));\n\
            htbl_set_attr(H, id_succ, ATTR_LIVE, FALSE);\n\
            darray_push(scc, &id_succ);\n\
          } while (id_succ != id);\n\
          if(!proviso) {\n\
            por_analysis_scc(H, scc);\n\
          }\n\
        }\n\
      }\n\
\n\
      /*\n\
       * and finally pop the state\n\
       */\n\
      context_incr_stat(STAT_STATES_PROCESSED, w, 1);\n\
      dfs_stack_pop(stack);\n\
      if(dfs_stack_size(stack)) {\n\
        now = dfs_recover_state(stack, now, w, heap);\n\
      }\n\
      state_popped = TRUE;\n\
      id_popped = id;\n\
    }\n\
        \n\
    /**\n\
     * 2nd case for the state on top of the stack: some of its events\n\
     * remain to be executed => we execute the next one\n\
     **/\n\
    else {\n\
      \n\
      /*\n\
       * get the next event to process on the top state and execute it\n\
       */\n\
      dfs_stack_pick_event(stack, &e);\n\
      event_exec(e, now);\n\
      context_incr_stat(STAT_EVENT_EXEC, w, 1);\n\
\n\
      /*\n\
       * try to insert the successor\n\
       */\n\
      htbl_insert(H, now, &is_new, &id_succ, &h);\n\
\n\
      /*\n\
       * if we check an LTL property and are in the red search, test\n\
       * whether the state reached is the seed.  exit the loop if this\n\
       * is the case\n\
       */\n\
      if(check_ltl && !blue && (id_succ == id_seed)) {\n\
        dfs_stack_create_trace(stack);\n\
        break;\n\
      }\n\
      \n\
      /*\n\
       * see if it must be pushed on the stack to be processed\n\
       */\n\
      if(blue) {\n\
	context_incr_stat(STAT_ARCS, w, 1);\n\
        push = is_new\n\
          || (!(on_stack = htbl_get_worker_attr(H, id_succ, ATTR_CYAN, w)) &&\n\
              !htbl_get_attr(H, id_succ, ATTR_BLUE));\n\
      } else {\n\
        push = is_new\n\
          || (!(on_stack = htbl_get_worker_attr(H, id_succ, ATTR_PINK, w)) &&\n\
              !htbl_get_attr(H, id_succ, ATTR_RED));\n\
      }\n\
\n\
      if(push) { /* successor state must be explored */\n\
        dfs_push_new_state(id_succ, FALSE);\n\
      } else {\n\
        now = dfs_recover_state(stack, now, w, heap);\n\
\n\
        /*\n\
         * tarjan: we reach a live state.\n\
         */\n\
        if(tarjan && htbl_get_attr(H, id_succ, ATTR_LIVE)) {\n\
          index_other = htbl_get_attr(H, id_succ, ATTR_INDEX);\n\
          lowlink = htbl_get_attr(H, id, ATTR_LOWLINK);\n\
          if(lowlink > index_other) {\n\
            htbl_set_attr(H, id, ATTR_LOWLINK, index_other);\n\
          }\n\
        }\n\
\n\
        /*\n\
         * proviso is on: if the state is on the stack and the current\n\
         * state is unsafe, we set the unsafe-successor flag of the\n\
         * current state and the to-revisit flag of the sucessor\n\
         */\n\
        if(proviso && on_stack && !htbl_get_attr(H, id, ATTR_SAFE)) {\n\
          htbl_set_attr(H, id, ATTR_UNSAFE_SUCC, TRUE);\n\
          htbl_set_attr(H, id_succ, ATTR_TO_REVISIT, TRUE);          \n\
        }\n\
      }\n\
    }\n\
  }\n\
\n\
  /*\n\
   * free everything\n\
   */\n\
  dfs_stack_free(stack);\n\
  heap_free(heap);\n\
  if(cndfs) {\n\
    darray_free(red_states);\n\
  }\n\
  if(tarjan) {\n\
    darray_free(scc);\n\
    darray_free(scc_stack);\n\
    context_set_stat(STAT_STATES_UNSAFE, 0, por_analysis_no_unsafe_states());\n\
  }\n\
\n\
  return NULL;\n\
}\n\
\n\
void dfs\n\
() {\n\
  H = htbl_default_new();\n\
  if(CFG_ALGO_DDFS) {\n\
    ddfs_comm_start(H);\n\
  }\n\
  launch_and_wait_workers(&dfs_worker);\n\
  if(CFG_ALGO_DDFS) {\n\
    context_stop_search();\n\
    ddfs_comm_end();\n\
  }\n\
  htbl_free(H);\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "dfs_stack.h", "w")
    f.write ("\
/**\n\
 * @file dfs_stack.h\n\
 * @brief Implementation of the DFS stack used by DFS based algorithms.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 *\n\
 * A DFS stack has an in memory part which consists of two blocks B1,\n\
 * B2 of states.  States are first pushed on B1 and then on B2 when B1\n\
 * is full.  When both are full, B1 is written to disk, B1 = B2, and\n\
 * B2 = empty.  When the last state is popped from the stack (i.e., B1\n\
 * is empty), a block is read from disk and put in B1.\n\
 *\n\
 * The stack stores state identifiers unless some technique preventing\n\
 * the recovery of states from the hash table is used (e.g., hash\n\
 * compaction).  In this case, the stack also stores full states.  The\n\
 * stack also stores enabled events of states.\n\
 */\n\
\n\
#ifndef LIB_DFS_STACK\n\
#define LIB_DFS_STACK\n\
\n\
#include \"includes.h\"\n\
#include \"config.h\"\n\
#include \"htbl.h\"\n\
\n\
/**\n\
 * @typedef the stack type\n\
 */\n\
typedef struct struct_dfs_stack_t * dfs_stack_t;\n\
\n\
\n\
/**\n\
 * @brief DFS stack constructor.\n\
 * @param id - unique id of the stack\n\
 * @param block_size - size in states of an in memory block of states\n\
 * @param shuffle - TRUE if enabled events of a stack state are randomly\n\
 *        shuffled (e.g., for MC-NDFS)\n\
 * @param states_stored - TRUE if states are fully stored in the stack (i.e.,\n\
 *        not just the state ids)\n\
 */\n\
dfs_stack_t dfs_stack_new\n\
(int id,\n\
 uint32_t block_size,\n\
 bool_t shuffle,\n\
 bool_t states_stored);\n\
\n\
\n\
/**\n\
 * @brief Free a DFS stack.\n\
 */\n\
void dfs_stack_free\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Return the number of states in the stack.\n\
 */\n\
unsigned int dfs_stack_size\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Push an item on top of the stack\n\
 */\n\
void dfs_stack_push\n\
(dfs_stack_t stack,\n\
 htbl_id_t sid,\n\
 state_t s);\n\
\n\
\n\
/**\n\
 * @brief Pop the item on top of the stack.\n\
 */\n\
void dfs_stack_pop\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Return the item on top of the stack\n\
 */\n\
htbl_id_t dfs_stack_top\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Return a copy of the state on top of the stack that is\n\
 *        allocated in heap h.\n\
 */\n\
state_t dfs_stack_top_state\n\
(dfs_stack_t stack,\n\
 heap_t h);\n\
\n\
\n\
/**\n\
 * @brief Return enabled events of the state on top of the stack.\n\
 */\n\
event_list_t dfs_stack_top_events\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Compute the enabled events of the state on top of the stack.\n\
 * @param s - the state on top of the stack if states are not stored in the\n\
 *        stack\n\
 * @param filter - TRUE if enabled events are filtered according to POR\n\
 * @param e - the event executed to reach s (to apply edge-lean reduction).\n\
 *        NULL if edge-reduction if OFF or s is the initial state\n\
 */\n\
event_list_t dfs_stack_compute_events\n\
(dfs_stack_t stack,\n\
 state_t s,\n\
 bool_t filter,\n\
 event_t * e);\n\
\n\
\n\
/**\n\
 * @brief Pick the next enabled event of the state on top of the\n\
 *        stack.\n\
 */\n\
void dfs_stack_pick_event\n\
(dfs_stack_t stack,\n\
 event_t * e);\n\
\n\
\n\
/**\n\
 * @brief Undo the last executed event on the state on top of the\n\
 *        stack.\n\
 * @param s - the state\n\
 */\n\
void dfs_stack_event_undo\n\
(dfs_stack_t stack,\n\
 state_t s);\n\
\n\
\n\
/**\n\
 * @brief Check if the state on top of the stack has been expanded.\n\
 */\n\
bool_t dfs_stack_top_expanded\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Check if the state on top of the stack has been fully\n\
 *        expanded.\n\
 */\n\
bool_t dfs_stack_fully_expanded\n\
(dfs_stack_t stack);\n\
\n\
\n\
/**\n\
 * @brief Create a trace in the global context from the initial state\n\
 *        to the state on top of the stack.\n\
 */\n\
void dfs_stack_create_trace\n\
(dfs_stack_t stack);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "dfs_stack.c", "w")
    f.write ("\
#include \"dfs_stack.h\"\n\
#include \"model.h\"\n\
#include \"context.h\"\n\
#include \"reduction.h\"\n\
\n\
#define DFS_STACK_BLOCKS 2\n\
\n\
typedef struct {\n\
  htbl_id_t id;\n\
  event_list_t en;\n\
  event_t e;\n\
  bool_t e_set;\n\
  mem_size_t heap_pos;\n\
  bool_t fully_expanded;\n\
  state_t s;\n\
} dfs_stack_item_t;\n\
\n\
typedef struct {\n\
  dfs_stack_item_t * items;\n\
} struct_dfs_stack_block_t;\n\
\n\
typedef struct_dfs_stack_block_t * dfs_stack_block_t;\n\
\n\
struct struct_dfs_stack_t {\n\
  dfs_stack_block_t blocks[DFS_STACK_BLOCKS];\n\
  heap_t heaps[DFS_STACK_BLOCKS];\n\
  int32_t id;\n\
  uint8_t current;\n\
  int32_t top;\n\
  uint32_t size;\n\
  uint32_t files;\n\
  uint32_t block_size;\n\
  bool_t shuffle;\n\
  bool_t states_stored;\n\
  rseed_t seed;  \n\
};\n\
\n\
typedef struct struct_dfs_stack_t struct_dfs_stack_t;\n\
\n\
dfs_stack_block_t dfs_stack_block_new\n\
(uint32_t block_size) {\n\
  dfs_stack_block_t result;\n\
\n\
  result = mem_alloc(SYSTEM_HEAP,\n\
                     sizeof(struct_dfs_stack_block_t));\n\
  result->items = mem_alloc(SYSTEM_HEAP,\n\
                            block_size * sizeof(dfs_stack_item_t));\n\
  return result;\n\
}\n\
\n\
void dfs_stack_block_free\n\
(dfs_stack_block_t block) {\n\
  free(block->items);\n\
  free(block);\n\
}\n\
\n\
dfs_stack_t dfs_stack_new\n\
(int id,\n\
 uint32_t block_size,\n\
 bool_t shuffle,\n\
 bool_t states_stored) {\n\
  dfs_stack_t result;\n\
  int i;\n\
\n\
  result = mem_alloc(SYSTEM_HEAP, sizeof(struct_dfs_stack_t));\n\
  result->id = id;\n\
  result->block_size = block_size;\n\
  result->shuffle = shuffle;\n\
  result->states_stored = states_stored;\n\
  result->top = - 1;\n\
  result->size = 0;\n\
  result->current = 0;\n\
  result->files = 0;\n\
  result->seed = random_seed(id);\n\
  for(i = 0; i < DFS_STACK_BLOCKS; i ++) {\n\
    result->heaps[i] = local_heap_new();\n\
    result->blocks[i] = dfs_stack_block_new(result->block_size);\n\
  }\n\
  return result;\n\
}\n\
\n\
void dfs_stack_free\n\
(dfs_stack_t stack) {\n\
  int i;\n\
  char buffer[256];\n\
\n\
  if(stack) {\n\
    for(i = 0; i < stack->files; i ++) {\n\
      sprintf(buffer, \"STACK-%d-%d\", stack->id, i);\n\
      unlink(buffer);\n\
    }\n\
    for(i = 0; i < DFS_STACK_BLOCKS; i ++) {\n\
      if(stack->blocks[i]) {\n\
	dfs_stack_block_free(stack->blocks[i]);\n\
      }\n\
      if(stack->heaps[i]) {\n\
	heap_free(stack->heaps[i]);\n\
      }\n\
    }\n\
    free(stack);\n\
  }\n\
}\n\
\n\
unsigned int dfs_stack_size\n\
(dfs_stack_t stack) {\n\
  if(stack) {\n\
    return stack->size;\n\
  } else {\n\
    return 0;\n\
  }\n\
}\n\
\n\
void dfs_stack_write\n\
(dfs_stack_t stack) {\n\
  int i, len;\n\
  unsigned int w;\n\
  FILE * f;\n\
  char buffer[10000];\n\
  heap_t h = stack->heaps[0];\n\
  dfs_stack_block_t block = stack->blocks[0];\n\
  dfs_stack_item_t item;\n\
\n\
  sprintf(buffer, \"STACK-%d-%d\", stack->id, stack->files);\n\
  f = fopen(buffer, \"w\");\n\
  for(i = 0; i < stack->block_size; i ++) {\n\
    item = block->items[i];\n\
\n\
    /*  event list  */\n\
    w = event_list_char_size(item.en);\n\
    event_list_serialise(item.en, buffer);\n\
    fwrite(&w, sizeof(unsigned int), 1, f);\n\
    fwrite(buffer, w, 1, f);\n\
\n\
    /*  last event  */\n\
    w = event_char_size(item.e);\n\
    event_serialise(item.e, buffer);\n\
    fwrite(&w, sizeof(unsigned int), 1, f);\n\
    fwrite(buffer, w, 1, f);\n\
\n\
    /*  state id  */\n\
    fwrite(&item.id, sizeof(htbl_id_t), 1, f);\n\
\n\
    /*  por info  */\n\
    fwrite(&item.fully_expanded, sizeof(bool_t), 1, f);\n\
\n\
    /*  state  */\n\
    if(stack->states_stored) {\n\
      len = state_char_size(item.s);\n\
      fwrite(&len, sizeof(int), 1, f);\n\
      state_serialise(item.s, buffer);\n\
      fwrite(buffer, len, 1, f);\n\
    }\n\
  }\n\
  fclose(f);\n\
  stack->files ++;\n\
}\n\
\n\
void dfs_stack_read\n\
(dfs_stack_t stack) {\n\
  int i, len;\n\
  unsigned int w, en_size;\n\
  FILE * f;\n\
  char buffer[10000], name[20];\n\
  dfs_stack_item_t item;\n\
  heap_t h = stack->heaps[0];\n\
\n\
  stack->files --;\n\
  sprintf(name, \"STACK-%d-%d\", stack->id, stack->files);\n\
  f = fopen(name, \"r\");\n\
  heap_reset(h);\n\
  for(i = 0; i < stack->block_size; i ++) {\n\
    item.heap_pos = heap_get_position(h);\n\
    \n\
    /*  event list  */\n\
    fread(&w, sizeof(unsigned int), 1, f);\n\
    fread(buffer, w, 1, f);\n\
    item.en = event_list_unserialise_mem(buffer, h);\n\
    \n\
    /*  last event  */\n\
    fread(&w, sizeof(unsigned int), 1, f);\n\
    fread(buffer, w, 1, f);\n\
    item.e = event_unserialise_mem(buffer, h);\n\
    item.e_set = TRUE;\n\
    \n\
    /*  state id  */\n\
    fread(&item.id, sizeof(htbl_id_t), 1, f);\n\
\n\
    /*  por info  */\n\
    fread(&item.fully_expanded, sizeof(bool_t), 1, f);\n\
\n\
    /*  state  */\n\
    if(stack->states_stored) {\n\
      fread(&len, sizeof(int), 1, f);\n\
      fread(buffer, len, 1, f);\n\
      item.s = state_unserialise_mem(buffer, h);\n\
    }\n\
    stack->blocks[0]->items[i] = item;\n\
  }\n\
  fclose(f);\n\
  remove(name);\n\
}\n\
\n\
void dfs_stack_push\n\
(dfs_stack_t stack,\n\
 htbl_id_t sid,\n\
 state_t s) {\n\
  heap_t h = stack->heaps[stack->current];\n\
  dfs_stack_item_t item;\n\
  \n\
  stack->top ++;\n\
  stack->size ++;\n\
  if(stack->top == stack->block_size) {\n\
    if(stack->current == 1) {\n\
      dfs_stack_write(stack);\n\
      dfs_stack_block_free(stack->blocks[0]);\n\
      stack->blocks[0] = stack->blocks[1];\n\
      stack->blocks[1] = dfs_stack_block_new(stack->block_size);\n\
      heap_free(stack->heaps[0]);\n\
      stack->heaps[0] = stack->heaps[1];\n\
      stack->heaps[1] = local_heap_new();\n\
    }\n\
    stack->current = 1;\n\
    stack->top = 0;\n\
  }\n\
  h = stack->heaps[stack->current];\n\
  item.id = sid;\n\
  item.en = NULL;\n\
  item.e_set = FALSE;\n\
  if(stack->states_stored) {\n\
    item.s = state_copy_mem(s,h);\n\
  }\n\
  stack->blocks[stack->current]->items[stack->top] = item;\n\
}\n\
\n\
void dfs_stack_pop\n\
(dfs_stack_t stack) {\n\
  heap_t h = stack->heaps[stack->current];\n\
  dfs_stack_item_t item = stack->blocks[stack->current]->items[stack->top];\n\
  \n\
  assert(0 != stack->size);\n\
  heap_set_position(h, item.heap_pos);\n\
  stack->top --;\n\
  stack->size --;\n\
  if(stack->size > 0 && stack->top == -1) {\n\
    if(stack->current == 0) {\n\
      assert(stack->files > 0);\n\
      dfs_stack_read(stack);\n\
    }\n\
    stack->current = 0;\n\
    stack->top = stack->block_size - 1;\n\
  }\n\
}\n\
\n\
htbl_id_t dfs_stack_top\n\
(dfs_stack_t stack) {\n\
  assert(0 != stack->size);\n\
  return stack->blocks[stack->current]->items[stack->top].id;\n\
}\n\
\n\
state_t dfs_stack_top_state\n\
(dfs_stack_t stack,\n\
 heap_t h) {\n\
  state_t result;\n\
\n\
  assert(stack->states_stored);\n\
  assert(0 != stack->size);\n\
  result = stack->blocks[stack->current]->items[stack->top].s;\n\
  result = state_copy_mem(result, h);\n\
  return result;\n\
}\n\
\n\
event_list_t dfs_stack_top_events\n\
(dfs_stack_t stack) {\n\
  assert(0 != stack->size);\n\
  return stack->blocks[stack->current]->items[stack->top].en;\n\
}\n\
\n\
event_list_t dfs_stack_compute_events\n\
(dfs_stack_t stack,\n\
 state_t s,\n\
 bool_t filter,\n\
 event_t * e) {\n\
  heap_t h = stack->heaps[stack->current];\n\
  event_list_t result;\n\
  dfs_stack_item_t item = stack->blocks[stack->current]->items[stack->top];\n\
  bool_t reduced;\n\
\n\
  assert(0 != stack->size);\n\
  item.heap_pos = heap_get_position(h);\n\
  \n\
  if(filter) {\n\
    result = state_events_reduced_mem(s, &reduced, h);\n\
    item.fully_expanded = !reduced;\n\
  } else {\n\
    result = state_events_mem(s, h);\n\
    item.fully_expanded = TRUE;\n\
  }\n\
  if(e != NULL) {\n\
    edge_lean_reduction(result, *e);\n\
  }\n\
  item.en = result;\n\
  stack->blocks[stack->current]->items[stack->top] = item;\n\
  return result;\n\
}\n\
\n\
void dfs_stack_pick_event\n\
(dfs_stack_t stack,\n\
 event_t * e) {\n\
  dfs_stack_item_t item = stack->blocks[stack->current]->items[stack->top];\n\
  int chosen;\n\
  \n\
  if(stack->shuffle) {\n\
    list_pick_random(item.en, &item.e, &stack->seed);\n\
  } else {\n\
    list_pick_first(item.en, &item.e);\n\
  }\n\
  item.e_set = TRUE;\n\
  stack->blocks[stack->current]->items[stack->top] = item;\n\
  *e = item.e;\n\
}\n\
\n\
void dfs_stack_event_undo\n\
(dfs_stack_t stack,\n\
 state_t s) {\n\
  dfs_stack_item_t item = stack->blocks[stack->current]->items[stack->top];\n\
   \n\
  event_undo(item.e, s);\n\
}\n\
\n\
bool_t dfs_stack_top_expanded\n\
(dfs_stack_t stack) {\n\
  dfs_stack_item_t item = stack->blocks[stack->current]->items[stack->top];\n\
  \n\
  return list_is_empty(item.en);\n\
} \n\
\n\
bool_t dfs_stack_fully_expanded\n\
(dfs_stack_t stack) {  \n\
  dfs_stack_item_t item;\n\
  \n\
  item = stack->blocks[stack->current]->items[stack->top];\n\
  return item.fully_expanded;\n\
}\n\
\n\
void dfs_stack_create_trace\n\
(dfs_stack_t stack) {\n\
  event_t e;\n\
  dfs_stack_item_t item;\n\
  int i;\n\
  event_list_t trace = list_new(SYSTEM_HEAP, sizeof(event_t), event_free_void);\n\
\n\
  dfs_stack_pop(stack);\n\
  while(stack->size > 0) {\n\
    item = stack->blocks[stack->current]->items[stack->top];\n\
    if(item.e_set) {\n\
      e = event_copy(item.e);\n\
      list_prepend(trace, &e);\n\
    }\n\
    dfs_stack_pop(stack);\n\
  }\n\
  context_set_trace(trace);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "errors.h", "w")
    f.write ("\
/**\n\
 * @file errors.h\n\
 * @brief Error handling.\n\
 * @date 12 nov 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_ERRORS\n\
#define LIB_ERRORS\n\
\n\
unsigned int error_throw\n\
(char * msg);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "errors.c", "w")
    f.write ("\
#include \"errors.h\"\n\
#include \"context.h\"\n\
\n\
unsigned int error_throw\n\
(char * msg) {\n\
  context_error(msg);\n\
  return 0;\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "event.h", "w")
    f.write ("\
/**\n\
 * @file event.h\n\
 * @brief Event definition.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_EVENT\n\
#define LIB_EVENT\n\
\n\
#include \"model.h\"\n\
#include \"heap.h\"\n\
#include \"prop.h\"\n\
#include \"state.h\"\n\
#include \"config.h\"\n\
\n\
typedef list_t mevent_list_t;\n\
typedef list_t event_list_t;\n\
\n\
void mevent_free_void\n\
(void * data);\n\
\n\
uint32_t mevent_list_char_size\n\
(mevent_list_t l);\n\
\n\
void mevent_list_serialise\n\
(mevent_list_t l,\n\
 bit_vector_t v);\n\
\n\
mevent_list_t mevent_list_unserialise\n\
(bit_vector_t v);\n\
\n\
mevent_list_t mevent_list_unserialise_mem\n\
(bit_vector_t v,\n\
 heap_t heap);\n\
\n\
\n\
#if CFG_ACTION_CHECK_LTL == 1\n\
\n\
/**\n\
 *  event definition when doing LTL model checking\n\
 */\n\
\n\
typedef struct {\n\
  bool_t dummy;\n\
  uint8_t m;\n\
  uint8_t b;\n\
} event_id_t;\n\
\n\
typedef struct {\n\
  bool_t dummy;\n\
  mevent_t m;\n\
  bevent_t b;\n\
} event_t;\n\
\n\
bool_t event_is_dummy(event_t e);\n\
void event_free(event_t e);\n\
void event_free_void(void * e);\n\
event_t event_copy(event_t e);\n\
event_t event_copy_mem(event_t e, heap_t h);\n\
event_id_t event_id(event_t e);\n\
void event_exec(event_t e, state_t s);\n\
void event_undo(event_t e, state_t s);\n\
void event_to_xml(event_t e, FILE * f);\n\
order_t event_cmp(event_t e, event_t f);\n\
bool_t event_are_independent(event_t e, event_t f);\n\
unsigned int event_char_size(event_t e);\n\
void event_serialise(event_t e, bit_vector_t v);\n\
event_t event_unserialise(bit_vector_t v);\n\
event_t event_unserialise_mem(bit_vector_t v, heap_t heap);\n\
\n\
event_list_t state_events(state_t s);\n\
event_list_t state_events_mem(state_t s, heap_t heap);\n\
event_t state_event(state_t s, event_id_t id);\n\
event_t state_event_mem(state_t s, event_id_t id, heap_t heap);\n\
event_list_t state_events_reduced(state_t s, bool_t * red);\n\
event_list_t state_events_reduced_mem(state_t s, bool_t * red, heap_t heap);\n\
state_t state_succ(state_t s, event_t e);\n\
state_t state_succ_mem(state_t s, event_t e, heap_t heap);\n\
state_t state_pred(state_t s, event_t e);\n\
state_t state_pred_mem(state_t s, event_t e, heap_t heap);\n\
\n\
unsigned int event_list_char_size(event_list_t l);\n\
void event_list_serialise(event_list_t l, bit_vector_t v);\n\
event_list_t event_list_unserialise(bit_vector_t v);\n\
event_list_t event_list_unserialise_mem(bit_vector_t v, heap_t heap);\n\
\n\
#else\n\
\n\
/**\n\
 *  event definition when not doing LTL model checking: an event\n\
 *  is simply an mevent\n\
 */\n\
\n\
\n\
typedef mevent_t event_t;\n\
typedef mevent_id_t event_id_t;\n\
\n\
#define event_is_dummy(e) FALSE\n\
#define event_free mevent_free\n\
#define event_free_void mevent_free_void\n\
#define event_copy mevent_copy\n\
#define event_copy_mem mevent_copy_mem\n\
#define event_id mevent_id\n\
#define event_exec mevent_exec\n\
#define event_undo mevent_undo\n\
#define event_to_xml mevent_to_xml\n\
#define event_cmp mevent_cmp\n\
#define event_are_independent mevent_are_independent\n\
#define event_char_size mevent_char_size\n\
#define event_serialise mevent_serialise\n\
#define event_unserialise mevent_unserialise\n\
#define event_unserialise_mem mevent_unserialise_mem\n\
\n\
#define state_events mstate_events\n\
#define state_events_mem mstate_events_mem\n\
#define state_event mstate_event\n\
#define state_event_mem mstate_event_mem\n\
#define state_events_reduced mstate_events_reduced\n\
#define state_events_reduced_mem mstate_events_reduced_mem\n\
#define state_succ mstate_succ\n\
#define state_succ_mem mstate_succ_mem\n\
#define state_pred mstate_pred\n\
#define state_pred_mem mstate_pred_mem\n\
\n\
#define event_list_char_size mevent_list_char_size\n\
#define event_list_serialise mevent_list_serialise\n\
#define event_list_unserialise mevent_list_unserialise\n\
#define event_list_unserialise_mem mevent_list_unserialise_mem\n\
\n\
#endif\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "event.c", "w")
    f.write ("\
#include \"event.h\"\n\
#include \"reduction.h\"\n\
\n\
void mevent_free_void\n\
(void * data) {\n\
  mevent_free(* ((mevent_t *) data));\n\
}\n\
\n\
uint32_t mevent_char_size_void\n\
(void * e) {\n\
  return mevent_char_size(* ((mevent_t *) e));\n\
}\n\
\n\
void mevent_serialise_void\n\
(void * e,\n\
 char * data) {\n\
  return mevent_serialise(* ((mevent_t *) e), (bit_vector_t) data);\n\
}\n\
\n\
void mevent_unserialise_void\n\
(char * data,\n\
 heap_t heap,\n\
 void * item) {\n\
  mevent_t e = mevent_unserialise_mem(data, heap);\n\
  memcpy(item, &e, sizeof(mevent_t));\n\
}\n\
\n\
uint32_t mevent_list_char_size\n\
(mevent_list_t l) {\n\
  return list_char_size(l, mevent_char_size_void);\n\
}\n\
\n\
void mevent_list_serialise\n\
(mevent_list_t l,\n\
 bit_vector_t v) {\n\
  list_serialise(l, v, mevent_char_size_void, mevent_serialise_void);\n\
}\n\
\n\
mevent_list_t mevent_list_unserialise\n\
(bit_vector_t v) {  \n\
  return mevent_list_unserialise_mem(v, SYSTEM_HEAP);\n\
}\n\
\n\
mevent_list_t mevent_list_unserialise_mem\n\
(bit_vector_t v,\n\
 heap_t heap) {\n\
  return list_unserialise(heap, sizeof(mevent_t), mevent_free_void,\n\
                          v, mevent_char_size_void, mevent_unserialise_void);\n\
}\n\
\n\
#if CFG_ACTION_CHECK_LTL == 1\n\
\n\
bool_t event_is_dummy\n\
(event_t e) {\n\
  return e.dummy;\n\
}\n\
\n\
void event_free\n\
(event_t e) {\n\
  if(!e.dummy) {\n\
    mevent_free(e.m);\n\
  }\n\
}\n\
\n\
void event_free_void\n\
(void * e) {\n\
  event_free(* (event_t *) e);\n\
}\n\
\n\
event_t event_copy\n\
(event_t e) {\n\
  return event_copy_mem(e, SYSTEM_HEAP);\n\
}\n\
\n\
event_t event_copy_mem\n\
(event_t e,\n\
 heap_t h) {\n\
  event_t result;\n\
  result.dummy = e.dummy;\n\
  result.b = e.b;\n\
  if(!e.dummy) {\n\
    result.m = mevent_copy_mem(e.m, h);\n\
  }\n\
  return result;\n\
}\n\
\n\
event_id_t event_id\n\
(event_t e) {\n\
  /*  not implemented  */\n\
  assert(0);\n\
}\n\
\n\
void event_exec\n\
(event_t e,\n\
 state_t s) {\n\
  if(!e.dummy) {\n\
    mevent_exec(e.m, s->m);\n\
  }\n\
  s->b = e.b.to;\n\
}\n\
\n\
void event_undo\n\
(event_t e,\n\
 state_t s) {\n\
  if(!e.dummy) {\n\
    mevent_undo(e.m, s->m);\n\
  }\n\
  s->b = e.b.from;\n\
}\n\
\n\
void event_to_xml\n\
(event_t e,\n\
 FILE * f) {\n\
  assert(!e.dummy);\n\
  mevent_to_xml(e.m, f);\n\
}\n\
\n\
order_t event_cmp\n\
(event_t e,\n\
 event_t f) {\n\
  order_t cmp;\n\
  if((cmp = bevent_cmp(e.b, f.b)) != EQUAL) return cmp;\n\
  else if(e.dummy && f.dummy) return EQUAL;\n\
  else if(e.dummy) return LESS;\n\
  else if(f.dummy) return GREATER;\n\
  else return mevent_cmp(e.m, f.m);\n\
}\n\
\n\
bool_t event_are_independent\n\
(event_t e,\n\
 event_t f) {\n\
  return mevent_are_independent(e.m, f.m);\n\
}\n\
\n\
unsigned int event_char_size\n\
(event_t e) {\n\
  return 1 + 2 * sizeof(bstate_t) + (e.dummy ? 0 : mevent_char_size(e.m));\n\
}\n\
\n\
void event_serialise\n\
(event_t e,\n\
 bit_vector_t v) {\n\
  const unsigned int bsize = sizeof(bstate_t);\n\
  \n\
  memcpy(v, &e.b.from, bsize);\n\
  memcpy(v + bsize, &e.b.to, bsize);\n\
  memcpy(v + bsize + bsize, &e.dummy, 1);\n\
  if(!e.dummy) {\n\
    mevent_serialise(e.m, v + bsize + bsize + 1);\n\
  }\n\
}\n\
\n\
event_t event_unserialise\n\
(bit_vector_t v) {\n\
  return event_unserialise_mem(v, SYSTEM_HEAP);\n\
}\n\
\n\
event_t event_unserialise_mem\n\
(bit_vector_t v,\n\
 heap_t heap) {\n\
  const unsigned int bsize = sizeof(bstate_t);\n\
  event_t result;\n\
  \n\
  result.b.to = 0;\n\
  result.b.from = 0;\n\
  memcpy(&result.b.from, v, bsize);\n\
  memcpy(&result.b.to, v + bsize, bsize);\n\
  memcpy(&result.dummy, v + bsize + bsize, 1);\n\
  if(!result.dummy) {\n\
    result.m = mevent_unserialise_mem(v + bsize + bsize + 1, heap);\n\
  }\n\
  return result;\n\
}\n\
\n\
event_list_t state_events\n\
(state_t s) {\n\
  return state_events_mem(s, SYSTEM_HEAP);\n\
}\n\
\n\
event_list_t state_events_mem_with_reduction\n\
(state_t s,\n\
 bool_t reduce,\n\
 bool_t * reduced,\n\
 heap_t heap) {\n\
  event_t e;\n\
  event_list_t result = list_new(heap, sizeof(event_t), event_free_void);\n\
  bstate_t succs[256];\n\
  uint32_t size;\n\
  list_iter_t it;\n\
  list_t m_en;\n\
  int i, no_succs;\n\
\n\
  if(reduce) {\n\
    m_en = mstate_events_reduced_mem(s->m, reduced, heap);\n\
  } else {\n\
    m_en = mstate_events_mem(s->m, heap);    \n\
  }\n\
  bstate_succs(s->b, s->m, succs, &no_succs);\n\
\n\
  e.b.from = s->b;\n\
  if(succs == 0) {\n\
    \n\
    /**\n\
     *  buchi state does not have enabled events => the resulting list\n\
     *  is empty\n\
     */\n\
    list_free(m_en);\n\
    \n\
  } else if(list_size(m_en) == 0) {\n\
    \n\
    /**\n\
     *  model state does not have enabled events => the resulting list\n\
     *  is the list of buchi events\n\
     */\n\
    e.dummy = TRUE;\n\
    for(i = 0; i < no_succs; i ++) {\n\
      e.b.to = succs[i];\n\
      list_append(result, &e);\n\
    }\n\
  } else {\n\
    \n\
    /**\n\
     *  buchi and model states both have enabled events => the\n\
     *  resulting list is the cartesian product of both\n\
     */\n\
    e.dummy = FALSE;\n\
    for(i = 0; i < no_succs; i ++) {\n\
      e.b.to = succs[i];\n\
      for(it = list_get_iter(m_en);\n\
          !list_iter_at_end(it);\n\
          it = list_iter_next(it)) {\n\
        e.m = * ((mevent_t *) list_iter_item(it));\n\
        e.m = mevent_copy_mem(e.m, heap);\n\
        list_append(result, &e);\n\
      }\n\
    }\n\
  }\n\
  list_free(m_en);\n\
  return result;\n\
}\n\
\n\
event_list_t state_events_mem\n\
(state_t s,\n\
 heap_t heap) {\n\
  return state_events_mem_with_reduction(s, FALSE, NULL, heap);\n\
}\n\
\n\
event_t state_event\n\
(state_t s,\n\
 event_id_t id) {\n\
  return state_event_mem(s, id, SYSTEM_HEAP);\n\
}\n\
\n\
event_t state_event_mem\n\
(state_t s,\n\
 event_id_t id,\n\
 heap_t heap) {\n\
  /*  not implemented  */\n\
  assert(0);\n\
}\n\
\n\
event_list_t state_events_reduced\n\
(state_t s,\n\
 bool_t * red) {\n\
  return state_events_reduced_mem(s, red, SYSTEM_HEAP);\n\
}\n\
\n\
event_list_t state_events_reduced_mem\n\
(state_t s,\n\
 bool_t * red,\n\
 heap_t heap) {\n\
  return state_events_mem_with_reduction(s, TRUE, red, heap);  \n\
}\n\
\n\
state_t state_succ\n\
(state_t s,\n\
 event_t e) {\n\
  return state_succ_mem(s, e, SYSTEM_HEAP);\n\
}\n\
\n\
state_t state_succ_mem\n\
(state_t s,\n\
 event_t e,\n\
 heap_t heap) {\n\
  /*  not implemented  */\n\
  assert(0);\n\
}\n\
\n\
state_t state_pred\n\
(state_t s,\n\
 event_t e) {\n\
  return state_pred_mem(s, e, SYSTEM_HEAP);\n\
}\n\
\n\
state_t state_pred_mem\n\
(state_t s,\n\
 event_t e,\n\
 heap_t heap) {\n\
  /*  not implemented  */\n\
  assert(0);\n\
}\n\
\n\
uint32_t event_char_size_void\n\
(void * e) {\n\
  return event_char_size(* ((event_t *) e));\n\
}\n\
\n\
void event_serialise_void\n\
(void * e,\n\
 char * data) {\n\
  return event_serialise(* ((event_t *) e), (bit_vector_t) data);\n\
}\n\
\n\
void event_unserialise_void\n\
(char * data,\n\
 heap_t heap,\n\
 void * item) {\n\
  event_t e = event_unserialise_mem(data, heap);\n\
  memcpy(item, &e, sizeof(event_t));\n\
}\n\
\n\
unsigned int event_list_char_size\n\
(event_list_t l) {\n\
  return list_char_size(l, event_char_size_void);\n\
}\n\
\n\
void event_list_serialise\n\
(event_list_t l,\n\
 bit_vector_t v) {\n\
  list_serialise(l, v, event_char_size_void, event_serialise_void);\n\
}\n\
\n\
event_list_t event_list_unserialise\n\
(bit_vector_t v) {\n\
  return event_list_unserialise_mem(v, SYSTEM_HEAP);\n\
}\n\
\n\
event_list_t event_list_unserialise_mem\n\
(bit_vector_t v,\n\
 heap_t heap) {\n\
  return list_unserialise(heap, sizeof(event_t), event_free_void,\n\
                          v, event_char_size_void, event_unserialise_void);\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "harray.h", "w")
    f.write ("\
/**\n\
 * @file harray.h\n\
 * @brief Implementation of an hash array.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_HARRAY\n\
#define LIB_HARRAY\n\
\n\
#include \"common.h\"\n\
#include \"heap.h\"\n\
\n\
typedef hash_key_t harray_key_t;\n\
\n\
typedef uint32_t harray_index_t;\n\
\n\
typedef uint32_t harray_size_t;\n\
\n\
typedef uint8_t harray_status_t;\n\
\n\
typedef void * harray_value_t;\n\
\n\
typedef void * harray_iter_data_t;\n\
\n\
typedef void (* harray_iter_func_t) (harray_key_t, harray_value_t,\n\
				     harray_iter_data_t);\n\
\n\
typedef bool_t (* harray_pred_func_t) (harray_key_t, harray_value_t,\n\
				       harray_iter_data_t);\n\
\n\
typedef harray_key_t (* harray_hash_func_t) (harray_value_t);\n\
\n\
typedef order_t (* harray_cmp_func_t) (harray_value_t, harray_value_t);\n\
\n\
typedef void (* harray_free_func_t) (harray_value_t);\n\
\n\
typedef struct {\n\
  heap_t             heap;\n\
  harray_size_t      num_items;\n\
  harray_size_t      size;\n\
  harray_status_t *  status;\n\
  harray_key_t *     keys;\n\
  harray_value_t *   values;\n\
  harray_hash_func_t fhash;\n\
  harray_cmp_func_t  fcmp;\n\
  harray_free_func_t ffree;\n\
} struct_harray_t;\n\
\n\
typedef struct_harray_t * harray_t;\n\
\n\
harray_t harray_new\n\
(heap_t             heap,\n\
 harray_size_t      size,\n\
 harray_hash_func_t fhash,\n\
 harray_cmp_func_t  fcmp,\n\
 harray_free_func_t ffree);\n\
\n\
void harray_free\n\
(harray_t harray);\n\
\n\
harray_size_t harray_num_items\n\
(harray_t harray);\n\
\n\
bool_t harray_insert\n\
(harray_t harray,\n\
 harray_value_t val);\n\
\n\
void harray_delete\n\
(harray_t harray,\n\
 harray_value_t val);\n\
\n\
harray_value_t harray_lookup\n\
(harray_t harray,\n\
 harray_value_t val);\n\
\n\
void harray_app\n\
(harray_t harray,\n\
 harray_iter_func_t f,\n\
 harray_iter_data_t data);\n\
\n\
void harray_filter\n\
(harray_t harray,\n\
 harray_pred_func_t f,\n\
 harray_iter_data_t data);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "harray.c", "w")
    f.write ("\
#include \"harray.h\"\n\
\n\
#define HARRAY_NONE 0\n\
#define HARRAY_SOME 1\n\
#define HARRAY_DEL  2\n\
\n\
harray_t harray_new\n\
(heap_t             heap,\n\
 harray_size_t      size,\n\
 harray_hash_func_t fhash,\n\
 harray_cmp_func_t  fcmp,\n\
 harray_free_func_t ffree) {\n\
  harray_index_t i;\n\
  harray_t result = mem_alloc (heap, sizeof (struct_harray_t));\n\
  result->num_items = 0;\n\
  result->heap = heap;\n\
  result->size = size;\n\
  result->fhash = fhash;\n\
  result->fcmp = fcmp;\n\
  result->ffree = ffree;\n\
  result->status = mem_alloc (heap, size * sizeof (harray_status_t));\n\
  result->keys = mem_alloc (heap, size * sizeof (harray_key_t));\n\
  result->values = mem_alloc (heap, size * sizeof (harray_value_t));\n\
  for (i = 0; i < size; i ++) {\n\
    result->status[i] = HARRAY_NONE;\n\
  }\n\
  return result;\n\
}\n\
\n\
void harray_free\n\
(harray_t harray) {\n\
  harray_index_t i;\n\
  if (harray->ffree) {\n\
    for (i = 0; i < harray->size; i ++) {\n\
      if (harray->status[i] == HARRAY_SOME) {\n\
	(*harray->ffree) (harray->values[i]);\n\
      }\n\
    }\n\
  }\n\
  mem_free (harray->heap, harray->status);\n\
  mem_free (harray->heap, harray->keys);\n\
  mem_free (harray->heap, harray->values);\n\
  mem_free (harray->heap, harray);\n\
}\n\
\n\
harray_size_t harray_num_items\n\
(harray_t harray) {\n\
  return harray->num_items;\n\
}\n\
\n\
bool_t harray_insert\n\
(harray_t       harray,\n\
 harray_value_t val) {\n\
  harray_key_t key = (*harray->fhash) (val);\n\
  harray_index_t new_pos, pos = key % harray->size, fst_pos = pos;\n\
  bool_t loop = TRUE;\n\
  bool_t pos_found = FALSE;\n\
  bool_t result = FALSE;\n\
\n\
  while (loop) {\n\
    switch (harray->status[pos]) {\n\
    case HARRAY_NONE: {\n\
      if (pos_found) {\n\
	pos = new_pos;\n\
      }\n\
      harray->status[pos] = HARRAY_SOME;\n\
      harray->keys[pos] = key;\n\
      harray->values[pos] = val;\n\
      harray->num_items ++;\n\
      loop = FALSE;\n\
      result = TRUE;\n\
      break;\n\
    }\n\
    case HARRAY_SOME: {\n\
      if ((harray->keys[pos] == key) &&\n\
	  (EQUAL == (*harray->fcmp) (val, harray->values[pos]))) {\n\
	loop = FALSE;\n\
      } else {\n\
	pos = (pos + 1) % harray->size;\n\
      }\n\
      break;\n\
    }\n\
    case HARRAY_DEL: {\n\
      if (!pos_found) {\n\
	pos_found = TRUE;\n\
	new_pos = pos;\n\
      }\n\
      pos = (pos + 1) % harray->size;\n\
      break;\n\
    }\n\
    }\n\
    assert(!loop || pos != fst_pos);\n\
  }\n\
  return result;\n\
}\n\
\n\
void harray_delete\n\
(harray_t       harray,\n\
 harray_value_t val) {\n\
  /*  not implemented  */\n\
  assert(0);\n\
}\n\
\n\
harray_value_t harray_lookup\n\
(harray_t       harray,\n\
 harray_value_t val) {\n\
  harray_value_t result = NULL;\n\
  harray_key_t key = (*harray->fhash) (val);\n\
  harray_index_t pos = key % harray->size;\n\
  bool_t loop = TRUE;\n\
\n\
  while (loop) {\n\
    switch (harray->status[pos]) {\n\
    case HARRAY_NONE: {\n\
      loop = FALSE;\n\
    }\n\
    case HARRAY_DEL: {\n\
      pos = (pos + 1) % harray->size;\n\
      break;\n\
    }\n\
    case HARRAY_SOME: {\n\
      if ((harray->keys[pos] == key) &&\n\
	  (EQUAL == (*harray->fcmp) (val, harray->values[pos]))) {\n\
	result = harray->values[pos];\n\
	loop = FALSE;\n\
      } else {\n\
	pos = (pos + 1) % harray->size;\n\
      }\n\
      break;\n\
    }\n\
    }\n\
  }  \n\
  return result;\n\
}\n\
\n\
void harray_app\n\
(harray_t           harray,\n\
 harray_iter_func_t f,\n\
 harray_iter_data_t data) {\n\
  harray_index_t i;\n\
\n\
  for (i = 0; i < harray->size; i ++) {\n\
    if (HARRAY_SOME == harray->status[i]) {\n\
      (*f) (harray->keys[i], harray->values[i], data);\n\
    }\n\
  }\n\
}\n\
\n\
void harray_filter\n\
(harray_t           harray,\n\
 harray_pred_func_t f,\n\
 harray_iter_data_t data) {\n\
  harray_index_t i;\n\
\n\
  for (i = 0; i < harray->size; i ++) {\n\
    if (HARRAY_SOME == harray->status[i]\n\
	&& (!(*f) (harray->keys[i], harray->values[i], data))) {\n\
      harray->status[i] = HARRAY_DEL;\n\
      if (harray->ffree) {\n\
	(*harray->ffree) (harray->values[i]);\n\
      }\n\
    }\n\
  }\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "htbl.h", "w")
    f.write ("\
/**\n\
 * @file htbl.h\n\
 * @brief Implementation of an hash table supporting concurrent accesses.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 *\n\
 * The hash table is a small variation of the structure presented in:\n\
 *\n\
 * Boosting Multi-Core Reachability Performance with Shared Hash Tables\n\
 * by Alfons Laarman, Jaco van de Pol, Michael Weber.\n\
 * in Formal Methods in Computer-Aided Design.\n\
 *\n\
 */\n\
\n\
#ifndef LIB_HTBL\n\
#define LIB_HTBL\n\
\n\
#include \"state.h\"\n\
#include \"event.h\"\n\
#include \"heap.h\"\n\
#include \"config.h\"\n\
\n\
\n\
/**\n\
 * state attribute definitions\n\
 */\n\
typedef enum {\n\
  ATTR_CYAN,\n\
  ATTR_BLUE,\n\
  ATTR_PINK,\n\
  ATTR_RED,\n\
  ATTR_PRED,\n\
  ATTR_EVT,\n\
  ATTR_INDEX,\n\
  ATTR_LOWLINK,\n\
  ATTR_LIVE,\n\
  ATTR_SAFE,\n\
  ATTR_UNSAFE_SUCC,\n\
  ATTR_TO_REVISIT\n\
} attr_state_t;\n\
\n\
typedef struct struct_htbl_t * htbl_t;\n\
\n\
typedef uint64_t htbl_id_t;\n\
\n\
typedef void (* htbl_fold_func_t)\n\
(state_t, htbl_id_t, void *);\n\
\n\
\n\
/**\n\
 * @brief htbl_new\n\
 */\n\
htbl_t htbl_new\n\
(bool_t use_system_heap,\n\
 uint64_t hash_size,\n\
 uint16_t no_workers,\n\
 bool_t hash_compaction,\n\
 uint32_t attrs);\n\
\n\
\n\
/**\n\
 * @brief htbl_default_new\n\
 */\n\
htbl_t htbl_default_new\n\
();\n\
\n\
\n\
/**\n\
 * @brief htbl_free\n\
 */\n\
void htbl_free\n\
(htbl_t tbl);\n\
\n\
\n\
/**\n\
 * @brief htbl_contains\n\
 */\n\
bool_t htbl_contains\n\
(htbl_t tbl,\n\
 state_t s,\n\
 htbl_id_t * id,\n\
 hash_key_t * h);\n\
\n\
\n\
/**\n\
 * @brief htbl_insert\n\
 */\n\
void htbl_insert\n\
(htbl_t tbl,\n\
 state_t s,\n\
 bool_t * is_new,\n\
 htbl_id_t * id,\n\
 hash_key_t * h);\n\
\n\
\n\
/**\n\
 * @brief htbl_insert_hashed\n\
 */\n\
void htbl_insert_hashed\n\
(htbl_t tbl,\n\
 state_t s,\n\
 hash_key_t h,\n\
 bool_t * is_new,\n\
 htbl_id_t * id);\n\
\n\
\n\
/**\n\
 * @brief htbl_insert_serialised\n\
 */\n\
void htbl_insert_serialised\n\
(htbl_t tbl,\n\
 bit_vector_t s,\n\
 uint16_t s_char_len,\n\
 hash_key_t h,\n\
 bool_t * is_new,\n\
 htbl_id_t * id);\n\
\n\
\n\
/**\n\
 * @brief htbl_erase\n\
 */\n\
void htbl_erase\n\
(htbl_t tbl,\n\
 htbl_id_t id);\n\
\n\
\n\
/**\n\
 * @brief htbl_get\n\
 */\n\
state_t htbl_get\n\
(htbl_t tbl,\n\
 htbl_id_t id);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_mem\n\
 */\n\
state_t htbl_get_mem\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 heap_t heap);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_serialised\n\
 */\n\
void htbl_get_serialised\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 bit_vector_t * s,\n\
 uint16_t * size,\n\
 hash_key_t * h);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_hash\n\
 */\n\
hash_key_t htbl_get_hash\n\
(htbl_t tbl,\n\
 htbl_id_t id);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_attr\n\
 */\n\
uint64_t htbl_get_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr);\n\
\n\
\n\
/**\n\
 * @brief htbl_set_attr\n\
 */\n\
void htbl_set_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr,\n\
 uint64_t val);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_worker_attr\n\
 */\n\
uint64_t htbl_get_worker_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr,\n\
 worker_id_t w);\n\
\n\
\n\
/**\n\
 * @brief htbl_set_worker_attr\n\
 */\n\
void htbl_set_worker_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr,\n\
 worker_id_t w,\n\
 uint64_t val);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_any_cyan\n\
 */\n\
bool_t htbl_get_any_cyan\n\
(htbl_t tbl,\n\
 htbl_id_t id);\n\
\n\
\n\
/**\n\
 * @brief htbl_fold\n\
 */\n\
void htbl_fold\n\
(htbl_t tbl,\n\
 htbl_fold_func_t f,\n\
 void * data);\n\
\n\
\n\
/**\n\
 * @brief htbl_reset\n\
 */\n\
void htbl_reset\n\
(htbl_t tbl);\n\
\n\
\n\
/**\n\
 * @brief htbl_has_attr\n\
 */\n\
bool_t htbl_has_attr\n\
(htbl_t tbl,\n\
 attr_state_t attr);\n\
\n\
\n\
/**\n\
 * @brief htbl_get_trace\n\
 */\n\
list_t htbl_get_trace\n\
(htbl_t tbl,\n\
 htbl_id_t id);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "htbl.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"htbl.h\"\n\
#include \"context.h\"\n\
#include \"bit_stream.h\"\n\
\n\
#define ATTR_ID(a) (1 << a)\n\
\n\
#define NO_ATTRS 12\n\
\n\
const uint16_t ATTR_WIDTH[] = {\n\
  1, /* cyan */\n\
  1, /* blue */\n\
  1, /* pink */\n\
  1,  /* red */\n\
  CHAR_BIT * sizeof(htbl_id_t), /* pred */\n\
  CHAR_BIT * sizeof(mevent_id_t), /* evt*/\n\
  32, /* index */\n\
  32, /* lowlink */\n\
  1, /* live */\n\
  1, /* safe */\n\
  1, /* unsafe successor */\n\
  1  /* to revisit */\n\
};\n\
\n\
const bool_t ATTR_OF_WORKER[] = {\n\
  1, /*  cyan  */\n\
  0,\n\
  1, /*  pink  */\n\
  0,\n\
  0,\n\
  0,\n\
  0,\n\
  0,\n\
  0,\n\
  0,\n\
  0,\n\
  0\n\
};\n\
\n\
#define BUCKET_EMPTY 1\n\
#define BUCKET_READY 2\n\
#define BUCKET_WRITE 3\n\
\n\
#define MAX_TRIALS 10000\n\
\n\
typedef uint8_t bucket_status_t;\n\
\n\
struct struct_htbl_t {\n\
  bool_t hash_compaction;\n\
  uint32_t attrs;\n\
  uint32_t attrs_char_size;\n\
  uint32_t attr_pos[NO_ATTRS];\n\
  uint16_t no_workers;\n\
  uint64_t hash_size;\n\
  heap_t heap;\n\
  hash_key_t * hash;\n\
  bucket_status_t * update_status;\n\
  bucket_status_t * status;\n\
  bit_vector_t hc_attrs;\n\
  bit_vector_t * state;\n\
  uint16_t * state_len;\n\
};\n\
typedef struct struct_htbl_t struct_htbl_t;\n\
\n\
const struct timespec SLEEP_TIME = { 0, 10 };\n\
\n\
#define BIT_STREAM_INIT_ON_ATTRS(tbl, id, bits) {                       \\\n\
    if(tbl->hash_compaction) {                                          \\\n\
      bit_stream_init(bits, tbl->hc_attrs + id * tbl->attrs_char_size); \\\n\
    } else {                                                            \\\n\
      bit_stream_init(bits, tbl->state[id]);                            \\\n\
    }                                                                   \\\n\
  }\n\
\n\
htbl_t htbl_new\n\
(bool_t use_system_heap,\n\
 uint64_t hash_size,\n\
 uint16_t no_workers,\n\
 bool_t hash_compaction,\n\
 uint32_t attrs) {\n\
  const heap_t heap = SYSTEM_HEAP;\n\
  uint64_t i;\n\
  htbl_t result;\n\
  worker_id_t w;\n\
  uint32_t pos = 0, width;\n\
  \n\
  result = mem_alloc(SYSTEM_HEAP, sizeof(struct_htbl_t));\n\
  result->hash_compaction = hash_compaction;\n\
  result->attrs = attrs;\n\
  for(i = 0; i < NO_ATTRS; i ++) {\n\
    if(htbl_has_attr(result, i)) {\n\
      width = ATTR_WIDTH[i];\n\
      if(ATTR_OF_WORKER[i]) {\n\
        width *= no_workers;\n\
      }\n\
      result->attr_pos[i] = pos;\n\
      pos += width;\n\
    }\n\
  }\n\
  result->attrs_char_size = pos / 8;\n\
  if(pos % 8 != 0) {\n\
    result->attrs_char_size ++;\n\
  }  \n\
  result->heap = use_system_heap ? SYSTEM_HEAP : local_heap_new();\n\
  result->no_workers = no_workers;\n\
  result->hash_size = hash_size;\n\
  result->hash = mem_alloc(heap, hash_size * sizeof(hash_key_t));\n\
  result->status = mem_alloc(heap, hash_size * sizeof(bucket_status_t));\n\
  result->update_status = mem_alloc(heap, hash_size * sizeof(bucket_status_t));\n\
  if(hash_compaction) {\n\
    result->hc_attrs = mem_alloc(heap, hash_size * result->attrs_char_size);\n\
    memset(result->hc_attrs, 0, hash_size * result->attrs_char_size);\n\
  } else {\n\
    result->state = mem_alloc(heap, hash_size * sizeof(bit_vector_t));\n\
    result->state_len = mem_alloc(heap, hash_size * sizeof(uint16_t));\n\
  }\n\
  for(i = 0; i < result->hash_size; i++) {\n\
    result->update_status[i] = BUCKET_READY;\n\
    result->status[i] = BUCKET_EMPTY;\n\
    if(!hash_compaction) {\n\
      result->state[i] = NULL;\n\
      result->state_len[i] = 0;\n\
    }\n\
  }\n\
  return result;\n\
\n\
}\n\
\n\
htbl_t htbl_default_new\n\
() {\n\
  uint32_t attrs = 0;\n\
  uint16_t no_workers;\n\
\n\
  /**\n\
   *  check which attributes are enabled according to the\n\
   *  configuration\n\
   */\n\
  attrs |= ATTR_ID(ATTR_CYAN);\n\
  attrs |= ATTR_ID(ATTR_BLUE);\n\
  if(CFG_ACTION_CHECK_LTL) {\n\
    attrs |= ATTR_ID(ATTR_PINK);\n\
    attrs |= ATTR_ID(ATTR_RED);\n\
  }\n\
  if(CFG_ALGO_BFS) {\n\
    attrs |= ATTR_ID(ATTR_PRED);\n\
    attrs |= ATTR_ID(ATTR_EVT);\n\
  }\n\
  if(CFG_ALGO_TARJAN) {\n\
    attrs |= ATTR_ID(ATTR_INDEX);\n\
    attrs |= ATTR_ID(ATTR_LOWLINK);\n\
    attrs |= ATTR_ID(ATTR_LIVE);\n\
    attrs |= ATTR_ID(ATTR_SAFE);\n\
  }\n\
  if(CFG_PROVISO) {\n\
    attrs |= ATTR_ID(ATTR_SAFE);\n\
    attrs |= ATTR_ID(ATTR_UNSAFE_SUCC);\n\
    attrs |= ATTR_ID(ATTR_TO_REVISIT);\n\
  }\n\
  \n\
  no_workers = CFG_NO_WORKERS;\n\
  if(CFG_DISTRIBUTED) {\n\
    no_workers ++;\n\
  }\n\
  return htbl_new(no_workers > 1, CFG_HASH_SIZE, no_workers,\n\
                  CFG_HASH_COMPACTION, attrs);\n\
}\n\
\n\
void htbl_free\n\
(htbl_t tbl) {\n\
  uint64_t i = 0;\n\
  worker_id_t w;\n\
\n\
  if(tbl->hash_compaction) {\n\
    mem_free(SYSTEM_HEAP, tbl->hc_attrs);\n\
  } else {\n\
    for(i = 0; i < tbl->hash_size; i++) {\n\
      if(tbl->state[i]) {\n\
        mem_free(tbl->heap, tbl->state[i]);\n\
      }\n\
    }\n\
    mem_free(SYSTEM_HEAP, tbl->state);\n\
    mem_free(SYSTEM_HEAP, tbl->state_len);\n\
  }\n\
  mem_free(SYSTEM_HEAP, tbl->hash);\n\
  mem_free(SYSTEM_HEAP, tbl->status);\n\
  mem_free(SYSTEM_HEAP, tbl->update_status);\n\
  if(tbl->heap) {\n\
    heap_free(tbl->heap);\n\
  }\n\
  mem_free(SYSTEM_HEAP, tbl);\n\
}\n\
\n\
void htbl_reset\n\
(htbl_t tbl) {\n\
  heap_reset(tbl->heap);\n\
}\n\
\n\
bool_t htbl_contains\n\
(htbl_t tbl,\n\
 state_t s,\n\
 htbl_id_t * id,\n\
 hash_key_t * h) {\n\
  htbl_id_t pos, init_pos;\n\
  bit_vector_t se_other;\n\
  bool_t found;\n\
\n\
  (*h) = state_hash(s);\n\
  init_pos = pos = (*h) % tbl->hash_size;\n\
  while(TRUE) {\n\
    if(tbl->status[pos] == BUCKET_EMPTY) {\n\
      return FALSE;\n\
    }\n\
    while(BUCKET_WRITE == tbl->status[pos]) {\n\
      context_sleep(SLEEP_TIME);\n\
    }\n\
    if(tbl->status[pos] == BUCKET_READY) {\n\
      found = (tbl->hash[pos] == (*h));\n\
      if(found && !tbl->hash_compaction) {\n\
        se_other = tbl->state[pos] + tbl->attrs_char_size;\n\
        found = state_cmp_vector(s, se_other);\n\
      }\n\
      if(found) {\n\
        (*id) = pos;\n\
        return TRUE;\n\
      }\n\
    }\n\
    if((pos = (pos + 1) % tbl->hash_size) == init_pos) {\n\
      return FALSE;\n\
    }\n\
  }\n\
}\n\
\n\
void htbl_insert_real\n\
(htbl_t tbl,\n\
 state_t * s,\n\
 bit_vector_t se,\n\
 uint16_t se_char_len,\n\
 bool_t * is_new,\n\
 htbl_id_t * id,\n\
 hash_key_t * h,\n\
 bool_t h_set) {\n\
  uint32_t trials = 0;\n\
  bit_stream_t bits;\n\
  htbl_id_t pos;\n\
  bit_vector_t se_other;\n\
  bool_t found;\n\
\n\
  /**\n\
   *  compute the hash value\n\
   */\n\
  if(tbl->hash_compaction) {\n\
    if(NULL == se && !h_set) {\n\
      (*h) = state_hash(*s);\n\
    }\n\
  } else {\n\
    if(!h_set) {\n\
      (*h) = state_hash(*s);\n\
    }\n\
  }\n\
  pos = (*h) % tbl->hash_size;\n\
\n\
  while(TRUE) {\n\
      \n\
    /**\n\
     *  we found a bucket where to insert the state => claim it\n\
     */\n\
    if(CAS(&tbl->status[pos], BUCKET_EMPTY, BUCKET_WRITE)) {\n\
\n\
      /**\n\
       *  state insertion\n\
       */\n\
      if(!tbl->hash_compaction) {\n\
        if(NULL == se) {\n\
          se_char_len = state_char_size(*s);\n\
        }\n\
        tbl->state[pos] = mem_alloc0(tbl->heap,\n\
                                     se_char_len + tbl->attrs_char_size);\n\
        if(NULL == se) {\n\
          state_serialise(*s, tbl->state[pos] + tbl->attrs_char_size);\n\
        } else {\n\
          memcpy(tbl->state[pos] + tbl->attrs_char_size, se, se_char_len);\n\
        }\n\
        tbl->state_len[pos] = se_char_len;\n\
      }\n\
      tbl->hash[pos] = *h;\n\
      tbl->status[pos] = BUCKET_READY;\n\
      (*is_new) = TRUE;\n\
      (*id) = pos;\n\
      return;\n\
    }\n\
    \n\
    /**\n\
     *  wait for the bucket to be readable\n\
     */\n\
    while(BUCKET_WRITE == tbl->status[pos]) {\n\
      context_sleep(SLEEP_TIME);\n\
    }\n\
\n\
    /**\n\
     *  the bucket is occupied and readable => compare the state in\n\
     *  the bucket to the state to insert\n\
     */\n\
    if(tbl->status[pos] == BUCKET_READY) {\n\
      found = (tbl->hash[pos] == (*h));\n\
      if(found && !tbl->hash_compaction) {\n\
        se_other = tbl->state[pos] + tbl->attrs_char_size;\n\
        if(NULL == se) {\n\
          found = state_cmp_vector(*s, se_other);\n\
        } else {\n\
          found = 0 == memcmp(se, se_other, se_char_len);\n\
        }\n\
      }\n\
      if(found) {\n\
        (*is_new) = FALSE;\n\
        (*id) = pos;\n\
        return;\n\
      }\n\
    }\n\
\n\
    /**\n\
     *  give up if MAX_TRIALS buckets have been checked\n\
     */\n\
    if((++ trials) == MAX_TRIALS) {\n\
      context_error(\"state table too small (increase --hash-size and rerun)\");\n\
      (*is_new) = FALSE;\n\
      return;\n\
    }\n\
    pos = (pos + 1) % tbl->hash_size;\n\
  }\n\
}\n\
\n\
void htbl_insert\n\
(htbl_t tbl,\n\
 state_t s,\n\
 bool_t * is_new,\n\
 htbl_id_t * id,\n\
 hash_key_t * h) {\n\
  htbl_insert_real(tbl, &s, NULL, 0, is_new, id, h, FALSE);\n\
}\n\
\n\
void htbl_insert_hashed\n\
(htbl_t tbl,\n\
 state_t s,\n\
 hash_key_t h,\n\
 bool_t * is_new,\n\
 htbl_id_t * id) {\n\
  htbl_insert_real(tbl, &s, NULL, 0, is_new, id, &h, TRUE);\n\
}\n\
\n\
void htbl_insert_serialised\n\
(htbl_t tbl,\n\
 bit_vector_t s,\n\
 uint16_t s_char_len,\n\
 hash_key_t h,\n\
 bool_t * is_new,\n\
 htbl_id_t * id) {\n\
  htbl_insert_real(tbl, NULL, s, s_char_len, is_new, id, &h, TRUE);\n\
}\n\
\n\
state_t htbl_get\n\
(htbl_t tbl,\n\
 htbl_id_t id) {\n\
  return htbl_get_mem(tbl, id, SYSTEM_HEAP);\n\
}\n\
\n\
state_t htbl_get_mem\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 heap_t heap) {\n\
  state_t result;\n\
\n\
  assert(!tbl->hash_compaction);\n\
  result = state_unserialise_mem(tbl->state[id] + tbl->attrs_char_size, heap);\n\
  return result;\n\
}\n\
\n\
hash_key_t htbl_get_hash\n\
(htbl_t tbl,\n\
 htbl_id_t id) {\n\
  return tbl->hash[id];\n\
}\n\
\n\
bool_t htbl_has_attr\n\
(htbl_t tbl,\n\
 attr_state_t attr) {\n\
  return (tbl->attrs & ATTR_ID(attr)) ? TRUE : FALSE;\n\
}\n\
\n\
#define HTBL_GET_ATTR(shift) {                                          \\\n\
    const uint32_t pos = tbl->attr_pos[attr];                           \\\n\
    const uint32_t width = ATTR_WIDTH[attr];                            \\\n\
    uint64_t result;                                                    \\\n\
    bit_stream_t bits;                                                  \\\n\
                                                                        \\\n\
    BIT_STREAM_INIT_ON_ATTRS(tbl, id, bits);                            \\\n\
    bit_stream_move(bits, pos + shift);                                 \\\n\
    bit_stream_get(bits, result, width);                                \\\n\
    return result;                                                      \\\n\
}\n\
\n\
uint64_t htbl_get_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr) {\n\
  assert(htbl_has_attr(tbl, attr));\n\
  HTBL_GET_ATTR(0);\n\
}\n\
\n\
uint64_t htbl_get_worker_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr,\n\
 worker_id_t w) {\n\
  assert(htbl_has_attr(tbl, attr));\n\
  HTBL_GET_ATTR(w);\n\
}\n\
\n\
#define HTBL_SET_ATTR(shift) {                                          \\\n\
    const uint32_t pos = tbl->attr_pos[attr];                           \\\n\
    const uint32_t width = ATTR_WIDTH[attr];                            \\\n\
    bit_stream_t bits;                                                  \\\n\
                                                                        \\\n\
    BIT_STREAM_INIT_ON_ATTRS(tbl, id, bits);                            \\\n\
    bit_stream_move(bits, pos + shift);                                 \\\n\
    if(tbl->no_workers > 1) {                                           \\\n\
      while(!CAS(&tbl->update_status[id],                               \\\n\
                 BUCKET_READY, BUCKET_WRITE)) {                         \\\n\
        context_sleep(SLEEP_TIME);                                      \\\n\
      }                                                                 \\\n\
    }                                                                   \\\n\
    bit_stream_set(bits, val, width);                                   \\\n\
    tbl->update_status[id] = BUCKET_READY;                              \\\n\
  }\n\
\n\
void htbl_set_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr,\n\
 uint64_t val) {\n\
  assert(htbl_has_attr(tbl, attr));\n\
  HTBL_SET_ATTR(0);\n\
}\n\
\n\
void htbl_set_worker_attr\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 attr_state_t attr,\n\
 worker_id_t w,\n\
 uint64_t val) {\n\
  assert(htbl_has_attr(tbl, attr));\n\
  HTBL_SET_ATTR(w);\n\
}\n\
\n\
bool_t htbl_get_any_cyan\n\
(htbl_t tbl,\n\
 htbl_id_t id) {\n\
  worker_id_t w;\n\
  \n\
  for(w = 0; w < tbl->no_workers; w ++) {\n\
    if(htbl_get_worker_attr(tbl, id, ATTR_CYAN, w)) {\n\
      return TRUE;\n\
    }\n\
  }\n\
  return FALSE;\n\
}\n\
\n\
void htbl_erase\n\
(htbl_t tbl,\n\
 htbl_id_t id) {\n\
  if(tbl->hash_compaction) {\n\
    memset(tbl->hc_attrs + id * tbl->attrs_char_size, 0, tbl->attrs_char_size);\n\
  } else {\n\
    mem_free(tbl->heap, tbl->state[id]);\n\
    tbl->state[id] = NULL;\n\
  }\n\
  tbl->status[id] = BUCKET_EMPTY;\n\
  tbl->update_status[id] = BUCKET_READY;\n\
}\n\
\n\
void htbl_get_serialised\n\
(htbl_t tbl,\n\
 htbl_id_t id,\n\
 bit_vector_t * s,\n\
 uint16_t * size,\n\
 hash_key_t * h) {\n\
  assert(!tbl->hash_compaction);\n\
  (*s) = tbl->state[id] + tbl->attrs_char_size;\n\
  (*size) = tbl->state_len[id];\n\
  (*h) = tbl->hash[id];\n\
}\n\
\n\
void htbl_fold\n\
(htbl_t tbl,\n\
 htbl_fold_func_t f,\n\
 void * data) {\n\
  state_t s;\n\
  uint64_t pos;\n\
  heap_t h = local_heap_new();\n\
  \n\
  for(pos = 0; pos < tbl->hash_size; pos ++) {\n\
    if(tbl->status[pos] == BUCKET_READY) {\n\
      s = state_unserialise_mem(tbl->state[pos] + tbl->attrs_char_size, h);\n\
      f(s, pos, data);\n\
      state_free(s);\n\
      heap_reset(h);\n\
    }\n\
  }\n\
  heap_free(h);\n\
}\n\
\n\
list_t htbl_get_trace\n\
(htbl_t tbl,\n\
 htbl_id_t id) {\n\
  htbl_id_t id_pred;\n\
  mevent_id_t evt;\n\
  list_t result = list_new(SYSTEM_HEAP, sizeof(mevent_id_t), NULL);\n\
\n\
  assert(htbl_has_attr(tbl, ATTR_PRED));\n\
  while(id != (id_pred = htbl_get_attr(tbl, id, ATTR_PRED))) {\n\
    evt = htbl_get_attr(tbl, id, ATTR_EVT);\n\
    list_prepend(result, &evt);\n\
    id = id_pred;\n\
  }\n\
  return result;\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "heap.h", "w")
    f.write ("\
/**\n\
 * @file heap.h\n\
 * @brief Implementation of various heap structures.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_HEAP\n\
#define LIB_HEAP\n\
\n\
#include \"common.h\"\n\
\n\
#define SYSTEM_HEAP NULL\n\
#define LOCAL_HEAP  0\n\
\n\
void init_heap\n\
();\n\
\n\
typedef uint64_t mem_size_t;\n\
\n\
typedef void * heap_t;\n\
\n\
\n\
/**\n\
 * @brief local_heap_new\n\
 */\n\
heap_t local_heap_new\n\
();\n\
\n\
\n\
/**\n\
 * @brief mem_alloc\n\
 */\n\
void * mem_alloc\n\
(heap_t heap,\n\
 mem_size_t size);\n\
\n\
\n\
/**\n\
 * @brief mem_alloc0\n\
 */\n\
void * mem_alloc0\n\
(heap_t heap,\n\
 mem_size_t size);\n\
\n\
\n\
/**\n\
 * @brief mem_free\n\
 */\n\
void mem_free\n\
(heap_t heap,\n\
 void * ptr);\n\
\n\
\n\
/**\n\
 * @brief heap_reset\n\
 */\n\
void heap_reset\n\
(heap_t heap);\n\
\n\
\n\
/**\n\
 * @brief heap_free\n\
 */\n\
void heap_free\n\
(heap_t heap);\n\
\n\
\n\
/**\n\
 * @brief heap_get_position\n\
 */\n\
mem_size_t heap_get_position\n\
(heap_t heap);\n\
\n\
\n\
/**\n\
 * @brief heap_set_position\n\
 */\n\
void heap_set_position\n\
(heap_t heap,\n\
 mem_size_t pos);\n\
\n\
\n\
/**\n\
 * @brief heap_has_mem_free\n\
 */\n\
bool_t heap_has_mem_free\n\
(heap_t heap);\n\
\n\
\n\
/**\n\
 * @brief heap_size\n\
 */\n\
mem_size_t heap_size\n\
(heap_t heap);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "heap.c", "w")
    f.write ("\
#include \"heap.h\"\n\
\n\
#define LOCAL_HEAP_BLOCK_SIZE 100000\n\
\n\
#define HEAP_TYPES 1\n\
\n\
#define MALLOC(ptr, ptr_type, size) {           \\\n\
    assert(ptr = (ptr_type) malloc(size));      \\\n\
  }\n\
\n\
typedef struct {\n\
  void * data;\n\
  mem_size_t next;\n\
  mem_size_t first;\n\
} local_heap_block_t;\n\
\n\
typedef struct {\n\
  unsigned char type;\n\
  mem_size_t block_size;  \n\
  local_heap_block_t * blocks;\n\
  uint32_t current;\n\
  uint32_t no_blocks;\n\
  mem_size_t pos;\n\
} struct_local_heap_t;\n\
\n\
typedef struct_local_heap_t * local_heap_t;\n\
\n\
heap_t local_heap_new\n\
() {\n\
  local_heap_t result;\n\
  local_heap_block_t block;\n\
  \n\
  MALLOC(result, local_heap_t, sizeof(struct_local_heap_t));\n\
  MALLOC(result->blocks, local_heap_block_t *, sizeof(local_heap_block_t));\n\
  result->type = LOCAL_HEAP;\n\
  result->pos = 0;\n\
  result->block_size = LOCAL_HEAP_BLOCK_SIZE;\n\
  result->current = 0;\n\
  result->no_blocks = 1;\n\
  \n\
  MALLOC(result->blocks[0].data, void *, result->block_size);\n\
  result->blocks[0].first = 0;\n\
  result->blocks[0].next = 0;\n\
  return result;\n\
}\n\
\n\
local_heap_t local_heap_free\n\
(local_heap_t heap) {\n\
  int i;\n\
\n\
  for(i = 0; i < heap->no_blocks; i ++) {\n\
    free(heap->blocks[i].data);\n\
  }\n\
  free(heap->blocks);\n\
  free(heap);\n\
}\n\
\n\
void local_heap_reset\n\
(local_heap_t heap) {\n\
  heap->current = 0;\n\
  heap->pos = 0;\n\
  heap->blocks[0].first = 0;\n\
  heap->blocks[0].next = 0;\n\
}\n\
\n\
mem_size_t local_heap_size\n\
(local_heap_t heap) {\n\
  return heap->pos;\n\
}\n\
\n\
void * local_heap_mem_alloc\n\
(local_heap_t heap,\n\
 mem_size_t size) {\n\
  int i;\n\
  void * result;\n\
  local_heap_block_t * block = &(heap->blocks[heap->current]);\n\
  local_heap_block_t * new_blocks;\n\
\n\
  assert(size <= heap->block_size);\n\
  if(block->next + size > heap->block_size) {\n\
    heap->current ++;\n\
    if(heap->current == heap->no_blocks) {\n\
      MALLOC(new_blocks, local_heap_block_t *,\n\
             (heap->no_blocks * 2) * sizeof(local_heap_block_t));\n\
      for(i = 0; i < heap->no_blocks; i ++) {\n\
        new_blocks[i] = heap->blocks[i];\n\
      }\n\
      heap->no_blocks *= 2;\n\
      for(; i < heap->no_blocks; i ++) {\n\
        MALLOC(new_blocks[i].data, void *, heap->block_size);\n\
      }\n\
      free(heap->blocks);\n\
      heap->blocks = new_blocks;\n\
    }\n\
    block = &(heap->blocks[heap->current]);\n\
    block->first = (heap->blocks[heap->current - 1].first +\n\
                    heap->blocks[heap->current - 1].next);\n\
    block->next = 0;\n\
  }\n\
  result = block->data + block->next;\n\
  block->next += size;\n\
  heap->pos += size;\n\
  return result;\n\
}\n\
\n\
mem_size_t local_heap_get_position\n\
(local_heap_t heap) {\n\
  return heap->pos;\n\
}\n\
\n\
void local_heap_set_position\n\
(local_heap_t heap,\n\
 mem_size_t pos) {\n\
  int i;\n\
  bool_t found = FALSE;\n\
  local_heap_block_t block;\n\
  mem_size_t current = 0;\n\
\n\
  for(i = heap->current; i >= 0 && heap->blocks[i].first > pos; i --);\n\
  assert(i >= 0);\n\
  heap->current = i;\n\
  heap->blocks[i].next = pos - heap->blocks[i].first;\n\
  heap->pos = pos;\n\
}\n\
\n\
void local_heap_mem_free\n\
(local_heap_t heap,\n\
 void * ptr) {\n\
}\n\
\n\
bool_t local_heap_has_mem_free\n\
(local_heap_t heap) {\n\
  return FALSE;\n\
}\n\
\n\
\n\
typedef void(* heap_free_func_t)(void *);\n\
typedef void(* heap_reset_func_t)(void *);\n\
typedef void *(* heap_mem_alloc_func_t)(void *, mem_size_t);\n\
typedef void(* heap_mem_free_func_t)(void *, void *);\n\
typedef mem_size_t(* heap_size_func_t) (void *);\n\
typedef bool_t(* heap_has_mem_free_func_t)(void *);\n\
typedef void(* heap_set_position_func_t)(void *, mem_size_t);\n\
typedef mem_size_t (* heap_get_position_func_t)(void *);\n\
\n\
heap_free_func_t heap_free_funcs[HEAP_TYPES];\n\
heap_reset_func_t heap_reset_funcs[HEAP_TYPES];\n\
heap_mem_alloc_func_t heap_mem_alloc_funcs[HEAP_TYPES];\n\
heap_mem_free_func_t heap_mem_free_funcs[HEAP_TYPES];\n\
heap_size_func_t heap_size_funcs[HEAP_TYPES];\n\
heap_has_mem_free_func_t heap_has_mem_free_funcs[HEAP_TYPES];\n\
heap_set_position_func_t heap_set_position_funcs[HEAP_TYPES];\n\
heap_get_position_func_t heap_get_position_funcs[HEAP_TYPES];\n\
\n\
\n\
/*\n\
 *  generic heap operations\n\
 */\n\
void heap_free\n\
(heap_t heap) {\n\
  if(heap) {\n\
    heap_free_funcs[((char *) heap)[0]](heap);\n\
  }\n\
}\n\
\n\
void heap_reset\n\
(heap_t heap) {\n\
  if(heap) {\n\
    heap_reset_funcs[((char *) heap)[0]](heap);\n\
  }\n\
}\n\
\n\
void * mem_alloc\n\
(heap_t heap,\n\
 mem_size_t size) {\n\
  if(NULL == heap) {\n\
    return malloc(size);\n\
  }\n\
  else {\n\
    return heap_mem_alloc_funcs[((char *) heap)[0]](heap, size);\n\
  }\n\
}\n\
\n\
void * mem_alloc0\n\
(heap_t heap,\n\
 mem_size_t size) {\n\
  void * result = mem_alloc(heap, size);\n\
  memset(result, 0, size);\n\
  return result;\n\
}\n\
\n\
void mem_free\n\
(heap_t heap,\n\
 void * ptr) {\n\
  if(NULL == heap) {\n\
    free(ptr);\n\
  }\n\
  else {\n\
    heap_mem_free_funcs[((char *) heap)[0]](heap, ptr);\n\
  }\n\
}\n\
\n\
mem_size_t heap_get_position\n\
(heap_t heap) {\n\
  if(heap) {\n\
    return heap_get_position_funcs[((char *) heap)[0]](heap);\n\
  } else {\n\
    return 0;\n\
  }\n\
}\n\
\n\
void heap_set_position\n\
(heap_t heap,\n\
 mem_size_t pos) {\n\
  if(heap) {\n\
    heap_set_position_funcs[((char *) heap)[0]](heap, pos);\n\
  }\n\
}\n\
\n\
bool_t heap_has_mem_free\n\
(heap_t heap) {\n\
  if(heap) {\n\
    return heap_has_mem_free_funcs[((char *) heap)[0]](heap);\n\
  } else {\n\
    return TRUE;\n\
  }\n\
}\n\
\n\
mem_size_t heap_size\n\
(heap_t heap) {\n\
  if(heap) {\n\
    return heap_size_funcs[((char *) heap)[0]](heap);\n\
  } else {\n\
    return UINT_MAX;\n\
  }\n\
}\n\
\n\
\n\
void init_heap\n\
() {\n\
  unsigned char t;\n\
\n\
  t = LOCAL_HEAP;\n\
  heap_free_funcs[t] =\n\
    (heap_free_func_t) local_heap_free;\n\
  heap_reset_funcs[t] =\n\
    (heap_reset_func_t) local_heap_reset;\n\
  heap_mem_alloc_funcs[t] =\n\
    (heap_mem_alloc_func_t) local_heap_mem_alloc;\n\
  heap_mem_free_funcs[t] =\n\
    (heap_mem_free_func_t) local_heap_mem_free;\n\
  heap_get_position_funcs[t] =\n\
    (heap_get_position_func_t) local_heap_get_position;\n\
  heap_set_position_funcs[t] =\n\
    (heap_set_position_func_t) local_heap_set_position;\n\
  heap_has_mem_free_funcs[t] =\n\
    (heap_has_mem_free_func_t) local_heap_has_mem_free;\n\
  heap_size_funcs[t] =\n\
    (heap_size_func_t) local_heap_size;\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "graph.h", "w")
    f.write ("\
/**\n\
 * @file graph.h\n\
 * @brief Implementation of graph routines to generate a graph report in a CPN\n\
 *        Tools style.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_GRAPH\n\
#define LIB_GRAPH\n\
\n\
#include \"heap.h\"\n\
\n\
#define GT_NODE 1\n\
#define GT_EDGE 2\n\
\n\
typedef uint8_t edge_num_t;\n\
typedef uint32_t node_t;\n\
\n\
void graph_make_report\n\
(char * in_file,\n\
 char * out_file);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "graph.c", "w")
    f.write ("\
#include \"graph.h\"\n\
#include \"model.h\"\n\
#include \"config.h\"\n\
\n\
#if defined(MODEL_HAS_GRAPH_ROUTINES)\n\
#include \"model_graph.h\"\n\
#else\n\
typedef int model_graph_data_t;\n\
void model_graph_data_init(model_graph_data_t * mdata, uint32_t states) {}\n\
void model_graph_data_free(model_graph_data_t * mdata) {}\n\
void model_graph_data_output(model_graph_data_t mdata, FILE * out) {}\n\
void model_graph_dfs_start(model_graph_data_t mdata) {}\n\
void model_graph_dfs_stop(model_graph_data_t mdata) {}\n\
void model_graph_dfs_push(model_graph_data_t mdata, edge_num_t num,\n\
                          bool_t new_succ) {}\n\
void model_graph_dfs_pop(model_graph_data_t mdata) {}\n\
void model_graph_scc_dfs_start(model_graph_data_t mdata) {}\n\
void model_graph_scc_dfs_stop(model_graph_data_t mdata) {}\n\
void model_graph_scc_dfs_push(model_graph_data_t mdata, edge_num_t num) {}\n\
void model_graph_scc_dfs_pop(model_graph_data_t mdata) {}\n\
void model_graph_scc_enter(model_graph_data_t mdata, bool_t terminal) {}\n\
void model_graph_scc_exit(model_graph_data_t mdata) {}\n\
#endif\n\
\n\
\n\
#define GRAPH_MAX_BFS_LEVELS 65536\n\
\n\
\n\
typedef struct {\n\
  edge_num_t num;\n\
  node_t dest;\n\
} edge_data_t;\n\
\n\
typedef struct {\n\
  uint8_t no_succs;\n\
  edge_data_t * out;\n\
} node_data_t;\n\
\n\
typedef struct {\n\
  unsigned int no_nodes;\n\
  unsigned int no_edges;\n\
  node_data_t * data;\n\
  node_t root;\n\
  heap_t heap;\n\
} struct_graph_t;\n\
\n\
typedef struct_graph_t * graph_t;\n\
\n\
void graph_free\n\
(graph_t graph) {\n\
  unsigned int i;\n\
  for(i = 0; i < graph->no_nodes; i ++) {\n\
    mem_free(graph->heap, graph->data[i].out);\n\
  }\n\
  mem_free(graph->heap, graph->data);\n\
  mem_free(graph->heap, graph);\n\
}\n\
\n\
graph_t graph_load_main\n\
(char * in_file,\n\
 heap_t heap,\n\
 unsigned int max) {\n\
  unsigned int i;\n\
  char t;\n\
  uint8_t no_succs;\n\
  node_t n, o;\n\
  FILE * f = fopen(in_file, \"r\");\n\
  graph_t result = NULL;\n\
  edge_data_t * out;\n\
  edge_num_t num;\n\
\n\
  if(f) {\n\
    result = mem_alloc(heap, sizeof(struct_graph_t));\n\
    result->heap = heap;\n\
    result->no_nodes = 0;\n\
    result->no_edges = 0;\n\
    result->root = 0;\n\
    result->data = mem_alloc(heap, sizeof(node_data_t) * max);\n\
    for(i = 0; i < max; i ++) {\n\
      result->data[i].no_succs = 0;\n\
      result->data[i].out = NULL;\n\
    }\n\
    while(fread(&t, 1, 1, f)) {\n\
      switch(t) {\n\
      case GT_NODE: {\n\
	fread(&n, sizeof(node_t), 1, f);\n\
	if(n >= max) {\n\
	  graph_free(result);\n\
	  fclose(f);\n\
	  return NULL;\n\
	}\n\
	fread(&no_succs, sizeof(uint8_t), 1, f);\n\
	if(!no_succs) {\n\
	  out = NULL;\n\
	} else {\n\
	  out = mem_alloc(heap, sizeof(node_t) * no_succs);\n\
	  for(i = 0; i < no_succs; i ++) {\n\
	    fread(&(out[i].num),  sizeof(edge_num_t), 1, f);\n\
	    fread(&(out[i].dest), sizeof(node_t), 1, f);\n\
	  }\n\
	}\n\
	result->data[n].out = out;\n\
	result->data[n].no_succs = no_succs;\n\
	result->no_nodes ++;\n\
	result->no_edges += no_succs;\n\
	break;\n\
      }\n\
      case GT_EDGE: {\n\
	fread(&n, sizeof(node_t), 1, f);\n\
        if(n >= max) {\n\
          graph_free(result);\n\
          fclose(f);\n\
          return NULL;\n\
        }\n\
	fread(&num, sizeof(edge_num_t), 1, f);\n\
	fread(&o, sizeof(node_t), 1, f);\n\
	out = mem_alloc(heap,\n\
                        sizeof(edge_data_t) * (result->data[n].no_succs + 1));\n\
	for(i = 0; i < result->data[n].no_succs; i ++) {\n\
          out[i] = result->data[n].out[i];\n\
        }\n\
	out[i].dest = o;\n\
	out[i].num = num;\n\
	if(result->data[n].out) {\n\
	  mem_free(heap, result->data[n].out);\n\
	}\n\
	result->data[n].out = out;\n\
	result->data[n].no_succs ++;\n\
	result->no_edges ++;\n\
	break;\n\
      }\n\
      default: {\n\
	printf(\"error: graph_load read an incorrect GT: %d\\n\", t);\n\
        assert(FALSE);\n\
      }\n\
      }\n\
    }\n\
    fclose(f);\n\
  }\n\
  return result;\n\
}\n\
\n\
graph_t graph_load\n\
(char *  in_file,\n\
 heap_t  heap) {\n\
  unsigned int max = 4;\n\
  graph_t result = NULL;\n\
\n\
  while(NULL == result) {\n\
    result = graph_load_main(in_file, heap, max);\n\
    max = max * 2;\n\
  }\n\
  return result;\n\
}\n\
\n\
\n\
\n\
/*\n\
 *  DFS exploration data\n\
 */\n\
typedef struct {\n\
  uint32_t scc_count;\n\
  uint32_t scc_trivial;\n\
  uint32_t scc_terminal;\n\
  uint32_t scc_largest;\n\
  uint32_t front_edges;\n\
  uint32_t cross_edges;\n\
  uint32_t back_edges;\n\
  uint32_t max_stack;\n\
  uint32_t shortest_cycle;\n\
  uint32_t samples;\n\
  uint32_t * stack_samples_id;\n\
  uint32_t * stack_samples_size;\n\
} dfs_data_t;\n\
\n\
/*\n\
 *  degree data\n\
 */\n\
typedef struct {\n\
  float avg;\n\
  uint32_t max_in;\n\
  uint32_t max_out;\n\
  uint32_t degs;\n\
  uint32_t * nodes_per_in;\n\
  uint32_t * nodes_per_out;\n\
} degree_data_t;\n\
\n\
/*\n\
 *  BFS exploration data\n\
 */\n\
typedef struct {\n\
  uint32_t levels;\n\
  uint32_t max_level;\n\
  uint32_t ble;\n\
  uint32_t max_ble;\n\
  float avg_ble;\n\
  uint32_t * states;\n\
  uint32_t * edges;\n\
  uint32_t * ble_lengths;\n\
} bfs_data_t;\n\
\n\
\n\
\n\
/*\n\
 *  Function: graph_degree\n\
 */\n\
void graph_degree \n\
(graph_t graph,\n\
 degree_data_t * data,\n\
 model_graph_data_t mdata) {\n\
  node_data_t * N = graph->data;\n\
  node_t * in_deg;\n\
  int i, j;\n\
\n\
  in_deg = mem_alloc(SYSTEM_HEAP, sizeof(node_t) * graph->no_nodes);\n\
  for(i = 0; i < graph->no_nodes; i ++) {\n\
    in_deg[i] = 0;\n\
  }\n\
\n\
  data->avg = (float) graph->no_edges / (float) graph->no_nodes;\n\
  data->max_in = 0;\n\
  data->max_out = N[graph->root].no_succs;\n\
  for(i = 0; i < graph->no_nodes; i ++) {\n\
    if(data->max_out < N[i].no_succs) {\n\
      data->max_out = N[i].no_succs;\n\
    }\n\
    for(j = 0; j < N[i].no_succs; j ++) {\n\
      if((++ in_deg[N[i].out[j].dest]) > data->max_in) {\n\
	data->max_in = in_deg[N[i].out[j].dest];\n\
      }\n\
    }\n\
  }\n\
  data->degs = data->max_in;\n\
  if(data->max_out > data->degs) {\n\
    data->degs = data->max_out;\n\
  }\n\
  data->nodes_per_in = mem_alloc(SYSTEM_HEAP,\n\
                                 sizeof(uint32_t) * (data->degs + 1));\n\
  data->nodes_per_out = mem_alloc(SYSTEM_HEAP, \n\
                                  sizeof(uint32_t) * (data->degs + 1));\n\
  for(i = 0; i <= data->degs; i ++) {\n\
    data->nodes_per_in[i] = 0;\n\
    data->nodes_per_out[i] = 0;\n\
  }\n\
  for(i = 0; i < graph->no_nodes; i ++) {\n\
    data->nodes_per_in[in_deg[i]] ++;\n\
    data->nodes_per_out[N[i].no_succs] ++;\n\
  }\n\
\n\
  mem_free(SYSTEM_HEAP, in_deg);\n\
}\n\
\n\
\n\
\n\
/*\n\
 *  Function: graph_bfs\n\
 */\n\
void graph_bfs\n\
(graph_t graph,\n\
 bfs_data_t * data,\n\
 model_graph_data_t mdata) {\n\
  uint32_t fst = 0;\n\
  uint32_t last = 0;\n\
  uint32_t old = 1;\n\
  uint32_t current = 1;\n\
  uint32_t next = 0;\n\
  uint32_t edges = 0;\n\
  uint32_t lg;\n\
  uint32_t * depth;\n\
  uint64_t ble_length_sum = 0;\n\
  int i;\n\
  node_t * queue;\n\
  bool_t * visited;\n\
  node_data_t * N = graph->data;\n\
  node_t now, succ;\n\
\n\
  data->levels = 0;\n\
  data->max_level = 1;\n\
  data->ble = 0;\n\
  data->max_ble = 0;\n\
  data->avg_ble = 0.0;\n\
  data->states = mem_alloc(SYSTEM_HEAP,\n\
                           sizeof(uint32_t) * GRAPH_MAX_BFS_LEVELS);\n\
  data->edges = mem_alloc(SYSTEM_HEAP,\n\
                          sizeof(uint32_t) * GRAPH_MAX_BFS_LEVELS);\n\
  data->ble_lengths = mem_alloc(SYSTEM_HEAP,\n\
                                sizeof(uint32_t) * GRAPH_MAX_BFS_LEVELS);\n\
  for(i = 0; i < GRAPH_MAX_BFS_LEVELS; i ++) {\n\
    data->ble_lengths[i] = 0;\n\
  }\n\
\n\
  queue = mem_alloc(SYSTEM_HEAP, sizeof(node_t) * graph->no_nodes);\n\
  depth = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * graph->no_nodes);\n\
  visited = mem_alloc(SYSTEM_HEAP, sizeof(bool_t) * graph->no_nodes);\n\
\n\
  for(i = 0; i < graph->no_nodes; i ++) {\n\
    visited[i] = 0;\n\
  }\n\
  queue[0] = graph->root;\n\
  depth[graph->root] = 0;\n\
  visited[graph->root] = TRUE;\n\
\n\
  while(fst <= last) {\n\
    now = queue[fst];\n\
    for(i = 0; i < N[now].no_succs; i ++) {\n\
      edges ++;\n\
      succ = N[now].out[i].dest;\n\
      if(visited[succ]) {\n\
	if(depth[succ] != data->levels + 1) {\n\
	  data->ble ++;\n\
	  lg = data->levels - depth[succ];\n\
	  ble_length_sum += lg;\n\
	  data->ble_lengths[lg] ++;\n\
	  if(lg > data->max_ble) { data->max_ble = lg; }\n\
	}	\n\
      } else {\n\
	visited[succ] = TRUE;\n\
	depth[succ] = data->levels + 1;\n\
	queue[++ last] = succ;\n\
	next ++;\n\
      }\n\
    }\n\
    fst ++;\n\
    current --;\n\
    if(0 == current) {  /*  BFS level terminated  */\n\
      if(next > data->max_level) { data->max_level = next; }\n\
      data->states[data->levels] = old;\n\
      data->edges[data->levels] = edges;\n\
      data->levels ++;\n\
      old = next;\n\
      current = next;\n\
      next = 0;\n\
      edges = 0;\n\
    }\n\
  }\n\
  data->avg_ble = (float) ble_length_sum / (float) data->ble;\n\
\n\
  mem_free(SYSTEM_HEAP, depth);\n\
  mem_free(SYSTEM_HEAP, queue);\n\
  mem_free(SYSTEM_HEAP, visited);\n\
}\n\
\n\
\n\
\n\
/*\n\
 *  Function: graph_dfs\n\
 */\n\
void graph_dfs\n\
(graph_t graph,\n\
 dfs_data_t * data,\n\
 model_graph_data_t mdata) {\n\
  uint8_t * scc;\n\
  uint8_t * visited;\n\
  uint8_t * next;\n\
  uint32_t * depth;\n\
  uint32_t * index;\n\
  uint32_t * low_link;\n\
  bool_t * scc_terminal;\n\
  uint32_t idx = 0;\n\
  uint32_t scc_size = 1;\n\
  int top = 0, scc_top = 0, i;\n\
  node_data_t * N = graph->data;\n\
  node_t * stack;\n\
  node_t * scc_stack;\n\
  node_t now, succ;\n\
  bool_t loop;\n\
  unsigned int sampling_period = graph->no_nodes / 1000;\n\
  \n\
  if(sampling_period == 0) {\n\
    sampling_period = 1;\n\
  }\n\
\n\
  data->scc_count = 0;\n\
  data->scc_trivial = 0;\n\
  data->scc_terminal = 0;\n\
  data->scc_largest = 0;\n\
  data->shortest_cycle = 0;\n\
  data->front_edges = 0;\n\
  data->cross_edges = 0;\n\
  data->back_edges = 0;\n\
  data->max_stack = 0;\n\
  data->samples = 0;\n\
  data->stack_samples_id =\n\
    mem_alloc(SYSTEM_HEAP,\n\
              sizeof(uint32_t) * graph->no_nodes / sampling_period);\n\
  data->stack_samples_size =\n\
    mem_alloc(SYSTEM_HEAP,\n\
              sizeof(uint32_t) * graph->no_nodes / sampling_period);\n\
\n\
  scc_terminal = mem_alloc(SYSTEM_HEAP, sizeof(bool_t) * graph->no_nodes);\n\
  visited = mem_alloc(SYSTEM_HEAP, sizeof(uint8_t) * graph->no_nodes);\n\
  next = mem_alloc(SYSTEM_HEAP, sizeof(uint8_t) * graph->no_nodes);\n\
  scc = mem_alloc(SYSTEM_HEAP, sizeof(uint8_t) * graph->no_nodes);\n\
  stack = mem_alloc(SYSTEM_HEAP, sizeof(node_t) * graph->no_nodes);\n\
  scc_stack = mem_alloc(SYSTEM_HEAP, sizeof(node_t) * graph->no_nodes);\n\
  depth = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * graph->no_nodes);\n\
  index = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * graph->no_nodes);\n\
  low_link = mem_alloc(SYSTEM_HEAP, sizeof(uint32_t) * graph->no_nodes);\n\
\n\
  data->front_edges = 0;\n\
  data->cross_edges = 0;\n\
  data->back_edges = 0;\n\
  data->max_stack = 0;\n\
\n\
  loop = TRUE;\n\
  for(top = 0; top < graph->no_nodes; top ++) {\n\
    visited[top] = 0;\n\
  }\n\
  top = 0;\n\
  scc_top = 0;\n\
  stack[0] = graph->root;\n\
  next[0] = 0;\n\
  scc_stack[0] = graph->root;\n\
  scc_terminal[0] = TRUE;\n\
  scc[graph->root] = TRUE;\n\
  depth[graph->root] = 0;\n\
  visited[graph->root] = 1;\n\
  index[graph->root] = idx;\n\
  low_link[graph->root] = idx;\n\
  idx ++;\n\
\n\
  /*\n\
   *  main DFS loop\n\
   */\n\
  model_graph_dfs_start(mdata);\n\
  while(loop) {\n\
    now = stack[top];\n\
    if(next[top] >= N[now].no_succs) {  /*  backtrack  */\n\
      visited[now] ++;\n\
      if(index[now] == low_link[now]) {  /*  pop the root of an SCC  */\n\
	scc_size = 0;\n\
	do {\n\
	  now = scc_stack[scc_top];\n\
	  scc[now] = FALSE;\n\
	  scc_top --;\n\
	  scc_size ++;\n\
	} while(scc_top >= 0 && now != stack[top]);\n\
	if(scc_terminal[now]) {\n\
	  data->scc_terminal ++;\n\
	  for(i = top - 1; i >= 0 && scc_terminal[stack[i]]; i --) {\n\
	    scc_terminal[stack[i]] = FALSE;\n\
	  }\n\
	}\n\
	data->scc_count ++;\n\
	if(scc_size == 1) { data->scc_trivial ++; }\n\
	if(scc_size > data->scc_largest) { data->scc_largest = scc_size; }\n\
      }\n\
      if(0 == top) {\n\
	loop = FALSE;\n\
      } else {\n\
	model_graph_dfs_pop(mdata);\n\
	top --;\n\
	if(low_link[stack[top]] > low_link[now]) {\n\
	  low_link[stack[top]] = low_link[now];\n\
	}\n\
      }\n\
    } else {  /*  visit a successor  */\n\
      succ = N[now].out[next[top]].dest;\n\
      next[top] ++;\n\
      model_graph_dfs_push(mdata, N[now].out[next[top] - 1].num,\n\
			   (0 == visited[succ]) ? TRUE : FALSE);\n\
      if(0 == visited[succ]) {  /*  successor is new  */\n\
	top ++;\n\
	scc_top ++;\n\
	next[top] = 0;\n\
	stack[top] = succ;\n\
	scc_stack[scc_top] = succ;\n\
	scc_terminal[succ] = TRUE;\n\
	scc[succ] = TRUE;\n\
	depth[succ] = top;\n\
	visited[succ] ++;\n\
	index[succ] = idx;\n\
	low_link[succ] = idx;\n\
	idx ++;\n\
	if(top + 1 > data->max_stack) { data->max_stack = top + 1; }\n\
	if(0 == idx % sampling_period) {\n\
	  data->stack_samples_id[data->samples] = idx;\n\
	  data->stack_samples_size[data->samples] = top + 1;\n\
	  data->samples ++;\n\
	}\n\
	data->front_edges ++;\n\
      } else {  /*  successor is not new  */\n\
	if(scc[succ]) {\n\
	  if(low_link[now] > index[succ]) {\n\
	    low_link[now] = index[succ];\n\
	  }\n\
	} else {\n\
	  for(i = top; i >= 0 && scc_terminal[stack[i]]; i --) {\n\
	    scc_terminal[stack[i]] = FALSE;\n\
	  }	  \n\
	}\n\
	if(1 == visited[succ]) {  /*  successor is on stack  */\n\
	  data->back_edges ++;\n\
	  if(data->shortest_cycle == 0 ||\n\
             top - depth[succ] + 1 < data->shortest_cycle) {\n\
	    data->shortest_cycle = top - depth[succ] + 1;\n\
	  }\n\
	} else {  /*  successor has left stack  */\n\
	  data->cross_edges ++;\n\
	}\n\
      }\n\
    }\n\
  }\n\
  model_graph_dfs_stop(mdata);\n\
\n\
  /*\n\
   *  main SCC-DFS loop\n\
   */\n\
  loop = TRUE;\n\
  for(top = 0; top < graph->no_nodes; top ++) {\n\
    visited[top] = 0;\n\
  }\n\
  top = 0;\n\
  stack[0] = graph->root;\n\
  next[0] = 0;\n\
  visited[graph->root] = 1;\n\
  model_graph_scc_dfs_start(mdata);\n\
  while(loop) {\n\
    now = stack[top];\n\
    if(index[now] == low_link[now] && next[top] == 0) {\n\
      model_graph_scc_enter(mdata, scc_terminal[now]);\n\
    }\n\
    if(next[top] >= N[now].no_succs) {  /*  backtrack  */\n\
      if(index[now] == low_link[now]) {  /*  pop the root of an SCC  */\n\
	model_graph_scc_exit(mdata);\n\
      }\n\
      if(0 == top) {\n\
	loop = FALSE;\n\
      } else {\n\
	model_graph_scc_dfs_pop(mdata);\n\
	top --;\n\
      }\n\
    } else {  /*  visit a successor  */\n\
      succ = N[now].out[next[top]].dest;\n\
      next[top] ++;\n\
      model_graph_scc_dfs_push(mdata, N[now].out[next[top] - 1].num);\n\
      if(visited[succ]) {  /*  successor is not new  */\n\
	model_graph_scc_dfs_pop(mdata);\n\
      } else {\n\
	top ++;\n\
	next[top] = 0;\n\
	stack[top] = succ;\n\
	visited[succ] = 1;\n\
      }\n\
    }\n\
  }\n\
  model_graph_scc_dfs_stop(mdata);\n\
\n\
  mem_free(SYSTEM_HEAP, depth);\n\
  mem_free(SYSTEM_HEAP, next);\n\
  mem_free(SYSTEM_HEAP, visited);\n\
  mem_free(SYSTEM_HEAP, stack);\n\
  mem_free(SYSTEM_HEAP, index);\n\
  mem_free(SYSTEM_HEAP, low_link);\n\
  mem_free(SYSTEM_HEAP, scc);\n\
  mem_free(SYSTEM_HEAP, scc_stack);\n\
  mem_free(SYSTEM_HEAP, scc_terminal);\n\
}\n\
\n\
\n\
\n\
/*\n\
 *  Function: graph_make_statistics\n\
 */\n\
void graph_make_statistics\n\
(graph_t graph,\n\
 char * out_file) {\n\
\n\
  FILE * f = fopen(out_file, \"w\");\n\
  bfs_data_t B;\n\
  dfs_data_t D;\n\
  degree_data_t E;\n\
  int i;\n\
  model_graph_data_t mdata;\n\
\n\
  model_graph_data_init(&mdata, graph->no_nodes);\n\
\n\
  fprintf(f, \"<?xml version=\\\"1.0\\\" encoding=\\\"ISO-8859-1\\\"?>\\n\");\n\
  fprintf(f, \"<state-space-info>\\n\\n\");\n\
\n\
  fprintf(f, \"<model>%s</model>\\n\", model_name());\n\
  fprintf(f, \"<language>%s</language>\\n\", CFG_LANGUAGE);\n\
  fprintf(f, \"<date>%s</date>\\n\", CFG_DATE);\n\
  fprintf(f, \"<filePath>%s</filePath>\\n\", CFG_FILE_PATH);\n\
#if defined(MODEL_HAS_XML_PARAMETERS)\n\
  model_xml_parameters(f);\n\
#endif\n\
\n\
  fprintf(f, \"<states>%d</states>\\n\", graph->no_nodes);\n\
  fprintf(f, \"<edges>%d</edges>\\n\\n\", graph->no_edges);\n\
\n\
  /*\n\
   *  BFS statistics\n\
   */\n\
  graph_bfs(graph, &B, mdata);\n\
  fprintf(f, \"<bfs-info>\\n\");\n\
  fprintf(f, \"<levels>%d</levels>\\n\", B.levels);\n\
  fprintf(f, \"<max-level>%d</max-level>\\n\", B.max_level);\n\
  fprintf(f, \"<back-level-edges>%d</back-level-edges>\\n\", B.ble);\n\
  fprintf(f, \"<max-back-level-edge>%d</max-back-level-edge>\\n\", B.max_ble);\n\
  fprintf(f, \"<avg-back-level-edge>%.2f</avg-back-level-edge>\\n\", B.avg_ble);\n\
  fprintf(f, \"<bfs-levels>\\n\");\n\
  for(i = 0; i < B.levels; i ++) {\n\
    fprintf(f, \"<level id=\\\"%d\\\">\", i);\n\
    fprintf(f, \"<states>%d</states>\", B.states[i]);\n\
    fprintf(f, \"<edges>%d</edges>\", B.edges[i]);\n\
    fprintf(f, \"</level>\\n\");\n\
  }\n\
  fprintf(f, \"</bfs-levels>\\n\");\n\
  fprintf(f, \"<back-level-lengths>\\n\");\n\
  if(B.ble > 0) {\n\
    for(i = 0; i <= B.max_ble; i ++) {\n\
      fprintf(f, \"<length id=\\\"%d\\\">%.4f</length>\\n\", i,\n\
              100.0 *(float) B.ble_lengths[i] /(float) B.ble);\n\
    }\n\
  }\n\
  fprintf(f, \"</back-level-lengths>\\n\");\n\
  fprintf(f, \"</bfs-info>\\n\\n\");\n\
  mem_free(SYSTEM_HEAP, B.states);\n\
  mem_free(SYSTEM_HEAP, B.edges);\n\
  mem_free(SYSTEM_HEAP, B.ble_lengths);\n\
\n\
  /*\n\
   *  degress statistics\n\
   */\n\
  graph_degree(graph, &E, mdata);\n\
  fprintf(f, \"<degrees>\\n\");\n\
  fprintf(f, \"<avg>%.4f</avg>\\n\", E.avg);\n\
  fprintf(f, \"<max-in>%d</max-in>\\n\", E.max_in);\n\
  fprintf(f, \"<max-out>%d</max-out>\\n\", E.max_out);\n\
  for(i = 0; i <= E.degs; i ++) {\n\
    fprintf(f, \"<degree id=\\\"%d\\\"><in>%d</in><out>%d</out></degree>\\n\",\n\
            i, E.nodes_per_in[i], E.nodes_per_out[i]);\n\
  }\n\
  fprintf(f, \"</degrees>\\n\\n\");\n\
  mem_free(SYSTEM_HEAP, E.nodes_per_in);\n\
  mem_free(SYSTEM_HEAP, E.nodes_per_out);\n\
\n\
  /*\n\
   *  SCC statistics\n\
   */\n\
  graph_dfs(graph, &D, mdata);\n\
  fprintf(f, \"<scc-info>\\n\");\n\
  fprintf(f, \"<count>%d</count>\\n\", D.scc_count);\n\
  fprintf(f, \"<trivial>%d</trivial>\\n\", D.scc_trivial);\n\
  fprintf(f, \"<terminal>%d</terminal>\\n\", D.scc_terminal);\n\
  fprintf(f, \"<largest>%d</largest>\\n\", D.scc_largest);\n\
  fprintf(f, \"</scc-info>\\n\\n\");\n\
\n\
  /*\n\
   *  DFS statistics\n\
   */\n\
  fprintf(f, \"<dfs-info>\\n\");\n\
  for(i = 0; i < D.samples; i ++) {\n\
    fprintf(f, \"<stack-size id=\\\"%d\\\">%.4f</stack-size>\\n\",\n\
            D.stack_samples_id[i],\n\
            100.0 *\n\
	    (float) D.stack_samples_size[i] /(float) graph->no_nodes);\n\
\n\
  }\n\
  fprintf(f, \"<max-stack>%d</max-stack>\\n\", D.max_stack);\n\
  fprintf(f, \"<front-edges>%d</front-edges>\\n\", D.front_edges);\n\
  fprintf(f, \"<back-edges>%d</back-edges>\\n\", D.back_edges);\n\
  fprintf(f, \"<cross-edges>%d</cross-edges>\\n\", D.cross_edges);\n\
  fprintf(f, \"<shortest-cycle>%d</shortest-cycle>\\n\", D.shortest_cycle);\n\
  fprintf(f, \"</dfs-info>\\n\\n\");\n\
  mem_free(SYSTEM_HEAP, D.stack_samples_id);\n\
  mem_free(SYSTEM_HEAP, D.stack_samples_size);\n\
\n\
  /*\n\
   *  model specific data\n\
   */\n\
  model_graph_data_output(mdata, f);\n\
  model_graph_data_free(&mdata);\n\
  \n\
  fprintf(f, \"</state-space-info>\\n\");\n\
  fclose(f);\n\
}\n\
\n\
\n\
\n\
void graph_make_report\n\
(char * in_file,\n\
 char * out_file) {\n\
  graph_t g = graph_load(in_file, SYSTEM_HEAP);\n\
  graph_make_statistics(g, out_file);\n\
  graph_free(g);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "includes.h", "w")
    f.write ("\
/**\n\
 * @file includes.h\n\
 * @brief Single file including all necessary system files.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_INCLUDES\n\
#define LIB_INCLUDES\n\
\n\
/*  for pthread_barrier_t and stdio.h */\n\
#define _XOPEN_SOURCE 700\n\
\n\
#include \"stdio.h\"\n\
#include \"stdlib.h\"\n\
#include \"stdarg.h\"\n\
#include \"limits.h\"\n\
#include \"pthread.h\"\n\
#include \"assert.h\"\n\
#include \"malloc.h\"\n\
#include \"math.h\"\n\
#include \"string.h\"\n\
#include \"limits.h\"\n\
#include \"sys/times.h\"\n\
#include \"sys/time.h\"\n\
#include \"time.h\"\n\
#include \"unistd.h\"\n\
#include \"semaphore.h\"\n\
#include \"signal.h\"\n\
#include \"stdint.h\"\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "list.h", "w")
    f.write ("\
/**\n\
 * @file list.h\n\
 * @brief Implementation of lists.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_LIST\n\
#define LIB_LIST\n\
\n\
#include \"includes.h\"\n\
#include \"heap.h\"\n\
\n\
typedef uint32_t list_index_t;\n\
\n\
typedef uint32_t list_size_t;\n\
\n\
typedef struct struct_list_t * list_t;\n\
\n\
typedef struct struct_list_node_t * list_iter_t;\n\
\n\
typedef void (* list_free_func_t) (void *);\n\
typedef char (* list_pred_func_t) (void *, void *);\n\
typedef void (* list_app_func_t) (void *, void *);\n\
typedef uint32_t (* list_char_size_func_t) (void *);\n\
typedef void (* list_serialise_func_t) (void *, char *);\n\
typedef void (* list_unserialise_func_t) (char *, heap_t, void *);\n\
typedef int (* list_item_cmp_func_t) (void *, void *);\n\
\n\
\n\
/**\n\
 * @brief list_new\n\
 */\n\
list_t list_new\n\
(heap_t heap,\n\
 uint32_t sizeof_item,\n\
 list_free_func_t free_func);\n\
\n\
\n\
/**\n\
 * @brief list_is_empty\n\
 */\n\
char list_is_empty\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_size\n\
 */\n\
list_size_t list_size\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_free\n\
 */\n\
void list_free\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_reset\n\
 */\n\
void list_reset\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_copy\n\
 */\n\
list_t list_copy\n\
(list_t list,\n\
 heap_t heap,\n\
 list_free_func_t free_func);\n\
\n\
\n\
/**\n\
 * @brief list_first\n\
 */\n\
void * list_first\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_last\n\
 */\n\
void * list_last\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_nth\n\
 */\n\
void * list_nth\n\
(list_t list,\n\
 list_index_t n);\n\
\n\
\n\
/**\n\
 * @brief list_app\n\
 */\n\
void list_app\n\
(list_t list,\n\
 list_app_func_t app_func,\n\
 void * data);\n\
\n\
\n\
/**\n\
 *  @brief list_prepend\n\
 */\n\
void list_prepend\n\
(list_t list,\n\
 void * item);\n\
\n\
\n\
/**\n\
 *  @brief list_append\n\
 */\n\
void list_append\n\
(list_t list,\n\
 void * item);\n\
\n\
\n\
/**\n\
 * @brief list_insert_sorted\n\
 */\n\
void list_insert_sorted\n\
(list_t list,\n\
 void * item,\n\
 list_item_cmp_func_t item_cmp_func);\n\
\n\
\n\
/**\n\
 *  @brief list_pick_last\n\
 */\n\
void list_pick_last\n\
(list_t list,\n\
 void * item);\n\
\n\
\n\
/**\n\
 *  @brief list_pick_first\n\
 */\n\
void list_pick_first\n\
(list_t list,\n\
 void * item);\n\
\n\
\n\
/**\n\
 *  @brief list_pick_random\n\
 */\n\
void list_pick_random\n\
(list_t list,\n\
 void * item,\n\
 rseed_t * seed);\n\
\n\
\n\
/**\n\
 *  @brief list_find\n\
 */\n\
void * list_find\n\
(list_t list,\n\
 list_pred_func_t pred_func,\n\
 void * find_data);\n\
\n\
\n\
/**\n\
 *  @brief list_filter\n\
 */\n\
void list_filter\n\
(list_t list,\n\
 list_pred_func_t pred_func,\n\
 void * filter_data);\n\
\n\
\n\
/**\n\
 *  @brief list_char_size\n\
 */\n\
uint32_t list_char_size\n\
(list_t list,\n\
 list_char_size_func_t char_size_func);\n\
\n\
\n\
/**\n\
 *  @brief list_serialise\n\
 */\n\
void list_serialise\n\
(list_t list,\n\
 char * data,\n\
 list_char_size_func_t char_size_func,\n\
 list_serialise_func_t serialise_func);\n\
\n\
\n\
/**\n\
 *  @brief list_unserialise\n\
 */\n\
\n\
list_t list_unserialise\n\
(heap_t heap,\n\
 uint32_t sizeof_item,\n\
 list_free_func_t free_func,\n\
 char * data,\n\
 list_char_size_func_t char_size_func,\n\
 list_unserialise_func_t unserialise_func);\n\
\n\
\n\
/**\n\
 * @brief list_get_iter\n\
 */\n\
list_iter_t list_get_iter\n\
(list_t list);\n\
\n\
\n\
/**\n\
 * @brief list_iter_next\n\
 */\n\
list_iter_t list_iter_next\n\
(list_iter_t it);\n\
\n\
\n\
/**\n\
 * @brief list_iter_at_end\n\
 */\n\
char list_iter_at_end\n\
(list_iter_t it);\n\
\n\
\n\
/**\n\
 * @brief list_iter_item\n\
 */\n\
void * list_iter_item\n\
(list_iter_t it);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "list.c", "w")
    f.write ("\
#include \"list.h\"\n\
\n\
struct struct_list_node_t {\n\
  void * item;\n\
  struct struct_list_node_t * prev;\n\
  struct struct_list_node_t * next;\n\
};\n\
typedef struct struct_list_node_t struct_list_node_t;\n\
typedef struct_list_node_t * list_node_t;\n\
\n\
struct struct_list_t {\n\
  heap_t heap;\n\
  list_size_t no_items;\n\
  list_node_t first;\n\
  list_node_t last;\n\
  uint32_t sizeof_item;\n\
  list_free_func_t free_func;  \n\
};\n\
\n\
typedef struct struct_list_t struct_list_t;\n\
\n\
list_t list_new\n\
(heap_t heap,\n\
 uint32_t sizeof_item,\n\
 list_free_func_t free_func) {\n\
  list_t result;\n\
\n\
  result = mem_alloc(heap, sizeof(struct_list_t));\n\
  result->heap = heap;\n\
  result->no_items = 0;\n\
  result->first = NULL;\n\
  result->last = NULL;\n\
  result->free_func = free_func;\n\
  result->sizeof_item = sizeof_item;\n\
  return result;\n\
}\n\
\n\
void list_free\n\
(list_t list) {\n\
  list_node_t ptr = list->first, next;\n\
\n\
  if(heap_has_mem_free(list->heap)) {\n\
    while(ptr) {\n\
      next = ptr->next;\n\
      if(list->free_func) {\n\
        list->free_func(ptr->item);\n\
      }\n\
      mem_free(list->heap, ptr->item);\n\
      mem_free(list->heap, ptr);\n\
      ptr = next;\n\
    }\n\
    mem_free(list->heap, list);\n\
  }\n\
}\n\
\n\
void list_reset\n\
(list_t list) {\n\
  list_node_t ptr = list->first, next;\n\
\n\
  if(heap_has_mem_free(list->heap)) {\n\
    while(ptr) {\n\
      next = ptr->next;\n\
      if(list->free_func) {\n\
        list->free_func(ptr->item);\n\
      }\n\
      mem_free(list->heap, ptr->item);\n\
      mem_free(list->heap, ptr);\n\
      ptr = next;\n\
    }\n\
  }\n\
  list->no_items = 0;\n\
  list->first = NULL;\n\
  list->last = NULL;\n\
}\n\
\n\
char list_is_empty\n\
(list_t list) {\n\
  return 0 == list->no_items;\n\
}\n\
\n\
list_size_t list_size\n\
(list_t list) {\n\
  return list->no_items;\n\
}\n\
\n\
list_t list_copy\n\
(list_t list,\n\
 heap_t heap,\n\
 list_free_func_t free_func) {\n\
  list_t result;\n\
  list_node_t ptr;\n\
\n\
  result = list_new(heap, list->sizeof_item, free_func);\n\
  for(ptr = list->first; ptr; ptr = ptr->next) {\n\
    list_append(result, ptr->item);\n\
  }\n\
  return result;\n\
}\n\
\n\
void * list_first\n\
(list_t list) {\n\
  void * result;\n\
\n\
  assert(list->first);\n\
  return list->first->item;\n\
}\n\
\n\
void * list_last\n\
(list_t list) {\n\
  assert(list->last);\n\
  return list->last->item;\n\
}\n\
\n\
void * list_nth\n\
(list_t list,\n\
 list_index_t n) {\n\
  void * result;\n\
  list_node_t ptr = list->first;\n\
  list_index_t i = n;\n\
  \n\
  while(i) {\n\
    assert(ptr);\n\
    ptr = ptr->next;\n\
    i --;\n\
  }\n\
  assert(ptr);\n\
  return ptr->item;\n\
}\n\
\n\
void list_app\n\
(list_t list,\n\
 list_app_func_t app_func,\n\
 void * data) {\n\
  list_node_t ptr = list->first;\n\
\n\
  while(ptr) {\n\
    app_func(ptr->item, data);\n\
    ptr = ptr->next;\n\
  }\n\
}\n\
\n\
void list_prepend\n\
(list_t list,\n\
 void * item) {\n\
  list_node_t ptr = mem_alloc(list->heap, sizeof(struct_list_node_t));\n\
\n\
  ptr->item = mem_alloc(list->heap, list->sizeof_item);\n\
  memcpy(ptr->item, item, list->sizeof_item);\n\
  ptr->prev = NULL;\n\
  if(!list->first) {\n\
    ptr->next = NULL;\n\
    list->first = ptr;\n\
    list->last = ptr;\n\
  } else {\n\
    ptr->next = list->first;\n\
    list->first->prev = ptr;\n\
    list->first = ptr;\n\
  }\n\
  list->no_items ++;\n\
}\n\
\n\
void list_append\n\
(list_t list,\n\
 void * item) {\n\
  list_node_t ptr = mem_alloc(list->heap, sizeof(struct_list_node_t));\n\
\n\
  ptr->item = mem_alloc(list->heap, list->sizeof_item);\n\
  memcpy(ptr->item, item, list->sizeof_item);\n\
  ptr->next = NULL;\n\
  if(!list->first) {\n\
    ptr->prev = NULL;\n\
    list->first = ptr;\n\
    list->last = ptr;\n\
  } else {\n\
    ptr->prev = list->last;\n\
    list->last->next = ptr;\n\
    list->last = ptr;\n\
  }\n\
  list->no_items ++;\n\
}\n\
\n\
void list_insert_sorted\n\
(list_t list,\n\
 void * item,\n\
 list_item_cmp_func_t item_cmp_func) {\n\
  list_node_t ptr = list->first;\n\
  list_node_t new_node;\n\
  int cmp = 1;\n\
\n\
  while(ptr && (cmp = item_cmp_func(ptr->item, item)) == -1) {\n\
    ptr = ptr->next;\n\
  }\n\
  if(cmp != 0) {\n\
    if(ptr == list->first) {\n\
      list_prepend(list, item);\n\
    } else if(NULL == ptr) {\n\
      list_append(list, item);\n\
    } else {\n\
      new_node = mem_alloc(list->heap, sizeof(struct_list_node_t));\n\
      new_node->item = mem_alloc(list->heap, list->sizeof_item);\n\
      memcpy(new_node->item, item, list->sizeof_item);\n\
      new_node->prev = ptr->prev;\n\
      new_node->next = ptr;\n\
      ptr->prev->next = new_node;\n\
      ptr->prev = new_node;\n\
      list->no_items ++;\n\
    }\n\
  }\n\
}\n\
\n\
void list_pick_last\n\
(list_t list,\n\
 void * item) {\n\
  assert(list->last);\n\
  if(item) {\n\
    memcpy(item, list->last->item, list->sizeof_item);\n\
  }\n\
  mem_free(list->heap, list->last->item);\n\
  if(list->first == list->last) {\n\
    mem_free(list->heap, list->first);\n\
    list->first = NULL;\n\
    list->last = NULL;\n\
  } else {\n\
    list->last = list->last->prev;\n\
    mem_free(list->heap, list->last->next);\n\
    list->last->next = NULL;\n\
  }\n\
  list->no_items --;  \n\
}\n\
\n\
void list_pick_first\n\
(list_t list,\n\
 void * item) {\n\
  assert(list->first);\n\
  if(item) {\n\
    memcpy(item, list->first->item, list->sizeof_item);\n\
  }\n\
  mem_free(list->heap, list->first->item);\n\
  if(list->first == list->last) {\n\
    mem_free(list->heap, list->first);\n\
    list->first = NULL;\n\
    list->last = NULL;\n\
  } else {\n\
    list->first = list->first->next;\n\
    mem_free(list->heap, list->first->prev);\n\
    list->first->prev = NULL;\n\
  }\n\
  list->no_items --;\n\
}\n\
\n\
void list_pick_random\n\
(list_t list,\n\
 void * item,\n\
 rseed_t * seed) {\n\
  list_node_t ptr = list->first;\n\
  uint32_t rnd = random_int(seed) % list->no_items;\n\
\n\
  while(rnd) {\n\
    ptr = ptr->next;\n\
    rnd --;\n\
  }\n\
  if(item) {\n\
    memcpy(item, ptr->item, list->sizeof_item);\n\
  }\n\
  mem_free(list->heap, ptr->item);\n\
  if(ptr->prev) {\n\
    ptr->prev->next = ptr->next;\n\
  } else {\n\
    list->first = ptr->next;\n\
  }\n\
  if(ptr->next) {\n\
    ptr->next->prev = ptr->prev;\n\
  } else {\n\
    list->last = ptr->next;\n\
  }\n\
  mem_free(list->heap, ptr);\n\
  list->no_items --;\n\
}\n\
\n\
void * list_find\n\
(list_t list,\n\
 list_pred_func_t pred_func,\n\
 void * find_data) {\n\
  void * result = NULL;\n\
  list_node_t ptr = list->first;\n\
\n\
  while(ptr && !result) {\n\
    if(pred_func(ptr->item, find_data)) {\n\
      result = ptr->item;\n\
    }\n\
    ptr = ptr->next;\n\
  }\n\
  return result;\n\
}\n\
\n\
void list_filter\n\
(list_t list,\n\
 list_pred_func_t pred_func,\n\
 void * filter_data) {\n\
  list_node_t ptr = list->first, next, prev;\n\
\n\
  prev = NULL;\n\
  while(ptr) {\n\
    next = ptr->next;\n\
    if(!pred_func(ptr->item, filter_data)) {\n\
      prev = ptr;\n\
    } else {\n\
      if(prev) {\n\
	prev->next = next;\n\
	if(next) {\n\
	  next->prev = prev;\n\
	} else {\n\
	  list->last = prev;\n\
	}\n\
      } else {\n\
	list->first = next;\n\
	if(next) {\n\
	  next->prev = NULL;\n\
	}\n\
      }\n\
      mem_free(list->heap, ptr->item);\n\
      mem_free(list->heap, ptr);\n\
      list->no_items --;\n\
    }\n\
    ptr = next;\n\
  }\n\
}\n\
\n\
uint32_t list_char_size\n\
(list_t list,\n\
 list_char_size_func_t char_size_func) {\n\
  uint32_t result = sizeof(list_size_t);\n\
  list_node_t ptr = list->first;\n\
\n\
  while(ptr) {\n\
    result += char_size_func(ptr->item);\n\
    ptr = ptr->next;\n\
  }\n\
  return result;\n\
}\n\
\n\
void list_serialise\n\
(list_t list,\n\
 char * data,\n\
 list_char_size_func_t char_size_func,\n\
 list_serialise_func_t serialise_func) {\n\
  const list_size_t size = list->no_items;\n\
  list_node_t ptr = list->first;\n\
  uint32_t pos = sizeof(list_size_t);\n\
\n\
  memcpy(data, &size, sizeof(list_size_t));\n\
  while(ptr) {\n\
    serialise_func(ptr->item, data + pos);\n\
    pos += char_size_func(ptr->item);\n\
    ptr = ptr->next;\n\
  }\n\
}\n\
\n\
list_t list_unserialise\n\
(heap_t heap,\n\
 uint32_t sizeof_item,\n\
 list_free_func_t free_func,\n\
 char * data,\n\
 list_char_size_func_t char_size_func,\n\
 list_unserialise_func_t unserialise_func) {\n\
  list_node_t ptr, prev = NULL;\n\
  list_t result = list_new(heap, sizeof_item, free_func);\n\
  uint32_t size, pos;\n\
\n\
  memcpy(&size, data, sizeof(list_size_t));\n\
  pos = sizeof(list_size_t);\n\
  result->no_items = size;\n\
  while(size) {\n\
    ptr = mem_alloc(heap, sizeof(struct_list_node_t));\n\
    if(!result->first) {\n\
      result->first = ptr;\n\
    }\n\
    if(prev) {\n\
      prev->next = ptr;\n\
    }\n\
    ptr->prev = prev;\n\
    ptr->next = NULL;\n\
    ptr->item = mem_alloc(heap, result->sizeof_item);\n\
    unserialise_func(data + pos, heap, ptr->item);\n\
    pos += char_size_func(ptr->item);\n\
    size --;\n\
    prev = ptr;\n\
  }\n\
  result->last = ptr;\n\
  return result;\n\
}\n\
\n\
list_iter_t list_get_iter\n\
(list_t list) {\n\
  return list->first;\n\
}\n\
\n\
list_iter_t list_iter_next\n\
(list_iter_t it) {\n\
  return it->next;\n\
}\n\
\n\
char list_iter_at_end\n\
(list_iter_t it) {\n\
  if(it) {\n\
    return 0;\n\
  } else {\n\
    return 1;\n\
  }\n\
}\n\
\n\
void * list_iter_item\n\
(list_iter_t it) {\n\
  return it->item;\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "main.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"context.h\"\n\
#include \"dfs.h\"\n\
#include \"bfs.h\"\n\
#include \"delta_ddd.h\"\n\
#include \"simulator.h\"\n\
#include \"rwalk.h\"\n\
#include \"graph.h\"\n\
#include \"bit_stream.h\"\n\
#include \"comm_shmem.h\"\n\
#include \"papi_stats.h\"\n\
\n\
int main\n\
(int argc,\n\
 char ** argv) {\n\
  int i;\n\
  double comp_time;\n\
\n\
  /**\n\
   * initialisation of all libraries\n\
   */\n\
  init_heap();\n\
  init_bit_stream();\n\
  init_model();\n\
  if(CFG_DISTRIBUTED) {\n\
    init_comm_shmem();\n\
  }\n\
  if(CFG_WITH_PAPI) {\n\
    init_papi_stats();\n\
  }\n\
  init_context();\n\
\n\
  if(CFG_ACTION_SIMULATE) { \n\
    simulator();\n\
  } else {\n\
\n\
    /**\n\
     * get compilation time from command line\n\
     */\n\
    for(i = 1; i < argc; i += 2) {\n\
      if(0 == strcmp(argv[i], \"comp-time\")) {\n\
        sscanf(argv[i + 1], \"%lf\", &comp_time);\n\
        context_set_stat(STAT_COMP_TIME, 0, comp_time * 1000000.0);\n\
      }\n\
    }\n\
\n\
    /**\n\
     * catch SIGINT by changing the context state\n\
     */\n\
    signal(SIGINT, context_interruption_handler);\n\
    \n\
    /**\n\
     * launch the appropriate search algorithm\n\
     */\n\
    if(CFG_ALGO_BFS || CFG_ALGO_DBFS) {\n\
      bfs();\n\
    } else if(CFG_ALGO_DFS || CFG_ALGO_DDFS || CFG_ALGO_TARJAN) {\n\
      dfs();\n\
    } else if(CFG_ALGO_DELTA_DDD) {\n\
      delta_ddd();\n\
    } else if(CFG_ALGO_RWALK) {\n\
      rwalk();\n\
    }\n\
\n\
    /**\n\
     * generation of the reachability graph report\n\
     */\n\
    if(CFG_ACTION_BUILD_GRAPH\n\
       && TERM_SEARCH_TERMINATED == context_termination_state()) {\n\
      graph_make_report(CFG_GRAPH_FILE, CFG_RG_REPORT_FILE);\n\
    }\n\
    \n\
    /**\n\
     * termination of all libraries\n\
     */\n\
    finalise_context();\n\
    if(CFG_DISTRIBUTED) {\n\
      finalise_comm_shmem();\n\
    }\n\
    if(CFG_WITH_PAPI) {\n\
      finalise_papi_stats();\n\
    }\n\
  }\n\
\n\
  exit(EXIT_SUCCESS);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "observer.h", "w")
    f.write ("\
/**\n\
 * @file observer.h\n\
 * @brief Implementation of an observer thread that periodically prints some\n\
 *        statistics during the search.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_OBSERVER\n\
#define LIB_OBSERVER\n\
\n\
#include \"includes.h\"\n\
\n\
\n\
/**\n\
 * @brief Code of the observer thread.\n\
 * @param arg - ignored\n\
 * @return always NULL\n\
 */\n\
void * observer_worker\n\
(void * arg);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "observer.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"observer.h\"\n\
#include \"context.h\"\n\
#include \"bfs.h\"\n\
#include \"delta_ddd.h\"\n\
#include \"dfs.h\"\n\
#include \"rwalk.h\"\n\
\n\
void * observer_worker\n\
(void * arg) {\n\
  float time = 0;\n\
  struct timeval now;\n\
  float mem, cpu, cpu_avg = 0;\n\
  double processed;\n\
  double stored;\n\
  char name[100], pref[100];\n\
  int n = 0;\n\
 \n\
  pref[0] = 0;  \n\
  if(CFG_WITH_OBSERVER) {\n\
    if(CFG_DISTRIBUTED) {\n\
      gethostname(name, 1024);\n\
      sprintf(pref, \"[%s:%d] \", name, getpid());\n\
    }\n\
    printf(\"%sRunning...\\n\", pref);\n\
  }\n\
  while(context_keep_searching()) {\n\
    n ++;\n\
    sleep(1);\n\
    gettimeofday(&now, NULL);\n\
    mem = mem_usage();\n\
    cpu = context_cpu_usage();\n\
    if(context_keep_searching()) {\n\
      cpu_avg = (cpu + (n - 1) * cpu_avg) / n;\n\
    }\n\
    processed = context_get_stat(STAT_STATES_PROCESSED);\n\
    stored = context_get_stat(STAT_STATES_STORED);\n\
    context_set_stat(STAT_MAX_MEM_USED, 0, mem);\n\
    time = ((float) duration(context_start_time(), now)) / 1000000.0;\n\
    if(CFG_WITH_OBSERVER) {\n\
      printf(\"\\n%sTime elapsed    :   %8.2f s.\\n\", pref, time);\n\
      printf(\"%sStates stored   :%'11llu\\n\", pref, (uint64_t) stored);\n\
      printf(\"%sStates processed:%'11llu\\n\", pref, (uint64_t) processed);\n\
      printf(\"%sMemory usage    :   %8.1f MB.\\n\", pref, mem);\n\
      printf(\"%sCPU usage       :   %8.2f %c\\n\", pref, cpu, '%');\n\
    }\n\
    \n\
    /*\n\
     *  check for limits\n\
     */\n\
    if(CFG_MEMORY_LIMITED && mem > CFG_MAX_MEMORY) {\n\
      context_set_termination_state(TERM_MEMORY_EXHAUSTED);\n\
    }\n\
    if(CFG_TIME_LIMITED && time > (float) CFG_MAX_TIME) {\n\
      context_set_termination_state(TERM_TIME_ELAPSED);\n\
    }\n\
    if(CFG_STATE_LIMITED && processed > CFG_MAX_STATE) {\n\
      context_set_termination_state(TERM_STATE_LIMIT_REACHED);\n\
    }\n\
  }\n\
  if(cpu_avg != 0) {\n\
    context_set_stat(STAT_AVG_CPU_USAGE, 0, cpu_avg);\n\
  }\n\
\n\
  if(CFG_WITH_OBSERVER) {\n\
    printf(\"\\n%sdone.\\n\", pref);\n\
  }\n\
  return NULL;\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "papi_stats.h", "w")
    f.write ("\
/**\n\
 * @file bfs.h\n\
 * @brief \n\
 * @date 16 oct 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_PAPI_STATS\n\
#define LIB_PAPI_STATS\n\
\n\
\n\
/**\n\
 * @brief init_papi_stats\n\
 */\n\
void init_papi_stats\n\
();\n\
\n\
\n\
/**\n\
 * @brief finalise_papi_stats\n\
 */\n\
void finalise_papi_stats\n\
();\n\
\n\
\n\
/**\n\
 * @brief papi_stats_output\n\
 */\n\
void papi_stats_output\n\
(FILE * f);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "papi_stats.c", "w")
    f.write ("\
#include \"includes.h\"\n\
#include \"common.h\"\n\
#include \"config.h\"\n\
#include \"papi_stats.h\"\n\
\n\
#if CFG_WITH_PAPI == 1\n\
#include \"papi.h\"\n\
\n\
#define PAPI_STATS_NO_EVENTS 6\n\
int PAPI_STATS_ALL_EVENTS [PAPI_STATS_NO_EVENTS] = {\n\
  PAPI_L1_TCM,\n\
  PAPI_L1_TCH,\n\
  PAPI_L2_TCM,\n\
  PAPI_L2_TCH,\n\
  PAPI_L3_TCM,\n\
  PAPI_L3_TCH\n\
};\n\
int PAPI_STATS_EVENT_SET;\n\
int PAPI_STATS_EVENTS[PAPI_STATS_NO_EVENTS];\n\
#endif\n\
\n\
\n\
void init_papi_stats\n\
() {\n\
  int i, rc, n;\n\
  \n\
#if CFG_WITH_PAPI == 1\n\
  if(PAPI_library_init(PAPI_VER_CURRENT) != PAPI_VER_CURRENT) {\n\
    /*  do something here  */\n\
  } else {\n\
    PAPI_STATS_EVENT_SET = PAPI_NULL;\n\
    if((rc = PAPI_create_eventset(&PAPI_STATS_EVENT_SET)) != PAPI_OK) {\n\
      assert(0);\n\
    } else {\n\
      for(n = 0, i = 0; i < PAPI_STATS_NO_EVENTS; i ++) {\n\
        rc = PAPI_add_event(PAPI_STATS_EVENT_SET, PAPI_STATS_ALL_EVENTS[i]);\n\
        if(rc != PAPI_OK) {\n\
          /*  do something here  */\n\
        } else {\n\
          PAPI_STATS_EVENTS[n ++] = PAPI_STATS_ALL_EVENTS[i];\n\
        }\n\
      }\n\
      PAPI_start(PAPI_STATS_EVENT_SET);\n\
    }\n\
  }\n\
#endif\n\
}\n\
\n\
\n\
void finalise_papi_stats\n\
() {\n\
#if CFG_WITH_PAPI == 1\n\
  if(PAPI_is_initialized()) {\n\
    PAPI_shutdown();\n\
  }\n\
#endif\n\
}\n\
\n\
\n\
void papi_stats_get_stat_name\n\
(int stat,\n\
 char * name) {\n\
#if CFG_WITH_PAPI == 1\n\
  switch(stat) {\n\
  case PAPI_L1_TCM: sprintf(name, \"lvl1TotalCacheMiss\"); break;\n\
  case PAPI_L1_TCH: sprintf(name, \"lvl1TotalCacheHit\"); break;\n\
  case PAPI_L2_TCM: sprintf(name, \"lvl2TotalCacheMiss\"); break;\n\
  case PAPI_L2_TCH: sprintf(name, \"lvl2TotalCacheHit\"); break;\n\
  case PAPI_L3_TCM: sprintf(name, \"lvl3TotalCacheMiss\"); break;\n\
  case PAPI_L3_TCH: sprintf(name, \"lvl3TotalCacheHit\"); break;\n\
  default: assert(0);\n\
  }\n\
#endif\n\
}\n\
\n\
void papi_stats_output\n\
(FILE * f) {  \n\
#if CFG_WITH_PAPI == 1\n\
  int i, rc, n;\n\
  long long values[PAPI_STATS_NO_EVENTS];\n\
  char stat_name[256];\n\
  \n\
  n = PAPI_num_events(PAPI_STATS_EVENT_SET);\n\
  PAPI_stop(PAPI_STATS_EVENT_SET, values);\n\
  fprintf(f, \"<papiStatistics>\\n\");\n\
  for(i = 0; i < n; i ++) {\n\
    papi_stats_get_stat_name(PAPI_STATS_EVENTS[i], stat_name);\n\
    fprintf(f, \"<%s>%llu</%s>\\n\", stat_name, values[i], stat_name);\n\
  }\n\
  fprintf(f, \"</papiStatistics>\\n\");\n\
#endif\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "por_analysis.h", "w")
    f.write ("\
#include \"model.h\"\n\
#include \"htbl.h\"\n\
#include \"darray.h\"\n\
\n\
#ifndef LIB_POR_ANALYSIS\n\
#define LIB_POR_ANALYSIS\n\
\n\
void por_analysis_scc\n\
(htbl_t H,\n\
 darray_t scc);\n\
\n\
uint64_t por_analysis_no_unsafe_states\n\
();\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "por_analysis.c", "w")
    f.write ("\
#include \"common.h\"\n\
#include \"por_analysis.h\"\n\
#include \"reduction.h\"\n\
\n\
uint64_t POR_ANALYSIS_NO_UNSAFE_STATES = 0;\n\
\n\
uint64_t por_analysis_no_unsafe_states\n\
() {\n\
  return POR_ANALYSIS_NO_UNSAFE_STATES;\n\
}\n\
\n\
bool_t por_analysis_state_is_unsafe\n\
(darray_t unsafe,\n\
 htbl_id_t id) {\n\
  int i;\n\
\n\
  for(i = 0; i < darray_size(unsafe); i ++) {\n\
    if(id == * ((htbl_id_t *) darray_get(unsafe, i))) {\n\
      return TRUE;\n\
    }\n\
  }\n\
  return FALSE;\n\
}\n\
\n\
void por_analysis_scc\n\
(htbl_t H,\n\
 darray_t scc) {\n\
  uint32_t i;\n\
  state_t s, succ;\n\
  htbl_id_t id, id_succ;\n\
  bool_t changes = TRUE, reduced;\n\
  heap_t heap = local_heap_new();\n\
  list_t en;\n\
  event_t e;\n\
  hash_key_t h;\n\
  bool_t all_succ_safe;\n\
  darray_t unsafe = darray_new(SYSTEM_HEAP, sizeof(htbl_id_t));\n\
\n\
  /*\n\
   * initialise the set of unsafe states of the scc\n\
   */\n\
  for(i = 0; i < darray_size(scc); i ++) {\n\
    id = * ((htbl_id_t *) darray_get(scc, i));\n\
    if(!htbl_get_attr(H, id, ATTR_SAFE)) {\n\
      darray_push(unsafe, &id);\n\
    }\n\
  }\n\
    \n\
  while(changes) {\n\
    changes = FALSE;\n\
    i = 0;\n\
    while(i < darray_size(unsafe)) {\n\
      id = * ((htbl_id_t *) darray_get(unsafe, i));\n\
      heap_reset(heap);\n\
      s = htbl_get_mem(H, id, heap);\n\
      en = state_events_reduced_mem(s, &reduced, heap);\n\
      all_succ_safe = TRUE;\n\
      while(!list_is_empty(en) && all_succ_safe) {\n\
        list_pick_first(en, &e);\n\
        succ = state_succ_mem(s, e, heap);\n\
        if(htbl_contains(H, succ, &id_succ, &h)\n\
           && por_analysis_state_is_unsafe(unsafe, id_succ)) {\n\
          all_succ_safe = FALSE;\n\
        }\n\
      }\n\
      if(!all_succ_safe) {\n\
        i ++;\n\
      } else {\n\
        htbl_set_attr(H, id, ATTR_SAFE, TRUE);\n\
        id = * ((htbl_id_t *) darray_pop(unsafe));\n\
        if(i != darray_size(unsafe)) {\n\
          darray_set(unsafe, i, &id);\n\
        }\n\
        changes = TRUE;          \n\
      }\n\
    }\n\
  }\n\
\n\
  for(i = 0; i < darray_size(scc); i ++) {\n\
    id = * ((htbl_id_t *) darray_get(scc, i));\n\
    if(!htbl_get_attr(H, id, ATTR_SAFE)) {\n\
      POR_ANALYSIS_NO_UNSAFE_STATES ++;\n\
    }\n\
  }\n\
  heap_free(heap);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "reduction.h", "w")
    f.write ("\
/**\n\
 * @file reduction.h\n\
 * @brief Implementation of various reduction methods.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_REDUCTION\n\
#define LIB_REDUCTION\n\
\n\
#include \"includes.h\"\n\
#include \"context.h\"\n\
#include \"event.h\"\n\
\n\
\n\
/**\n\
 * @brief edge_lean_reduction\n\
 */\n\
void edge_lean_reduction\n\
(event_list_t en,\n\
 event_t e);\n\
\n\
\n\
/**\n\
 * @brief mstate_events_reduced_mem\n\
 */\n\
list_t mstate_events_reduced_mem\n\
(mstate_t s,\n\
 bool_t * reduced,\n\
 heap_t heap);\n\
\n\
\n\
/**\n\
 * @brief mstate_events_reduced\n\
 */\n\
list_t mstate_events_reduced\n\
(mstate_t s,\n\
 bool_t * reduced);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "reduction.c", "w")
    f.write ("\
#include \"reduction.h\"\n\
#include \"event.h\"\n\
\n\
char edge_lean_is_independent_and_inferior\n\
(void * item,\n\
 void * data) {\n\
  event_t e = * ((event_t *) item);\n\
  event_t f = * ((event_t *) data);\n\
\n\
  if(event_are_independent(e, f) && (LESS == event_cmp(e, f))) {\n\
    return TRUE;\n\
  } else {\n\
    return FALSE;\n\
  }\n\
}\n\
\n\
void edge_lean_reduction\n\
(event_list_t en,\n\
 event_t e) {\n\
  list_filter(en, edge_lean_is_independent_and_inferior, &e);\n\
}\n\
\n\
char por_is_safe_and_invisible\n\
(void * item,\n\
 void * data) {\n\
   mevent_t e = * (mevent_t *) item;\n\
\n\
   if(mevent_is_safe(e) && !mevent_is_visible(e)) {\n\
     return TRUE;\n\
   } else {\n\
     return FALSE;\n\
   }\n\
}\n\
\n\
char por_is_not_id\n\
(void * item,\n\
 void * data) {\n\
   mevent_t e = * (mevent_t *) item;\n\
   mevent_id_t id = * (mevent_id_t *) data;\n\
   \n\
   if(mevent_id(e) != id) {\n\
     return TRUE;\n\
   } else {\n\
     return FALSE;\n\
   }\n\
}\n\
\n\
char por_in_set_and_invisible\n\
(void * item,\n\
 void * data) {\n\
   mevent_t e = * (mevent_t *) item;\n\
   \n\
   if(mevent_safe_set(e) > 0 && !mevent_is_visible(e)) {\n\
     return TRUE;\n\
   } else {\n\
     return FALSE;\n\
   }\n\
}\n\
\n\
char por_in_set_and_visible\n\
(void * item,\n\
 void * data) {\n\
   mevent_t e = * (mevent_t *) item;\n\
   unsigned int set = * (unsigned int *) data;\n\
   if(mevent_safe_set(e) == set && mevent_is_visible(e)) {\n\
     return TRUE;\n\
   } else {\n\
     return FALSE;\n\
   }\n\
}\n\
\n\
char por_is_not_in_set\n\
(void * item,\n\
 void * data) {\n\
   mevent_t e = * (mevent_t *) item;\n\
   unsigned int set = * (unsigned int *) data;\n\
   \n\
   if(mevent_safe_set(e) != set) {\n\
     return TRUE;\n\
   } else {\n\
     return FALSE;\n\
   }\n\
}\n\
\n\
mevent_list_t mstate_events_reduced_mem\n\
(mstate_t s,\n\
 bool_t * reduced,\n\
 heap_t heap) {\n\
  mevent_id_t eid;\n\
  mevent_t e;\n\
  void * data;\n\
  unsigned int set;\n\
  list_t result = mstate_events_mem(s, heap);\n\
  const list_size_t len = list_size(result);\n\
   \n\
  if(data = list_find(result, por_is_safe_and_invisible, NULL)) {\n\
    e = * (mevent_t *) data;\n\
    eid = mevent_id(e);\n\
    list_filter(result, por_is_not_id, &eid);\n\
  } else if(data = list_find(result, por_in_set_and_invisible, NULL)) {\n\
    e = * (mevent_t *) data;\n\
    set = mevent_safe_set(e);\n\
    data = &set;\n\
    if(NULL == list_find(result, por_in_set_and_visible, data)) {\n\
      list_filter(result, por_is_not_in_set, data);\n\
    }\n\
  }\n\
#if defined(MODEL_HAS_DYNAMIC_POR_REDUCTION) && CFG_DYNAMIC_POR == 1\n\
  else {\n\
    dynamic_por_reduction(s, result);\n\
  }\n\
#endif\n\
  *reduced = (list_size(result) != len) ? TRUE : FALSE;\n\
  return result;\n\
}\n\
\n\
mevent_list_t mstate_events_reduced\n\
(mstate_t s,\n\
 bool_t * reduced) {\n\
  return mstate_events_reduced_mem(s, reduced, SYSTEM_HEAP);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "rwalk.h", "w")
    f.write ("\
/**\n\
 * @file rwalk.h\n\
 * @brief Implementation of RWALK (random walk) algorithm.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_RWALK\n\
#define LIB_RWALK\n\
\n\
#include \"includes.h\"\n\
\n\
/**\n\
 * @brief Launch the random walk algorithm.\n\
 */\n\
void rwalk\n\
();\n\
\n\
\n\
/**\n\
 * @brief Report on the RWALK progress.\n\
 */\n\
void rwalk_progress_report\n\
(uint64_t * states_stored);\n\
\n\
\n\
/**\n\
 * @brief Finalisation of the RWALK.  Used to free data allocated by\n\
 *        rwalk.\n\
 */\n\
void rwalk_finalise\n\
();\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "rwalk.c", "w")
    f.write ("\
#include \"rwalk.h\"\n\
#include \"context.h\"\n\
#include \"prop.h\"\n\
#include \"workers.h\"\n\
\n\
\n\
void * rwalk_worker\n\
(void * arg) {\n\
  worker_id_t w = (worker_id_t) (long) arg;\n\
  state_t s;\n\
  event_list_t en;\n\
  event_t e;\n\
  int i;\n\
  unsigned int seed = random_seed(w);\n\
  unsigned int en_size;\n\
  heap_t heap;\n\
  event_list_t trace, new_trace;\n\
  \n\
  heap = local_heap_new();\n\
  while(context_keep_searching()) {\n\
    heap_reset(heap);\n\
    s = state_initial_mem(heap);\n\
    trace = list_new(heap, sizeof(event_t), event_free_void);\n\
    for(i = 0; i < CFG_RWALK_MAX_DEPTH && context_keep_searching(); i ++) {\n\
      en = state_events_mem(s, heap);\n\
      en_size = list_size(en);\n\
      if(CFG_ACTION_CHECK_SAFETY && state_check_property(s, en)) {\n\
        /*  copy the trace to the system heap  */\n\
        new_trace = list_new(SYSTEM_HEAP, sizeof(event_t), event_free_void);\n\
        while(!list_is_empty(trace)) {\n\
          list_pick_first(trace, &e);\n\
          e = event_copy(e);\n\
          list_append(new_trace, &e);\n\
        }\n\
	context_faulty_state(s);\n\
        context_set_trace(new_trace);\n\
	break;\n\
      }\n\
      if(0 != en_size) {\n\
        list_pick_random(en, &e, &seed);\n\
	event_exec(e, s);\n\
        list_append(trace, &e);\n\
      }\n\
      context_incr_stat(STAT_EVENT_EXEC, w, 1);\n\
      context_incr_stat(STAT_STATES_PROCESSED, w, 1);\n\
      context_incr_stat(STAT_ARCS, w, en_size);\n\
      list_free(en);\n\
      if(0 == en_size) {\n\
        context_incr_stat(STAT_STATES_DEADLOCK, w, 1);\n\
	break;\n\
      }\n\
    }\n\
    list_free(trace);\n\
    state_free(s);\n\
  }\n\
  heap_free(heap);\n\
}\n\
\n\
void rwalk\n\
() {\n\
  launch_and_wait_workers(&rwalk_worker);\n\
}\n\
\n\
void rwalk_progress_report\n\
(uint64_t * states_stored) {\n\
  *states_stored = 0;\n\
}\n\
\n\
void rwalk_finalise\n\
() {\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "simulator.h", "w")
    f.write ("\
/**\n\
 * @file simulator.h\n\
 * @brief Implementation of the simulation mode.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_SIMULATOR\n\
#define LIB_SIMULATOR\n\
\n\
#include \"includes.h\"\n\
#include \"common.h\"\n\
#include \"model.h\"\n\
\n\
/**\n\
 * @brief Launches the simulation mode.\n\
 */\n\
void simulator\n\
();\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "simulator.c", "w")
    f.write ("\
#include \"config.h\"\n\
#include \"simulator.h\"\n\
#include \"model.h\"\n\
#include \"list.h\"\n\
#include \"event.h\"\n\
#include \"context.h\"\n\
\n\
\n\
bool_t check_error() {\n\
  if(!context_error_raised()) {\n\
    return TRUE;\n\
  } else {\n\
    printf(\"model error: %s\\n\", context_error_msg());\n\
    context_flush_error();\n\
    return FALSE;\n\
  }\n\
}\n\
\n\
void simulator() {\n\
  unsigned int i;\n\
  bool_t loop = TRUE;\n\
  char * cmd = NULL;\n\
  mstate_t s;\n\
  mevent_t e;\n\
  size_t n;\n\
  char prop[65536];\n\
  state_list_t stack;\n\
  event_list_t stack_evts;\n\
  event_list_t en;\n\
  list_iter_t it;\n\
\n\
  s = mstate_initial();\n\
  stack = list_new(SYSTEM_HEAP, sizeof(state_t), state_free_void);\n\
  stack_evts = list_new(SYSTEM_HEAP, sizeof(event_t), event_free_void);\n\
  list_append(stack, &s);\n\
  while(loop) {\n\
    printf(\"# \");\n\
    fflush(stdout);\n\
    n = getline(&cmd, &n, stdin);\n\
    if(n == -1) {\n\
      printf(\"\\n\");\n\
      continue;\n\
    }\n\
    cmd[n - 1] = '\\0';\n\
    if(!strcmp(cmd, \"show\")) {\n\
      s = * ((mstate_t *) list_last(stack));\n\
      mstate_print(s, stdout);\n\
    } else if(!strcmp(cmd, \"stack\")) {\n\
      if(list_is_empty(stack_evts)) {\n\
	printf(\"stack is empty\\n\");\n\
      } else {\n\
	for(it = list_get_iter(stack_evts);\n\
	    !list_iter_at_end(it);\n\
	    it = list_iter_next(it)) {\n\
	  e = * ((mevent_t *) list_iter_item(it));\n\
	  mevent_print(e, stdout);\n\
	}\n\
      }\n\
    } else if(!strncmp(cmd, \"eval \", 5)) {\n\
      sscanf(cmd, \"eval %s\", &prop[0]);\n\
      if(!model_is_state_proposition(prop)) {\n\
	printf(\"error: %s is not a proposition of the model\\n\", prop);\n\
      } else {\n\
	printf(\"evaluation of proposition %s: \", prop);\n\
        s = * ((mstate_t *) list_last(stack));\n\
	if(model_check_state_proposition(prop, s)) {\n\
	  printf(\"true\\n\");\n\
	} else {\n\
	  printf(\"false\\n\");\n\
	}\n\
      }\n\
    } else if(!strncmp(cmd, \"push \", 5)) {\n\
      sscanf(cmd, \"push %d\", &i);\n\
      s = * ((mstate_t *) list_last(stack));\n\
      en = mstate_events(s);\n\
      if(check_error()) {\n\
	if(i < 1 || i > list_size(en)) {\n\
	  printf(\"error: state has %d enabled event(s)\\n\", list_size(en));\n\
	} else {\n\
	  e = * ((mevent_t *) list_nth(en, i - 1));\n\
	  s = mstate_succ(s, e);\n\
	  if(check_error()) {\n\
	    e = mevent_copy(e);\n\
	    list_append(stack, &s);\n\
	    list_append(stack_evts, &e);\n\
	  } else {\n\
	    mstate_free(s);\n\
	  }\n\
	}\n\
      }\n\
      list_free(en);\n\
    } else if(!strcmp(cmd, \"pop\")) {\n\
      if(list_is_empty(stack_evts)) {\n\
	printf(\"error: stack is empty\\n\");\n\
      } else {\n\
	list_pick_last(stack, &s);\n\
	mstate_free(s);\n\
	list_pick_last(stack_evts, &e);\n\
	mevent_free(e);\n\
      }\n\
    } else if(!strcmp(cmd, \"enabled\")) {\n\
      s = * ((mstate_t *) list_last(stack));\n\
      en = mstate_events(s);\n\
      if(check_error()) {\n\
        if(list_is_empty(en)) {\n\
          printf(\"no enabled event\\n\");\n\
        } else {\n\
          for(i = 0; i < list_size(en); i ++) {\n\
            printf(\"%3d: \", i + 1);\n\
            e = * ((mevent_t *) list_nth(en, i));\n\
            mevent_print(e, stdout);\n\
          }\n\
        }\n\
      }\n\
      list_free(en);\n\
    } else if(!strcmp(cmd, \"help\")) {\n\
      printf(\"\\\n\
show    -> show the current state (the one on top of the stack)\\n\\\n\
stack   -> show the stack of executed events\\n\\\n\
enabled -> show enabled events of the current state\\n\\\n\
pop     -> pop the state on top of the stack\\n\\\n\
push N  -> push the Nth successor of the current state on the stack\\n\\\n\
eval P  -> evaluate proposition on the current state\\n\\\n\
help\\n\\\n\
quit\\n\");\n\
    } else if(!strcmp(cmd, \"quit\")) {\n\
      loop = FALSE;\n\
    } else if(cmd[0] != '\\0') {\n\
      printf(\"error: unrecognized command: %s\\n\", cmd);\n\
    }\n\
    free(cmd);\n\
    cmd = NULL;\n\
  }\n\
  list_free(stack);\n\
  list_free(stack_evts);\n\
}\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "state.h", "w")
    f.write ("\
/**\n\
 * @file state.h\n\
 * @brief State definition.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_STATE\n\
#define LIB_STATE\n\
\n\
#include \"model.h\"\n\
#include \"heap.h\"\n\
#include \"list.h\"\n\
#include \"prop.h\"\n\
#include \"config.h\"\n\
\n\
typedef list_t state_list_t;\n\
\n\
void mstate_free_void\n\
(void * data);\n\
\n\
#if CFG_ACTION_CHECK_LTL == 1\n\
\n\
/**\n\
 *  state definition when doing LTL model checking\n\
 */\n\
\n\
#include \"buchi.h\"\n\
\n\
typedef struct {\n\
  mstate_t m;  /*  state of the model  */\n\
  bstate_t b;  /*  state of the buchi automaton  */\n\
  heap_t heap;\n\
} struct_state_t;\n\
typedef struct_state_t * state_t;\n\
\n\
bool_t state_equal(state_t s, state_t t);\n\
bool_t state_accepting(state_t s);\n\
state_t state_initial();\n\
state_t state_initial_mem(heap_t heap);\n\
void state_free(state_t s);\n\
void state_free_void(void * s);\n\
hash_key_t state_hash(state_t s);\n\
state_t state_copy(state_t s);\n\
state_t state_copy_mem(state_t s, heap_t heap);\n\
void state_print(state_t s, FILE *  out);\n\
void state_to_xml(state_t s, FILE *  out);\n\
unsigned int state_char_size(state_t s);\n\
void state_serialise(state_t s, bit_vector_t v);\n\
state_t state_unserialise(bit_vector_t v);\n\
state_t state_unserialise_mem(bit_vector_t v, heap_t heap);\n\
bool_t state_cmp_vector(state_t s, bit_vector_t v);\n\
\n\
#else\n\
\n\
/**\n\
 *  state definition when not doing LTL model checking\n\
 */\n\
\n\
typedef mstate_t state_t;\n\
\n\
#define state_equal mstate_equal\n\
#define state_accepting(s) FALSE\n\
#define state_initial mstate_initial\n\
#define state_initial_mem mstate_initial_mem\n\
#define state_free mstate_free\n\
#define state_free_void mstate_free_void\n\
#define state_hash mstate_hash\n\
#define state_copy mstate_copy\n\
#define state_copy_mem mstate_copy_mem\n\
#define state_print mstate_print\n\
#define state_to_xml mstate_to_xml\n\
#define state_char_size mstate_char_size\n\
#define state_serialise mstate_serialise\n\
#define state_unserialise mstate_unserialise\n\
#define state_unserialise_mem mstate_unserialise_mem\n\
#define state_cmp_vector mstate_cmp_vector\n\
\n\
#endif\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "state.c", "w")
    f.write ("\
#include \"state.h\"\n\
\n\
void mstate_free_void\n\
(void * data) {\n\
  mstate_free(*((mstate_t *) data));\n\
}\n\
\n\
\n\
#if CFG_ACTION_CHECK_LTL == 1\n\
\n\
bool_t state_equal\n\
(state_t s,\n\
 state_t t) {\n\
  return mstate_equal(s->m, t->m) && (s->b == t->b);\n\
}\n\
\n\
bool_t state_accepting\n\
(state_t s) {\n\
  return bstate_accepting(s->b);\n\
}\n\
\n\
state_t state_initial\n\
() {\n\
  return state_initial_mem(SYSTEM_HEAP);\n\
}\n\
\n\
state_t state_initial_mem\n\
(heap_t heap) {\n\
  state_t result;\n\
  result = mem_alloc(heap, sizeof(struct_state_t));\n\
  result->m = mstate_initial_mem(heap);\n\
  result->b = bstate_initial();\n\
  result->heap = heap;\n\
  return result;\n\
}\n\
\n\
void state_free\n\
(state_t s) {\n\
  mstate_free(s->m);\n\
  mem_free(s->heap, s);\n\
}\n\
\n\
void state_free_void(void * s) {\n\
  state_free(*((state_t *) s));\n\
}\n\
\n\
hash_key_t state_hash\n\
(state_t s) {\n\
  return mstate_hash(s->m) + s->b;\n\
}\n\
\n\
state_t state_copy\n\
(state_t s) {\n\
  return state_copy_mem(s, SYSTEM_HEAP);\n\
}\n\
\n\
state_t state_copy_mem\n\
(state_t s,\n\
 heap_t heap) {\n\
  state_t result;\n\
  \n\
  result = mem_alloc(heap, sizeof(struct_state_t));\n\
  result->m = mstate_copy_mem(s->m, heap);\n\
  result->b = s->b;\n\
  result->heap = heap;\n\
  return result;\n\
}\n\
\n\
void state_print\n\
(state_t s,\n\
 FILE * out) {\n\
  mstate_print(s->m, out);\n\
}\n\
\n\
void state_to_xml\n\
(state_t s,\n\
 FILE * out) {\n\
  mstate_to_xml(s->m, out);\n\
}\n\
\n\
unsigned int state_char_size\n\
(state_t s) {\n\
  return sizeof(bstate_t) + mstate_char_size(s->m);\n\
}\n\
\n\
void state_serialise\n\
(state_t s,\n\
 bit_vector_t v) {  \n\
  memcpy(v, &(s->b), sizeof(bstate_t));\n\
  mstate_serialise(s->m, v + sizeof(bstate_t));\n\
}\n\
\n\
state_t state_unserialise\n\
(bit_vector_t v) {\n\
  return state_unserialise_mem(v, SYSTEM_HEAP);\n\
}\n\
\n\
state_t state_unserialise_mem\n\
(bit_vector_t v,\n\
 heap_t heap) {\n\
  unsigned int bsize = sizeof(bstate_t);\n\
  state_t result = mem_alloc(heap, sizeof(struct_state_t));\n\
  \n\
  result->b = 0;\n\
  memcpy(&(result->b), v, bsize);\n\
  result->m = mstate_unserialise_mem(v + bsize, heap);\n\
  result->heap = heap;\n\
  return result;\n\
}\n\
\n\
bool_t state_cmp_vector\n\
(state_t s,\n\
 bit_vector_t v) {\n\
  bstate_t b = 0;\n\
\n\
  memcpy(&b, v, sizeof(bstate_t));\n\
  if(s->b != b) {\n\
    return FALSE;\n\
  }\n\
  return mstate_cmp_vector(s->m, v + sizeof(bstate_t));\n\
}\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "workers.h", "w")
    f.write ("\
/**\n\
 * @file workers.h\n\
 * @brief Several routines to handle worker threads.\n\
 * @date 12 sep 2017\n\
 * @author Sami Evangelista\n\
 */\n\
\n\
#ifndef LIB_WORKERS\n\
#define LIB_WORKERS\n\
\n\
#include \"common.h\"\n\
#include \"includes.h\"\n\
\n\
/**\n\
 * @brief a function executed by a worker thread\n\
 */\n\
typedef void *(* worker_func_t) (void *);\n\
\n\
/**\n\
 * @brief Launch the worker threads and wait for their termination.\n\
 * @arg f - the worker code\n\
 */\n\
void launch_and_wait_workers\n\
(worker_func_t f);\n\
\n\
#endif\n\
"    )
    f.close ()
    ############################################################
    f = open (dir + "/" + "workers.c", "w")
    f.write ("\
#include \"workers.h\"\n\
#include \"context.h\"\n\
\n\
#define WORKERS_DEBUG_XXX\n\
\n\
void launch_and_wait_workers\n\
(worker_func_t f) {\n\
  worker_id_t w;\n\
  void * dummy;\n\
  uint16_t no_workers = context_no_workers();\n\
  pthread_t * workers = context_workers();\n\
  \n\
  for(w = 0; w < no_workers; w ++) {\n\
    pthread_create(&(workers[w]), NULL, f, (void *) (long) w);\n\
#if defined(WORKERS_DEBUG)\n\
    printf(\"[%d] worker %d launched\\n\", context_proc_id(), w);\n\
#endif\n\
  }\n\
  for(w = 0; w < no_workers; w ++) {\n\
    pthread_join(workers[w], &dummy);\n\
#if defined(WORKERS_DEBUG)\n\
    printf(\"[%d] worker %d has terminated\\n\", context_proc_id(), w);\n\
#endif\n\
  }\n\
}\n\
"    )
    f.close ()



if (len (sys.argv) != 2):
    print ("usage: helena-generate-checker directory")
    exit (1)
else:
    genFiles (sys.argv[1])
    exit (0)
