def _truth(self, f: Formula, trace: FiniteTrace, position: int): assert trace.alphabet == self.alphabet truth = self._truth # LDLfFormulas if isinstance(f, AtomicFormula): return f.symbol in trace.get(position) elif isinstance(f, Not): return not self.truth(f.f, trace, position) elif isinstance(f, And): return self.truth(f.f1, trace, position) and self.truth(f.f2, trace, position) elif isinstance(f, PathExpressionEventually): path = f.p assert self._is_path(path) if isinstance(path, PathExpressionTest): return truth(path.f, trace, position) and truth(f.f, trace, position) elif isinstance(path, PathExpressionUnion): return truth(PathExpressionEventually(path.p1, f.f), trace, position) or truth( PathExpressionEventually(path.p2, f.f), trace, position) elif isinstance(path, PathExpressionSequence): return truth(PathExpressionEventually(path.p1, PathExpressionEventually(path.p2, f.f)), trace, position) elif isinstance(path, PathExpressionStar): return truth(f.f, trace, position) or ( position < trace.last() and truth(PathExpressionEventually(path.p, PathExpressionEventually(path, f.f)), trace, position) and not self._is_testonly(path) ) # Should be a Propositional Formula else: pl, I = PL._from_set_of_propositionals(trace.get(position), trace.alphabet) return position < trace.last() and pl.truth(path, I) and truth(f.f, trace, position + 1) else: raise ValueError("Argument not a valid Formula")
def _truth(self, f: Formula, trace: FiniteTrace, start: int, end: int): assert self._is_formula(f) assert trace.alphabet == self.alphabet truth = self.truth if isinstance(f, PathExpressionUnion): return truth(f.p1, trace, start, end) or truth( f.p2, trace, start, end) if isinstance(f, PathExpressionSequence): return any( truth(f.p1, trace, start, k) and truth(f.p2, trace, k, end) for k in range(start, end + 1)) if isinstance(f, PathExpressionStar): return end == start or any( truth(f.p, trace, start, k) and truth(f, trace, k, end) for k in range(start, end + 1)) else: pl, I = PL._from_set_of_propositionals(trace.get(start), self.alphabet) assert pl.is_formula(f) return end == start + 1 and end <= trace.length() and pl.truth( f, I)
def delta(self, f: Formula, action: FrozenSet[Symbol], epsilon=False): # TODO: should return [True|False]Formula or simply True/False? pl, I = PL._from_set_of_propositionals(action, self.alphabet) if pl.is_formula(f): return self.delta(PathExpressionEventually(f, LogicalTrue()), action, epsilon) elif isinstance(f, LogicalTrue): return TrueFormula() elif isinstance(f, LogicalFalse): return FalseFormula() elif isinstance(f, And): return And(self.delta(f.f1, action), self.delta(f.f2, action, epsilon)) elif isinstance(f, Or): return Or(self.delta(f.f1, action), self.delta(f.f2, action, epsilon)) elif isinstance(f, PathExpressionEventually): if pl.is_formula(f.p): if not epsilon and pl.truth(f.p, I): return self._expand(f.f) else: return FalseFormula() elif isinstance(f.p, PathExpressionTest): return And(self.delta(f.p.f, action, epsilon), self.delta(f.f, action, epsilon)) elif isinstance(f.p, PathExpressionUnion): return Or( self.delta(PathExpressionEventually(f.p.p1, f.f), action, epsilon), self.delta(PathExpressionEventually(f.p.p2, f.f), action, epsilon)) elif isinstance(f.p, PathExpressionSequence): e2 = PathExpressionEventually(f.p.p2, f.f) e1 = PathExpressionEventually(f.p.p1, e2) return self.delta(e1, action, epsilon) elif isinstance(f.p, PathExpressionStar): o1 = self.delta(f.f, action, epsilon) o2 = self.delta(PathExpressionEventually(f.p.p, F(f)), action, epsilon) return Or(o1, o2) elif isinstance(f, PathExpressionAlways): if pl.is_formula(f.p): if not epsilon and pl.truth(f.p, I): return self._expand(f.f) else: return TrueFormula() elif isinstance(f.p, PathExpressionTest): o1 = self.delta(self.to_nnf(Not(f.p.f)), action, epsilon) o2 = self.delta(f.f, action, epsilon) return Or(o1, o2) elif isinstance(f.p, PathExpressionUnion): return And( self.delta(PathExpressionAlways(f.p.p1, f.f), action, epsilon), self.delta(PathExpressionAlways(f.p.p2, f.f), action, epsilon)) elif isinstance(f.p, PathExpressionSequence): return self.delta( PathExpressionAlways(f.p.p1, PathExpressionAlways(f.p.p2, f.f)), action, epsilon) elif isinstance(f.p, PathExpressionStar): a1 = self.delta(f.f, action, epsilon) a2 = self.delta(PathExpressionAlways(f.p.p, T(f)), action, epsilon) return And(a1, a2) elif isinstance(f, F): return FalseFormula() elif isinstance(f, T): return TrueFormula() else: raise ValueError
def to_nfa(self, f: Formula): # TODO: optimize!!! assert self.is_formula(f) nnf_f = self.to_nnf(f) alphabet = powerset(self.alphabet.symbols) initial_states = {frozenset([nnf_f])} final_states = {frozenset()} delta = set() pl, I = PL._from_set_of_propositionals(set(), Alphabet(set())) d = self.delta(nnf_f, frozenset(), epsilon=True) if pl.truth(d, I): final_states.add(frozenset([nnf_f])) states = {frozenset(), frozenset([nnf_f])} states_changed, delta_changed = True, True while states_changed or delta_changed: states_changed, delta_changed = False, False for actions_set in alphabet: states_list = list(states) for q in states_list: delta_formulas = [ self.delta(subf, actions_set) for subf in q ] atomics = [ s for subf in delta_formulas for s in PL.find_atomics(subf) ] symbol2formula = { Symbol(str(f)): f for f in atomics if f != TrueFormula() and f != FalseFormula() } formula2atomic_formulas = { f: AtomicFormula.fromName(str(f)) if f != TrueFormula() and f != FalseFormula() else f for f in atomics } transformed_delta_formulas = [ self._tranform_delta(f, formula2atomic_formulas) for f in delta_formulas ] conjunctions = And.chain(transformed_delta_formulas) models = frozenset( PL(Alphabet( set(symbol2formula))).minimal_models(conjunctions)) if len(models) == 0: continue for min_model in models: q_prime = frozenset({ symbol2formula[s] for s in min_model.symbol2truth if min_model.symbol2truth[s] }) len_before = len(states) states.add(q_prime) if len(states) == len_before + 1: states_list.append(q_prime) states_changed = True len_before = len(delta) delta.add((q, actions_set, q_prime)) if len(delta) == len_before + 1: delta_changed = True # check if q_prime should be added as final state if len(q_prime) == 0: final_states.add(q_prime) else: q_prime_delta_conjunction = And.chain([ self.delta(subf, frozenset(), epsilon=True) for subf in q_prime ]) pl, I = PL._from_set_of_propositionals( set(), Alphabet(set())) if pl.truth(q_prime_delta_conjunction, I): final_states.add(q_prime) return { "alphabet": alphabet, "states": frozenset(states), "initial_states": frozenset(initial_states), "transitions": delta, "accepting_states": frozenset(final_states) }