Exemplo n.º 1
0
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()]
Exemplo n.º 2
0
def test_delta():
    parser = LDLfParser()
    i_ = {}
    i_a = {"A": True}
    i_b = {"B": True}
    i_ab = {"A": True, "B": True}

    true = PLTrue()
    false = PLFalse()
    tt = PLAtomic(LDLfLogicalTrue())
    ff = PLAtomic(LDLfLogicalFalse())

    assert parser("<A>tt").delta(i_) == false
    assert parser("<A>tt").delta(i_a) == tt
    assert parser("<A>tt").delta(i_b) == false
    assert parser("<A>tt").delta(i_ab) == tt

    assert parser("[B]ff").delta(i_) == true
    assert parser("[B]ff").delta(i_a) == true
    assert parser("[B]ff").delta(i_b) == ff
    assert parser("[B]ff").delta(i_ab) == ff

    f = parser("!(<?(!last)>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()]
Exemplo n.º 3
0
    def __init__(self,
                 input_space,
                 bricks_cols=3,
                 bricks_rows=3,
                 lines_num=3,
                 gamma=0.99,
                 on_the_fly=False):
        assert lines_num == bricks_cols or lines_num == bricks_rows
        self.line_symbols = [Symbol("l%s" % i) for i in range(lines_num)]
        lines = self.line_symbols

        parser = LDLfParser()

        string_formula = get_breakout_lines_formula(lines)
        print(string_formula)
        f = parser(string_formula)
        reward = 10000

        super().__init__(BreakoutGoalFeatureExtractor(input_space,
                                                      bricks_cols=bricks_cols,
                                                      bricks_rows=bricks_rows),
                         set(lines),
                         f,
                         reward,
                         gamma=gamma,
                         on_the_fly=on_the_fly)
Exemplo n.º 4
0
def test_ldlf_example_readme():
    from flloat.parser.ldlf import LDLfParser

    parser = LDLfParser()
    formula = "<true*; a & b>tt"
    parsed_formula = parser(formula)

    assert (
        str(parsed_formula) == "<((true)* ; (b & a))>(tt)"
        or str(parsed_formula) == "<((true)* ; (a & b))>(tt)"
    )
    assert parsed_formula.find_labels() == {c for c in "ab"}

    t1 = [
        {"a": False, "b": False},
        {"a": True, "b": False},
        {"a": True, "b": False},
        {"a": True, "b": True},
        {"a": False, "b": False},
    ]
    assert parsed_formula.truth(t1, 0)
    t2 = [{"a": False, "b": False}, {"a": True, "b": False}, {"a": False, "b": True}]
    assert not parsed_formula.truth(t2, 0)

    dfa = parsed_formula.to_automaton()
    assert dfa.accepts(t1)
    assert not dfa.accepts(t2)
Exemplo n.º 5
0
def test_find_labels():
    parser = LDLfParser()

    f = "< (!(A | B | C ))* ; (A | C) ; (!(A | B | C))* ; (B | C) ><true>tt"
    formula = parser(f)
    assert formula.find_labels() == {c for c in "ABC"}

    f = "(<(((?(<B>tt));true)*) ; (? (<(A & B)>tt))>tt)"
    formula = parser(f)
    assert formula.find_labels() == {c for c in "AB"}
Exemplo n.º 6
0
def test_nnf():
    parser = LDLfParser()

    assert parser("!tt").to_nnf() == LDLfLogicalFalse()
    assert parser("!!tt").to_nnf() == LDLfLogicalTrue()

    f = parser("!(<!(A&B)>end)").to_nnf()
    ff = parser("[!A | !B]<true>tt")
    assert f == ff
    assert parser("!(<!(A&B)>end)").to_nnf() == parser("[!A | !B]<true>tt")

    f = parser("!(<((!(A<->D))+((B;C)*)+(?(!last)))>[(true)*]end)")
    assert f.to_nnf() == f.to_nnf().to_nnf()
Exemplo n.º 7
0
def test_nnf():
    parser = LDLfParser()

    assert parser("!tt").to_nnf() == LDLfLogicalFalse()
    assert parser("!!tt").to_nnf() == LDLfLogicalTrue()

    assert parser("!(<!(A&B)>end)").to_nnf() == parser("[!A | !B]<true>tt")

    f = parser("!(<!(A<->D)+(B;C)*+(!last)?>[(true)*]end)")
    assert f.to_nnf() == parser(
        "[(([true]<true>tt)? + ((B ; C))* + ((A | D) & (!(D) | !(A))))]<(true)*><true>tt"
    )
    assert f.to_nnf() == f.to_nnf().to_nnf().to_nnf().to_nnf()
Exemplo n.º 8
0
    def __init__(self, on_the_fly=False):
        self.row_symbols = [Symbol(r) for r in ["r0", "r1", "r2"]]
        rows = self.row_symbols

        parser = LDLfParser()
        f = parser(
            "<(!r0 & !r1 & !r2)*;(r0 & !r1 & !r2)*;(r0 & r1 & !r2)*; r0 & r1 & r2>tt"
        )
        reward = 10000

        super().__init__(BreakoutRowBottomUpGoalFeatureExtractor(),
                         set(rows),
                         f,
                         reward,
                         on_the_fly=on_the_fly)
Exemplo n.º 9
0
def make_env(config: MinecraftConfiguration,
             output_dir,
             goal_reward: float = 1000.0,
             reward_shaping: bool = True) -> gym.Env:
    """
    Make the Minecraft environment.

    :param config: the Minecraft configuration.
    :param output_dir: the path to the output directory.
    :param reward_shaping: apply automata-based reward shaping.
    :return: the Gym environment.
    """
    temporal_goals = []
    for t in config.tasks:
        formula_string = make_goal(t)
        print("Formula: {}".format(formula_string))
        formula = LDLfParser()(formula_string)
        tg = TemporalGoal(
            formula=formula,
            reward=goal_reward,
            # labels=LABELS,
            reward_shaping=reward_shaping,
            zero_terminal_state=False,
            extract_fluents=extract_minecraft_fluents)
        temporal_goals.append(tg)

        tg._automaton.to_dot(
            os.path.join(output_dir, "true_automaton_{}".format(t.name)))
        print("Original automaton at {}".format(
            os.path.join(output_dir, "true_automaton_{}.svg".format(t.name))))

    env = MinecraftTemporalWrapper(
        MinecraftExpertWrapper(config),
        temporal_goals,
        combine=lambda obs, qs: tuple((*obs, *qs)),
        feature_extractor=lambda obs, action:
        (obs["x"], obs["y"], obs["theta"])
        if config.action_space_type == ActionSpaceType.DIFFERENTIAL else
        (obs["x"], obs["y"]))

    positive_traces_path = Path(output_dir, "positive_traces.txt")
    negative_traces_path = Path(output_dir, "negative_traces.txt")
    env = TemporalGoalWrapperLogTraces(env, extract_minecraft_fluents,
                                       positive_traces_path,
                                       negative_traces_path)

    return env
def make_env(config: BreakoutConfiguration,
             output_dir,
             goal_reward: float = 1000.0,
             reward_shaping: bool = True) -> gym.Env:
    """
    Make the Breakout environment.

    :param config: the Breakout configuration.
    :param output_dir: the path to the output directory.
    :param reward_shaping: apply automata-based reward shaping.
    :return: the Gym environment.
    """
    unwrapped_env = BreakoutExpertWrapper(config)

    formula_string = make_goal(config.brick_cols)
    formula = LDLfParser()(formula_string)
    labels = {"c{}".format(i) for i in range(config.brick_cols)}
    tg = TemporalGoal(formula=formula,
                      reward=goal_reward,
                      labels=labels,
                      reward_shaping=reward_shaping,
                      zero_terminal_state=False,
                      extract_fluents=extract_breakout_fluents)

    print("Formula: {}".format(formula_string))
    tg._automaton.to_dot(os.path.join(output_dir, "true_automaton"))
    print("Original automaton at {}".format(
        os.path.join(output_dir, "true_automaton.svg")))

    env = TemporalGoalWrapper(
        unwrapped_env,
        [tg],
        combine=lambda obs, qs: tuple((*obs, *qs)),
        feature_extractor=(
            lambda obs, action: (
                obs["paddle_x"],  #obs["paddleup_x"],
            )))

    positive_traces_path = Path(output_dir, "positive_traces.txt")
    negative_traces_path = Path(output_dir, "negative_traces.txt")
    env = TemporalGoalWrapperLogTraces(env, extract_breakout_fluents,
                                       positive_traces_path,
                                       negative_traces_path)

    return env
Exemplo n.º 11
0
def make_env(config: SapientinoConfiguration,
             output_dir,
             goal_reward: float = 1000.0,
             reward_shaping: bool = True) -> gym.Env:
    """
    Make the Breakout environment.

    :param config: the Breakout configuration.
    :param output_dir: the path to the output directory.
    :param reward_shaping: apply automata-based reward shaping.
    :return: the Gym environment.
    """

    formula_string = make_goal()
    print("Formula: {}".format(formula_string))
    formula = LDLfParser()(formula_string)
    tg = TemporalGoal(formula=formula,
                      reward=goal_reward,
                      labels={color
                              for color in colors}.union({"bad_beep"}),
                      reward_shaping=reward_shaping,
                      zero_terminal_state=False,
                      extract_fluents=extract_sapientino_fluents)

    tg._automaton.to_dot(os.path.join(output_dir, "true_automaton"))
    print("Original automaton at {}".format(
        os.path.join(output_dir, "true_automaton.svg")))

    env = SapientinoTemporalWrapper(
        SapientinoWrapper(SapientinoDictSpace(config)), [tg],
        combine=lambda obs, qs: tuple((*obs, *qs)),
        feature_extractor=lambda obs, action: (obs["x"], obs["y"], obs["th"])
        if config.differential else (obs["x"], obs["y"]))

    positive_traces_path = Path(output_dir, "positive_traces.txt")
    negative_traces_path = Path(output_dir, "negative_traces.txt")
    env = TemporalGoalWrapperLogTraces(env, extract_sapientino_fluents,
                                       positive_traces_path,
                                       negative_traces_path)

    return env
Exemplo n.º 12
0
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)
Exemplo n.º 13
0
    def __init__(self,
                 input_space,
                 formula_string,
                 gamma=0.99,
                 on_the_fly=False):
        # self.location_syms = [Symbol(l[0]) for l in LOCATIONS]
        # self.get, self.use = Symbol("get"), Symbol("use")
        self.locations = [l[0] for l in LOCATIONS]

        parser = LDLfParser()
        # parser = LTLfParser()
        print(formula_string)
        f = parser(formula_string)
        reward = 1

        super().__init__(MinecraftTEFeatureExtractor(input_space),
                         f.find_labels(),
                         f,
                         reward,
                         gamma=gamma,
                         on_the_fly=on_the_fly)
