You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

313 lines
11 KiB

  1. /*
  2. * Copyright 2011-2016 Formal Methods and Tools, University of Twente
  3. * Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* Do not include this file directly. Instead, include sylvan.h */
  18. #ifndef SYLVAN_LDD_H
  19. #define SYLVAN_LDD_H
  20. #ifdef __cplusplus
  21. extern "C" {
  22. #endif /* __cplusplus */
  23. typedef uint64_t MDD; // Note: low 40 bits only
  24. static const MDD lddmc_false = 0;
  25. static const MDD lddmc_true = 1;
  26. /* Initialize LDD functionality */
  27. void sylvan_init_ldd(void);
  28. /* Primitives */
  29. MDD lddmc_makenode(uint32_t value, MDD ifeq, MDD ifneq);
  30. MDD lddmc_extendnode(MDD mdd, uint32_t value, MDD ifeq);
  31. uint32_t lddmc_getvalue(MDD mdd);
  32. MDD lddmc_getdown(MDD mdd);
  33. MDD lddmc_getright(MDD mdd);
  34. MDD lddmc_follow(MDD mdd, uint32_t value);
  35. /**
  36. * Copy nodes in relations.
  37. * A copy node represents 'read x, then write x' for every x.
  38. * In a read-write relation, use copy nodes twice, once on read level, once on write level.
  39. * Copy nodes are only supported by relprod, relprev and union.
  40. */
  41. /* Primitive for special 'copy node' (for relprod/relprev) */
  42. MDD lddmc_make_copynode(MDD ifeq, MDD ifneq);
  43. int lddmc_iscopy(MDD mdd);
  44. MDD lddmc_followcopy(MDD mdd);
  45. /**
  46. * Infrastructure for external references using a hash table.
  47. * Two hash tables store external references: a pointers table and a values table.
  48. * The pointers table stores pointers to MDD variables, manipulated with protect and unprotect.
  49. * The values table stores MDD, manipulated with ref and deref.
  50. * We strongly recommend using the pointers table whenever possible.
  51. */
  52. /**
  53. * Store the pointer <ptr> in the pointers table.
  54. */
  55. void lddmc_protect(MDD* ptr);
  56. /**
  57. * Delete the pointer <ptr> from the pointers table.
  58. */
  59. void lddmc_unprotect(MDD* ptr);
  60. /**
  61. * Compute the number of pointers in the pointers table.
  62. */
  63. size_t lddmc_count_protected(void);
  64. /**
  65. * Store the MDD <dd> in the values table.
  66. */
  67. MDD lddmc_ref(MDD dd);
  68. /**
  69. * Delete the MDD <dd> from the values table.
  70. */
  71. void lddmc_deref(MDD dd);
  72. /**
  73. * Compute the number of values in the values table.
  74. */
  75. size_t lddmc_count_refs(void);
  76. /**
  77. * Call mtbdd_gc_mark_rec for every mtbdd you want to keep in your custom mark functions.
  78. */
  79. VOID_TASK_DECL_1(lddmc_gc_mark_rec, MDD)
  80. #define lddmc_gc_mark_rec(mdd) CALL(lddmc_gc_mark_rec, mdd)
  81. /* Sanity check - returns depth of MDD including 'true' terminal or 0 for empty set */
  82. #ifndef NDEBUG
  83. size_t lddmc_test_ismdd(MDD mdd);
  84. #endif
  85. /* Operations for model checking */
  86. TASK_DECL_2(MDD, lddmc_union, MDD, MDD);
  87. #define lddmc_union(a, b) CALL(lddmc_union, a, b)
  88. TASK_DECL_2(MDD, lddmc_minus, MDD, MDD);
  89. #define lddmc_minus(a, b) CALL(lddmc_minus, a, b)
  90. TASK_DECL_3(MDD, lddmc_zip, MDD, MDD, MDD*);
  91. #define lddmc_zip(a, b, res) CALL(lddmc_zip, a, b, res)
  92. TASK_DECL_2(MDD, lddmc_intersect, MDD, MDD);
  93. #define lddmc_intersect(a, b) CALL(lddmc_intersect, a, b)
  94. TASK_DECL_3(MDD, lddmc_match, MDD, MDD, MDD);
  95. #define lddmc_match(a, b, proj) CALL(lddmc_match, a, b, proj)
  96. MDD lddmc_union_cube(MDD a, uint32_t* values, size_t count);
  97. int lddmc_member_cube(MDD a, uint32_t* values, size_t count);
  98. MDD lddmc_cube(uint32_t* values, size_t count);
  99. MDD lddmc_union_cube_copy(MDD a, uint32_t* values, int* copy, size_t count);
  100. int lddmc_member_cube_copy(MDD a, uint32_t* values, int* copy, size_t count);
  101. MDD lddmc_cube_copy(uint32_t* values, int* copy, size_t count);
  102. TASK_DECL_3(MDD, lddmc_relprod, MDD, MDD, MDD);
  103. #define lddmc_relprod(a, b, proj) CALL(lddmc_relprod, a, b, proj)
  104. TASK_DECL_4(MDD, lddmc_relprod_union, MDD, MDD, MDD, MDD);
  105. #define lddmc_relprod_union(a, b, meta, un) CALL(lddmc_relprod_union, a, b, meta, un)
  106. /**
  107. * Calculate all predecessors to a in uni according to rel[proj]
  108. * <proj> follows the same semantics as relprod
  109. * i.e. 0 (not in rel), 1 (read+write), 2 (read), 3 (write), -1 (end; rest=0)
  110. */
  111. TASK_DECL_4(MDD, lddmc_relprev, MDD, MDD, MDD, MDD);
  112. #define lddmc_relprev(a, rel, proj, uni) CALL(lddmc_relprev, a, rel, proj, uni)
  113. // so: proj: -2 (end; quantify rest), -1 (end; keep rest), 0 (quantify), 1 (keep)
  114. TASK_DECL_2(MDD, lddmc_project, MDD, MDD);
  115. #define lddmc_project(mdd, proj) CALL(lddmc_project, mdd, proj)
  116. TASK_DECL_3(MDD, lddmc_project_minus, MDD, MDD, MDD);
  117. #define lddmc_project_minus(mdd, proj, avoid) CALL(lddmc_project_minus, mdd, proj, avoid)
  118. TASK_DECL_4(MDD, lddmc_join, MDD, MDD, MDD, MDD);
  119. #define lddmc_join(a, b, a_proj, b_proj) CALL(lddmc_join, a, b, a_proj, b_proj)
  120. /* Write a DOT representation */
  121. void lddmc_printdot(MDD mdd);
  122. void lddmc_fprintdot(FILE *out, MDD mdd);
  123. void lddmc_fprint(FILE *out, MDD mdd);
  124. void lddmc_print(MDD mdd);
  125. void lddmc_printsha(MDD mdd);
  126. void lddmc_fprintsha(FILE *out, MDD mdd);
  127. void lddmc_getsha(MDD mdd, char *target); // at least 65 bytes...
  128. /**
  129. * Calculate number of satisfying variable assignments.
  130. * The set of variables must be >= the support of the MDD.
  131. * (i.e. all variables in the MDD must be in variables)
  132. *
  133. * The cached version uses the operation cache, but is limited to 64-bit floating point numbers.
  134. */
  135. typedef double lddmc_satcount_double_t;
  136. // if this line below gives an error, modify the above typedef until fixed ;)
  137. typedef char __lddmc_check_float_is_8_bytes[(sizeof(lddmc_satcount_double_t) == sizeof(uint64_t))?1:-1];
  138. TASK_DECL_1(lddmc_satcount_double_t, lddmc_satcount_cached, MDD);
  139. #define lddmc_satcount_cached(mdd) CALL(lddmc_satcount_cached, mdd)
  140. TASK_DECL_1(long double, lddmc_satcount, MDD);
  141. #define lddmc_satcount(mdd) CALL(lddmc_satcount, mdd)
  142. /**
  143. * A callback for enumerating functions like sat_all_par, collect and match
  144. * Example:
  145. * TASK_3(void*, my_function, uint32_t*, values, size_t, count, void*, context) ...
  146. * For collect, use:
  147. * TASK_3(MDD, ...)
  148. */
  149. LACE_TYPEDEF_CB(void, lddmc_enum_cb, uint32_t*, size_t, void*);
  150. LACE_TYPEDEF_CB(MDD, lddmc_collect_cb, uint32_t*, size_t, void*);
  151. VOID_TASK_DECL_5(lddmc_sat_all_par, MDD, lddmc_enum_cb, void*, uint32_t*, size_t);
  152. #define lddmc_sat_all_par(mdd, cb, context) CALL(lddmc_sat_all_par, mdd, cb, context, 0, 0)
  153. VOID_TASK_DECL_3(lddmc_sat_all_nopar, MDD, lddmc_enum_cb, void*);
  154. #define lddmc_sat_all_nopar(mdd, cb, context) CALL(lddmc_sat_all_nopar, mdd, cb, context)
  155. TASK_DECL_5(MDD, lddmc_collect, MDD, lddmc_collect_cb, void*, uint32_t*, size_t);
  156. #define lddmc_collect(mdd, cb, context) CALL(lddmc_collect, mdd, cb, context, 0, 0)
  157. VOID_TASK_DECL_5(lddmc_match_sat_par, MDD, MDD, MDD, lddmc_enum_cb, void*);
  158. #define lddmc_match_sat_par(mdd, match, proj, cb, context) CALL(lddmc_match_sat_par, mdd, match, proj, cb, context)
  159. int lddmc_sat_one(MDD mdd, uint32_t *values, size_t count);
  160. MDD lddmc_sat_one_mdd(MDD mdd);
  161. #define lddmc_pick_cube lddmc_sat_one_mdd
  162. /**
  163. * Callback functions for visiting nodes.
  164. * lddmc_visit_seq sequentially visits nodes, down first, then right.
  165. * lddmc_visit_par visits nodes in parallel (down || right)
  166. */
  167. LACE_TYPEDEF_CB(int, lddmc_visit_pre_cb, MDD, void*); // int pre(MDD, context)
  168. LACE_TYPEDEF_CB(void, lddmc_visit_post_cb, MDD, void*); // void post(MDD, context)
  169. LACE_TYPEDEF_CB(void, lddmc_visit_init_context_cb, void*, void*, int); // void init_context(context, parent, is_down)
  170. typedef struct lddmc_visit_node_callbacks {
  171. lddmc_visit_pre_cb lddmc_visit_pre;
  172. lddmc_visit_post_cb lddmc_visit_post;
  173. lddmc_visit_init_context_cb lddmc_visit_init_context;
  174. } lddmc_visit_callbacks_t;
  175. VOID_TASK_DECL_4(lddmc_visit_par, MDD, lddmc_visit_callbacks_t*, size_t, void*);
  176. #define lddmc_visit_par(mdd, cbs, ctx_size, context) CALL(lddmc_visit_par, mdd, cbs, ctx_size, context);
  177. VOID_TASK_DECL_4(lddmc_visit_seq, MDD, lddmc_visit_callbacks_t*, size_t, void*);
  178. #define lddmc_visit_seq(mdd, cbs, ctx_size, context) CALL(lddmc_visit_seq, mdd, cbs, ctx_size, context);
  179. size_t lddmc_nodecount(MDD mdd);
  180. void lddmc_nodecount_levels(MDD mdd, size_t *variables);
  181. /**
  182. * Functional composition
  183. * For every node at depth <depth>, call function cb (MDD -> MDD).
  184. * and replace the node by the result of the function
  185. */
  186. LACE_TYPEDEF_CB(MDD, lddmc_compose_cb, MDD, void*);
  187. TASK_DECL_4(MDD, lddmc_compose, MDD, lddmc_compose_cb, void*, int);
  188. #define lddmc_compose(mdd, cb, context, depth) CALL(lddmc_compose, mdd, cb, context, depth)
  189. /**
  190. * SAVING:
  191. * use lddmc_serialize_add on every MDD you want to store
  192. * use lddmc_serialize_get to retrieve the key of every stored MDD
  193. * use lddmc_serialize_tofile
  194. *
  195. * LOADING:
  196. * use lddmc_serialize_fromfile (implies lddmc_serialize_reset)
  197. * use lddmc_serialize_get_reversed for every key
  198. *
  199. * MISC:
  200. * use lddmc_serialize_reset to free all allocated structures
  201. * use lddmc_serialize_totext to write a textual list of tuples of all MDDs.
  202. * format: [(<key>,<level>,<key_low>,<key_high>,<complement_high>),...]
  203. *
  204. * for the old lddmc_print functions, use lddmc_serialize_totext
  205. */
  206. size_t lddmc_serialize_add(MDD mdd);
  207. size_t lddmc_serialize_get(MDD mdd);
  208. MDD lddmc_serialize_get_reversed(size_t value);
  209. void lddmc_serialize_reset(void);
  210. void lddmc_serialize_totext(FILE *out);
  211. void lddmc_serialize_tofile(FILE *out);
  212. void lddmc_serialize_fromfile(FILE *in);
  213. /**
  214. * Infrastructure for internal references.
  215. * Every thread has its own reference stacks. There are three stacks: pointer, values, tasks stack.
  216. * The pointers stack stores pointers to LDD variables, manipulated with pushptr and popptr.
  217. * The values stack stores LDD, manipulated with push and pop.
  218. * The tasks stack stores Lace tasks (that return LDD), manipulated with spawn and sync.
  219. *
  220. * It is recommended to use the pointers stack for local variables and the tasks stack for tasks.
  221. */
  222. /**
  223. * Push a LDD variable to the pointer reference stack.
  224. * During garbage collection the variable will be inspected and the contents will be marked.
  225. */
  226. void lddmc_refs_pushptr(const MDD *ptr);
  227. /**
  228. * Pop the last <amount> LDD variables from the pointer reference stack.
  229. */
  230. void lddmc_refs_popptr(size_t amount);
  231. /**
  232. * Push an LDD to the values reference stack.
  233. * During garbage collection the references LDD will be marked.
  234. */
  235. MDD lddmc_refs_push(MDD dd);
  236. /**
  237. * Pop the last <amount> LDD from the values reference stack.
  238. */
  239. void lddmc_refs_pop(long amount);
  240. /**
  241. * Push a Task that returns an LDD to the tasks reference stack.
  242. * Usage: lddmc_refs_spawn(SPAWN(function, ...));
  243. */
  244. void lddmc_refs_spawn(Task *t);
  245. /**
  246. * Pop a Task from the task reference stack.
  247. * Usage: MDD result = lddmc_refs_sync(SYNC(function));
  248. */
  249. MDD lddmc_refs_sync(MDD dd);
  250. #ifdef __cplusplus
  251. }
  252. #endif /* __cplusplus */
  253. #endif