Example #1
0
 def test_and(self):
     ast = negation_normal_form(parse_ctlq("AX AG (? & False)"))
     ast2 = negation_normal_form(parse_ctlq("AX AG ?"))
     self.assertTrue(check_ctlqx(ast))
     self.assertTrue(check_ctlqx(ast2))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast), solve_ctlqx(fsm, ast2))
Example #2
0
 def test_and(self):
     ast = negation_normal_form(parse_ctlq("AX AG (? & False)"))
     ast2 = negation_normal_form(parse_ctlq("AX AG ?"))
     self.assertTrue(check_ctlqx(ast))
     self.assertTrue(check_ctlqx(ast2))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast), solve_ctlqx(fsm, ast2))
Example #3
0
 def test_false(self):
     ast = negation_normal_form(
         parse_ctlq("A['admin = bob' oW A['admin = alice' oU AG ?]]"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast),
                      BDD.false(fsm.bddEnc.DDmanager))
Example #4
0
 def test_or(self):
     ast = negation_normal_form(parse_ctlq("AF ('admin = bob' | AG ?)"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     solution = {HashableDict({'admin': 'alice', 'state': 'waiting'}),
                 HashableDict({'admin': 'alice', 'state': 'processing'})}
     self.assertCountEqual(bdd_to_set(fsm, solve_ctlqx(fsm, ast)), solution)
Example #5
0
 def test_false(self):
     ast = negation_normal_form(
         parse_ctlq("A['admin = bob' oW A['admin = alice' oU AG ?]]")
     )
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast),
                      BDD.false(fsm.bddEnc.DDmanager))
