def ltl2prefix(ltl: str):
    parser = LTLfParser()
    formula = parser(
        ltl.replace('1', 'true').replace('0', 'false').replace('W', 'R'))
    return preorder(formula).replace('true',
                                     '1').replace('false',
                                                  '0').replace('R', 'W')
Пример #2
0
def test_ltlf_example_readme():
    from ltlf2dfa.parser.ltlf import LTLfParser

    parser = LTLfParser()
    formula = "G(a -> X b)"
    parsed_formula = parser(formula)

    assert str(parsed_formula) == "G((a -> X(b)))"
    assert parsed_formula.find_labels() == [c for c in "ab"]
Пример #3
0
def test_mona():
    parser = LTLfParser()
    a, b, c = [LTLfAtomic(c) for c in "abc"]
    tt = LTLfTrue()
    ff = LTLfFalse()

    assert a.to_mona(v="0") == "(0 in A)"
    assert b.to_mona(v="0") == "(0 in B)"
    assert c.to_mona(v="0") == "(0 in C)"
    assert tt.to_mona(v="0") == "true"
    assert ff.to_mona(v="0") == "false"

    f = parser("!(a & !b)")
    assert f.to_mona(v="0") == "~(((0 in A) & ~((0 in B))))"

    f = parser("!(!a | b)")
    assert f.to_mona(v="0") == "~((~((0 in A)) | (0 in B)))"

    f = parser("!(a <-> b)")
    assert (f.to_nnf().to_mona(
        v="0") == "((~((0 in A)) | ~((0 in B))) & ((0 in A) | (0 in B)))")

    # Next and Weak Next
    f = parser("X(a & b)")
    assert f.to_mona(v="0") == "(ex1 v_1: v_1=1 & ((v_1 in A) & (v_1 in B)))"

    f = parser("WX (a & b)")
    assert (f.to_mona(v="0") ==
            "((0 = max($)) | (ex1 v_1: v_1=1 & ((v_1 in A) & (v_1 in B))))")

    # Until and Release
    f = parser("a U b")
    assert (
        f.to_mona(v="0") ==
        "(ex1 v_1: 0<=v_1&v_1<=max($) & (v_1 in B) & (all1 v_2: 0<=v_2&v_2<v_1"
        " => (v_2 in A)))")
    f = parser("a R b")
    assert (
        f.to_mona(v="0") ==
        "((ex1 v_1: 0<=v_1&v_1<=max($) & (v_1 in A) & (all1 v_2: 0<=v_2&v_2<=v_1"
        " => (v_2 in B))) | (all1 v_2: 0<=v_2&v_2<=max($) => (v_2 in B)))")

    # Eventually and Always
    f = parser("F(a & b)")
    assert (
        f.to_mona(v="0") ==
        "(ex1 v_1: 0<=v_1&v_1<=max($) & ((v_1 in A) & (v_1 in B)) & (all1 v_2: "
        "0<=v_2&v_2<v_1 => true))")
    f = parser("G(a | b)")
    assert (
        f.to_mona(v="0") ==
        "((ex1 v_1: 0<=v_1&v_1<=max($) & false & (all1 v_2: 0<=v_2&v_2<=v_1 => "
        "((v_2 in A) | (v_2 in B)))) | (all1 v_2: 0<=v_2&v_2<=max($) => ((v_2 in A) "
        "| (v_2 in B))))")
Пример #4
0
def dfa():
    formula_string = request.form["inputFormula"]
    control_set = request.form["controllables"]
    uncontrol_set = request.form["uncontrollables"]
    assert formula_string
    automa_name = "dfa_" + str(datetime.datetime.now()).replace(
        " ", "_") + "_" + str(uuid.uuid4())
    isLtlf = True
    if all(c in FUTURE_OPS for c in formula_string if c.isupper()):

        f_parser = LTLfParser()
        try:
            formula = f_parser(formula_string)
        except Exception as e:
            if request.form.get("exampleCheck1"):
                return render_template("dfa.html",
                                       error=str(e).encode("utf-8"))
            return render_template("index.html", error=str(e).encode("utf-8"))
    else:
        assert all(c in PAST_OPS for c in formula_string if c.isupper())
        isLtlf = False
        p_parser = PLTLfParser()
        try:
            formula = p_parser(formula_string)
        except Exception as e:
            if request.form.get("exampleCheck1"):
                return render_template("dfa.html",
                                       error=str(e).encode("utf-8"))
            return render_template("index.html", error=str(e).encode("utf-8"))

    dfa = ltl2dfagame(formula_string, control_set, uncontrol_set, isLtlf)
    write_dot_file(str(dfa), automa_name)
    subprocess.call('dot -Tsvg {} -o {}'.format(
        "{}/static/dot/{}.dot".format(PACKAGE_DIR, automa_name),
        "{}/static/tmp/{}.svg".format(PACKAGE_DIR, automa_name)),
                    shell=True)

    encoding = encode_svg("{}/static/tmp/{}.svg".format(
        PACKAGE_DIR, automa_name)).decode("utf-8")
    piero_encoding = encode_svg(
        "{}/static/tmp/piero.svg".format(PACKAGE_DIR)).decode("utf-8")

    os.unlink("{}/static/dot/{}.dot".format(PACKAGE_DIR, automa_name))
    os.unlink("{}/static/tmp/{}.svg".format(PACKAGE_DIR, automa_name))
    os.unlink("{}/static/tmp/piero.svg".format(PACKAGE_DIR))

    return render_template("dfa.html",
                           formula=formula,
                           output=piero_encoding,
                           output2=encoding)
