def __init__(self, locations: List[LTL]): variables = Variables() pattern_formula = [] guarantee = "F(" for n, location in enumerate(locations): variables.extend(location.variables) guarantee += location.formula if n == len(locations) - 1: for _ in range(len(locations)): guarantee += ")" else: guarantee += " & F(" pattern_formula.append(guarantee) for n, location in enumerate(locations): if n < len(locations) - 1: pattern_formula.append("(!" + locations[n + 1].formula + " U " + locations[n].formula + ")") pattern_formula = And(pattern_formula) super().__init__(pattern_formula, locations, variables)
def __iand__(self, other): """self &= other Modifies self with the conjunction with other""" if not isinstance(other, LTL): return AttributeError if self.context is not None and other.context is not None: if self.context != other.context: raise DifferentContextException(self.context, other.context) if self.context is None and other.context is not None: raise DifferentContextException(self.context, other.context) """Contexts must be equal""" if self.__formula == "TRUE": self.__formula = deepcopy(other.formula) self.__variables = deepcopy(other.variables) self.__cnf = deepcopy(other.cnf) return self if other.formula == "TRUE": return self if other.formula == "FALSE": self.__formula = "FALSE" self.__cnf |= other.cnf return self self.__formula = And([self.__formula, other.unsaturated]) self.__variables |= other.variables self.__cnf |= other.cnf if not self.is_satisfiable(): raise InconsistentException(self, other) return self
def __init__(self, locations: List[LTL] = None): variables = Variables() pattern_formula = [] formula = "" for i, location in enumerate(locations): variables.extend(location.variables) formula += "F(" + location.formula if i < len(locations) - 1: formula += " & " for i in range(0, len(locations)): formula += ")" pattern_formula.append(formula) for n, location in enumerate(locations): if n < len(locations) - 1: pattern_formula.append("(!" + locations[n + 1].formula + " U " + locations[n].formula + ")") for n, location in enumerate(locations): if n < len(locations) - 1: pattern_formula.append("(!" + locations[n].formula + " U (" + locations[n].formula + " & X(!" + locations[n].formula + " U(" + locations[n + 1].formula + "))))") pattern_formula = And(pattern_formula) super().__init__(pattern_formula, locations, variables)
def check_satisfiability(variables: List[str], propositions: Union[List[str], str]) -> bool: if isinstance(propositions, str): propositions = [propositions] if len(propositions) == 1 and propositions[0] == "TRUE": return True if len(propositions) == 0: return True """Write the NuSMV file""" with open(smvfile, 'w') as ofile: ofile.write('MODULE main\n') ofile.write('VAR\n') for v in list(set(variables)): ofile.write('\t' + v + ";\n") ofile.write('\n') ofile.write('LTLSPEC ') ofile.write(str(Not(And(propositions)))) ofile.write('\n') try: output = subprocess.check_output( ['nuXmv', smvfile], encoding='UTF-8', stderr=subprocess.DEVNULL).splitlines() output = [ x for x in output if not (x[:3] == '***' or x[:7] == 'WARNING' or x == '') ] for line in output: if line[:16] == '-- specification': if 'is false' in line: print("\t\t\tSAT:\t" + str(And(propositions))) return True elif 'is true' in line: return False except Exception as e: with open(smvfile, 'r') as fin: print(fin.read()) raise e
def __init__(self, locations: List[LTL] = None): variables = Variables() pattern_formula = [] for location in locations: variables.extend(location.variables) pattern_formula.append("G(F(" + location.formula + "))") pattern_formula = And(pattern_formula) super().__init__(pattern_formula, locations, variables)
def __init__(self, locations: List[LTL]): variables = Variables() pattern_formula = [] for location in locations: variables |= location.variables pattern_formula.append("F(" + location.formula + ")") pattern_formula = And(pattern_formula) super().__init__(pattern_formula, locations, variables)
def extract_ltl_rules(context_rules: Dict) -> List[LTL]: """Dict: ltl_formula -> list_of_variables_involved""" ltl_list: List[LTL] = [] if "mutex" in context_rules: for cvars in context_rules["mutex"]: if len(cvars) > 0: variables: Variables = Variables() ltl = "G(" for vs in cvars: variables.extend(vs.variables) cvars_str = [n.formula for n in cvars] clauses = [] for vs_a in cvars_str: clause = [] clause.append(deepcopy(vs_a)) for vs_b in cvars_str: if vs_a is not vs_b: clause.append(Not(deepcopy(vs_b))) clauses.append(And(clause)) ltl += Or(clauses) ltl += ")" ltl_list.append(LTL(formula=ltl, variables=variables)) if "inclusion" in context_rules: for cvars in context_rules["inclusion"]: if len(cvars) > 0: variables: Variables = Variables() ltl = "G(" for i, vs in enumerate(cvars): variables.extend(vs.variables) ltl += str(vs) if i < (len(cvars) - 1): ltl += " -> " ltl += ")" ltl_list.append(LTL(formula=ltl, variables=variables)) if "liveness" in context_rules: for cvars in context_rules["liveness"]: variables: Variables = Variables() ltl = "G( F(" variables.extend(cvars.variables) ltl += str(cvars) ltl += "))" ltl_list.append(LTL(formula=ltl, variables=variables)) return ltl_list
def prioritize_goal(first_priority_goal, second_priority_goal): pass """ Makes the assumption of one goal dependent on the satisfiability of the assumptions of the second goal """ variables = [] stronger_assumptions_list = [] for contract in first_priority_goal.contracts: variables |= contract.variables stronger_assumptions_list.append(And(contract.assumptions)) for contract in second_priority_goal.contracts: contract.add_variables(variables) contract.add_assumptions(Not(Or(stronger_assumptions_list)))
def remove(self, element): self.cnf.remove(element) if len(self.cnf) == 0: self.__formula: str = "TRUE" self.__cnf: Set['LTL'] = {self} self.__variables: Variables = Variables() return cnf_str = [x.formula for x in self.cnf] self.__formula: str = And(cnf_str) self.__variables: Variables = Variables() variables = set() for x in self.cnf: variables.add(x.variables) self.__variables &= variables
def conjoin_with_formula(self, other: 'LTL') -> bool: """Returns True if other has been conjoined""" if self.formula == "FALSE": print( "The conjunction has no effects since the current formula is FALSE" ) return False if self.formula == "TRUE": self.formula = deepcopy(other.formula) self.variables = deepcopy(other.variables) return True if other.formula == "FALSE": self.formula = "FALSE" return True if other.formula == "TRUE": print( "The conjunction has no effects since the other formula is FALSE" ) return False if other <= self: """the other formula is a refinement of the current formula""" self.formula = deepcopy(other.formula) self.variables = deepcopy(other.variables) return True if self.is_satisfiable_with(other): new_formula = deepcopy(self) new_formula.variables.extend(other.variables) new_formula.formula = And([new_formula.formula, other.formula]) """If by conjoining other, the result should be a refinement of the existing formula""" if new_formula <= self: self.formula = deepcopy(new_formula.formula) self.variables = deepcopy(new_formula.variables) return True else: raise InconsistentException(self, other)
def __init__(self, locations: List[str] = None): conj_list = [] guarantee = "F(" for n, location in enumerate(locations): guarantee += location if n == len(locations) - 1: for _ in range(len(locations)): guarantee += ")" else: guarantee += " & F(" conj_list.append(guarantee) for n, location in enumerate(locations): if n < len(locations) - 1: conj_list.append("(!" + locations[n + 1] + " U " + locations[n] + ")") super().__init__(locations, And(conj_list))
def __init__(self, formulae: List['LTL'], simplify=True): "formulae: list of formula to conjoin" "LTL formula" self.__formula: LTL = None "List of LTL formulae in conjunction that it is formed of" self.__list: List[LTL] = None if len(formulae) == 0: self.__formula: LTL = LTL("TRUE") self.__list: List[LTL] = [] else: if simplify: self.__formula: LTL = LTL(formulae[0].formula, formulae[0].variables) self.__list: List[LTL] = [formulae[0]] if len(formulae) > 1: try: added_formulae = self.__formula.conjoin_with(formulae[1:]) self.list.extend(added_formulae) except InconsistentException as e: raise e else: variables = Variables() formulae_str = [] for formula in formulae: variables.extend(formula.variables) formulae_str.append(formula.formula) try: self.__formula: LTL = LTL(And(formulae_str), variables) except InconsistentException as e: raise e self.__list: List[LTL] = formulae
def extract_saturated_guarantees_from( goals: Union[CGTGoal, List[CGTGoal]]) -> List[str]: if isinstance(goals, CGTGoal): goals = [goals] assumptions_goals = [] guarantees_goals = [] variables_goals = set() for goal in goals: goal_variables = set() goal_new_variables = set() goal_old_variables = set() assumptions_guarantee_pairs = [] for contract in goal.contracts: a_boolean, a_new_vars, a_old_vars = traslate_boolean( str(contract.assumptions.formula)) g_boolean, g_new_vars, g_old_vars = traslate_boolean( str(contract.guarantees.formula)) vars = [v.name for v in contract.variables.list] goal_variables.update(vars) a_new_vars.extend(g_old_vars) a_old_vars.extend(g_old_vars) goal_new_variables.update(a_new_vars) goal_old_variables.update(a_old_vars) assumptions_guarantee_pairs.append((a_boolean, g_boolean)) goal_variables = goal_variables - goal_old_variables goal_variables.update(goal_new_variables) assumptions_goal = Or([a for (a, goal) in assumptions_guarantee_pairs]) guarantees_goal = And( [Implies(a, goal) for (a, goal) in assumptions_guarantee_pairs]) guarantees_goals.append(guarantees_goal) variables_goals.update(goal_variables) return guarantees_goals
def extract_rules(rules: Dict) -> Dict: """Translates the rules in LTL formulae and returnes a dictionary of 5 cathegories""" """Dictionary to return""" rules_ltl = {} if "gridworld" in rules: rules_ltl["gridworld"] = [] for elem, adjacent in rules["gridworld"].items(): ltl = "G(" ltl += elem.formula + " -> X (" ltl += " | ".join([a.formula for a in adjacent]) ltl += "))" variables = Variables() variables |= elem.variables for a in adjacent: variables |= a.variables rules_ltl["gridworld"].append( LTL(formula=ltl, variables=variables, kind="gridworld")) if "context" in rules: rules_ltl["context"] = [] if "mutex" in rules["context"]: for mtx_elements in rules["context"]["mutex"]: if len(mtx_elements) > 0: variables: Variables = Variables() ltl = "G(" for vs in mtx_elements: variables |= vs.variables mtx_elements_str = [n.formula for n in mtx_elements] clauses = [] for vs_a in mtx_elements_str: clause = [deepcopy(vs_a)] for vs_b in mtx_elements_str: if vs_a is not vs_b: clause.append(Not(deepcopy(vs_b))) clauses.append(And(clause)) ltl += Or(clauses) ltl += ")" rules_ltl["context"].append( LTL(formula=ltl, variables=variables, kind="context")) if "inclusion" in rules["context"]: for pre, post in rules["context"]["inclusion"].items(): variables = Variables() variables |= pre.variables | post.variables ltl = "G((" + pre.formula + ") -> (" + post.formula + "))" rules_ltl["context"].append( LTL(formula=ltl, variables=variables, kind="context")) if "context_gridworld" in rules: rules_ltl["context_gridworld"] = [] for pre, post in rules["context_gridworld"].items(): variables = Variables() variables |= pre.variables | post.variables ltl = "G((" + pre.formula + ") -> (" + post.formula + "))" rules_ltl["context_gridworld"].append( LTL(formula=ltl, variables=variables, kind="context_gridworld")) if "constraints" in rules: rules_ltl["constraints"] = [] if "mutex" in rules["constraints"]: for mtx_elements in rules["constraints"]["mutex"]: if len(mtx_elements) > 0: variables: Variables = Variables() ltl = "G(" for vs in mtx_elements: variables |= vs.variables mtx_elements_str = [n.formula for n in mtx_elements] clauses = [] for vs_a in mtx_elements_str: clause = [deepcopy(vs_a)] for vs_b in mtx_elements_str: if vs_a is not vs_b: clause.append(Not(deepcopy(vs_b))) clauses.append(And(clause)) ltl += Or(clauses) ltl += ")" rules_ltl["constraints"].append( LTL(formula=ltl, variables=variables, kind="constraints")) if "inclusion" in rules["constraints"]: for pre, post in rules["constraints"]["inclusion"].items(): variables = Variables() variables |= pre.variables | post.variables ltl = "G((" + pre.formula + ") -> (" + post.formula + "))" rules_ltl["constraints"].append( LTL(formula=ltl, variables=variables, kind="constraints")) return rules_ltl
def __init__(self, formula: str = None, variables: Variables = None, cnf: Set['LTL'] = None, kind: str = None, context: 'LTL' = None, skip_checks: bool = False): """Basic LTL formula. It can be build by a single formula (str) or by a conjunction of other LTL formulae (CNF form)""" self.__saturation = None if formula is not None and cnf is None: if variables is None: variables = extract_variable(str(formula)) """String representing the LTL""" self.__formula: str = formula """Variables present in the formula""" self.__variables: Variables = variables """Set of LTL that conjoined result in the formula""" self.__cnf: Set['LTL'] = {self} """Adding context""" self.__context = context if not skip_checks: if not self.is_satisfiable(): raise InconsistentException(self, self) elif cnf is not None and formula is None: cnf_str = [x.formula for x in cnf] self.__formula: str = And(cnf_str) self.__variables: Variables = Variables() for x in cnf: self.__variables |= x.variables self.__cnf: Set[Union['LTL']] = cnf """Adding context""" self.__context = context if not skip_checks and len(cnf) > 1: if not self.is_satisfiable(): raise InconsistentException(self, self) elif cnf is None and formula is None: self.__formula: str = "TRUE" self.__cnf: Set['LTL'] = {self} self.__variables: Variables = Variables() self.__context = None else: raise Exception("Wrong parameters LTL construction") if kind is not None: self.__kind: str = kind else: self.__kind: str = ""
def __init__(self, locations: List[str] = None): conj_list = [] for location in locations: conj_list.append("G(F(" + location + "))") super().__init__(locations, And(conj_list))
def parse_controller(file_path: str) -> Tuple[str, str, str, str]: """Returns: assumptions, guarantees, inputs, outputs""" assumptions = [] guarantees = [] inputs = [] outputs = [] file_header = "" with open(file_path, 'r') as ifile: for line in ifile: line, ntabs = _count_line(line) # skip empty lines if not line: continue # parse file header line elif ntabs == FILE_HEADER_INDENT: if ASSUMPTIONS_HEADER == line: if file_header == "": file_header = line else: Exception("File format not supported") elif CONSTRAINTS_HEADER == line: if file_header == ASSUMPTIONS_HEADER: file_header = line else: Exception("File format not supported") elif GUARANTEES_HEADER == line: if file_header == CONSTRAINTS_HEADER: file_header = line else: Exception("File format not supported") elif INS_HEADER == line: if file_header == GUARANTEES_HEADER: file_header = line else: Exception("File format not supported") elif OUTS_HEADER == line: if file_header == INS_HEADER: file_header = line else: Exception("File format not supported") elif END_HEADER == line: if file_header == OUTS_HEADER: if len(assumptions) == 0: assumptions.append("true") return And(assumptions), And(guarantees), ",".join( inputs), ",".join(outputs) else: Exception("File format not supported") else: raise Exception("Unexpected File Header: " + line) else: if ASSUMPTIONS_HEADER == file_header: if ntabs == DATA_INDENT: assumptions.append(line.strip()) if CONSTRAINTS_HEADER == file_header: if ntabs == DATA_INDENT: guarantees.append(line.strip()) if GUARANTEES_HEADER == file_header: if ntabs == DATA_INDENT: guarantees.append(line.strip()) if INS_HEADER == file_header: if ntabs == DATA_INDENT: inputs.append(line.strip()) if OUTS_HEADER == file_header: if ntabs == DATA_INDENT: outputs.append(line.strip())