def test_delta(): parser = LDLfParser() sa, sb, sc = "A", "B", "C" a, b, c = PLAtomic(sa), PLAtomic(sb), PLAtomic(sc) i_ = PLFalseInterpretation() i_a = PLInterpretation({sa}) i_b = PLInterpretation({sb}) i_ab = PLInterpretation({sa, sb}) true = PLTrue() false = PLFalse() tt = LDLfLogicalTrue() ff = LDLfLogicalFalse() assert parser("<A>tt").delta(i_) == false assert parser("<A>tt").delta(i_a) == PLAtomic(tt) assert parser("<A>tt").delta(i_b) == false assert parser("<A>tt").delta(i_ab) == PLAtomic(tt) assert parser("[B]ff").delta(i_) == true assert parser("[B]ff").delta(i_a) == true assert parser("[B]ff").delta(i_b) == PLAtomic(ff) assert parser("[B]ff").delta(i_ab) == PLAtomic(ff) f = parser("!(<!(A<->B)+(B;A)*+(!last)?>[(true)*]end)") assert f.delta(i_) == f.to_nnf().delta(i_) assert f.delta(i_ab) == f.to_nnf().delta(i_ab) assert f.delta(i_, epsilon=True) == f.to_nnf().delta(i_, epsilon=True) assert f.delta(i_ab, epsilon=True) == f.to_nnf().delta(i_ab, epsilon=True) # with epsilon=True, the result is either PLTrue or PLFalse assert f.delta(i_, epsilon=True) in [PLTrue(), PLFalse()]
def test_nnf(): parser = PLParser() sa, sb = "A", "B" a, b = PLAtomic(sa), PLAtomic(sb) i_ = PLInterpretation(set()) i_a = PLInterpretation({sa}) i_b = PLInterpretation({sb}) i_ab = PLInterpretation({sa, sb}) not_a_and_b = parser("!(A&B)") nnf_not_a_and_b = parser("!A | !B") assert not_a_and_b.to_nnf() == nnf_not_a_and_b assert nnf_not_a_and_b == nnf_not_a_and_b.to_nnf() dup = parser("!(A | A)") nnf_dup = dup.to_nnf() assert nnf_dup == PLNot(a) material_implication = parser("!A | B <-> !(A & !B) <-> A->B") nnf_material_implication = parser( "((!A | B) & (!A | B) & (!A | B)) | ((A & !B) & (A & !B) & (A & !B))") nnf_m = material_implication.to_nnf() assert nnf_m == nnf_material_implication.to_nnf() assert nnf_m.truth(i_) == material_implication.truth( i_) == nnf_material_implication.truth(i_) == True assert nnf_m.truth(i_a) == material_implication.truth( i_a) == nnf_material_implication.truth(i_a) == True assert nnf_m.truth(i_b) == material_implication.truth( i_b) == nnf_material_implication.truth(i_b) == True assert nnf_m.truth(i_ab) == material_implication.truth( i_ab) == nnf_material_implication.truth(i_ab) == True
def setup_class(cls): cls.parser = LTLfParser() cls.a, cls.b, cls.c = "A", "B", "C" cls.alphabet_abc = {cls.a, cls.b, cls.c} cls.i_ = PLInterpretation(set()) cls.i_a = PLInterpretation({cls.a}) cls.i_b = PLInterpretation({cls.b}) cls.i_ab = PLInterpretation({cls.a, cls.b})
def setup_class(cls): cls.sa, cls.sb = "a", "b" cls.i_ = PLInterpretation(set()) cls.i_a = PLInterpretation({cls.sa}) cls.i_b = PLInterpretation({cls.sb}) cls.i_ab = PLInterpretation({cls.sa, cls.sb}) cls.a, cls.b = PLAtomic(cls.sa), PLAtomic(cls.sb)
def __init__(self, dfaotf: DFAOTF, alphabet: Alphabet, reward, gamma=0.99): self.dfaotf = dfaotf self.alphabet = Alphabet( {PLInterpretation(set(sym)) for sym in powerset(alphabet.symbols)}) self.reward = reward self.gamma = gamma self.dfaotf.reset() initial_state = self.dfaotf.cur_state self.id2state = {0: initial_state} self.state2id = {initial_state: 0} self.states = {0} self.initial_state = 0 self.transition_function = {} self.final_states = set() self.failure_states = set() # a list of (old_state, label, new_state) to keep track of the sequence of states and labels self.trace = [] self.changed = False dfa = DFA(alphabet, frozenset(self.states), self.initial_state, frozenset(self.final_states), self.transition_function) self._automaton = RewardAutomaton(dfa, alphabet, dfaotf.f, reward, gamma=gamma)
def make_transition(self, s: Set[Symbol]): i = PLInterpretation(s) old_state = self.cur_state super().make_transition(i) reward = self.get_immediate_reward(old_state, self.cur_state) self.visited_states.add(self.cur_state) return reward
def to_automaton(f, labels: Optional[Set[Symbol]] = None): initial_state = frozenset({frozenset({PLAtomic(f)})}) states = {initial_state} final_states = set() transition_function = {} # the alphabet is the powerset of the set of fluents alphabet = powerset(labels if labels is not None else f.find_labels()) if f.delta(PLFalseInterpretation(), epsilon=True) == PLTrue(): final_states.add(initial_state) visited = set() to_be_visited = {initial_state} while len(to_be_visited) != 0: for q in list(to_be_visited): to_be_visited.remove(q) for actions_set in alphabet: new_state = _make_transition(q, PLInterpretation(actions_set)) if new_state not in states: states.add(new_state) to_be_visited.add(new_state) transition_function.setdefault( q, {})[PLInterpretation(actions_set)] = new_state if new_state not in visited: visited.add(new_state) if _is_true(new_state): final_states.add(new_state) new_alphabet = {PLInterpretation(set(sym)) for sym in alphabet} dfa = DFA(states, new_alphabet, initial_state, final_states, transition_function) dfa = dfa.minimize() dfa = dfa.trim() return dfa
def test_truth(): sa, sb = "a", "b" a, b = PLAtomic(sa), PLAtomic(sb) i_ = PLFalseInterpretation() i_a = PLInterpretation({sa}) i_b = PLInterpretation({sb}) i_ab = PLInterpretation({sa, sb}) tr_false_a_b_ab = FiniteTrace([i_, i_a, i_b, i_ab, i_]) tt = LDLfLogicalTrue() ff = LDLfLogicalFalse() assert tt.truth(tr_false_a_b_ab, 0) assert not ff.truth(tr_false_a_b_ab, 0) assert not LDLfNot(tt).truth(tr_false_a_b_ab, 0) assert LDLfNot(ff).truth(tr_false_a_b_ab, 0) assert LDLfAnd([LDLfPropositional(a), LDLfPropositional(b)]).truth(tr_false_a_b_ab, 3) assert not LDLfDiamond(RegExpPropositional(PLAnd([a, b])), tt).truth( tr_false_a_b_ab, 0) parser = LDLfParser() trace = FiniteTrace.from_symbol_sets([{}, {"A"}, {"A"}, {"A", "B"}, {}]) formula = "<true*;A&B>tt" parsed_formula = parser(formula) assert parsed_formula.truth(trace, 0) formula = "[(A+!B)*]<C>tt" parsed_formula = parser(formula) assert not parsed_formula.truth(trace, 1) formula = "<(<!C>tt)?><A>tt" parsed_formula = parser(formula) assert parsed_formula.truth(trace, 1) formula = "<!C+A>tt" parsed_formula = parser(formula) assert parsed_formula.truth(trace, 1)
def to_automaton(f, labels:Set[Symbol]=None, minimize=True): initial_state = frozenset({frozenset({f.to_nnf()})}) states = {initial_state} final_states = set() transition_function = {} # the alphabet is the powerset of the set of fluents alphabet = powerset(labels) if DFAOTF._is_true(initial_state): final_states.add(initial_state) visited = set() to_be_visited = {initial_state} while len(to_be_visited)!=0: for q in list(to_be_visited): to_be_visited.remove(q) for actions_set in alphabet: new_state = DFAOTF._make_transition(q, PLInterpretation(actions_set)) if not new_state in states: states.add(new_state) to_be_visited.add(new_state) transition_function.setdefault(q, {})[PLInterpretation(actions_set)] = new_state if new_state not in visited: visited.add(new_state) if DFAOTF._is_true(new_state): final_states.add(new_state) new_alphabet = PythomataAlphabet({PLInterpretation(set(sym)) for sym in alphabet}) dfa = DFA(new_alphabet, frozenset(states), initial_state, frozenset(final_states), transition_function) if minimize: dfa = dfa.minimize().trim() return dfa
def make_transition(self, s: Set[Symbol]): i = PLInterpretation(s) old_state = self.dfaotf.cur_state self.dfaotf.make_transition(i) new_state = self.dfaotf.cur_state self._update_from_transition(old_state, i, new_state) if len(self._automaton.accepting_states) > 0: reward = self._automaton.get_immediate_reward( self.state2id[old_state], self.state2id[self.dfaotf.cur_state]) else: if self.is_failed(): reward = -self.reward elif old_state != new_state: # give an optimistic reward to help exploration reward = self.reward * 10e-4 else: reward = 0 return reward
def fromStringSets(l:List[Set[str]]): return FiniteTrace([PLInterpretation(frozenset({Symbol(string) for string in s})) for s in l])
def fromSymbolSets(l:List[Set[Symbol]]): return FiniteTrace([PLInterpretation(s) for s in l])
def setup_class(cls): cls.parser = LDLfParser() cls.i_ = PLInterpretation(set()) cls.i_a = PLInterpretation({"A"}) cls.i_b = PLInterpretation({"B"}) cls.i_ab = PLInterpretation({"A", "B"})
def setup_class(cls): cls.parser = LTLfParser() cls.i_, cls.i_a, cls.i_b, cls.i_ab = \ PLFalseInterpretation(), PLInterpretation({"A"}), PLInterpretation({"B"}), PLInterpretation({"A", "B"}) cls.true = PLTrue() cls.false = PLFalse()
def to_automaton_(f, labels:Set[Symbol]=None): """ DEPRECATED From a LDLfFormula, build the automaton. :param f: a LDLfFormula; :param labels: a set of Symbol, the fluents of our domain. If None, retrieve them from the formula; :param determinize: True if you need to determinize the NFA, obtaining a DFA; :param minimize: True if you need to minimize the DFA (if determinize is False this flag has no effect.) :return: a NFA or a DFA which accepts the same traces that makes the formula True. """ nnf = f.to_nnf() if labels is None: # if the labels of the formula are not specified in input, # retrieve them from the formula labels = nnf.find_labels() # the alphabet is the powerset of the set of fluents alphabet = powerset(labels) initial_state = MacroState({nnf}) final_states = {MacroState()} delta = set() d = f.delta(PLFalseInterpretation(), epsilon=True) if d.truth(d): final_states.add(initial_state) states = {MacroState(), initial_state} 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 function applied to every formula in the macro state Q delta_formulas = [f.delta(actions_set) for f in q] # find the list of atoms, which are "true" atoms (i.e. propositional atoms) or LDLf formulas atomics = [s for subf in delta_formulas for s in find_atomics(subf)] # "freeze" the found atoms as symbols and build a mapping from symbols to formulas symbol2formula = {Symbol(str(f)): f for f in atomics if f != PLTrue() and f != PLFalse()} # build a map from formula to a "freezed" propositional Atomic Formula formula2atomic_formulas = { f: PLAtomic(Symbol(str(f))) if f != PLTrue() and f != PLFalse()# and not isinstance(f, PLAtomic) else f for f in atomics } # the final list of Propositional Atomic Formulas, one for each formula in the original macro state Q transformed_delta_formulas = [_transform_delta(f, formula2atomic_formulas) for f in delta_formulas] # the empty conjunction stands for true if len(transformed_delta_formulas) == 0: conjunctions = PLTrue() elif len(transformed_delta_formulas) == 1: conjunctions = transformed_delta_formulas[0] else: conjunctions = PLAnd(transformed_delta_formulas) # the model in this case is the smallest set of symbols s.t. the conjunction of "freezed" atomic formula # is true. models = frozenset(conjunctions.minimal_models(Alphabet(symbol2formula))) if len(models) == 0: continue for min_model in models: q_prime = MacroState( {symbol2formula[s] for s in min_model.true_propositions}) 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: subf_deltas = [subf.delta(PLFalseInterpretation(), epsilon=True) for subf in q_prime] if len(subf_deltas)==1: q_prime_delta_conjunction = subf_deltas[0] else: q_prime_delta_conjunction = PLAnd(subf_deltas) if q_prime_delta_conjunction.truth(PLFalseInterpretation()): final_states.add(q_prime) alphabet = PythomataAlphabet({PLInterpretation(set(sym)) for sym in alphabet}) delta = frozenset((i, PLInterpretation(set(a)), o) for i, a, o in delta) nfa = NFA.fromTransitions( alphabet=alphabet, states=frozenset(states), initial_state=initial_state, accepting_states=frozenset(final_states), transitions=delta ) return nfa