Пример #5
0
def test_QuotedFormula():
    from ltlf2dfa.base import QuotedFormula
    from ltlf2dfa.ltlf import LTLfAnd, LTLfAtomic
    from ltlf2dfa.parser.ltlf import LTLfParser

    f = LTLfParser()("!(G a)")
    qf = QuotedFormula(f)
    atomf = LTLfAnd([LTLfAtomic(f), LTLfAtomic(f)])

    assert qf.wrapped is f

    dir_qf = dir(qf)
    for member in dir(f):
        assert member in dir_qf
        assert hasattr(qf, member)
Пример #6
0
def test_hash_consistency_after_pickling():
    from ltlf2dfa.parser.ltlf import LTLfParser
    import pickle

    parser = LTLfParser()
    formula = "F (a & !b)"
    old_obj = parser(formula)

    h = hash(old_obj)
    pickle.dump(old_obj, open("temp", "wb"))
    new_obj = pickle.load(open("temp", "rb"))

    assert new_obj._hash is None
    assert h == hash(new_obj)

    os.remove("temp")
Пример #7
0
def ltl2dfagame(ltl, controllables, uncontrollables, isLtlf):
      
      controllables = controllables.split(' ')
      uncontrollables = uncontrollables.split(' ')
      print("controllables :")
      print( controllables)

      print("uncontrollables :")
      print( uncontrollables)

      controllables = set(controllables)
      uncontrollables = set(uncontrollables)

      ### trasformazione in automata (LTL2DFA)
      
      if(isLtlf):
        parser = LTLfParser()
      else:
        parser = PLTLfParser()

      formula = parser(ltl)       

      print("converting to automaton....")
      dfa = formula.to_dfa()
      print(dfa)                          # prints the DFA in DOT format

      ### trasformazione in automata (PYTHOMATA)
      dfa = converter(dfa)

      ### stampo automa normale
      graph = dfa.to_graphviz()
      #graph.render(outputFileName+"_normal")

      ### calcolo winning dict
      print("\n\n#############  winning_dict ################")
      win_dict = winning_dict(dfa, controllables, uncontrollables)
      #print(win_dict)

      ### stampo winning map
      graph = to_graphviz_winning_map(dfa, win_dict)
      #graph.render(outputFileName)
      return graph
Пример #8
0
def execute(planning_domain, planning_problem, goal_formula):
    """Execute the compilation."""
    pddl_parser = PDDLParser()
    parsed_domain = pddl_parser(planning_domain)
    parsed_problem = pddl_parser(planning_problem)
    # parsed_domain = planning_domain
    # parsed_problem = planning_problem

    symbols = compute_symb_vars(goal_formula)
    if not check_symbols(
            symbols,
            parsed_domain):  # TODO: it checks symbols but not objects....
        raise ValueError("[ERROR]: Formula symbols not in the domain.")

    if all(c in FUTURE_OPS for c in goal_formula if c.isupper()):
        f_parser = LTLfParser()
        try:
            formula = f_parser(goal_formula)
        except Exception:
            raise ParsingError()

    else:
        assert all(c in PAST_OPS for c in goal_formula if c.isupper())
        p_parser = PLTLfParser()
        try:
            formula = p_parser(goal_formula)
        except Exception:
            raise ParsingError()

    mona_output = formula.to_dfa(mona_dfa_out=True)
    dfa = parse_dfa(mona_output)
    operators_trans, parameters = dfa.create_operators_trans(
        parsed_domain.predicates, symbols)

    new_domain = parsed_domain.get_new_domain(parameters, dfa.states,
                                              operators_trans)
    new_problem = parsed_problem.get_new_problem(list(dfa.accepting_states),
                                                 symbols)

    return new_domain, new_problem