Exemplo n.º 14
0
def test_ldlf_example_readme():
    from flloat.parser.ldlf import LDLfParser

    parser = LDLfParser()
    formula = "<true*; A & B>tt"
    parsed_formula = parser(formula)

    assert str(parsed_formula) == "<((true)* ; (B & A))>(tt)" or str(
        parsed_formula) == "<((true)* ; (A & B))>(tt)"
    assert parsed_formula.find_labels() == {c for c in "AB"}

    from flloat.semantics.traces import FiniteTrace

    t1 = FiniteTrace.from_symbol_sets([{}, {"A"}, {"A"}, {"A", "B"}, {}])
    assert parsed_formula.truth(t1, 0)

    t2 = FiniteTrace.from_symbol_sets([{}, {"A"}, {"B"}])
    assert not parsed_formula.truth(t2, 0)

    dfa = parsed_formula.to_automaton()
    assert dfa.accepts(t1.trace)
    assert not dfa.accepts(t2.trace)
Exemplo n.º 15
0
    def __init__(self,
                 input_space,
                 gamma=0.99,
                 on_the_fly=False,
                 relaxed=True):
        self.color_syms = [Symbol(c) for c in COLORS] + [Symbol("no_color")]
        self.bip = Symbol("bip")

        parser = LDLfParser()

        if not relaxed:
            # the formula
            sb = str(self.bip)
            not_bip = ";(!%s)*;" % sb
            and_bip = lambda x: str(x) + " & " + sb
            # every color-bip in sequence, no bip between colors.
            formula_string = "<(!%s)*;" % sb + not_bip.join(
                map(and_bip, self.color_syms[:-1])) + ">tt"
        else:
            sb = str(self.bip)
            not_bip = ";true*;"
            and_bip = lambda x: str(x) + " & " + sb
            # every color-bip in sequence, no bip between colors.
            formula_string = "<true*;" + not_bip.join(
                map(and_bip, self.color_syms[:-1])) + ">tt"

        print(formula_string)
        f = parser(formula_string)

        reward = 1

        super().__init__(SapientinoTEFeatureExtractor(input_space),
                         set(self.color_syms).union({self.bip}),
                         f,
                         reward,
                         gamma=gamma,
                         on_the_fly=on_the_fly)
