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
297 lines
11 KiB
/*
|
|
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
|
|
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* Do not include this file directly. Instead, include sylvan.h */
|
|
|
|
#ifndef SYLVAN_BDD_H
|
|
#define SYLVAN_BDD_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
|
|
/* For strictly non-MT BDDs */
|
|
static inline int
|
|
sylvan_isconst(MTBDD bdd)
|
|
{
|
|
return bdd == mtbdd_true || bdd == mtbdd_false ? 1 : 0;
|
|
}
|
|
|
|
static inline int
|
|
sylvan_isnode(MTBDD bdd)
|
|
{
|
|
return bdd != mtbdd_true && bdd != mtbdd_false ? 1 : 0;
|
|
}
|
|
|
|
/**
|
|
* Granularity (BDD only) determines usage of operation cache.
|
|
* The smallest value is 1: use the operation cache always.
|
|
* Higher values mean that the cache is used less often. Variables are grouped
|
|
* such that the cache is used when going to the next group, i.e., with
|
|
* granularity=3, variables [0,1,2] are in the first group, [3,4,5] in the next, etc.
|
|
* Then no caching occur between 0->1, 1->2, 0->2. Caching occurs on 0->3, 1->4, 2->3, etc.
|
|
*
|
|
* The appropriate value depends on the number of variables and the structure of
|
|
* the decision diagrams. When in doubt, choose a low value (1-5). The performance
|
|
* gain can be around 0-10%, so it is not extremely important.
|
|
*/
|
|
void sylvan_set_granularity(int granularity);
|
|
int sylvan_get_granularity(void);
|
|
|
|
/*
|
|
* Unary, binary and if-then-else operations.
|
|
* These operations are all implemented by NOT, AND and XOR.
|
|
*/
|
|
static inline BDD
|
|
sylvan_not(BDD a)
|
|
{
|
|
return a ^ sylvan_complement;
|
|
}
|
|
|
|
TASK_DECL_4(BDD, sylvan_ite, BDD, BDD, BDD, BDDVAR);
|
|
#define sylvan_ite(a,b,c) (CALL(sylvan_ite,a,b,c,0))
|
|
TASK_DECL_3(BDD, sylvan_and, BDD, BDD, BDDVAR);
|
|
#define sylvan_and(a,b) (CALL(sylvan_and,a,b,0))
|
|
TASK_DECL_3(BDD, sylvan_xor, BDD, BDD, BDDVAR);
|
|
#define sylvan_xor(a,b) (CALL(sylvan_xor,a,b,0))
|
|
#define sylvan_equiv(a,b) sylvan_not(sylvan_xor(a,b))
|
|
#define sylvan_or(a,b) sylvan_not(sylvan_and(sylvan_not(a),sylvan_not(b)))
|
|
#define sylvan_nand(a,b) sylvan_not(sylvan_and(a,b))
|
|
#define sylvan_nor(a,b) sylvan_not(sylvan_or(a,b))
|
|
#define sylvan_imp(a,b) sylvan_not(sylvan_and(a,sylvan_not(b)))
|
|
#define sylvan_invimp(a,b) sylvan_not(sylvan_and(sylvan_not(a),b))
|
|
#define sylvan_biimp sylvan_equiv
|
|
#define sylvan_diff(a,b) sylvan_and(a,sylvan_not(b))
|
|
#define sylvan_less(a,b) sylvan_and(sylvan_not(a),b)
|
|
|
|
/* Create a BDD representing just <var> or the negation of <var> */
|
|
static inline BDD
|
|
sylvan_nithvar(uint32_t var)
|
|
{
|
|
return sylvan_not(sylvan_ithvar(var));
|
|
}
|
|
|
|
/**
|
|
* Existential and universal quantification.
|
|
*/
|
|
TASK_DECL_3(BDD, sylvan_exists, BDD, BDD, BDDVAR);
|
|
#define sylvan_exists(a, vars) (CALL(sylvan_exists, a, vars, 0))
|
|
#define sylvan_forall(a, vars) (sylvan_not(CALL(sylvan_exists, sylvan_not(a), vars, 0)))
|
|
|
|
/**
|
|
* Projection. (Same as existential quantification, but <vars> contains variables to keep.
|
|
*/
|
|
TASK_DECL_2(BDD, sylvan_project, BDD, BDD);
|
|
#define sylvan_project(a, vars) CALL(sylvan_project, a, vars)
|
|
|
|
/**
|
|
* Compute \exists <vars>: <a> \and <b>
|
|
*/
|
|
TASK_DECL_4(BDD, sylvan_and_exists, BDD, BDD, BDDSET, BDDVAR);
|
|
#define sylvan_and_exists(a,b,vars) CALL(sylvan_and_exists,a,b,vars,0)
|
|
|
|
/**
|
|
* Compute and_exists, but as a projection (only keep given variables)
|
|
*/
|
|
TASK_DECL_3(BDD, sylvan_and_project, BDD, BDD, BDDSET);
|
|
#define sylvan_and_project(a,b,vars) CALL(sylvan_and_project,a,b,vars)
|
|
|
|
/**
|
|
* Compute R(s,t) = \exists x: A(s,x) \and B(x,t)
|
|
* or R(s) = \exists x: A(s,x) \and B(x)
|
|
* Assumes s,t are interleaved with s even and t odd (s+1).
|
|
* Parameter vars is the cube of all s and/or t variables.
|
|
* Other variables in A are "ignored" (existential quantification)
|
|
* Other variables in B are kept
|
|
* Alternatively, vars=false means all variables are in vars
|
|
*
|
|
* Use this function to concatenate two relations --> -->
|
|
* or to take the 'previous' of a set --> S
|
|
*/
|
|
TASK_DECL_4(BDD, sylvan_relprev, BDD, BDD, BDDSET, BDDVAR);
|
|
#define sylvan_relprev(a,b,vars) CALL(sylvan_relprev,a,b,vars,0)
|
|
|
|
/**
|
|
* Compute R(s) = \exists x: A(x) \and B(x,s)
|
|
* with support(result) = s, support(A) = s, support(B) = s+t
|
|
* Assumes s,t are interleaved with s even and t odd (s+1).
|
|
* Parameter vars is the cube of all s and/or t variables.
|
|
* Other variables in A are kept
|
|
* Other variables in B are "ignored" (existential quantification)
|
|
* Alternatively, vars=false means all variables are in vars
|
|
*
|
|
* Use this function to take the 'next' of a set S -->
|
|
*/
|
|
TASK_DECL_4(BDD, sylvan_relnext, BDD, BDD, BDDSET, BDDVAR);
|
|
#define sylvan_relnext(a,b,vars) CALL(sylvan_relnext,a,b,vars,0)
|
|
|
|
/**
|
|
* Computes the transitive closure by traversing the BDD recursively.
|
|
* See Y. Matsunaga, P. C. McGeer, R. K. Brayton
|
|
* On Computing the Transitive Closure of a State Transition Relation
|
|
* 30th ACM Design Automation Conference, 1993.
|
|
*
|
|
* The input BDD must be a transition relation that only has levels of s,t
|
|
* with s,t interleaved with s even and t odd, i.e.
|
|
* s level 0,2,4 matches with t level 1,3,5 and so forth.
|
|
*/
|
|
TASK_DECL_2(BDD, sylvan_closure, BDD, BDDVAR);
|
|
#define sylvan_closure(a) CALL(sylvan_closure,a,0);
|
|
|
|
/**
|
|
* Compute f@c (f constrain c), such that f and f@c are the same when c is true
|
|
* The BDD c is also called the "care function"
|
|
* Special cases:
|
|
* - f@0 = 0
|
|
* - f@1 = f
|
|
* - 0@c = 0
|
|
* - 1@c = 1
|
|
* - f@f = 1
|
|
* - f@not(f) = 0
|
|
*/
|
|
TASK_DECL_3(BDD, sylvan_constrain, BDD, BDD, BDDVAR);
|
|
#define sylvan_constrain(f,c) (CALL(sylvan_constrain, f, c, 0))
|
|
|
|
/**
|
|
* Compute restrict f@c, which uses a heuristic to try and minimize a BDD f with respect to a care function c
|
|
* Similar to constrain, but avoids introducing variables from c into f.
|
|
*/
|
|
TASK_DECL_3(BDD, sylvan_restrict, BDD, BDD, BDDVAR);
|
|
#define sylvan_restrict(f,c) (CALL(sylvan_restrict, f, c, 0))
|
|
|
|
/**
|
|
* Function composition.
|
|
* For each node with variable <key> which has a <key,value> pair in <map>,
|
|
* replace the node by the result of sylvan_ite(<value>, <low>, <high>).
|
|
*/
|
|
TASK_DECL_3(BDD, sylvan_compose, BDD, BDDMAP, BDDVAR);
|
|
#define sylvan_compose(f,m) (CALL(sylvan_compose, (f), (m), 0))
|
|
|
|
/**
|
|
* Calculate number of satisfying variable assignments.
|
|
* The set of variables must be >= the support of the BDD.
|
|
*/
|
|
|
|
TASK_DECL_3(double, sylvan_satcount, BDD, BDDSET, BDDVAR);
|
|
#define sylvan_satcount(bdd, variables) CALL(sylvan_satcount, bdd, variables, 0)
|
|
|
|
/**
|
|
* Create a BDD cube representing the conjunction of variables in their positive or negative
|
|
* form depending on whether the cube[idx] equals 0 (negative), 1 (positive) or 2 (any).
|
|
* CHANGED 2014/09/19: vars is now a BDDSET (ordered!)
|
|
*/
|
|
BDD sylvan_cube(BDDSET variables, uint8_t *cube);
|
|
TASK_DECL_3(BDD, sylvan_union_cube, BDD, BDDSET, uint8_t*);
|
|
#define sylvan_union_cube(bdd, variables, cube) CALL(sylvan_union_cube, bdd, variables, cube)
|
|
|
|
/**
|
|
* Pick one satisfying variable assignment randomly for which <bdd> is true.
|
|
* The <variables> set must include all variables in the support of <bdd>.
|
|
*
|
|
* The function will set the values of str, such that
|
|
* str[index] where index is the index in the <variables> set is set to
|
|
* 0 when the variable is negative, 1 when positive, or 2 when it could be either.
|
|
*
|
|
* This implies that str[i] will be set in the variable ordering as in <variables>.
|
|
*
|
|
* Returns 1 when succesful, or 0 when no assignment is found (i.e. bdd==sylvan_false).
|
|
*/
|
|
int sylvan_sat_one(BDD bdd, BDDSET variables, uint8_t* str);
|
|
|
|
/**
|
|
* Pick one satisfying variable assignment randomly from the given <bdd>.
|
|
* Functionally equivalent to performing sylvan_cube on the result of sylvan_sat_one.
|
|
* For the result: sylvan_and(res, bdd) = res.
|
|
*/
|
|
BDD sylvan_sat_one_bdd(BDD bdd);
|
|
#define sylvan_pick_cube sylvan_sat_one_bdd
|
|
|
|
BDD sylvan_sat_single(BDD bdd, BDDSET vars);
|
|
#define sylvan_pick_single_cube sylvan_sat_single
|
|
|
|
/**
|
|
* Enumerate all satisfying variable assignments from the given <bdd> using variables <vars>.
|
|
* Calls <cb> with four parameters: a user-supplied context, the array of BDD variables in <vars>,
|
|
* the cube (array of values 0 and 1 for each variables in <vars>) and the length of the two arrays.
|
|
*/
|
|
LACE_TYPEDEF_CB(void, enum_cb, void*, BDDVAR*, uint8_t*, int);
|
|
VOID_TASK_DECL_4(sylvan_enum, BDD, BDDSET, enum_cb, void*);
|
|
#define sylvan_enum(bdd, vars, cb, context) CALL(sylvan_enum, bdd, vars, cb, context)
|
|
VOID_TASK_DECL_4(sylvan_enum_par, BDD, BDDSET, enum_cb, void*);
|
|
#define sylvan_enum_par(bdd, vars, cb, context) CALL(sylvan_enum_par, bdd, vars, cb, context)
|
|
|
|
/**
|
|
* Enumerate all satisfyable variable assignments of the given <bdd> using variables <vars>.
|
|
* Calls <cb> with two parameters: a user-supplied context and the cube (array of
|
|
* values 0 and 1 for each variable in <vars>).
|
|
* The BDD that <cb> returns is pair-wise merged (using or) and returned.
|
|
*/
|
|
LACE_TYPEDEF_CB(BDD, sylvan_collect_cb, void*, uint8_t*);
|
|
TASK_DECL_4(BDD, sylvan_collect, BDD, BDDSET, sylvan_collect_cb, void*);
|
|
#define sylvan_collect(bdd, vars, cb, context) CALL(sylvan_collect, bdd, vars, cb, context)
|
|
|
|
/**
|
|
* Compute the number of distinct paths to sylvan_true in the BDD
|
|
*/
|
|
TASK_DECL_2(double, sylvan_pathcount, BDD, BDDVAR);
|
|
#define sylvan_pathcount(bdd) (CALL(sylvan_pathcount, bdd, 0))
|
|
|
|
/**
|
|
* SAVING:
|
|
* use sylvan_serialize_add on every BDD you want to store
|
|
* use sylvan_serialize_get to retrieve the key of every stored BDD
|
|
* use sylvan_serialize_tofile
|
|
*
|
|
* LOADING:
|
|
* use sylvan_serialize_fromfile (implies sylvan_serialize_reset)
|
|
* use sylvan_serialize_get_reversed for every key
|
|
*
|
|
* MISC:
|
|
* use sylvan_serialize_reset to free all allocated structures
|
|
* use sylvan_serialize_totext to write a textual list of tuples of all BDDs.
|
|
* format: [(<key>,<level>,<key_low>,<key_high>,<complement_high>),...]
|
|
*/
|
|
size_t sylvan_serialize_add(BDD bdd);
|
|
size_t sylvan_serialize_get(BDD bdd);
|
|
BDD sylvan_serialize_get_reversed(size_t value);
|
|
void sylvan_serialize_reset(void);
|
|
void sylvan_serialize_totext(FILE *out);
|
|
void sylvan_serialize_tofile(FILE *out);
|
|
void sylvan_serialize_fromfile(FILE *in);
|
|
|
|
static void __attribute__((unused))
|
|
sylvan_fprint(FILE *f, BDD bdd)
|
|
{
|
|
sylvan_serialize_reset();
|
|
size_t v = sylvan_serialize_add(bdd);
|
|
fprintf(f, "%s%zu,", bdd&sylvan_complement?"!":"", v);
|
|
sylvan_serialize_totext(f);
|
|
}
|
|
|
|
static void __attribute__((unused))
|
|
sylvan_print(BDD bdd)
|
|
{
|
|
return sylvan_fprint(stdout, bdd);
|
|
}
|
|
|
|
#include "sylvan_bdd_storm.h"
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|
|
|
|
#endif
|