debug!("merge_transitions requires full-domain transition relations; enabling relation extension");
let preprocessed_lts = preprocess_lts(manager_ref, lts, use_extended_relations, merge_transitions)?;
let num_of_states = approx_satcount(lts.states(), lts.state_variables().len() as VarNo, &mut satcount_cache);
// Caches for [refine]. `refine_cache` is the BDD-level memo and its allocation is reused across
// iterations (cleared each iteration). `claimed_blocks` records which old block ids have already
// been claimed (reused as-is) this iteration; `next_fresh_id` is the persistent counter handing
let mut refine_cache: FxHashMap<(BDDFunction, BDDFunction), BDDFunction> = FxHashMap::default();
// In the sigref algorithm, the partition is defined over the next state. When we compute the signature
// we then get (s, a, b), since in the signature we need to consider the block of the next state.
.map(|group| -> Result<_, MercError> { Ok(compute_vars_bdd(manager_ref, group.write_variables())?.1) })
let group_signature = variable_rename(manager_ref, &group_signature, &state_substitution)?;
/// Computes a partitioning of the transition groups for the given LTS based on the split signature option.
/// Two transition groups are combined if they share action labels, this ensures that in split signature mode
fn combine_transition_groups(manager_ref: &BDDManagerRef, lts: &SymbolicLtsBdd) -> Result<Vec<Vec<usize>>, MercError> {
// In split signature mode we must ensure that the action labels of all transition groups are disjoint. We do this by merging
let state_and_next_state_vars = manager_ref.with_manager_shared(|manager| -> Result<_, OutOfMemory> {
for (i, representative) in representatives.iter().enumerate().take(lts.transition_groups().len()) {
if let Some(result) = cache.get(&BDDFunction::from_edge(manager, manager.clone_edge(&bdd))) {
// There are variables in the range that are not in the domain, so this cannot be a function from domain to range.
/// Checks if the given BDD is a cube, i.e., it represents a single bitvector over the given variables.
for (state_var, next_state_var) in state_variables.iter().zip(next_state_variables.iter()).rev() {
eq = EdgeDropGuard::new(manager, reduce(manager, *state_var, low.into_edge(), high.into_edge())?);
/// Display helper that prints all vectors represented by the given signature BDD as numbers, by decoding
/// Display helper that prints all vectors represented by the given signature BDD as numbers, by decoding
fn new(signature: &'a BDDFunction, variables: &'a Vec<VarNo>, num_of_bits: &'a [u32], block_bits: u32) -> Self {
let block_variable_names = (0..num_of_bits).map(|i| format!("b_{}", i)).collect::<Vec<String>>();
let lts_bdd = SymbolicLtsBdd::from_symbolic_lts(&ldd_manager, &bdd_manager, <s).unwrap();
sigref_symbolic(&bdd_manager, <s_bdd, &Timing::new(), false, false, false, false).unwrap();
let lts_bdd_split = SymbolicLtsBdd::from_symbolic_lts(&ldd_manager, &bdd_manager_split, <s).unwrap();
let lts_bdd = SymbolicLtsBdd::from_symbolic_lts(&ldd_manager, &bdd_manager, <s_bdd).unwrap();
sigref_symbolic(&bdd_manager, <s_bdd, &Timing::new(), false, false, false, false).unwrap();
sigref_symbolic(&bdd_manager, <s_bdd, &Timing::new(), false, false, false, false).unwrap();
let lts_bdd = SymbolicLtsBdd::from_symbolic_lts(&ldd_manager, &bdd_manager, <s).unwrap();
sigref_symbolic(&bdd_manager, <s_bdd, &Timing::new(), false, false, false, false).unwrap();
let quotient_lts = quotient_symbolic(&bdd_manager, <s_bdd, &partition, &block_vars).unwrap();
let symbolic_lts_reduced = convert_symbolic_lts_bdd(&bdd_manager, &mut builder, "ient_lts).unwrap();