|
|
/*
* 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_LDD_H
#define SYLVAN_LDD_H
#ifdef __cplusplus
extern "C" { #endif /* __cplusplus */
typedef uint64_t MDD; // Note: low 40 bits only
static const MDD lddmc_false = 0; static const MDD lddmc_true = 1;
/* Initialize LDD functionality */ void sylvan_init_ldd(void);
/* Primitives */ MDD lddmc_makenode(uint32_t value, MDD ifeq, MDD ifneq); MDD lddmc_extendnode(MDD mdd, uint32_t value, MDD ifeq); uint32_t lddmc_getvalue(MDD mdd); MDD lddmc_getdown(MDD mdd); MDD lddmc_getright(MDD mdd); MDD lddmc_follow(MDD mdd, uint32_t value);
/**
* Copy nodes in relations. * A copy node represents 'read x, then write x' for every x. * In a read-write relation, use copy nodes twice, once on read level, once on write level. * Copy nodes are only supported by relprod, relprev and union. */
/* Primitive for special 'copy node' (for relprod/relprev) */ MDD lddmc_make_copynode(MDD ifeq, MDD ifneq); int lddmc_iscopy(MDD mdd); MDD lddmc_followcopy(MDD mdd);
/**
* Infrastructure for external references using a hash table. * Two hash tables store external references: a pointers table and a values table. * The pointers table stores pointers to MDD variables, manipulated with protect and unprotect. * The values table stores MDD, manipulated with ref and deref. * We strongly recommend using the pointers table whenever possible. */
/**
* Store the pointer <ptr> in the pointers table. */ void lddmc_protect(MDD* ptr);
/**
* Delete the pointer <ptr> from the pointers table. */ void lddmc_unprotect(MDD* ptr);
/**
* Compute the number of pointers in the pointers table. */ size_t lddmc_count_protected(void);
/**
* Store the MDD <dd> in the values table. */ MDD lddmc_ref(MDD dd);
/**
* Delete the MDD <dd> from the values table. */ void lddmc_deref(MDD dd);
/**
* Compute the number of values in the values table. */ size_t lddmc_count_refs(void);
/**
* Call mtbdd_gc_mark_rec for every mtbdd you want to keep in your custom mark functions. */ VOID_TASK_DECL_1(lddmc_gc_mark_rec, MDD) #define lddmc_gc_mark_rec(mdd) CALL(lddmc_gc_mark_rec, mdd)
/* Sanity check - returns depth of MDD including 'true' terminal or 0 for empty set */ #ifndef NDEBUG
size_t lddmc_test_ismdd(MDD mdd); #endif
/* Operations for model checking */ TASK_DECL_2(MDD, lddmc_union, MDD, MDD); #define lddmc_union(a, b) CALL(lddmc_union, a, b)
TASK_DECL_2(MDD, lddmc_minus, MDD, MDD); #define lddmc_minus(a, b) CALL(lddmc_minus, a, b)
TASK_DECL_3(MDD, lddmc_zip, MDD, MDD, MDD*); #define lddmc_zip(a, b, res) CALL(lddmc_zip, a, b, res)
TASK_DECL_2(MDD, lddmc_intersect, MDD, MDD); #define lddmc_intersect(a, b) CALL(lddmc_intersect, a, b)
TASK_DECL_3(MDD, lddmc_match, MDD, MDD, MDD); #define lddmc_match(a, b, proj) CALL(lddmc_match, a, b, proj)
MDD lddmc_union_cube(MDD a, uint32_t* values, size_t count); int lddmc_member_cube(MDD a, uint32_t* values, size_t count); MDD lddmc_cube(uint32_t* values, size_t count);
MDD lddmc_union_cube_copy(MDD a, uint32_t* values, int* copy, size_t count); int lddmc_member_cube_copy(MDD a, uint32_t* values, int* copy, size_t count); MDD lddmc_cube_copy(uint32_t* values, int* copy, size_t count);
TASK_DECL_3(MDD, lddmc_relprod, MDD, MDD, MDD); #define lddmc_relprod(a, b, proj) CALL(lddmc_relprod, a, b, proj)
TASK_DECL_4(MDD, lddmc_relprod_union, MDD, MDD, MDD, MDD); #define lddmc_relprod_union(a, b, meta, un) CALL(lddmc_relprod_union, a, b, meta, un)
/**
* Calculate all predecessors to a in uni according to rel[proj] * <proj> follows the same semantics as relprod * i.e. 0 (not in rel), 1 (read+write), 2 (read), 3 (write), -1 (end; rest=0) */ TASK_DECL_4(MDD, lddmc_relprev, MDD, MDD, MDD, MDD); #define lddmc_relprev(a, rel, proj, uni) CALL(lddmc_relprev, a, rel, proj, uni)
// so: proj: -2 (end; quantify rest), -1 (end; keep rest), 0 (quantify), 1 (keep)
TASK_DECL_2(MDD, lddmc_project, MDD, MDD); #define lddmc_project(mdd, proj) CALL(lddmc_project, mdd, proj)
TASK_DECL_3(MDD, lddmc_project_minus, MDD, MDD, MDD); #define lddmc_project_minus(mdd, proj, avoid) CALL(lddmc_project_minus, mdd, proj, avoid)
TASK_DECL_4(MDD, lddmc_join, MDD, MDD, MDD, MDD); #define lddmc_join(a, b, a_proj, b_proj) CALL(lddmc_join, a, b, a_proj, b_proj)
/* Write a DOT representation */ void lddmc_printdot(MDD mdd); void lddmc_fprintdot(FILE *out, MDD mdd);
void lddmc_fprint(FILE *out, MDD mdd); void lddmc_print(MDD mdd);
void lddmc_printsha(MDD mdd); void lddmc_fprintsha(FILE *out, MDD mdd); void lddmc_getsha(MDD mdd, char *target); // at least 65 bytes...
/**
* Calculate number of satisfying variable assignments. * The set of variables must be >= the support of the MDD. * (i.e. all variables in the MDD must be in variables) * * The cached version uses the operation cache, but is limited to 64-bit floating point numbers. */
typedef double lddmc_satcount_double_t; // if this line below gives an error, modify the above typedef until fixed ;)
typedef char __lddmc_check_float_is_8_bytes[(sizeof(lddmc_satcount_double_t) == sizeof(uint64_t))?1:-1];
TASK_DECL_1(lddmc_satcount_double_t, lddmc_satcount_cached, MDD); #define lddmc_satcount_cached(mdd) CALL(lddmc_satcount_cached, mdd)
TASK_DECL_1(long double, lddmc_satcount, MDD); #define lddmc_satcount(mdd) CALL(lddmc_satcount, mdd)
/**
* A callback for enumerating functions like sat_all_par, collect and match * Example: * TASK_3(void*, my_function, uint32_t*, values, size_t, count, void*, context) ... * For collect, use: * TASK_3(MDD, ...) */ LACE_TYPEDEF_CB(void, lddmc_enum_cb, uint32_t*, size_t, void*); LACE_TYPEDEF_CB(MDD, lddmc_collect_cb, uint32_t*, size_t, void*);
VOID_TASK_DECL_5(lddmc_sat_all_par, MDD, lddmc_enum_cb, void*, uint32_t*, size_t); #define lddmc_sat_all_par(mdd, cb, context) CALL(lddmc_sat_all_par, mdd, cb, context, 0, 0)
VOID_TASK_DECL_3(lddmc_sat_all_nopar, MDD, lddmc_enum_cb, void*); #define lddmc_sat_all_nopar(mdd, cb, context) CALL(lddmc_sat_all_nopar, mdd, cb, context)
TASK_DECL_5(MDD, lddmc_collect, MDD, lddmc_collect_cb, void*, uint32_t*, size_t); #define lddmc_collect(mdd, cb, context) CALL(lddmc_collect, mdd, cb, context, 0, 0)
VOID_TASK_DECL_5(lddmc_match_sat_par, MDD, MDD, MDD, lddmc_enum_cb, void*); #define lddmc_match_sat_par(mdd, match, proj, cb, context) CALL(lddmc_match_sat_par, mdd, match, proj, cb, context)
int lddmc_sat_one(MDD mdd, uint32_t *values, size_t count); MDD lddmc_sat_one_mdd(MDD mdd); #define lddmc_pick_cube lddmc_sat_one_mdd
/**
* Callback functions for visiting nodes. * lddmc_visit_seq sequentially visits nodes, down first, then right. * lddmc_visit_par visits nodes in parallel (down || right) */ LACE_TYPEDEF_CB(int, lddmc_visit_pre_cb, MDD, void*); // int pre(MDD, context)
LACE_TYPEDEF_CB(void, lddmc_visit_post_cb, MDD, void*); // void post(MDD, context)
LACE_TYPEDEF_CB(void, lddmc_visit_init_context_cb, void*, void*, int); // void init_context(context, parent, is_down)
typedef struct lddmc_visit_node_callbacks { lddmc_visit_pre_cb lddmc_visit_pre; lddmc_visit_post_cb lddmc_visit_post; lddmc_visit_init_context_cb lddmc_visit_init_context; } lddmc_visit_callbacks_t;
VOID_TASK_DECL_4(lddmc_visit_par, MDD, lddmc_visit_callbacks_t*, size_t, void*); #define lddmc_visit_par(mdd, cbs, ctx_size, context) CALL(lddmc_visit_par, mdd, cbs, ctx_size, context);
VOID_TASK_DECL_4(lddmc_visit_seq, MDD, lddmc_visit_callbacks_t*, size_t, void*); #define lddmc_visit_seq(mdd, cbs, ctx_size, context) CALL(lddmc_visit_seq, mdd, cbs, ctx_size, context);
size_t lddmc_nodecount(MDD mdd); void lddmc_nodecount_levels(MDD mdd, size_t *variables);
/**
* Functional composition * For every node at depth <depth>, call function cb (MDD -> MDD). * and replace the node by the result of the function */ LACE_TYPEDEF_CB(MDD, lddmc_compose_cb, MDD, void*); TASK_DECL_4(MDD, lddmc_compose, MDD, lddmc_compose_cb, void*, int); #define lddmc_compose(mdd, cb, context, depth) CALL(lddmc_compose, mdd, cb, context, depth)
/**
* SAVING: * use lddmc_serialize_add on every MDD you want to store * use lddmc_serialize_get to retrieve the key of every stored MDD * use lddmc_serialize_tofile * * LOADING: * use lddmc_serialize_fromfile (implies lddmc_serialize_reset) * use lddmc_serialize_get_reversed for every key * * MISC: * use lddmc_serialize_reset to free all allocated structures * use lddmc_serialize_totext to write a textual list of tuples of all MDDs. * format: [(<key>,<level>,<key_low>,<key_high>,<complement_high>),...] * * for the old lddmc_print functions, use lddmc_serialize_totext */ size_t lddmc_serialize_add(MDD mdd); size_t lddmc_serialize_get(MDD mdd); MDD lddmc_serialize_get_reversed(size_t value); void lddmc_serialize_reset(void); void lddmc_serialize_totext(FILE *out); void lddmc_serialize_tofile(FILE *out); void lddmc_serialize_fromfile(FILE *in);
/**
* Infrastructure for internal references. * Every thread has its own reference stacks. There are three stacks: pointer, values, tasks stack. * The pointers stack stores pointers to LDD variables, manipulated with pushptr and popptr. * The values stack stores LDD, manipulated with push and pop. * The tasks stack stores Lace tasks (that return LDD), manipulated with spawn and sync. * * It is recommended to use the pointers stack for local variables and the tasks stack for tasks. */
/**
* Push a LDD variable to the pointer reference stack. * During garbage collection the variable will be inspected and the contents will be marked. */ void lddmc_refs_pushptr(const MDD *ptr);
/**
* Pop the last <amount> LDD variables from the pointer reference stack. */ void lddmc_refs_popptr(size_t amount);
/**
* Push an LDD to the values reference stack. * During garbage collection the references LDD will be marked. */ MDD lddmc_refs_push(MDD dd);
/**
* Pop the last <amount> LDD from the values reference stack. */ void lddmc_refs_pop(long amount);
/**
* Push a Task that returns an LDD to the tasks reference stack. * Usage: lddmc_refs_spawn(SPAWN(function, ...)); */ void lddmc_refs_spawn(Task *t);
/**
* Pop a Task from the task reference stack. * Usage: MDD result = lddmc_refs_sync(SYNC(function)); */ MDD lddmc_refs_sync(MDD dd);
#ifdef __cplusplus
} #endif /* __cplusplus */
#endif
|