def __init__(self, atom: Union[Atom, str] = None, kind: FormulaKind = None): if kind is None: self.__kind = FormulaKind.UNDEFINED self.__kind = kind if self.__kind == FormulaKind.REFINEMENT_RULES or \ self.__kind == FormulaKind.ADJACENCY_RULES or \ self.__kind == FormulaKind.MUTEX_RULES: self.__spec_kind = SpecKind.RULE else: self.__spec_kind = SpecKind.UNDEFINED if isinstance(atom, str) and atom == "TRUE": from specification.atom import Atom new_atom = Atom("TRUE") self.__cnf: List[Set[Atom]] = [{new_atom}] self.__dnf: List[Set[Atom]] = [{new_atom}] elif isinstance(atom, str) and atom == "FALSE": from specification.atom import Atom new_atom = Atom("FALSE") self.__cnf: List[Set[Atom]] = [{new_atom}] self.__dnf: List[Set[Atom]] = [{new_atom}] elif atom is not None: self.__cnf: List[Set[Atom]] = [{atom}] self.__dnf: List[Set[Atom]] = [{atom}] else: raise Exception("Wrong parameters LTL_forced construction")
def __iand__(self, other: Union[Formula, Atom]) -> Formula: """self &= other Modifies self with the conjunction with other""" from specification.atom import Atom if isinstance(other, Atom): other = Formula(other) if other.is_false(): new_atom = Atom("FALSE") self.__cnf: List[Set[Atom]] = [{new_atom}] self.__dnf: List[Set[Atom]] = [{new_atom}] return self if other.is_true(): return self if other.is_true(): self.__cnf = other.cnf self.__dnf = other.dnf return self if self.is_true(): new_other = deepcopy(other) self.__cnf: List[Set[Atom]] = new_other.cnf self.__dnf: List[Set[Atom]] = new_other.dnf return self new_other = deepcopy(other) """Mutex Rules necessary for Satisfiability Check""" mutex_rules = Atom.extract_mutex_rules(self.typeset | other.typeset) """Cartesian product between the two dnf""" temp_dnf = [] for a, b in itertools.product(self.dnf, new_other.dnf): new_set = a | b check_formula = LogicTuple.and_([f.formula() for f in new_set]) """Adding Rules""" if mutex_rules is not None: check_formula = LogicTuple.and_( [check_formula, mutex_rules.formula()]) if Nuxmv.check_satisfiability(check_formula): temp_dnf.append(new_set) if len(temp_dnf) == 0: raise NotSatisfiableException(self, other, mutex_rules) else: self.__dnf = temp_dnf """Append to list if not already there""" for other_elem in new_other.cnf: if other_elem not in self.cnf: self.__cnf.append(other_elem) return self
def __init__(self, supertypes: Dict[AllTypes, Set[AllTypes]]): super().__init__(atom=Atom("TRUE"), kind=FormulaKind.REFINEMENT_RULES) for key_type, set_super_types in supertypes.items(): if isinstance(key_type, Boolean): for super_type in set_super_types: f = Logic.g_(Logic.implies_(key_type.name, super_type.name)) t = Typeset({key_type, super_type}) new_atom = Atom(formula=(f, t), kind=AtomKind.REFINEMENT_RULE) self.__iand__(new_atom)
def __ior__(self, other: Union[Formula, Atom]) -> Formula: """self |= other Modifies self with the disjunction with other""" from specification.atom import Atom if isinstance(other, Atom): other = Formula(other) if self.is_true(): return self if other.is_true(): new_atom = Atom("TRUE") self.__cnf: List[Set[Atom]] = [{new_atom}] self.__dnf: List[Set[Atom]] = [{new_atom}] return self if other.is_false(): return self new_other = deepcopy(other) """Cartesian product between the two cnf""" temp_cnf = [] for a, b in itertools.product(self.cnf, new_other.cnf): new_set = a | b check_formula = LogicTuple.or_([f.formula() for f in new_set]) if not Nuxmv.check_validity(check_formula): temp_cnf.append(new_set) else: pass if len(temp_cnf) == 0: """Result is TRUE""" new_atom = Atom("TRUE") self.__cnf: List[Set[Atom]] = [{new_atom}] self.__dnf: List[Set[Atom]] = [{new_atom}] return self else: self.__cnf = temp_cnf """Append to list if not already there""" for other_elem in new_other.dnf: if other_elem not in self.dnf: self.__dnf.append(other_elem) return self
def is_satisfiable(self) -> bool: sat_check_formula = self.formula() """If does not contain Mutex Rules already, extract them and check the satisfiability""" from specification.atom import Atom mutex_rules = Atom.extract_mutex_rules(self.typeset) if mutex_rules is not None: sat_check_formula = LogicTuple.and_( [self.formula(), mutex_rules.formula()]) return Nuxmv.check_satisfiability(sat_check_formula)
def __le__(self: Specification, other: Specification): """self <= other. True if self is a refinement of other""" if other.is_true(): return True """Check if self -> other is valid, considering the refinement rules r""" """((r & s1) -> s2) === r -> (s1 -> s2)""" from specification.atom import Atom refinement_rules = Atom.extract_refinement_rules(self.typeset | other.typeset) if refinement_rules is not None: # ref_check_formula = (self & refinement_rules) >> other ref_check_formula = LogicTuple.implies_( LogicTuple.and_([self.formula(), refinement_rules.formula()]), other.formula()) else: # ref_check_formula = self >> other ref_check_formula = LogicTuple.implies_(self.formula(), other.formula()) return Nuxmv.check_validity(ref_check_formula)
def create_transition_controller(self, start: Types, finish: Types, t_trans: int) -> Controller: t_controller_name = f"TRANS_{start.name}->{finish.name}" if self.session_name is None: folder_name = f"{self.t_controllers_folder_name}/{t_controller_name}" else: folder_name = f"{self.session_name}/{self.t_controllers_folder_name}/{t_controller_name}" typeset = Typeset({start, finish}) realizable = False for n_steps in range(1, t_trans): trans_spec_str = Logic.and_([start.name, Logic.xn_(finish.name, n_steps)]) trans_spec = Atom(formula=(trans_spec_str, typeset)) trans_contract = Contract(guarantees=trans_spec) try: controller_info = trans_contract.get_controller_info(world_ts=self.world.typeset) a, g, i, o = controller_info.get_strix_inputs() controller_synthesis_input = StringMng.get_controller_synthesis_str(controller_info) Store.save_to_file(controller_synthesis_input, f"t_controller_{start.name}_{finish.name}_specs.txt", folder_name) realized, kiss_mealy, time = Strix.generate_controller(a, g, i, o) if realized: realizable = True break except ControllerException as e: raise TransSynthesisFail(self, e) if not realizable: raise Exception( f"Controller [{start.name}, {finish.name}] cannot be synthetized in {t_trans} steps") else: Store.save_to_file(kiss_mealy, f"{start.name}_{finish.name}_mealy", folder_name) # Store.generate_eps_from_dot(dot_mealy, f"{start.name}_{finish.name}_dot", # folder_name) t_controller = Controller(mealy_machine=kiss_mealy, world=self.world, name=t_controller_name, synth_time=time) Store.save_to_file(str(t_controller), f"{start.name}_{finish.name}_table", folder_name) return t_controller
def _remove_atoms(self, atoms_to_remove: Set[Atom]): """Remove Atoms from Formula""" if len(atoms_to_remove) == 1 and list(atoms_to_remove)[0].is_true(): return """Remove from CNF""" for clause in self.__dnf: clause -= atoms_to_remove """Remove from CNF""" clause_cnf_to_remove = set() for clause in self.__cnf: """Remove clause if contains atoms to be removed""" if clause & atoms_to_remove: clause_cnf_to_remove |= clause """Filter out clauses""" for clause in list(self.cnf): if len(clause & clause_cnf_to_remove) > 0: self.__cnf.remove(clause) if len(self.atoms) == 0: new_atom = Atom("TRUE") self.__cnf: List[Set[Atom]] = [{new_atom}] self.__dnf: List[Set[Atom]] = [{new_atom}]
def get_controller_info(self, world_ts: Typeset = None) -> SynthesisInfo: """Extract All Info Needed to Build a Controller from the Contract""" if world_ts is None: world_ts = Typeset() """Assumptions""" a_initial: List[str] = [] a_fairness: List[str] = [] a_safety: List[str] = [] a_mutex: List[str] = [] """Guarantees""" g_initial: List[str] = [] g_safety: List[str] = [] g_mutex: List[str] = [] g_goal: List[str] = [] a_typeset = Typeset() g_typeset = Typeset() list, typeset = self.assumptions.formula(FormulaOutput.ListCNF) a_initial.extend(list) a_typeset |= typeset list, typeset = self.guarantees.formula(FormulaOutput.ListCNF) g_goal.extend(list) g_typeset |= typeset all_typeset = a_typeset | g_typeset | world_ts """Inputs typeset""" i_typeset = Typeset(all_typeset.extract_inputs()) """Output typeset""" o_typeset = Typeset(all_typeset.extract_outputs()) actions_typeset = Typeset(all_typeset.ext()) """Mutex""" ret = Atom.extract_mutex_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_mutex.extend(rules) ret = Atom.extract_mutex_rules(o_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_mutex.extend(rules) """For the rules we extracts rules from the variables based on assumptions and inputs""" a_typeset = a_typeset | i_typeset """We remove the inputs typeset from the guarantees and we incorporate the variables ts""" g_typeset = g_typeset - i_typeset """Adding Mutex Rules""" ret = Atom.extract_mutex_rules(a_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_mutex.extend(rules) a_typeset |= typeset ret = Atom.extract_mutex_rules(g_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_mutex.extend(rules) g_typeset |= typeset """Adjacecy rules can include things that are in the world_ts""" if world_ts is not None: adjacency_ts = g_typeset | world_ts else: adjacency_ts = g_typeset ret = Atom.extract_adjacency_rules(adjacency_ts, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_adjacency.extend(rules) g_typeset |= typeset """Adding Liveness To Sensors (input)""" ret = Atom.extract_liveness_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_liveness.extend(rules) """Extract Inputs and Outputs""" inputs = [t.name for t in (a_typeset | g_typeset).extract_inputs()] outputs = [t.name for t in (a_typeset | g_typeset).extract_outputs()] return SynthesisInfo(a_initial=assumptions, a_fairness=a_liveness, a_mutex=a_mutex, guarantees=guarantees, g_mutex=g_mutex, g_safety=g_adjacency, inputs=inputs, outputs=outputs)
def to_atom(self): from specification.atom import Atom, AtomKind from typeset import Typeset return Atom(formula=(self.name, Typeset({self})), check=False, kind=AtomKind.LOCATION)
def __init__(self, name: str = "c"): super().__init__(name) class GoD(ReachLocation): def __init__(self, name: str = "d"): super().__init__(name) a = GoA() b = GoB() c = GoC() d = GoD() a = Atom((a.name, Typeset({a}))) b = Atom((b.name, Typeset({b}))) c = Atom((c.name, Typeset({c}))) d = Atom((d.name, Typeset({d}))) test = a >> ~ a print(test.formula(FormulaOutput.CNF)[0]) print(test.formula(FormulaOutput.DNF)[0]) one = a & b print("\none") print(one.formula(FormulaOutput.CNF)[0]) print(one.formula(FormulaOutput.DNF)[0])
def to_atom(self): from specification.atom import Atom from typeset import Typeset return Atom(formula=(self.name, Typeset({self})), check=False)
K1(), # K2(), K3(), # R1(), # R2(), }, sensors={ ObjectRecognized(), Alexa(), GroceriesRecognized() }, contexts={ Housekeeping(), Party(), Cleanup(), Groceries(), Garbage() }) if __name__ == '__main__': w = RobocupHome() a_rules, a_ts = Atom.extract_mutex_rules(w.typeset, output=FormulaOutput.ListCNF) m_rules, m_ts = Atom.extract_adjacency_rules(w.typeset, output=FormulaOutput.ListCNF) print("\n".join(m_rules)) print(", ".join(m_ts.keys())) print("\n\n") print("\n".join(a_rules)) print(", ".join(a_ts.keys()))
def get_controller_info(self, world_ts: Typeset = None) -> SynthesisInfo: """Extract All Info Needed to Build a Controller from the Contract""" """Assumptions""" assumptions = [] a_mutex = [] a_liveness = [] """Guarantees""" guarantees = [] g_mutex = [] g_adjacency = [] a_typeset = Typeset() g_typeset = Typeset() list, typeset = self.assumptions.formula(FormulaOutput.ListCNF) assumptions.extend(list) a_typeset |= typeset list, typeset = self.guarantees.formula(FormulaOutput.ListCNF) guarantees.extend(list) g_typeset |= typeset if world_ts is not None: instance_ts = Typeset.get_instance_ts((a_typeset | g_typeset), world_ts) else: instance_ts = (a_typeset | g_typeset) """Extracting Inputs and Outputs Including the variables""" i_set, o_set = instance_ts.extract_inputs_outputs() i_typeset = Typeset(i_set) o_typeset = Typeset(o_set) """Mutex Rules""" ret = Atom.extract_mutex_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_mutex.extend(rules) ret = Atom.extract_mutex_rules(o_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_mutex.extend(rules) """Adjacecy Rules""" ret = Atom.extract_adjacency_rules(o_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_adjacency.extend(rules) """Adding Liveness To Sensors (input)""" ret = Atom.extract_liveness_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_liveness.extend(rules) """Adding context and active signal rules""" ret = Atom.context_active_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret assumptions.extend(rules) """Extract Inputs and Outputs""" inputs = [t.name for t in i_set] outputs = [t.name for t in o_set] return SynthesisInfo(assumptions=assumptions, a_liveness=a_liveness, a_mutex=a_mutex, guarantees=guarantees, g_mutex=g_mutex, g_adjacency=g_adjacency, inputs=inputs, outputs=outputs)