You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							145 lines
						
					
					
						
							4.4 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							145 lines
						
					
					
						
							4.4 KiB
						
					
					
				| import stormpy | |
| import stormpy.logic | |
| from stormpy.storage import BitVector | |
| from stormpy.utility import ShortestPathsGenerator | |
| from stormpy.utility import MatrixFormat | |
| from helpers.helper import get_example_path | |
| 
 | |
| import pytest | |
| import math | |
| 
 | |
| 
 | |
| # this is admittedly slightly overengineered | |
| 
 | |
| class ModelWithKnownShortestPaths: | |
|     """Knuth's die model with reference kSP methods""" | |
|     def __init__(self): | |
|         self.target_label = "one" | |
| 
 | |
|         program_path = get_example_path("dtmc", "die.pm") | |
|         raw_formula = "P=? [ F \"" + self.target_label + "\" ]" | |
|         program = stormpy.parse_prism_program(program_path) | |
|         formulas = stormpy.parse_formulas_for_prism_program(raw_formula, program) | |
| 
 | |
|         self.model = stormpy.build_model(program, formulas[0]) | |
| 
 | |
|     def probability(self, k): | |
|         return (1/2)**((2 * k) + 1) | |
| 
 | |
|     def state_set(self, k): | |
|         return BitVector(self.model.nr_states, [0, 1, 3, 7]) | |
| 
 | |
|     def path(self, k): | |
|         path = [0] + k * [1, 3] + [7] | |
|         return list(reversed(path))  # SPG returns traversal from back | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module", params=[1, 2, 3, 3000, 42]) | |
| def index(request): | |
|     return request.param | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module") | |
| def model_with_known_shortest_paths(): | |
|     return ModelWithKnownShortestPaths() | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module") | |
| def model(model_with_known_shortest_paths): | |
|     return model_with_known_shortest_paths.model | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module") | |
| def expected_distance(model_with_known_shortest_paths): | |
|     return model_with_known_shortest_paths.probability | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module") | |
| def expected_state_set(model_with_known_shortest_paths): | |
|     return model_with_known_shortest_paths.state_set | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module") | |
| def expected_path(model_with_known_shortest_paths): | |
|     return model_with_known_shortest_paths.path | |
| 
 | |
| 
 | |
| @pytest.fixture(scope="module") | |
| def target_label(model_with_known_shortest_paths): | |
|     return model_with_known_shortest_paths.target_label | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def state(model): | |
|     some_state = 7 | |
|     assert model.nr_states > some_state, "test model too small" | |
|     return some_state | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def state_list(model): | |
|     some_state_list = [4, 5, 7] | |
|     assert model.nr_states > max(some_state_list), "test model too small" | |
|     return some_state_list | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def state_bitvector(model, state_list): | |
|     return BitVector(length=model.nr_states, set_entries=state_list) | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def transition_matrix(model): | |
|     return model.transition_matrix | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def target_prob_map(model, state_list): | |
|     return {i: (1.0 if i in state_list else 0.0) for i in range(model.nr_states)} | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def target_prob_list(target_prob_map): | |
|     return [target_prob_map[i] for i in range(max(target_prob_map.keys()))] | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def initial_states(model): | |
|     return BitVector(model.nr_states, model.initial_states) | |
| 
 | |
| 
 | |
| @pytest.fixture | |
| def matrix_format(): | |
|     return MatrixFormat.Straight | |
| 
 | |
| 
 | |
| class TestShortestPaths: | |
|     def test_spg_ctor_bitvector_target(self, model, state_bitvector): | |
|         _ = ShortestPathsGenerator(model, state_bitvector) | |
| 
 | |
|     def test_spg_ctor_single_state_target(self, model, state): | |
|         _ = ShortestPathsGenerator(model, state) | |
| 
 | |
|     def test_spg_ctor_state_list_target(self, model, state_list): | |
|         _ = ShortestPathsGenerator(model, state_list) | |
| 
 | |
|     def test_spg_ctor_label_target(self, model, target_label): | |
|         _ = ShortestPathsGenerator(model, target_label) | |
| 
 | |
|     def test_spg_ctor_matrix_vector(self, transition_matrix, target_prob_list, initial_states, matrix_format): | |
|         _ = ShortestPathsGenerator(transition_matrix, target_prob_list, initial_states, matrix_format) | |
| 
 | |
|     def test_spg_ctor_matrix_map(self, transition_matrix, target_prob_map, initial_states, matrix_format): | |
|         _ = ShortestPathsGenerator(transition_matrix, target_prob_map, initial_states, matrix_format) | |
| 
 | |
|     def test_spg_distance(self, model, target_label, index, expected_distance): | |
|         spg = ShortestPathsGenerator(model, target_label) | |
|         assert math.isclose(spg.get_distance(index), expected_distance(index)) | |
| 
 | |
|     def test_spg_state_set(self, model, target_label, index, expected_state_set): | |
|         spg = ShortestPathsGenerator(model, target_label) | |
|         assert spg.get_states(index) == expected_state_set(index) | |
| 
 | |
|     def test_spg_state_list(self, model, target_label, index, expected_path): | |
|         spg = ShortestPathsGenerator(model, target_label) | |
|         assert spg.get_path_as_list(index) == expected_path(index)
 |