Пример #9
0
def test_parser():
    parser = LTLfParser()
    a, b, c = [LTLfAtomic(c) for c in "abc"]

    assert parser("!a | b <-> !(a & !b) <-> a->b") == LTLfEquivalence([
        LTLfOr([LTLfNot(a), b]),
        LTLfNot(LTLfAnd([a, LTLfNot(b)])),
        LTLfImplies([a, b]),
    ])

    assert parser("(X a) & (WX !b)") == LTLfAnd(
        [LTLfNext(a), LTLfWeakNext(LTLfNot(b))])

    assert parser("(F (a&b)) <-> !(G (!a | !b) )") == LTLfEquivalence([
        LTLfEventually(LTLfAnd([a, b])),
        LTLfNot(LTLfAlways(LTLfOr([LTLfNot(a), LTLfNot(b)]))),
    ])

    assert parser("(a U b U c) <-> !(!a R !b R !c)") == LTLfEquivalence([
        LTLfUntil([a, b, c]),
        LTLfNot(LTLfRelease([LTLfNot(a), LTLfNot(b),
                             LTLfNot(c)])),
    ])
Пример #10
0
def test_nnf():
    parser = LTLfParser()
    a, b, c = [LTLfAtomic(c) for c in "abc"]

    f = parser("!(a & !b)")
    assert f.to_nnf() == LTLfOr([LTLfNot(a), b])

    f = parser("!(!a | b)")
    assert f.to_nnf() == LTLfAnd([a, LTLfNot(b)])

    f = parser("!(a <-> b)")
    assert f.to_nnf() == LTLfAnd(
        [LTLfOr([LTLfNot(a), LTLfNot(b)]),
         LTLfOr([a, b])])

    # Next and Weak Next
    f = parser("!(X (a & b))")
    assert f.to_nnf() == LTLfWeakNext(LTLfOr([LTLfNot(a), LTLfNot(b)]))

    f = parser("!(WX (a & b))")
    assert f.to_nnf() == LTLfNext(LTLfOr([LTLfNot(a), LTLfNot(b)]))

    # Eventually and Always
    f = parser("!(F (a | b))")
    assert f.to_nnf() == LTLfAlways(LTLfAnd([LTLfNot(a), LTLfNot(b)])).to_nnf()

    # Until and Release
    f = parser("!(a U b)")
    assert f.to_nnf() == LTLfRelease([LTLfNot(a), LTLfNot(b)])
    f = parser("!(a R b)")
    assert f.to_nnf() == LTLfUntil([LTLfNot(a), LTLfNot(b)])

    f = parser("!(F (a | b))")
    assert f.to_nnf() == LTLfAlways(LTLfAnd([LTLfNot(a), LTLfNot(b)])).to_nnf()
    f = parser("!(G (a | b))")
    assert f.to_nnf() == LTLfEventually(LTLfAnd([LTLfNot(a),
                                                 LTLfNot(b)])).to_nnf()
Пример #11
0
def test_ltlf_dfa():
    parser = LTLfParser()

    f = parser("a")
    dfa = f.to_dfa(mona_dfa_out=False)
    mona_dfa = f.to_dfa(mona_dfa_out=True)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a"];
 1 -> 3 [label="a"];
 2 -> 2 [label="true"];
 3 -> 3 [label="true"];
}"""
    expected_mona = """DFA for formula with free variables: A 
Initial state: 0
Accepting states: 3 
Rejecting states: 0 1 2 

Automaton has 4 states and 4 BDD-nodes
Transitions:
State 0: X -> state 1
State 1: 0 -> state 2
State 1: 1 -> state 3
State 2: X -> state 2
State 3: X -> state 3
A counter-example of least length (0) is:
A               X 

A = {}

A satisfying example of least length (1) is:
A               X 1

