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.

297 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_BDD_H
  19. #define SYLVAN_BDD_H
  20. #ifdef __cplusplus
  21. extern "C" {
  22. #endif /* __cplusplus */
  23. /* For strictly non-MT BDDs */
  24. static inline int
  25. sylvan_isconst(MTBDD bdd)
  26. {
  27. return bdd == mtbdd_true || bdd == mtbdd_false ? 1 : 0;
  28. }
  29. static inline int
  30. sylvan_isnode(MTBDD bdd)
  31. {
  32. return bdd != mtbdd_true && bdd != mtbdd_false ? 1 : 0;
  33. }
  34. /**
  35. * Granularity (BDD only) determines usage of operation cache.
  36. * The smallest value is 1: use the operation cache always.
  37. * Higher values mean that the cache is used less often. Variables are grouped
  38. * such that the cache is used when going to the next group, i.e., with
  39. * granularity=3, variables [0,1,2] are in the first group, [3,4,5] in the next, etc.
  40. * Then no caching occur between 0->1, 1->2, 0->2. Caching occurs on 0->3, 1->4, 2->3, etc.
  41. *
  42. * The appropriate value depends on the number of variables and the structure of
  43. * the decision diagrams. When in doubt, choose a low value (1-5). The performance
  44. * gain can be around 0-10%, so it is not extremely important.
  45. */
  46. void sylvan_set_granularity(int granularity);
  47. int sylvan_get_granularity(void);
  48. /*
  49. * Unary, binary and if-then-else operations.
  50. * These operations are all implemented by NOT, AND and XOR.
  51. */
  52. static inline BDD
  53. sylvan_not(BDD a)
  54. {
  55. return a ^ sylvan_complement;
  56. }
  57. TASK_DECL_4(BDD, sylvan_ite, BDD, BDD, BDD, BDDVAR);
  58. #define sylvan_ite(a,b,c) (CALL(sylvan_ite,a,b,c,0))
  59. TASK_DECL_3(BDD, sylvan_and, BDD, BDD, BDDVAR);
  60. #define sylvan_and(a,b) (CALL(sylvan_and,a,b,0))
  61. TASK_DECL_3(BDD, sylvan_xor, BDD, BDD, BDDVAR);
  62. #define sylvan_xor(a,b) (CALL(sylvan_xor,a,b,0))
  63. #define sylvan_equiv(a,b) sylvan_not(sylvan_xor(a,b))
  64. #define sylvan_or(a,b) sylvan_not(sylvan_and(sylvan_not(a),sylvan_not(b)))
  65. #define sylvan_nand(a,b) sylvan_not(sylvan_and(a,b))
  66. #define sylvan_nor(a,b) sylvan_not(sylvan_or(a,b))
  67. #define sylvan_imp(a,b) sylvan_not(sylvan_and(a,sylvan_not(b)))
  68. #define sylvan_invimp(a,b) sylvan_not(sylvan_and(sylvan_not(a),b))
  69. #define sylvan_biimp sylvan_equiv
  70. #define sylvan_diff(a,b) sylvan_and(a,sylvan_not(b))
  71. #define sylvan_less(a,b) sylvan_and(sylvan_not(a),b)
  72. /* Create a BDD representing just <var> or the negation of <var> */
  73. static inline BDD
  74. sylvan_nithvar(uint32_t var)
  75. {
  76. return sylvan_not(sylvan_ithvar(var));
  77. }
  78. /**
  79. * Existential and universal quantification.
  80. */
  81. TASK_DECL_3(BDD, sylvan_exists, BDD, BDD, BDDVAR);
  82. #define sylvan_exists(a, vars) (CALL(sylvan_exists, a, vars, 0))
  83. #define sylvan_forall(a, vars) (sylvan_not(CALL(sylvan_exists, sylvan_not(a), vars, 0)))
  84. /**
  85. * Projection. (Same as existential quantification, but <vars> contains variables to keep.
  86. */
  87. TASK_DECL_2(BDD, sylvan_project, BDD, BDD);
  88. #define sylvan_project(a, vars) CALL(sylvan_project, a, vars)
  89. /**
  90. * Compute \exists <vars>: <a> \and <b>
  91. */
  92. TASK_DECL_4(BDD, sylvan_and_exists, BDD, BDD, BDDSET, BDDVAR);
  93. #define sylvan_and_exists(a,b,vars) CALL(sylvan_and_exists,a,b,vars,0)
  94. /**
  95. * Compute and_exists, but as a projection (only keep given variables)
  96. */
  97. TASK_DECL_3(BDD, sylvan_and_project, BDD, BDD, BDDSET);
  98. #define sylvan_and_project(a,b,vars) CALL(sylvan_and_project,a,b,vars)
  99. /**
  100. * Compute R(s,t) = \exists x: A(s,x) \and B(x,t)
  101. * or R(s) = \exists x: A(s,x) \and B(x)
  102. * Assumes s,t are interleaved with s even and t odd (s+1).
  103. * Parameter vars is the cube of all s and/or t variables.
  104. * Other variables in A are "ignored" (existential quantification)
  105. * Other variables in B are kept
  106. * Alternatively, vars=false means all variables are in vars
  107. *
  108. * Use this function to concatenate two relations --> -->
  109. * or to take the 'previous' of a set --> S
  110. */
  111. TASK_DECL_4(BDD, sylvan_relprev, BDD, BDD, BDDSET, BDDVAR);
  112. #define sylvan_relprev(a,b,vars) CALL(sylvan_relprev,a,b,vars,0)
  113. /**
  114. * Compute R(s) = \exists x: A(x) \and B(x,s)
  115. * with support(result) = s, support(A) = s, support(B) = s+t
  116. * Assumes s,t are interleaved with s even and t odd (s+1).
  117. * Parameter vars is the cube of all s and/or t variables.
  118. * Other variables in A are kept
  119. * Other variables in B are "ignored" (existential quantification)
  120. * Alternatively, vars=false means all variables are in vars
  121. *
  122. * Use this function to take the 'next' of a set S -->
  123. */
  124. TASK_DECL_4(BDD, sylvan_relnext, BDD, BDD, BDDSET, BDDVAR);
  125. #define sylvan_relnext(a,b,vars) CALL(sylvan_relnext,a,b,vars,0)
  126. /**
  127. * Computes the transitive closure by traversing the BDD recursively.
  128. * See Y. Matsunaga, P. C. McGeer, R. K. Brayton
  129. * On Computing the Transitive Closure of a State Transition Relation
  130. * 30th ACM Design Automation Conference, 1993.
  131. *
  132. * The input BDD must be a transition relation that only has levels of s,t
  133. * with s,t interleaved with s even and t odd, i.e.
  134. * s level 0,2,4 matches with t level 1,3,5 and so forth.
  135. */
  136. TASK_DECL_2(BDD, sylvan_closure, BDD, BDDVAR);
  137. #define sylvan_closure(a) CALL(sylvan_closure,a,0);
  138. /**
  139. * Compute f@c (f constrain c), such that f and f@c are the same when c is true
  140. * The BDD c is also called the "care function"
  141. * Special cases:
  142. * - f@0 = 0
  143. * - f@1 = f
  144. * - 0@c = 0
  145. * - 1@c = 1
  146. * - f@f = 1
  147. * - f@not(f) = 0
  148. */
  149. TASK_DECL_3(BDD, sylvan_constrain, BDD, BDD, BDDVAR);
  150. #define sylvan_constrain(f,c) (CALL(sylvan_constrain, f, c, 0))
  151. /**
  152. * Compute restrict f@c, which uses a heuristic to try and minimize a BDD f with respect to a care function c
  153. * Similar to constrain, but avoids introducing variables from c into f.
  154. */
  155. TASK_DECL_3(BDD, sylvan_restrict, BDD, BDD, BDDVAR);
  156. #define sylvan_restrict(f,c) (CALL(sylvan_restrict, f, c, 0))
  157. /**
  158. * Function composition.
  159. * For each node with variable <key> which has a <key,value> pair in <map>,
  160. * replace the node by the result of sylvan_ite(<value>, <low>, <high>).
  161. */
  162. TASK_DECL_3(BDD, sylvan_compose, BDD, BDDMAP, BDDVAR);
  163. #define sylvan_compose(f,m) (CALL(sylvan_compose, (f), (m), 0))
  164. /**
  165. * Calculate number of satisfying variable assignments.
  166. * The set of variables must be >= the support of the BDD.
  167. */
  168. TASK_DECL_3(double, sylvan_satcount, BDD, BDDSET, BDDVAR);
  169. #define sylvan_satcount(bdd, variables) CALL(sylvan_satcount, bdd, variables, 0)
  170. /**
  171. * Create a BDD cube representing the conjunction of variables in their positive or negative
  172. * form depending on whether the cube[idx] equals 0 (negative), 1 (positive) or 2 (any).
  173. * CHANGED 2014/09/19: vars is now a BDDSET (ordered!)
  174. */
  175. BDD sylvan_cube(BDDSET variables, uint8_t *cube);
  176. TASK_DECL_3(BDD, sylvan_union_cube, BDD, BDDSET, uint8_t*);
  177. #define sylvan_union_cube(bdd, variables, cube) CALL(sylvan_union_cube, bdd, variables, cube)
  178. /**
  179. * Pick one satisfying variable assignment randomly for which <bdd> is true.
  180. * The <variables> set must include all variables in the support of <bdd>.
  181. *
  182. * The function will set the values of str, such that
  183. * str[index] where index is the index in the <variables> set is set to
  184. * 0 when the variable is negative, 1 when positive, or 2 when it could be either.
  185. *
  186. * This implies that str[i] will be set in the variable ordering as in <variables>.
  187. *
  188. * Returns 1 when succesful, or 0 when no assignment is found (i.e. bdd==sylvan_false).
  189. */
  190. int sylvan_sat_one(BDD bdd, BDDSET variables, uint8_t* str);
  191. /**
  192. * Pick one satisfying variable assignment randomly from the given <bdd>.
  193. * Functionally equivalent to performing sylvan_cube on the result of sylvan_sat_one.
  194. * For the result: sylvan_and(res, bdd) = res.
  195. */
  196. BDD sylvan_sat_one_bdd(BDD bdd);
  197. #define sylvan_pick_cube sylvan_sat_one_bdd
  198. BDD sylvan_sat_single(BDD bdd, BDDSET vars);
  199. #define sylvan_pick_single_cube sylvan_sat_single
  200. /**
  201. * Enumerate all satisfying variable assignments from the given <bdd> using variables <vars>.
  202. * Calls <cb> with four parameters: a user-supplied context, the array of BDD variables in <vars>,
  203. * the cube (array of values 0 and 1 for each variables in <vars>) and the length of the two arrays.
  204. */
  205. LACE_TYPEDEF_CB(void, enum_cb, void*, BDDVAR*, uint8_t*, int);
  206. VOID_TASK_DECL_4(sylvan_enum, BDD, BDDSET, enum_cb, void*);
  207. #define sylvan_enum(bdd, vars, cb, context) CALL(sylvan_enum, bdd, vars, cb, context)
  208. VOID_TASK_DECL_4(sylvan_enum_par, BDD, BDDSET, enum_cb, void*);
  209. #define sylvan_enum_par(bdd, vars, cb, context) CALL(sylvan_enum_par, bdd, vars, cb, context)
  210. /**
  211. * Enumerate all satisfyable variable assignments of the given <bdd> using variables <vars>.
  212. * Calls <cb> with two parameters: a user-supplied context and the cube (array of
  213. * values 0 and 1 for each variable in <vars>).
  214. * The BDD that <cb> returns is pair-wise merged (using or) and returned.
  215. */
  216. LACE_TYPEDEF_CB(BDD, sylvan_collect_cb, void*, uint8_t*);
  217. TASK_DECL_4(BDD, sylvan_collect, BDD, BDDSET, sylvan_collect_cb, void*);
  218. #define sylvan_collect(bdd, vars, cb, context) CALL(sylvan_collect, bdd, vars, cb, context)
  219. /**
  220. * Compute the number of distinct paths to sylvan_true in the BDD
  221. */
  222. TASK_DECL_2(double, sylvan_pathcount, BDD, BDDVAR);
  223. #define sylvan_pathcount(bdd) (CALL(sylvan_pathcount, bdd, 0))
  224. /**
  225. * SAVING:
  226. * use sylvan_serialize_add on every BDD you want to store
  227. * use sylvan_serialize_get to retrieve the key of every stored BDD
  228. * use sylvan_serialize_tofile
  229. *
  230. * LOADING:
  231. * use sylvan_serialize_fromfile (implies sylvan_serialize_reset)
  232. * use sylvan_serialize_get_reversed for every key
  233. *
  234. * MISC:
  235. * use sylvan_serialize_reset to free all allocated structures
  236. * use sylvan_serialize_totext to write a textual list of tuples of all BDDs.
  237. * format: [(<key>,<level>,<key_low>,<key_high>,<complement_high>),...]
  238. */
  239. size_t sylvan_serialize_add(BDD bdd);
  240. size_t sylvan_serialize_get(BDD bdd);
  241. BDD sylvan_serialize_get_reversed(size_t value);
  242. void sylvan_serialize_reset(void);
  243. void sylvan_serialize_totext(FILE *out);
  244. void sylvan_serialize_tofile(FILE *out);
  245. void sylvan_serialize_fromfile(FILE *in);
  246. static void __attribute__((unused))
  247. sylvan_fprint(FILE *f, BDD bdd)
  248. {
  249. sylvan_serialize_reset();
  250. size_t v = sylvan_serialize_add(bdd);
  251. fprintf(f, "%s%zu,", bdd&sylvan_complement?"!":"", v);
  252. sylvan_serialize_totext(f);
  253. }
  254. static void __attribute__((unused))
  255. sylvan_print(BDD bdd)
  256. {
  257. return sylvan_fprint(stdout, bdd);
  258. }
  259. #include "sylvan_bdd_storm.h"
  260. #ifdef __cplusplus
  261. }
  262. #endif /* __cplusplus */
  263. #endif