Example #6
0
 def test_au(self):
     ast = negation_normal_form(parse_ctlq("A[? U 'state = processing']"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     solution = {HashableDict({'admin': 'none', 'state': 'starting'}),
                 HashableDict({'admin': 'none', 'state': 'choosing'}),
                 HashableDict({'admin': 'alice', 'state': 'waiting'}),
                 HashableDict({'admin': 'bob', 'state': 'waiting'})}
     self.assertCountEqual(bdd_to_set(fsm, solve_ctlqx(fsm, ast)), solution)
Example #7
0
 def test_simplify_fail(self):
     ast = negation_normal_form(parse_ctlq("?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model('examples/microwave.smv')
     with self.assertRaises(VariableNotInModelError):
         simplify(fsm, solve_ctlqx(fsm, ast), 1, ['a'])
     with self.assertRaises(ValueOutOfBoundsError):
         simplify(fsm, solve_ctlqx(fsm, ast), 0)
     with self.assertRaises(ValueOutOfBoundsError):
         simplify(fsm, solve_ctlqx(fsm, ast), 10)
Example #8
0
 def test_simplify_conjunction(self):
     ast = negation_normal_form(parse_ctlq("AG (? -> AF 'heat')"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model('examples/microwave.smv')
     simplification = simplify(fsm, solve_ctlqx(fsm, ast), 2)
     self.assertCountEqual('(error = FALSE)\n& (close = TRUE)\n&'
                           ' ((heat = FALSE & start = TRUE) |'
                           ' (heat = TRUE & start = TRUE) |'
                           ' (heat = TRUE & start = FALSE))',
                           simplification)
Example #9
0
 def test_or(self):
     ast = negation_normal_form(parse_ctlq("AF ('admin = bob' | AG ?)"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     solution = {
         HashableDict({
             'admin': 'alice',
             'state': 'waiting'
         }),
         HashableDict({
             'admin': 'alice',
             'state': 'processing'
         })
     }
     self.assertCountEqual(bdd_to_set(fsm, solve_ctlqx(fsm, ast)), solution)
Example #10
0
    def test_ko(self):
        kos = [
            "? <-> 'a'", "'a' <-> ?", "AF ?", "A['a' U ?]", "A['a' W ?]",
            "A['a' oU ?]", "A['a' oW ?]", "A[? dU 'a']", "A[? dW 'a']", "EX ?",
            "EF ?", "EG ?", "~AX ?", "~AF ?", "~AG ?", "E['a' U ?]",
            "E[? U 'a']", "E['a' W ?]", "E[? W 'a']", "E['a' oU ?]",
            "E[? oU 'a']", "E['a' oW ?]", "E[? oW 'a']", "E['a' dU ?]",
            "E[? dU 'a']", "E['a' dW ?]", "E[? dW 'a']", "~('a' -> AF ?)",
            "AF ('a' & AF ('b' | AG ?))", "AX ((AF A[? dU 'b']) | 'a')",
            "AF A[True oU A[? U 'a']]", "A['a' U A[True oU A[? U 'b']]]",
            "A['a' W A[True oU A[? U 'b']]]",
            "A['a' oU A[True oU A[? U 'b']]]",
            "A['a' oW A[True oU A[? U 'b']]]",
            "AF AX (A['a' W A[? U 'b']] | False)",
            "AF A['a' dW A['b' W A[? U 'c']]]",
            "AF A['a' oW A['b' W A[? U 'c']]]",
            "AF A[A['a' W A[? U 'b']] oW 'c']",
            "AF A['a' dU A['b' W A[? U 'c']]]",
            "AF A['a' oU A['b' W A[? U 'c']]]",
            "AF A[A['a' W A[? U 'b']] oU 'c']",
            "AF AX A[AF AX (AG ? & True) U False]",
            "A['a' U A['b' oU A[A[A['c' dW AG ?] W 'e'] oW 'f']]]",
            "AF AX ('a' & (('b' & A['c' oW AG ?]) | 'd'))",
            "AF AX ('a' & (('b' & ('c' | A['d' oW AG ?])) | 'e'))",
            "AF ('a' & A['b' oW (A['c' oW AG ?] | 'd')])",
            "AF AX A['b' oW (A['c' oW AG ?] | 'd')]",
            "AF AX (('a' | A[AG ? U 'b']) & 'c')",
            "AF ('a' & (A['b' oW (A['c' oW AG ?] | 'd')] | 'e'))",
            "A['a' U A['b' dW A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
            "A['a' U A['b' oU A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
            "A['a' U A[A['b' oU A[AG (AG ? | 'c') U 'd']] oU 'e']]",
            "A['a' U A['b' dU A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
            "A['a' U A[A['b' oU A[AG (AG ? | 'c') U 'd']] oW 'e']]",
            "A['a' U A['b' oW A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
            "AF A['a' oU A['b' oW A[AG A[AG ? U 'c'] U 'd']]]",
            "A['a' U AX A['b' U A[AG ? U 'c']]]",
            "A['a' U AX A['b' W A[AG ? U 'c']]]",
            "A['a' U AX A['b' dU A[AG ? U 'c']]]",
            "A['a' U AX A['b' dW A[AG ? U 'c']]]",
            "A['a' U AX A[A[AG ? U 'b'] U 'c']]",
            "A['a' U AX A[A[AG ? U 'b'] W 'c']]",
            "A['a' U AX A[A[AG ? U 'b'] oU 'c']]",
            "A['a' U AX A[A[AG ? U 'b'] oW 'c']]"
        ]

        for ko in kos:
            self.assertFalse(check_ctlqx(negation_normal_form(parse_ctlq(ko))))
Example #11
0
    def test_ko(self):
        kos = ["? <-> 'a'", "'a' <-> ?", "AF ?", "A['a' U ?]", "A['a' W ?]",
               "A['a' oU ?]", "A['a' oW ?]", "A[? dU 'a']", "A[? dW 'a']",
               "EX ?", "EF ?", "EG ?", "~AX ?", "~AF ?", "~AG ?", "E['a' U ?]",
               "E[? U 'a']", "E['a' W ?]", "E[? W 'a']", "E['a' oU ?]",
               "E[? oU 'a']", "E['a' oW ?]", "E[? oW 'a']", "E['a' dU ?]",
               "E[? dU 'a']", "E['a' dW ?]", "E[? dW 'a']", "~('a' -> AF ?)",
               "AF ('a' & AF ('b' | AG ?))", "AX ((AF A[? dU 'b']) | 'a')",
               "AF A[True oU A[? U 'a']]", "A['a' U A[True oU A[? U 'b']]]",
               "A['a' W A[True oU A[? U 'b']]]",
               "A['a' oU A[True oU A[? U 'b']]]",
               "A['a' oW A[True oU A[? U 'b']]]",
               "AF AX (A['a' W A[? U 'b']] | False)",
               "AF A['a' dW A['b' W A[? U 'c']]]",
               "AF A['a' oW A['b' W A[? U 'c']]]",
               "AF A[A['a' W A[? U 'b']] oW 'c']",
               "AF A['a' dU A['b' W A[? U 'c']]]",
               "AF A['a' oU A['b' W A[? U 'c']]]",
               "AF A[A['a' W A[? U 'b']] oU 'c']",
               "AF AX A[AF AX (AG ? & True) U False]",
               "A['a' U A['b' oU A[A[A['c' dW AG ?] W 'e'] oW 'f']]]",
               "AF AX ('a' & (('b' & A['c' oW AG ?]) | 'd'))",
               "AF AX ('a' & (('b' & ('c' | A['d' oW AG ?])) | 'e'))",
               "AF ('a' & A['b' oW (A['c' oW AG ?] | 'd')])",
               "AF AX A['b' oW (A['c' oW AG ?] | 'd')]",
               "AF AX (('a' | A[AG ? U 'b']) & 'c')",
               "AF ('a' & (A['b' oW (A['c' oW AG ?] | 'd')] | 'e'))",
               "A['a' U A['b' dW A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
               "A['a' U A['b' oU A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
               "A['a' U A[A['b' oU A[AG (AG ? | 'c') U 'd']] oU 'e']]",
               "A['a' U A['b' dU A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
               "A['a' U A[A['b' oU A[AG (AG ? | 'c') U 'd']] oW 'e']]",
               "A['a' U A['b' oW A['c' oU A[AG (AG ? | 'd') U 'e']]]]",
               "AF A['a' oU A['b' oW A[AG A[AG ? U 'c'] U 'd']]]",
               "A['a' U AX A['b' U A[AG ? U 'c']]]",
               "A['a' U AX A['b' W A[AG ? U 'c']]]",
               "A['a' U AX A['b' dU A[AG ? U 'c']]]",
               "A['a' U AX A['b' dW A[AG ? U 'c']]]",
               "A['a' U AX A[A[AG ? U 'b'] U 'c']]",
               "A['a' U AX A[A[AG ? U 'b'] W 'c']]",
               "A['a' U AX A[A[AG ? U 'b'] oU 'c']]",
               "A['a' U AX A[A[AG ? U 'b'] oW 'c']]"]

        for ko in kos:
            self.assertFalse(check_ctlqx(negation_normal_form(parse_ctlq(ko))))
Example #12
0
    def test_ok(self):
        oks = [
            "?", "~?", "? & 'a'", "'a' & ?", "? | 'a'", "'a' | ?", "? -> 'a'",
            "'a' -> ?", "AX ?", "AG ?", "~EX ?", "~EF ?", "A[? U 'a']",
            "A[? W 'a']", "A[? oU 'a']", "A[? oW 'a']", "A['a' dW ?]",
            "A['a' dU ?]", "AX ((AG A['b' dU ?]) | EX 'a')", "~(? -> AF 'a')",
            "True & A[? U 'a']", "True | A[? U 'a']",
            "True & A['a' oU A[? U 'b']]", "True | A['a' oU A[? U 'b']]",
            "AX A[? U 'a']", "AX A['a' oU A[? U 'b']]", "AF A[? U 'a']",
            "AG A[? U 'a']", "AG A['a' oU A[? U 'b']]", "A[A[? U 'a'] U 'b']",
            "A[A['a' oU A[? U 'b']] U 'c']", "A['a' U A[? U 'b']]",
            "A[A[? U 'a'] W 'b']", "A[A['a' oU A[? U 'b']] W 'c']",
            "A['a' W A[? U 'b']]", "A[A[? U 'a'] oU 'b']",
            "A[A['a' oU A[? U 'b']] oU 'c']", "A['a' dU A[? U 'b']]",
            "A['a' dU A['b' oU A[? U 'c']]]", "A[A[? oW 'a'] U 'b']",
            "A[A[? U 'a'] oW 'b']", "A[A['a' oU A[? U 'b']] oW 'c']",
            "A['a' oW A[? U 'b']]", "A['a' dW A[? U 'b']]",
            "A['a' dW A['b' oU A[? U 'c']]]", "A['a' W A['b' W A[? U 'c']]]",
            "A[A[A[? U 'a'] W 'b'] W 'c']", "A['a' U A['b' W A[? U 'c']]]",
            "A[A[A[? U 'a'] W 'b'] U 'c']", "AG A['b' W A[? U 'c']]",
            "AF A['b' W A[? U 'c']]", "A['a' dW A['b' W A['c' U AG AG ?]]]",
            "AF A['a' oW AG ?]", "A['a' oU A[AG ? oU 'b']]",
            "A['a' oW A[AG ? oW 'b']]", "A['a' dU A['b' dU A['c' oW AG ?]]]",
            "AX A['a' oW AG ?]", "AF A['a' oW ('b' | A['c' oW AG ?])]",
            "AF A[AG ? U False]",
            "A['a' dW A['b' oW A[A[A['c' oW AG ?] oU 'd'] oW 'e']]]",
            "A['a' U A['b' oW AG ?]]", "A['a' W A['b' oW AG ?]]",
            "A['a' oU A['b' oW AG ?]]", "AG A['a' oU A[AG ? U 'b']]",
            "AG AX AF ('a' | ('b' & AG A['c' oW AG ?]))",
            "A['a' W A[A['b' U A[AG A['c' oW AG ?] U 'd']] W 'e']]",
            "A['a' oW A[A['b' oU A[AG A['c' oW AG ?] oU 'd']] oW 'e']]",
            "A['a' dU A['b' dW AG A['c' oW AG ?]]]",
            "A['a' dU (AG A['b' dW ('c' | AG ?)] | 'd')]",
            "A[('a' | AG A['b' oU (AG ? | 'c')]) oU 'd']",
            "A[('a' | AG A['b' U (AG ? | 'c')]) U 'd']",
            "A[('a' | AG A['b' W (AG ? | 'c')]) W 'd']",
            "A['a' W A['b' oU A[A['c' oW AG ?] U 'd']]]",
            "A[A['a' oW A[A['b' oW AG ?] W 'c']] U 'd']",
            "A[A['a' oU A[AG ? U 'b']] W 'c']",
            "A['a' U A['b' oU A[AG ? U 'c']]]"
        ]

        for ok in oks:
            self.assertTrue(check_ctlqx(negation_normal_form(parse_ctlq(ok))))
Example #13
0
    def test_ok(self):
        oks = ["?", "~?", "? & 'a'", "'a' & ?", "? | 'a'", "'a' | ?",
               "? -> 'a'", "'a' -> ?", "AX ?", "AG ?", "~EX ?", "~EF ?",
               "A[? U 'a']", "A[? W 'a']", "A[? oU 'a']", "A[? oW 'a']",
               "A['a' dW ?]", "A['a' dU ?]", "AX ((AG A['b' dU ?]) | EX 'a')",
               "~(? -> AF 'a')", "True & A[? U 'a']", "True | A[? U 'a']",
               "True & A['a' oU A[? U 'b']]", "True | A['a' oU A[? U 'b']]",
               "AX A[? U 'a']", "AX A['a' oU A[? U 'b']]", "AF A[? U 'a']",
               "AG A[? U 'a']", "AG A['a' oU A[? U 'b']]",
               "A[A[? U 'a'] U 'b']", "A[A['a' oU A[? U 'b']] U 'c']",
               "A['a' U A[? U 'b']]", "A[A[? U 'a'] W 'b']",
               "A[A['a' oU A[? U 'b']] W 'c']", "A['a' W A[? U 'b']]",
               "A[A[? U 'a'] oU 'b']", "A[A['a' oU A[? U 'b']] oU 'c']",
               "A['a' dU A[? U 'b']]", "A['a' dU A['b' oU A[? U 'c']]]",
               "A[A[? oW 'a'] U 'b']", "A[A[? U 'a'] oW 'b']",
               "A[A['a' oU A[? U 'b']] oW 'c']", "A['a' oW A[? U 'b']]",
               "A['a' dW A[? U 'b']]", "A['a' dW A['b' oU A[? U 'c']]]",
               "A['a' W A['b' W A[? U 'c']]]", "A[A[A[? U 'a'] W 'b'] W 'c']",
               "A['a' U A['b' W A[? U 'c']]]", "A[A[A[? U 'a'] W 'b'] U 'c']",
               "AG A['b' W A[? U 'c']]", "AF A['b' W A[? U 'c']]",
               "A['a' dW A['b' W A['c' U AG AG ?]]]", "AF A['a' oW AG ?]",
               "A['a' oU A[AG ? oU 'b']]", "A['a' oW A[AG ? oW 'b']]",
               "A['a' dU A['b' dU A['c' oW AG ?]]]", "AX A['a' oW AG ?]",
               "AF A['a' oW ('b' | A['c' oW AG ?])]", "AF A[AG ? U False]",
               "A['a' dW A['b' oW A[A[A['c' oW AG ?] oU 'd'] oW 'e']]]",
               "A['a' U A['b' oW AG ?]]", "A['a' W A['b' oW AG ?]]",
               "A['a' oU A['b' oW AG ?]]", "AG A['a' oU A[AG ? U 'b']]",
               "AG AX AF ('a' | ('b' & AG A['c' oW AG ?]))",
               "A['a' W A[A['b' U A[AG A['c' oW AG ?] U 'd']] W 'e']]",
               "A['a' oW A[A['b' oU A[AG A['c' oW AG ?] oU 'd']] oW 'e']]",
               "A['a' dU A['b' dW AG A['c' oW AG ?]]]",
               "A['a' dU (AG A['b' dW ('c' | AG ?)] | 'd')]",
               "A[('a' | AG A['b' oU (AG ? | 'c')]) oU 'd']",
               "A[('a' | AG A['b' U (AG ? | 'c')]) U 'd']",
               "A[('a' | AG A['b' W (AG ? | 'c')]) W 'd']",
               "A['a' W A['b' oU A[A['c' oW AG ?] U 'd']]]",
               "A[A['a' oW A[A['b' oW AG ?] W 'c']] U 'd']",
               "A[A['a' oU A[AG ? U 'b']] W 'c']",
               "A['a' U A['b' oU A[AG ? U 'c']]]"]

        for ok in oks:
            self.assertTrue(check_ctlqx(negation_normal_form(parse_ctlq(ok))))
Example #14
0
 def test_au(self):
     ast = negation_normal_form(parse_ctlq("A[? U 'state = processing']"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     solution = {
         HashableDict({
             'admin': 'none',
             'state': 'starting'
         }),
         HashableDict({
             'admin': 'none',
             'state': 'choosing'
         }),
         HashableDict({
             'admin': 'alice',
             'state': 'waiting'
         }),
         HashableDict({
             'admin': 'bob',
             'state': 'waiting'
         })
     }
     self.assertCountEqual(bdd_to_set(fsm, solve_ctlqx(fsm, ast)), solution)
Example #15
0
 def test_not_placeholder(self):
     ast = negation_normal_form(parse_ctlq("~?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast),
                      fsm.reachable_states - fsm.init)
Example #16
0
def cli(model_path, query, order):
    """Solve QUERY that belongs to fragment CTLQx for model in MODEL_PATH."""
    try:
        # Parse `query` and transform it in NNF.
        ast = negation_normal_form(parse_ctlq(query))

        # Check that `query` belongs to fragment CTLQx.
        if not check_ctlqx(ast):
            click.echo('Error: {query} does not belong to CTLQx'
                       .format(query=query))
            # Quit PyTLQ.
            sys.exit()

        # Initialize NuSMV.
        with init_nusmv():
            # Load model from `model_path`.
            load(model_path)
            # Enable dynamic reordering of the variables.
            enable_dynamic_reordering()
            # Check if an order file is given.
            if order:
                # Build model with pre-calculated variable ordering.
                compute_model(variables_ordering=order)
            else:
                # Build model.
                compute_model()
            # Retrieve FSM of the model.
            fsm = prop_database().master.bddFsm

            # Solve `query` in `fsm`.
            solution = solve_ctlqx(fsm, ast)

            # Display solution.
            click.echo('Solution states:')
            if not solution:
                click.echo('No solution')
                # Quit PyTLQ.
                sys.exit()
            elif solution.is_false():
                click.echo('False')
                # Quit PyTLQ.
                sys.exit()
            else:
                size = fsm.count_states(solution)
                if size > 100:
                    if click.confirm('The number of states is too large'
                                     ' ({size}). Do you still want to print'
                                     ' them?'.format(size=size)):
                        pprint(bdd_to_set(fsm, solution))
                else:
                    pprint(bdd_to_set(fsm, solution))

            # Ask for further manipulations.
            while True:
                command = click.prompt('\nWhat do you want to do?'
                                       '\n  1. Project the solution on a'
                                       ' subset of the variables'
                                       '\n  2. Simplify the solution according'
                                       ' to Chan\'s approximate conjunctive'
                                       ' decomposition'
                                       '\n  3. Quit PyTLQ'
                                       '\nYour choice',
                                       type=click.IntRange(1, 3), default=3)

                # Check if solution must be projected or simplified.
                if command == 1 or command == 2:

                    # Gather more information.
                    click.echo('')
                    if command == 2:
                        maximum = click.prompt('Please enter the maximum'
                                               ' number of variables that must'
                                               ' appear in the conjuncts of'
                                               ' the simplification', type=int,
                                               default=1)
                    variables = click.prompt('Please enter the list of'
                                             ' variables of interest,'
                                             ' separated by commas', type=str,
                                             default='all the variables')
                    # Format `variables`.
                    if variables == 'all the variables':
                        variables = None
                    else:
                        variables = variables.replace(" ", "").split(',')

                    if command == 1:
                        # Project solution and display projection.
                        click.echo('\nProjection:')
                        click.echo(project(fsm, solution, variables))
                    else:
                        # Simplify solution and display simplification.
                        click.echo('\nApproximate conjunctive decomposition:')
                        click.echo(simplify(fsm, solution, maximum, variables))

                # No further manipulations are needed.
                else:
                    break

    except Exception as error:
        click.echo('Error: {msg}'.format(msg=error))
Example #17
0
 def test_not_placeholder(self):
     ast = negation_normal_form(parse_ctlq("~?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast),
                      fsm.reachable_states - fsm.init)
Example #18
0
 def test_ax(self):
     ast = negation_normal_form(parse_ctlq("AX ?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     solution = {HashableDict({'admin': 'none', 'state': 'choosing'})}
     self.assertCountEqual(bdd_to_set(fsm, solve_ctlqx(fsm, ast)), solution)
Example #19
0
 def test_ax(self):
     ast = negation_normal_form(parse_ctlq("AX ?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     solution = {HashableDict({'admin': 'none', 'state': 'choosing'})}
     self.assertCountEqual(bdd_to_set(fsm, solve_ctlqx(fsm, ast)), solution)
Example #20
0
def cli(model_path, query, order):
    """Solve QUERY that belongs to fragment CTLQx for model in MODEL_PATH."""
    try:
        # Parse `query` and transform it in NNF.
        ast = negation_normal_form(parse_ctlq(query))

        # Check that `query` belongs to fragment CTLQx.
        if not check_ctlqx(ast):
            click.echo("Error: {query} does not belong to CTLQx".format(query=query))
            # Quit PyTLQ.
            sys.exit()

        # Initialize NuSMV.
        with init_nusmv():
            # Load model from `model_path`.
            load(model_path)
            # Enable dynamic reordering of the variables.
            enable_dynamic_reordering()
            # Check if an order file is given.
            if order:
                # Build model with pre-calculated variable ordering.
                compute_model(variables_ordering=order)
            else:
                # Build model.
                compute_model()
            # Retrieve FSM of the model.
            fsm = prop_database().master.bddFsm

            # Solve `query` in `fsm`.
            solution = solve_ctlqx(fsm, ast)

            # Display solution.
            click.echo("Solution states:")
            if not solution:
                click.echo("No solution")
                # Quit PyTLQ.
                sys.exit()
            elif solution.is_false():
                click.echo("False")
                # Quit PyTLQ.
                sys.exit()
            else:
                size = fsm.count_states(solution)
                if size > 100:
                    if click.confirm(
                        "The number of states is too large"
                        " ({size}). Do you still want to print"
                        " them?".format(size=size)
                    ):
                        pprint(bdd_to_set(fsm, solution))
                else:
                    pprint(bdd_to_set(fsm, solution))

            # Ask for further manipulations.
            while True:
                command = click.prompt(
                    "\nWhat do you want to do?"
                    "\n  1. Project the solution on a"
                    " subset of the variables"
                    "\n  2. Simplify the solution according"
                    " to Chan's approximate conjunctive"
                    " decomposition"
                    "\n  3. Quit PyTLQ"
                    "\nYour choice",
                    type=click.IntRange(1, 3),
                    default=3,
                )

                # Check if solution must be projected or simplified.
                if command == 1 or command == 2:

                    # Gather more information.
                    click.echo("")
                    if command == 2:
                        maximum = click.prompt(
                            "Please enter the maximum"
                            " number of variables that must"
                            " appear in the conjuncts of"
                            " the simplification",
                            type=int,
                            default=1,
                        )
                    variables = click.prompt(
                        "Please enter the list of" " variables of interest," " separated by commas",
                        type=str,
                        default="all the variables",
                    )
                    # Format `variables`.
                    if variables == "all the variables":
                        variables = None
                    else:
                        variables = variables.replace(" ", "").split(",")

                    if command == 1:
                        # Project solution and display projection.
                        click.echo("\nProjection:")
                        click.echo(project(fsm, solution, variables))
                    else:
                        # Simplify solution and display simplification.
                        click.echo("\nApproximate conjunctive decomposition:")
                        click.echo(simplify(fsm, solution, maximum, variables))

                # No further manipulations are needed.
                else:
                    break

    except Exception as error:
        click.echo("Error: {msg}".format(msg=error))
Example #21
0
 def test_ag(self):
     ast = negation_normal_form(parse_ctlq("AG ?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast), fsm.reachable_states)
Example #22
0
 def test_simplify_all(self):
     ast = negation_normal_form(parse_ctlq("AG ?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model('examples/microwave.smv')
     simplification = simplify(fsm, solve_ctlqx(fsm, ast))
     self.assertEqual('No possible simplification', simplification)
Example #23
0
 def test_simplify_candidate(self):
     ast = negation_normal_form(parse_ctlq("?"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model('examples/short.smv')
     simplification = simplify(fsm, solve_ctlqx(fsm, ast))
     self.assertEqual('(state = ready)', simplification)
Example #24
0
 def test_aou(self):
     ast = negation_normal_form(parse_ctlq("A[? oU 'state = processing']"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model()
     self.assertEqual(solve_ctlqx(fsm, ast), fsm.reachable_states)
Example #25
0
 def test_project(self):
     ast = negation_normal_form(parse_ctlq("AG (? -> AF 'heat')"))
     self.assertTrue(check_ctlqx(ast))
     fsm = self.init_model('examples/microwave.smv')
     projection = project(fsm, solve_ctlqx(fsm, ast), ['error'])
     self.assertEqual('(error = FALSE)', projection)