Exemplo n.º 16
0
    def __init__(self,
                 input_space,
                 bricks_cols=3,
                 bricks_rows=3,
                 lines_num=3,
                 gamma=0.99,
                 on_the_fly=False):
        self.line_symbols = [Symbol("l%s" % i) for i in range(lines_num)]
        lines = self.line_symbols

        parser = LDLfParser()
        f = parser(
            "<(!l0 & !l1 & !l2)*;(l0 & !l1 & !l2);(l0 & !l1 & !l2)*;(l0 & l1 & !l2); (l0 & l1 & !l2)*; l0 & l1 & l2>tt"
        )
        reward = 10000

        super().__init__(BreakoutGoalFeatureExtractor(input_space,
                                                      bricks_cols=bricks_cols,
                                                      bricks_rows=bricks_rows),
                         set(lines),
                         f,
                         reward,
                         gamma=gamma,
                         on_the_fly=on_the_fly)
Exemplo n.º 17
0
 def setup_class(cls):
     cls.parser = LDLfParser()
     cls.trace = [{}, {"A": True}, {"A": True}, {"A": True, "B": True}, {}]
Exemplo n.º 18
0
def test_parser():
    parser = LDLfParser()
    a, b = PLAtomic("A"), PLAtomic("B")

    tt = LDLfLogicalTrue()
    ff = LDLfLogicalFalse()
    true = PLTrue()
    false = PLFalse()
    r_true = RegExpPropositional(true)
    r_false = RegExpPropositional(false)

    assert tt == parser("tt")
    assert ff == parser("ff")
    assert LDLfDiamond(r_true, tt) == parser("<true>tt")
    assert LDLfDiamond(r_false, tt) == parser("<false>tt")
    assert parser("!tt & <!A&B>tt") == LDLfAnd([
        LDLfNot(tt),
        LDLfDiamond(RegExpPropositional(PLAnd([PLNot(a), b])), tt)
    ])
    assert parser("[true*]([true]ff | <!A>tt | <(true)*><B>tt)") == LDLfBox(
        RegExpStar(r_true),
        LDLfOr([
            LDLfBox(r_true, ff),
            LDLfDiamond(RegExpPropositional(PLNot(a)), tt),
            LDLfDiamond(RegExpStar(r_true),
                        (LDLfDiamond(RegExpPropositional(b), tt))),
        ]),
    )

    assert parser("[A&B&A]ff <-> <A&B&A>tt") == LDLfEquivalence([
        LDLfBox(RegExpPropositional(PLAnd([a, b, a])), ff),
        LDLfDiamond(RegExpPropositional(PLAnd([a, b, a])), tt),
    ])

    assert parser("<A+B>tt") == LDLfDiamond(
        RegExpUnion([RegExpPropositional(a),
                     RegExpPropositional(b)]), tt)
    assert parser("<A;B>tt") == LDLfDiamond(
        RegExpSequence([RegExpPropositional(a),
                        RegExpPropositional(b)]), tt)
    assert parser("<A+(B;A)>end") == LDLfDiamond(
        RegExpUnion([
            RegExpPropositional(a),
            RegExpSequence([RegExpPropositional(b),
                            RegExpPropositional(a)]),
        ]),
        LDLfEnd(),
    )

    assert parser("!(<(!(A<->D))+((B;C)*)+(?!last)>[(true)*]end)") == LDLfNot(
        LDLfDiamond(
            RegExpUnion([
                RegExpPropositional(PLNot(PLEquivalence([a, PLAtomic("D")]))),
                RegExpStar(
                    RegExpSequence([
                        RegExpPropositional(PLAtomic("B")),
                        RegExpPropositional(PLAtomic("C")),
                    ])),
                RegExpTest(LDLfNot(LDLfLast())),
            ]),
            LDLfBox(RegExpStar(RegExpPropositional(PLTrue())), LDLfEnd()),
        ))
