use std::collections::HashSet;
use biodivine_lib_bdd::{Bdd, BddVariable, BddVariableSet};
use crate::kripke::KripkeStructure;
pub(crate) struct KripkeStructureBddRepresentation {
num_states : usize,
pub var_set : BddVariableSet,
pub raw_vars : Vec<BddVariable>,
transition_relation : Bdd,
negated_transition_relation : Bdd,
next_iff_current : Bdd
}
fn get_strict_state_formula_for_transition_relation(
is_next : bool,
num_states : usize,
var_set : &BddVariableSet,
raw_vars : &[BddVariable],
selected_state_id : usize
) -> Bdd {
let mut formula = var_set.mk_true();
for st_id in 0..num_states {
let var = if is_next {
raw_vars.get(num_states + st_id).unwrap()
} else {
raw_vars.get(st_id).unwrap()
};
let state_bdd = if st_id == selected_state_id {
var_set.mk_var(*var)
} else {
var_set.mk_var(*var).not()
};
formula = formula.and(&state_bdd);
}
formula
}
impl KripkeStructureBddRepresentation {
pub(crate) fn get_state_formula(&self, selected_state_id : usize) -> Bdd {
let mut formula = self.var_set.mk_true();
for st_id in 0..self.num_states {
let var = self.raw_vars.get(st_id).unwrap();
let state_bdd = if st_id == selected_state_id {
self.var_set.mk_var(*var)
} else {
self.var_set.mk_var(*var).not()
};
formula = formula.and(&state_bdd);
}
formula
}
pub(crate) fn get_states_set_formula(
&self,
selected_states_ids : &HashSet<usize>
) -> Bdd {
let mut formula = self.var_set.mk_false();
for st_id in selected_states_ids {
let state_bdd = self.get_state_formula(*st_id);
formula = formula.or(
&state_bdd
);
}
formula
}
pub fn from_kripke_structure<DOAP>(kripke : &KripkeStructure<DOAP>) -> Self {
let num_states = kripke.states.len();
let var_set = BddVariableSet::new_anonymous((num_states*2) as u16);
let raw_vars = var_set.variables();
let mut transition_relation = var_set.mk_false();
for (origin_st_id, k_state) in kripke.states.iter().enumerate() {
let origin_st_current_formula = get_strict_state_formula_for_transition_relation(
false,
num_states,
&var_set,
&raw_vars,
origin_st_id
);
for target_st_id in &k_state.outgoing_transitions_targets {
let target_st_next_formula = get_strict_state_formula_for_transition_relation(
true,
num_states,
&var_set,
&raw_vars,
*target_st_id
);
let transition_bdd = origin_st_current_formula.and(&target_st_next_formula);
transition_relation = transition_relation.or(&transition_bdd);
}
}
let negated_transition_relation = transition_relation.not();
let mut next_iff_current = var_set.mk_true();
for st_id in 0..num_states {
let st_current_var = raw_vars.get(st_id).unwrap();
let st_next_var = raw_vars.get(st_id + num_states).unwrap();
next_iff_current = next_iff_current.and(
&var_set.mk_var(*st_current_var).iff(&var_set.mk_var(*st_next_var))
);
}
Self {
num_states,var_set,raw_vars,transition_relation,negated_transition_relation,next_iff_current
}
}
pub fn get_pre_image_by_transition_relation(&self, kind : PreImageKind, current_states : &Bdd) -> Bdd {
match kind {
PreImageKind::Weak => {
current_states
.and(&self.next_iff_current)
.exists(&self.raw_vars[0..self.num_states])
.and(&self.transition_relation)
.exists(&self.raw_vars[self.num_states..])
},
PreImageKind::Strong => {
current_states
.and(&self.next_iff_current)
.exists(&self.raw_vars[0..self.num_states])
.or(&self.negated_transition_relation)
.for_all(&self.raw_vars[self.num_states..])
}
}
}
}
pub(crate) enum PreImageKind {
Weak,
Strong
}