def size(self): """ Reference: https://stackoverflow.com/questions/17920304/what-is-the-size-of-an-ltl-formula """ spot_formula = spot.formula(self.formula) unabbr_formula = str(spot.unabbreviate(spot_formula, "FGRMWie^")) return unabbr_formula.count("U") + unabbr_formula.count("X")
def evaluate(self, st, *args, **kwargs): """ Evaluates the PL formula over the given state. :param st: (pyobject) An object representing state. It is user's duty to ensure the implementation of given ``eval_func`` consumes the given state object correctly. :return: (bool) If PL formula is evaluated to be ``True`` or ``False`` over given state. :raises ValueError: When result of evaluation is not a boolean. """ # Evaluate alphabet to get a substitution map subs_map = self.alphabet.evaluate(st, args, kwargs) # Substitute valuation of APs in PL formula plf = self.substitute(subs_map) # Simplify the formula spot_formula = spot.formula(plf.formula) if spot_formula.is_tt(): return True elif spot_formula.is_ff(): return False raise ValueError( f"{self.formula}.evaluate(st={st}, args={args}, kwargs={kwargs})" f"returned {plf}, which is not a boolean. Was the substitution map complete?" )
def parse(self, formula: str): # Invoke spot parser try: spot_formula = spot.formula(formula) except SyntaxError: raise ParsingError( f"The string {formula} is NOT an acceptable AP name.") # Check if spot recognizes this as an AP if not spot_formula.is_literal() and not spot_formula.is_tt( ) and not spot_formula.is_ff(): raise ParsingError( f"The string {formula} is NOT an acceptable AP name.") # If input string is acceptable AP, then generate syntax tree and update internal variables tree = SyntaxTree() tree.build_from_spot_formula(spot_formula) self._tree = tree self._formula = formula # Special APs: true and false if spot_formula.is_tt(): self._eval_func = lambda st, *args, **kwargs: True if spot_formula.is_ff(): self._eval_func = lambda st, *args, **kwargs: False
def substitute(self, subs_map: dict): """ Substitutes the current AP with another AP according to given substitution map. :param subs_map: (dict[<Logic>: <Logic>]) A substitution map. :return: (AP) Substituted AP object. :raises KeyError: When subs_map does not contain the AP "self". """ # Copy the formula into a local variable formula = spot.formula(self.formula) # For all keys in substitution map, we try replacing self.formula with provided substitutions for p in subs_map: # Validate type of q. If q is True/False, replace with their logical equivalent. q = subs_map[p] if q is True: q = AP.TRUE if q is False: q = AP.FALSE if not isinstance(p, AP) or not isinstance(q, AP): warnings.warn( "PL.substitute(...) does not support substitution for non-AP objects. " "The results of substitution may not be correct!") # Create instances of spot formula spot_p = spot.formula(p.formula) spot_q = spot.formula(q.formula) # Invoke spot.formula.substitute (defined in iglsynth.util.spot) formula = formula.substitute(formula=spot_p, new_formula=spot_q) return PL(formula=str(formula))
def parse(self, formula: str): # Invoke spot parser try: spot_formula = spot.formula(formula) except SyntaxError: raise ParsingError( f"The string {formula} is NOT an acceptable PL formula name.") # Check if the formula is propositional logic formula mp_class = spot.mp_class(spot_formula) if mp_class != "B" and not spot_formula.is_tt( ) and not spot_formula.is_ff(): raise ParsingError( f"The string {formula} is NOT an acceptable PL formula.") # If input string is acceptable PL formula, then generate syntax tree and update internal variables tree = SyntaxTree() tree.build_from_spot_formula(spot_formula) # Set tree and formula string for PL formula self._tree = tree self._formula = formula # Update alphabet sigma = {AP(str(ap)) for ap in spot.atomic_prop_collect(spot_formula)} if self._alphabet is None: self._alphabet = Alphabet(sigma) else: assert sigma.issubset( self._alphabet ), f"Input formula contains APs not in alphabet, {self._alphabet}" # Special APs: true and false if spot_formula.is_tt(): self._eval_func = lambda st, *args, **kwargs: True if spot_formula.is_ff(): self._eval_func = lambda st, *args, **kwargs: False
def build_from_spot_formula(self, spot_formula): """ Constructs a syntax tree from a given spot formula. :param spot_formula: (:class:`spot.formula`) :return: None """ # Start with root of tree root = SyntaxTree.Vertex(spot_formula=spot_formula) self.add_vertex(root) self._root = root # Iteratively visit root in spot formula and build a tree in IGLSynth representation. stack = [root] while len(stack) > 0: # Create a vertex for current spot node. igl_vertex = stack.pop(0) spot_formula = spot.formula(igl_vertex.formula) # Get children of spot node and add them to stack. for spot_child in spot_formula: igl_vertex_child = SyntaxTree.Vertex(spot_formula=spot_child) stack.append(igl_vertex_child)
def is_contained_in(self, other): assert isinstance(other, ILogic) checker = spot.language_containment_checker() return checker.contained(spot.formula(self.formula), spot.formula(other.formula))
def is_equivalent(self, other): assert isinstance(other, ILogic) return spot.formula(self.formula) == spot.formula(other.formula)
def __eq__(self, other): assert isinstance(other, ILogic), f"An AP can only be compared with another ILogic formula. " \ f"Received other={type(other)}" return spot.formula(self.formula) == spot.formula(other.formula)
def __hash__(self): return spot.formula(self._formula).__hash__()
def __eq__(self, other): return spot.formula(self._formula) == spot.formula(other.formula)