Exemplo n.º 19
0
 def setup_class(cls):
     cls.parser = LDLfParser()
     cls.i_ = {}
     cls.i_a = {"A": True}
     cls.i_b = {"B": True}
     cls.i_ab = {"A": True, "B": True}
Exemplo n.º 20
0
    def __init__(
        self, env_name, fluents, n_functions, logdir=None, verbose=True
    ):
        """Initialize.

        :param env_name: a gym environment name.
        :param fluents: the list of propositional atoms that will be predicted.
        :param n_functions: number of predictions to valuate in parallel.
        :param logdir: if provided, the automaton just parsed is saved here.
        :param verbose: log the parsing step, because it may take a long time!
        """

        # Loading
        if verbose:
            print("> Parsing", env_name, "constraints")
        data = selector.read_back(env_name)
        json_constraints = data["constraints"]

        # Parsing
        constraint = " & ".join(json_constraints)
        formula = LDLfParser()(constraint)  # type: LDLfFormula

        # Check: all atoms must be evaluated
        atoms = formula.find_labels()
        all_predicted = all((a in fluents for a in atoms))
        if not all_predicted:
            raise ValueError(
                "One of the atoms " + str(atoms) + " is not in fluents")

        # Conversion (slow op)
        automaton = formula.to_automaton()  # type: SymbolicAutomaton
        automaton = automaton.determinize()
        if verbose:
            print("> Parsed")

        # Visualize the automaton
        if logdir is not None:
            graphviz = automaton.to_graphviz()
            graphviz.render(
                "constraint.gv", directory=logdir, view=False, cleanup=False)

        # Store
        self.env_name = env_name
        self.fluents = fluents
        self._str = constraint
        self._formula = formula
        self._automaton = automaton
        self._n_functions = n_functions
        self._n_fluents = len(self.fluents)

        # Automaton parallel execution
        self._tf_automata = TfSymbolicAutomaton(self._automaton, self.fluents)

        # Prepare buffers
        self._current_states = tf.Variable(
            tf.zeros([self._n_functions], dtype=tf.int32),
            trainable=False, name="current_states")
        self._final_counts = tf.Variable(
            tf.zeros(
                [self._n_functions, len(self._tf_automata.final_states)],
                dtype=tf.int32),
            trainable=False, name="final_counts_buffer")
        self._timestep = tf.Variable(0, trainable=False, name="timestep")

        # Ready for a new run
        self._reset()