A = {0}"""

    assert dfa == expected
    assert mona_dfa == expected_mona

    f = parser("true")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 1;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 1 [label="true"];
}"""
    assert dfa == expected

    f = parser("false")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle];
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 1 [label="true"];
}"""
    assert dfa == expected

    f = parser("G a")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 1;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a"];
 1 -> 1 [label="a"];
 2 -> 2 [label="true"];
}"""
    assert dfa == expected

    f = parser("F(a & b)")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 2;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 1 [label="~a | ~b"];
 1 -> 2 [label="a & b"];
 2 -> 2 [label="true"];
}"""
    assert dfa == expected

    f = parser("X(a)")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 4;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="true"];
 2 -> 3 [label="~a"];
 2 -> 4 [label="a"];
 3 -> 3 [label="true"];
 4 -> 4 [label="true"];
}"""
    assert dfa == expected

    f = parser("a U b")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected1 = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a & ~b"];
 1 -> 3 [label="b"];
 1 -> 4 [label="a & ~b"];
 2 -> 2 [label="true"];
 3 -> 3 [label="true"];
 4 -> 2 [label="~a & ~b"];
 4 -> 3 [label="b"];
 4 -> 4 [label="a & ~b"];
}"""
    expected2 = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a & ~b"];
 1 -> 3 [label="a & ~b"];
 1 -> 4 [label="b"];
 2 -> 2 [label="true"];
 3 -> 2 [label="~a & ~b"];
 3 -> 3 [label="a & ~b"];
 3 -> 4 [label="b"];
 4 -> 4 [label="true"];
}"""
    assert dfa == expected1 or expected2

    f = parser("G(a) & F(b)")
    dfa = f.to_dfa(mona_dfa_out=False)
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a"];
 1 -> 1 [label="a & ~b"];
 1 -> 3 [label="a & b"];
 2 -> 2 [label="true"];
 3 -> 2 [label="~a"];
 3 -> 3 [label="a"];
}"""
    assert dfa == expected
Пример #12
0
def test_ltlf_mona_dfa():
    parser = LTLfParser()

    f = parser("a")
    mona_dfa = f.to_dfa(mona_dfa_out=True)
    expected_mona = """DFA for formula with free variables: A 
Initial state: 0
Accepting states: 3 
Rejecting states: 0 1 2 

Automaton has 4 states and 4 BDD-nodes
Transitions:
State 0: X -> state 1
State 1: 0 -> state 2
State 1: 1 -> state 3
State 2: X -> state 2
State 3: X -> state 3
A counter-example of least length (0) is:
A               X 

A = {}

A satisfying example of least length (1) is:
A               X 1

A = {0}"""

    assert mona_dfa == expected_mona

    f = parser("true")
    mona_dfa = f.to_dfa(mona_dfa_out=True)
    expected_mona = """DFA for formula with free variables: 
Initial state: 0
Accepting states: 1 
Rejecting states: 0 

Automaton has 2 states and 1 BDD-node
Transitions:
State 0:  -> state 1
State 1:  -> state 1
Formula is valid
A satisfying example of least length (0) is:"""
    assert mona_dfa == expected_mona

    f = parser("false")
    mona_dfa = f.to_dfa(mona_dfa_out=True)
    expected_mona = """DFA for formula with free variables: 
Initial state: 0
Accepting states: 
Rejecting states: 0 

Automaton has 1 state and 1 BDD-node
Transitions:
State 0:  -> state 0
Formula is unsatisfiable

A counter-example of least length (0) is:"""
    assert mona_dfa == expected_mona

    f = parser("G a")
    mona_dfa = f.to_dfa(mona_dfa_out=True)
    expected_mona = """DFA for formula with free variables: A 
Initial state: 0
Accepting states: 1 
Rejecting states: 0 2 

Automaton has 3 states and 3 BDD-nodes
Transitions:
State 0: X -> state 1
State 1: 0 -> state 2
State 1: 1 -> state 1
State 2: X -> state 2
A counter-example of least length (1) is:
A               X 0

A = {}

A satisfying example of least length (0) is:
A               X 