Exemplo n.º 21
0
 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"})
Exemplo n.º 22
0
    RegExpStar,
    LDLfOr,
    RegExpUnion,
    RegExpSequence,
    LDLfEnd,
    RegExpTest,
    LDLfLast,
)
from flloat.parser.ldlf import LDLfParser
from flloat.pl import PLTrue, PLFalse, PLAnd, PLNot, PLAtomic, PLEquivalence
from .conftest import LDLfFixtures
from .strategies import propositional_words
from .parsing import ParsingCheck
from . import test_pl

parser = LDLfParser()


def test_parser():
    parser = LDLfParser()
    a, b = PLAtomic("A"), PLAtomic("B")

    tt = LDLfLogicalTrue()
    ff = LDLfLogicalFalse()
    true = PLTrue()
    false = PLFalse()
    r_true = RegExpPropositional(true)
    r_false = RegExpPropositional(false)

    assert tt == parser("tt")
    assert ff == parser("ff")
Exemplo n.º 23
0
    def __init__(
        self,
        env_name,
        fluents,
        reward,
        logdir,
        load=None,
        verbose=True,
    ):
        """Initialize.

        :param env_name: a gym atari environment name.
        :param fluents: the list of propositional atoms that are known at
            each step.
        :param reward: (float) this reward is returned when the execution
            reaches a final state (at the first instant an execution satisfies
            the restraining specification).
        :param logdir: the automaton just parsed is saved here.
        :param load: if provided, the automaton is not computed but loaded
            from this file. A path to a rb.pickle file.
        :param verbose: verbose flag (automaton conversion may take a while).
        """

        # Read
        data = selector.read_back(env_name)
        json_rb = data["restraining_bolt"] + data["constraints"]

        # Parsing
        restraining_spec = " & ".join(json_rb)
        formula = LDLfParser()(restraining_spec)  # type: LDLfFormula

        # Check: all atoms must be evaluated
        atoms = formula.find_labels()
        all_predicted = all((a in fluents for a in atoms))
        if not all_predicted:
            raise ValueError("One of the atoms " + str(atoms) +
                             " is not in fluents")

        # Parse
        if load is None:

            # Conversion (slow op)
            if verbose:
                print("> Parsing", env_name, "restraining specification")
            automaton = formula.to_automaton()  # type: SymbolicAutomaton
            automaton = automaton.determinize().complete()
            if verbose:
                print("> Parsed")

            # Save and visualize the automaton
            graphviz = automaton.to_graphviz()
            graphviz.render("rb.gv",
                            directory=logdir,
                            view=False,
                            cleanup=False)
            with open(os.path.join(logdir, "rb.pickle"), "wb") as f:
                pickle.dump(automaton, f)

        # Load
        else:
            with open(load, "rb") as f:
                automaton = pickle.load(f)
            if verbose:
                print(">", load, "loaded")

            # Visualize the automaton loaded (debugging)
            graphviz = automaton.to_graphviz()
            graphviz.render("loaded_rb.gv",
                            directory=logdir,
                            view=False,
                            cleanup=False)

        # Runner
        simulator = AutomatonSimulator(automaton)

        # Store
        self.env_name = env_name
        self.fluents = fluents
        self._str = restraining_spec
        self._formula = formula
        self._automaton = automaton
        self._simulator = simulator
        self._reward = reward
        self._last_state = None