A = {}"""
    assert mona_dfa == expected_mona

    f1 = parser("F(WX(false))")
    f2 = parser("F(!(X(!(false))))")
    mona_dfa_1 = f1.to_dfa(mona_dfa_out=True)
    mona_dfa_2 = f2.to_dfa(mona_dfa_out=True)
    assert mona_dfa_1 == mona_dfa_2

    f1 = parser("F(b & WX false) -> F(a & (WX false | X(WX false)))")
    f2 = parser(
        "((! (F (! ((! b) || (X (! false)))))) || (F (! ((! a) || (! ((! (X (! false))) || (X (! (X (! false))))))))))"
    )
    mona_dfa_1 = f1.to_dfa(mona_dfa_out=True)
    mona_dfa_2 = f2.to_dfa(mona_dfa_out=True)
    assert mona_dfa_1 == mona_dfa_2
Пример #13
0
def ltl2dfagame(ltl, controllables, uncontrollables, isLtlf):

    controllables = controllables.split(' ')
    uncontrollables = uncontrollables.split(' ')
    print("controllables :")
    print(controllables)

    print("uncontrollables :")
    print(uncontrollables)

    controllables = set(controllables)
    uncontrollables = set(uncontrollables)

    ### trasformazione in automata (LTL2DFA)

    if (isLtlf):
        parser = LTLfParser()
    else:
        parser = PLTLfParser()

    formula = parser(ltl)

    print("converting to automaton....")
    dfa = formula.to_dfa()
    print(dfa)  # prints the DFA in DOT format

    ### trasformazione in automata (PYTHOMATA)
    dfa = converter(dfa)

    ### stampo automa normale
    graph = dfa.to_graphviz()
    #graph.render(outputFileName+"_normal")

    ### calcolo winning dict
    print("\n\n#############  winning_dict ################")
    win_dict, strat_list = winning_dict(dfa, controllables, uncontrollables)
    #print(win_dict)

    ### stampo winning map

    graph, color_map = to_graphviz_winning_map(dfa, win_dict)
    #graph.render(outputFileName)

    ### stampo se e' realizzabile
    realizable = realizzabile(dfa, win_dict)
    #realizable = False
    ### stampo la strategy
    '''
      if realizable:
        strat, strat_list = computeStrategy(dfa, win_dict, controllables)
      else:
        strat_list = []
      '''
    if not realizable:
        strat_list = []
    ### plot
    print(color_map)
    plot(ltl, strat_list, realizable, controllables, uncontrollables,
         color_map)

    return graph
def ltl2turple(ltl: str):
    parser = LTLfParser()
    formula = parser(
        ltl.replace('1', 'true').replace('0', 'false').replace('W', 'R'))
    return preorder_turple(formula)
Пример #15
0
def test_ltlf_dfa():
    parser = LTLfParser()

    f = parser("a")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a"];
 1 -> 3 [label="a"];
 2 -> 2 [label="true"];
 3 -> 3 [label="true"];
}"""
    assert dfa == expected

    f = parser("true")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 1;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 1 [label="true"];
}"""
    assert dfa == expected

    f = parser("false")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle];
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 1 [label="true"];
}"""
    assert dfa == expected

    f = parser("G a")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a"];
 1 -> 3 [label="a"];
 2 -> 2 [label="true"];
 3 -> 2 [label="~a"];
 3 -> 3 [label="a"];
}"""
    assert dfa == expected

    f = parser("F(a & b)")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a | ~b"];
 1 -> 3 [label="a & b"];
 2 -> 2 [label="~a | ~b"];
 2 -> 3 [label="a & b"];
 3 -> 3 [label="true"];
}"""
    assert dfa == expected

    f = parser("X(a)")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 4;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="true"];
 2 -> 3 [label="~a"];
 2 -> 4 [label="a"];
 3 -> 3 [label="true"];
 4 -> 4 [label="true"];
}"""
    assert dfa == expected

    f = parser("a U b")
    dfa = f.to_dfa()
    expected1 = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a & ~b"];
 1 -> 3 [label="b"];
 1 -> 4 [label="a & ~b"];
 2 -> 2 [label="true"];
 3 -> 3 [label="true"];
 4 -> 2 [label="~a & ~b"];
 4 -> 3 [label="b"];
 4 -> 4 [label="a & ~b"];
}"""
    expected2 = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 3;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a & ~b"];
 1 -> 3 [label="a & ~b"];
 1 -> 4 [label="b"];
 2 -> 2 [label="true"];
 3 -> 2 [label="~a & ~b"];
 3 -> 3 [label="a & ~b"];
 3 -> 4 [label="b"];
 4 -> 4 [label="true"];
}"""
    assert dfa == expected1 or expected2

    f = parser("G(a) & F(b)")
    dfa = f.to_dfa()
    expected = """digraph MONA_DFA {
 rankdir = LR;
 center = true;
 size = "7.5,10.5";
 edge [fontname = Courier];
 node [height = .5, width = .5];
 node [shape = doublecircle]; 4;
 node [shape = circle]; 1;
 init [shape = plaintext, label = ""];
 init -> 1;
 1 -> 2 [label="~a"];
 1 -> 3 [label="a & ~b"];
 1 -> 4 [label="a & b"];
 2 -> 2 [label="true"];
 3 -> 2 [label="~a"];
 3 -> 3 [label="a & ~b"];
 3 -> 4 [label="a & b"];
 4 -> 2 [label="~a"];
 4 -> 4 [label="a"];
}"""
    assert dfa == expected