def test_set_bounds(self): prop = "P<0.4 [F \"one\"]" formula = stormpy.parse_properties(prop)[0].raw_formula expression_manager = stormpy.ExpressionManager() rational = stormpy.Rational("0.2") expression = expression_manager.create_rational(rational) formula.set_bound(stormpy.logic.ComparisonType.GEQ, expression) assert formula.threshold == stormpy.Rational("0.2") assert formula.comparison_type == stormpy.logic.ComparisonType.GEQ assert str(formula) == "P>=1/5 [F \"one\"]"
def _construct_violation_property(self): vp_index = len( self.formulae) - 1 # Compute the index of the violation property # Construct new violation property with respect to the currently optimal value vp = self._optimality_setting.get_violation_property( self._optimal_value, lambda x: self.sketch.expression_manager.create_rational( stormpy.Rational(x)), ) # Update the attributes of the family according to the new optimal values # For each family we need to update theirs formulae and formulae indices to check for family in self.families + [self.family]: # Replace the last violation property by newly one family.formulae[vp_index] = vp.raw_formula # When the violation property is not checking, we have to add its index if vp_index not in family.formulae_indices: family.formulae_indices.append(vp_index) family.model_check_formula(vp_index) family.bounds[vp_index] = Family.quotient_container( ).latest_result.result # Change the value of threshold of the violation formulae within constructed quotient MDP Family.set_thresholds(Family.get_thresholds()[:-1] + [vp.raw_formula.threshold])
def test_pycarl(self): import stormpy rational = stormpy.Rational(0.25) assert str(rational) == "1/4" pol1 = stormpy.FactorizedPolynomial(32) pol2 = stormpy.FactorizedPolynomial(2) rat = stormpy.FactorizedRationalFunction(pol1, pol2) assert str(rat) == "16"
def test_rational_expression(self): manager = stormpy.ExpressionManager() expression = manager.create_rational(stormpy.Rational(0.2)) assert expression.is_literal() assert not expression.contains_variables() assert not expression.has_boolean_type() assert not expression.has_integer_type() assert expression.has_rational_type()
def test_bounds(self): prop = "P=? [F \"one\"]" formula = stormpy.parse_properties(prop)[0].raw_formula assert not formula.has_bound prop = "P<0.4 [F \"one\"]" formula = stormpy.parse_properties(prop)[0].raw_formula assert formula.has_bound assert formula.threshold == stormpy.Rational("0.4") assert formula.comparison_type == stormpy.logic.ComparisonType.LESS
def run_feasibility(self): jani_program = self.sketch total_nr_options = self.hole_options.size() if self.input_has_optimality_property(): ct = stormpy.logic.ComparisonType.GREATER if self._optimality_setting.direction == 'max' \ else stormpy.logic.ComparisonType.LESS self.mc_formulae[len(self.mc_formulae) - 1].set_bound( ct, self.sketch.expression_manager.create_rational(stormpy.Rational(self._optimal_value)) ) estimation_timer = Timer() estimation_timer.start() for constant_assignment in itertools.product(*self.hole_options.values()): self.iterations += 1 if self.iterations % 10 == 0: logger.info(f"Iteration: {self.iterations} / {total_nr_options}") constants = [jani_program.get_constant(c).expression_variable for c in self.hole_options.keys()] substitution = dict(zip(constants, constant_assignment)) instance = jani_program.define_constants(substitution) mh = ModelHandling() mh.build_model(instance, self.mc_formulae, self.mc_formulae_alt) improved = False all_sat = True for formula_index in range(len(self.mc_formulae)): mc_result = mh.mc_model(index=formula_index).result satisfied = is_satisfied(self.mc_formulae[formula_index], mc_result.at(mh.full_mdp.initial_states[0])) # logger.debug(f"1-by-1: model checking DTMC against a formula with index {formula_index}: {satisfied}") if not satisfied: all_sat = False break if self.input_has_optimality_property() and formula_index == len(self.mc_formulae) - 1 and satisfied: improved = self._check_optimal_property(mh.full_mdp) if all_sat: if not self.input_has_optimality_property(): self.satisfying_assignment = {c.name: [v] for (c, v) in substitution.items()} break elif improved: self.satisfying_assignment = {c.name: [v] for (c, v) in substitution.items()} if self.iterations % 10 == 0: percentage_rejected = safe_division(self.iterations, total_nr_options) # division by zero fix iters_estimate = self.iterations / percentage_rejected time_estimate = estimation_timer.read() / percentage_rejected logger.info( f">> Performance estimation (unfeasible): " f"{iters_estimate} iterations in {time_estimate} sec " f"(opt: {self._optimal_value})." ) return self.iterations
def initialise(self): super().initialise() # QuotientBasedFamilyChecker.initialise(self) self.formulae = [ property_obj.raw_formula for property_obj in self.properties ] if self.input_has_optimality_property(): ct = stormpy.logic.ComparisonType.GREATER if self._optimality_setting.direction == 'max' \ else stormpy.logic.ComparisonType.LESS bound = self.sketch.expression_manager.create_rational( stormpy.Rational(self._optimal_value)) opt_formula = self._optimality_setting.criterion.raw_formula.clone( ) opt_formula.set_bound(ct, bound) self.formulae.append(opt_formula)
def compute_satisfying_regions(self, threshold, regions): # Compute all regions completely satisfying the threshold sample_regions = [] logging.debug( "Compute satisfying regions for threshold {}".format(threshold)) lower_bound = None upper_bound = threshold self.no_calls += len(regions) if self.verbose: logging.debug("Regions: {}".format(", ".join( str(region) for region in regions))) for region in regions: # Check region result = pla_helper.get_bound_region(region, self.solver, self.env, self.vars, False) if self.config.exact: result = stormpy.Rational(result) else: result = float(result) logging.debug("Result for {}: {}".format(region, result)) if result > threshold: # Discard region pass else: assert result <= threshold # Keep region sample_regions.append(region) if lower_bound is None or result < lower_bound: # New lower bound lower_bound = result # Sample remaining regions to possibly obtain better upper bound best_sample = None for region in sample_regions: point = region.middle() result = self.inst_checker.check( self.env, point.carl_valuation(self.vars)).at(self.initial_state) logging.debug("Result for point {}: {}".format(point, result)) if result < upper_bound: # Sample is new upper bound upper_bound = result best_sample = point return sample_regions, best_sample, lower_bound, upper_bound
def compute_satisfying_regions(self, pool, threshold, regions): # Compute all regions completely satisfying the threshold sample_regions = [] logging.debug( "Compute satisfying regions for threshold {}".format(threshold)) lower_bound = None upper_bound = threshold self.no_calls += len(regions) if self.verbose: logging.debug("Regions: {}".format(", ".join( str(region) for region in regions))) it = pool.starmap(get_bound_region_parallel, [(region, ) for region in regions]) for result, region in it: if self.config.exact: result = stormpy.Rational(result) else: result = float(result) logging.debug("Result for {}: {}".format(region, result)) if result > threshold: # Discard region pass else: assert result <= threshold # Keep region sample_regions.append(region) if lower_bound is None or result < lower_bound: # New lower bound lower_bound = result # Sample remaining regions to possibly obtain better upper bound best_sample = None it = pool.starmap(sample_point_parallel, [(region.middle(), self.config.exact) for region in sample_regions]) for result, point in it: logging.debug("Result for point {}: {}".format(point, result)) if result < upper_bound: # Sample is new upper bound upper_bound = result best_sample = point return sample_regions, best_sample, lower_bound, upper_bound
def __init__(self, prop, sketch=None, add_prerequisites=True): self.property = prop self.prerequisite_property = None if add_prerequisites and prop.raw_formula.is_reward_operator: assert prop.raw_formula.has_bound assert sketch prereq_thresh = prop.raw_formula.threshold_expr.manager.create_rational( stormpy.Rational(1)) operator = stormpy.ProbabilityOperator( prop.raw_formula.subformula.clone()) operator.set_bound(stormpy.logic.ComparisonType.GEQ, prereq_thresh) new_prop = stormpy.parse_properties_for_jani_model( str(operator), sketch) self.prerequisite_property = stormpy.Property( prop.name + "_prereq", new_prop[0].raw_formula, comment="Prerequisite")
def test_pdtmc_exact_instantiation_checker(self): program = stormpy.parse_prism_program( get_example_path("pdtmc", "herman5.pm")) formulas = stormpy.parse_properties_for_prism_program( "R=? [F \"stable\"]", program) model = stormpy.build_parametric_model(program, formulas) parameters = model.collect_probability_parameters() inst_checker = stormpy.pars.PDtmcExactInstantiationChecker(model) inst_checker.specify_formula( stormpy.ParametricCheckTask(formulas[0].raw_formula, True)) inst_checker.set_graph_preserving(True) env = stormpy.Environment() point = {p: stormpy.RationalRF("1/2") for p in parameters} result = inst_checker.check(env, point) assert isinstance(result, stormpy.ExplicitExactQuantitativeCheckResult) res = result.at(model.initial_states[0]) assert isinstance(res, stormpy.Rational) assert res == stormpy.Rational("29/15")
def load_prism_program(model_path, property_string, constants_string): program = stormpy.parse_prism_program(model_path) expr_manager = program.expression_manager constants = dict() if constants_string == "" else { it.split("=")[0]: it.split("=")[1] for it in constants_string.split(",") } constants = { program.get_constant(c).expression_variable: (expr_manager.create_integer(int(v)) if program.get_constant(c).type.is_integer else expr_manager.create_rational(stormpy.Rational(v))) for c, v in constants.items() } program = program.define_constants(constants) program = program.substitute_formulas() program = program.substitute_constants() props = stormpy.parse_properties_for_prism_program(property_string, program) return program, props
def example_analysis_03(): path = stormpy.examples.files.prism_dtmc_die prism_program = stormpy.parse_prism_program(path) formula_str = "P=? [F s=7 & d=2]" properties = stormpy.parse_properties(formula_str, prism_program) model = stormpy.build_model(prism_program, properties) env = stormpy.Environment() env.solver_environment.set_linear_equation_solver_type( stormpy.EquationSolverType.native) env.solver_environment.native_solver_environment.method = stormpy.NativeLinearEquationSolverMethod.optimistic_value_iteration env.solver_environment.native_solver_environment.precision = stormpy.Rational( "0.9") #env.solver_environment.native_solver_environment.maximum_iterations = 2 result = stormpy.model_checking(model, properties[0], environment=env) print(result.at(model.initial_states[0])) dd_model = stormpy.build_symbolic_model(prism_program, properties) result = stormpy.model_checking(dd_model, properties[0], environment=env) filter = stormpy.create_filter_initial_states_symbolic(dd_model) result.filter(filter) assert result.min == result.max print(result.min)
def _check_optimal_property(self, dtmc): # Model checking of the optimality property result = stormpy.model_checking(dtmc, self._optimality_setting.criterion) optimal_value = result.at(dtmc.initial_states[0]) # Check whether the improvement was achieved if self._optimality_setting.is_improvement(optimal_value, self._optimal_value): # Set the new values of the optimal attributes self._optimal_value = optimal_value # Construct new violation property with respect to the currently optimal value vp = self._optimality_setting.get_violation_property( self._optimal_value, lambda x: self.sketch.expression_manager.create_rational(stormpy.Rational(x)), ) # Replace the last violation property by newly one self.mc_formulae[len(self.mc_formulae) - 1] = vp.raw_formula logger.debug(f"Optimal value improved to: {self._optimal_value}") return True return False
def find_optimum(self, model_file, verbose=False): logging.info("Running PLA on single process") self.verbose = verbose result = Result(model_file, self.config) # Get initial regions by computing the roots time_roots_start = time.time() roots = analyse.gather_roots(self.model, self.vars) result.time_roots = time.time() - time_roots_start logging.info("Computing roots took {}s".format(result.time_roots)) # Create initial intervals per parameter by splitting at roots initial_intervals = dict() for p in self.vars: initial_interval = [] current = 0 + self.config.eps # 0 and 1 change graph structure for root in roots[p]: initial_interval.append(Interval(current, root)) current = root initial_interval.append(Interval(current, 1 - self.config.eps)) initial_intervals[p] = initial_interval # Create initial regions initial_regions = [] for product in itertools.product(*initial_intervals.values()): region = { p.name: interval for p, interval in zip(self.vars, product) } initial_regions.append(Region(region)) if verbose: logging.debug("------------") for region in initial_regions: logging.debug("Initial region {}".format(region)) logging.debug("------------") properties = stormpy.parse_properties("R=? [F \"stable\"]") assert len(properties) == 1 property = properties[0] self.inst_checker = pla_helper.init_instantiation_checker( self.model, property, self.config.exact) # Find upper bound start_pla = time.time() logging.info("No. initial regions: {}".format(len(initial_regions))) upper_bound, best_sample = self.sample_points(self.vars, self.config.no_samples) logging.info("Found upper bound {} for sample {}".format( upper_bound, best_sample)) logging.debug("Time: {:.3f}s".format(time.time() - start_pla)) if not self.config.exact: # Slightly increase upper bound to avoid precision issues upper_bound += 1e-4 lower_bound = 0 self.solver = pla_helper.init_solver(None, self.model, self.env) # Find optimum by iterating the following: # - use PLA (minimize) to obtain lower bounds # - discard all regions whose minimal result is greater than the current upper bound # - sample remaining regions to improve upper bound # - split remaining regions in half start_time_pla = time.time() regions = initial_regions iteration = 0 if self.config.exact: precision = stormpy.Rational(self.config.precision) else: precision = self.config.precision while upper_bound - lower_bound > precision: iteration += 1 if iteration == 1: # Use initial regions new_regions = regions else: # Split regions new_regions = [] for region in regions: # Split region into two self.no_splits += 1 new_regions.extend(region.split(self.vars)) regions, sample, lower_bound, upper_bound = self.compute_satisfying_regions( upper_bound, new_regions) iteration_time = time.time() - start_time_pla start_time_pla = time.time() logging.info( "Iteration {}: bounds: [{}, {}], best sample: {}, {} regions remaining, {} calls, {} splits, time: {:.3f}s" .format(iteration, lower_bound, upper_bound, best_sample, len(regions), self.no_calls, self.no_splits, iteration_time)) if sample is not None: best_sample = sample if verbose: logging.debug("------------") if self.config.exact: logging.debug( "Current bounds: [{}, {}], precision: {}".format( lower_bound, upper_bound, upper_bound - lower_bound)) else: logging.debug( "Current bounds: [{}, {}], precision: {:.1e}".format( lower_bound, upper_bound, upper_bound - lower_bound)) logging.debug("Best sample: {}".format(best_sample)) tmp = sort_regions(list(regions), self.vars) for region in tmp: logging.debug("Region {}".format(region)) logging.debug("Time: {:.3f}s".format(time.time() - start_time_pla)) logging.debug("------------") logging.info( "Remaining regions: {}, best sample: {}, {} calls, {} splits". format(len(regions), best_sample, self.no_calls, self.no_splits)) end_pla = time.time() result.time_analysis = end_pla - start_pla result.result_ert = Interval(lower_bound, upper_bound) result.best_sample = best_sample result.result_region = sort_regions(regions, self.vars) return result
def test_exact_matrix_builder(self): builder = stormpy.ExactSparseMatrixBuilder(force_dimensions=True) matrix = builder.build() assert matrix.nr_columns == 0 assert matrix.nr_rows == 0 assert matrix.nr_entries == 0 builder_5x5 = stormpy.ExactSparseMatrixBuilder(5, 5, force_dimensions=False) builder_5x5.add_next_value(0, 0, stormpy.Rational(1)) builder_5x5.add_next_value(0, 1, stormpy.Rational(1)) builder_5x5.add_next_value(2, 1, stormpy.Rational(1)) builder_5x5.add_next_value(2, 2, stormpy.Rational(2)) assert builder_5x5.get_last_column() == 2 assert builder_5x5.get_last_row() == 2 builder_5x5.add_next_value(3, 3, stormpy.Rational(1) / stormpy.Rational(6)) builder_5x5.add_next_value(3, 4, stormpy.Rational(1) / stormpy.Rational(6)) builder_5x5.add_next_value(4, 3, stormpy.Rational("1/6")) matrix_5x5 = builder_5x5.build() print(matrix_5x5) assert matrix_5x5.nr_columns == 5 assert matrix_5x5.nr_rows == 5 assert matrix_5x5.nr_entries == 7 for e in matrix_5x5: assert (e.value() == stormpy.Rational(1) and e.column < 2) or ( e.value() == stormpy.Rational(2) and e.column == 2) or ( e.column > 2 and e.value() == stormpy.Rational("1/6"))
def find_optimum(self, model_file, verbose=False): logging.info("Running PLA in parallel with {} processes".format( self.config.processes)) self.verbose = verbose result = Result(model_file, self.config) start_time = time.time() # Build model in single process model, _, _, time_build, time_bisim = build.build_model( model_file, self.config.hybrid, sylvan_threads=self.config.processes, sylvan_memory=self.config.memory_limit) result.time_build = time_build result.time_bisimulation = time_bisim # Create temporary file for DRN export start_export = time.time() _, drn_file = tempfile.mkstemp(suffix=".drn") # Export model to DRN format. Each process can then load the simplified model from the file. stormpy.export_parametric_to_drn(model, drn_file) end_export = time.time() result.time_export = end_export - start_export logging.info("Exporting model took {}s".format(result.time_export)) # Start parallelization with multiprocessing.Pool( self.config.processes, initializer=get_model, initargs=(drn_file, self.config.linear_equation_solver)) as pool: # Get loading times by trying to query all processes # As we cannot query each process directly, we start a number of tasks and hope that each process gets a task pids = set() max_time_load = 0 no_tasks_time = 1 while len(pids) < self.config.processes: logging.debug("Get loading times") it = pool.starmap( get_load_time, [(i, ) for i in range(self.config.processes * no_tasks_time)]) for time_load, pid in it: if pid not in pids: pids.add(pid) if time_load > max_time_load: max_time_load = time_load no_tasks_time += 1 result.time_load = max_time_load logging.info("Loading model took {}s".format(result.time_load)) # Get initial regions by computing the roots results = pool.apply_async(gather_roots_parallel, ) roots, parameters, time_roots = results.get() result.time_roots = time_roots logging.info("Computing roots took {}s".format(result.time_roots)) # Create initial intervals per parameter by splitting at roots initial_intervals = dict() for p in parameters: initial_interval = [] current = 0 + self.config.eps # 0 and 1 change graph structure for root in roots[p]: initial_interval.append(Interval(current, root)) current = root initial_interval.append(Interval(current, 1 - self.config.eps)) initial_intervals[p] = initial_interval # Create initial regions initial_regions = [] for product in itertools.product(*initial_intervals.values()): region = { p.name: interval for p, interval in zip(parameters, product) } initial_regions.append(Region(region)) if verbose: logging.debug("------------") for region in initial_regions: logging.debug("Initial region {}".format(region)) logging.debug("------------") # Find upper bound start_pla = time.time() logging.info("No. initial regions: {}".format( len(initial_regions))) upper_bound, best_sample = self.sample_points( pool, parameters, self.config.no_samples) logging.info("Found upper bound {} for sample {}".format( upper_bound, best_sample)) logging.debug("Time: {:.3f}s".format(time.time() - start_time)) if not self.config.exact: # Slightly increase upper bound to avoid precision issues upper_bound += 1e-4 lower_bound = 0 # Find optimum by iterating the following: # - use PLA (minimize) to obtain lower bounds # - discard all regions whose minimal result is greater than the current upper bound # - sample remaining regions to improve upper bound # - split remaining regions in half start_time_pla = time.time() start_last_iteration = start_time_pla iteration = 0 if self.config.exact: precision = stormpy.Rational(self.config.precision) else: precision = self.config.precision while upper_bound - lower_bound > precision: iteration += 1 if iteration == 1: # Use initial regions new_regions = initial_regions else: # Split regions new_regions = [] for region in regions: # Split region into two self.no_splits += 1 new_regions.extend(region.split(parameters)) regions, sample, lower_bound, upper_bound = self.compute_satisfying_regions( pool, upper_bound, new_regions) iteration_time = time.time() - start_time_pla start_time_pla = time.time() logging.info( "Iteration {}: bounds: [{}, {}], best sample: {}, {} regions remaining, {} calls, {} splits, time: {:.3f}s" .format(iteration, lower_bound, upper_bound, best_sample, len(regions), self.no_calls, self.no_splits, iteration_time)) if sample is not None: best_sample = sample if verbose: logging.debug("------------") if self.config.exact: logging.debug( "Current bounds: [{}, {}], precision: {}".format( lower_bound, upper_bound, upper_bound - lower_bound)) else: logging.debug( "Current bounds: [{}, {}], precision: {:.1e}". format(lower_bound, upper_bound, upper_bound - lower_bound)) logging.debug("Best sample: {}".format(best_sample)) tmp = sort_regions(list(regions), parameters) for region in tmp: logging.debug("Region {}".format(region)) logging.debug("Time: {:.3f}s".format(time.time() - start_time_pla)) logging.debug("------------") logging.info( "Remaining regions: {}, best sample: {}, {} calls, {} splits". format(len(regions), best_sample, self.no_calls, self.no_splits)) end_pla = time.time() result.time_analysis = end_pla - start_pla result.time_total = end_pla - start_time result.result_ert = Interval(lower_bound, upper_bound) result.best_sample = best_sample result.result_region = sort_regions(regions, parameters) return result
def test2(): t0 = time.time() #path = "collision_partial_obs_2d_upd_hobs_20_small.prism" path, interval_path, formula_str, threshold = input_files() prism_program = stormpy.parse_prism_program(path) #formula_str = "P=? [!\"bad\" U \"goal\"]" #formula_str = "P=? [F \"goal\"]" #interval_path="collision_partial_obs_2d_upd_hobs_20_small.intervals" opts = stormpy.DirectEncodingParserOptions() opts.build_choice_labels = True properties = stormpy.parse_properties_for_prism_program(formula_str, prism_program) # construct the pPOMDP import inspect print(inspect.getfullargspec(stormpy.build_parametric_model)) pomdp = stormpy.build_parametric_model(prism_program, properties) pomdp_parameters = pomdp.collect_probability_parameters() stormpy.export_parametric_to_drn(pomdp, "pomdp_ex") # make its representation canonic. pomdp = stormpy.pomdp.make_canonic(pomdp) #stormpy.export_parametric_to_drn(pomdp, "export_pomdp.drn") # construct the memory for the FSC # in this case, a selective counter with two states memory_builder = stormpy.pomdp.PomdpMemoryBuilder() memval=1 memory = memory_builder.build(stormpy.pomdp.PomdpMemoryPattern.selective_counter, memval) # apply the memory onto the POMDP to get the cartesian product pomdp = stormpy.pomdp.unfold_memory(pomdp, memory) print("Number of pomdp states before simple:",pomdp.nr_states) print("Number of transitions: {}".format(pomdp.nr_transitions)) # make the POMDP simple. This step is optional but often beneficial pomdp = stormpy.pomdp.make_simple(pomdp) print("Number of pomdp states after simple:",pomdp.nr_states) print("Number of transitions: {}".format(pomdp.nr_transitions)) # apply the unknown FSC to obtain a pmc from the POMDP pmc = stormpy.pomdp.apply_unknown_fsc(pomdp, stormpy.pomdp.PomdpFscApplicationMode.simple_linear) print("Number of pomdp states after simple",pmc.nr_states) print("Number of transitions: {}".format(pmc.nr_transitions)) print(pmc) print("applied pmc") path_pmc = "export_" + str(memval) + "_mem_" + path print(path_pmc) stormpy.export_parametric_to_drn(pmc, path_pmc) print("built model") #print(model.initial_states) fsc_parameters = pmc.collect_probability_parameters() - pomdp.collect_probability_parameters() print("number of pomdp parameters:",len(fsc_parameters)) #print(fsc_parameters) #print(pomdp_parameters) #intervals2, polyhedrons = interval_parser.parse_input(interval_path) intervals, polyhedrons,items = interval_parser.parse_model_interval(pmc,pomdp_parameters,interval_path) #for item in intervals: #print(item,"printing in the main") #for item in items: # print(item,"printing in the main") for p in polyhedrons: #print(p) p.compute_vertices() properties = stormpy.parse_properties(formula_str) print("Building model from {}".format(path)) #parameters = model.collect_probability_parameters() print(pmc.nr_states) prob0E, prob1A = stormpy.prob01max_states(pmc, properties[0].raw_formula.subformula) #print(prob0E) #threshold = 0.90 direction = "below" # can be "below" or "above" options = QcqpOptions(mu=1e4, maxiter=10000, graph_epsilon=1e-2, silent=False) # result = solver.run(reward_model_name ,model_rew, parameters_rew, rew0, rew_threshold, direction, options) solver = QcqpSolver_affine_simple_fun() result = solver.run(pmc, fsc_parameters, pomdp_parameters,properties, prob0E, prob1A, threshold, direction, options,intervals,items,True) print("number of iterations={}".format(solver.iterations)) print("solver time={}".format(solver.solver_timer)) #compute the policy against the robust interval #interval_path="collision_partial_obs_2d_upd_hobs_20_small.intervals" intervals, polyhedrons,items = interval_parser.parse_model_interval(pmc,pomdp_parameters,interval_path) regiondict = dict() for x in pomdp_parameters: for item in items: if item.name == x.name: regiondict[x] = (stormpy.RationalRF(item.lowerbound), stormpy.RationalRF(item.upperbound)) region = stormpy.pars.ParameterRegion(regiondict) instantiator = stormpy.pars.PartialPDtmcInstantiator(pmc) instantiated_model = instantiator.instantiate(solver.solver_params) env = stormpy.Environment() env.solver_environment.set_linear_equation_solver_type(stormpy.EquationSolverType.eigen) env.solver_environment.native_solver_environment.method = stormpy.NativeLinearEquationSolverMethod.optimistic_value_iteration env.solver_environment.native_solver_environment.precision = stormpy.Rational('0.01') start_check = time.time() region_checker = stormpy.pars.create_region_checker(env, instantiated_model, properties[0].raw_formula, allow_model_simplification=False) print("region check") result = region_checker.get_bound_all_states(env, region, maximise=False) end_check = time.time() print("model checking ans:") ansval=result.at(pmc.initial_states[0]) print(ansval) tend = time.time() print("Total time: ", str(tend - t0))
def create_symbolic_transitions(): prob_parameters = dict() for c in flat_program.constants: if c.defined: continue if not c.type.is_rational: continue prob_parameters[c.name] = c.expression_variable prob_parameters_set = set(prob_parameters.values()) symbolic_probabilities = {} for m in flat_program.modules: for cmd in m.commands: has_symbolic_transition = False for update in cmd.updates: probvariables = update.probability_expression.get_variables( ) if len(probvariables) == 0: continue if len(probvariables.intersection( prob_parameters_set)) == 0: continue if len(probvariables.difference(prob_parameters_set)) > 0: raise NotImplementedError( "We do not support probabilities that combine state variables and probability parameters" ) has_symbolic_transition = True if has_symbolic_transition: transitions = SymbDistribution([ update.probability_expression for update in cmd.updates ]) if transitions in symbolic_probabilities: symbolic_probabilities[transitions].append( cmd.global_index) else: symbolic_probabilities[transitions] = [ cmd.global_index ] dice_declarations = [] cmd_to_pardist = dict() cardinality = dict() for id, entry in enumerate(symbolic_probabilities.items()): probs, cmds = entry dice_declarations.append( f"//contains: discrete_sym(pardist{id}, {math.ceil(math.log2(len(probs)))}))" ) for cmd in cmds: cmd_to_pardist[cmd] = f"pardist{id}" cardinality[f"pardist{id}"] = math.ceil(math.log2(len(probs))) if parameter_instantiations is None or len( parameter_instantiations) == 0: pass elif isinstance(parameter_instantiations, dict): for assignment in itertools.product( *parameter_instantiations.values()): with open( output_path + "." + "-".join([ f"{p}-{v:.3f}" for p, v in zip( parameter_instantiations.keys(), assignment) ]) + ".eval", 'w') as file: #print(assignment) evaluation_dict = { prob_parameters[p]: expr_manager.create_rational(stormpy.Rational(v)) for p, v in zip(parameter_instantiations.keys(), assignment) } comments = False if comments: file.write("\n".join([ f"//{p}={v}" for p, v in zip( parameter_instantiations.keys(), assignment) ])) file.write("\n") for id, probs in enumerate( symbolic_probabilities.keys()): if len(probs) == 2: file.write(f"pardist{id}\t" + str( float(probs[0].substitute(evaluation_dict). evaluate_as_rational())) + "\n") else: file.write(f"pardist{id}\t" + "\t".join([ str( float( prob.substitute(evaluation_dict). evaluate_as_rational())) for prob in probs ]) + "\n") elif isinstance(parameter_instantiations, list): for id, assignment in enumerate(parameter_instantiations): indexname = "-".join( [f"{p}-{v:.3f}" for p, v in assignment.items()]) if len(indexname) > 20: indexname = str(id) with open(output_path + "." + indexname + ".eval", 'w') as file: print(assignment) evaluation_dict = { prob_parameters[p]: expr_manager.create_rational(stormpy.Rational(v)) for p, v in assignment.items() } comments = False if comments: file.write("\n".join( [f"//{p}={v}" for p, v in assignment.items()])) file.write("\n") for id, probs in enumerate( symbolic_probabilities.keys()): if len(probs) == 2: file.write(f"pardist{id}\t" + str( float(probs[0].substitute(evaluation_dict). evaluate_as_rational())) + "\n") else: file.write(f"pardist{id}\t" + "\t".join([ str( float( prob.substitute(evaluation_dict). evaluate_as_rational())) for prob in probs ]) + "\n") return dice_declarations, cardinality, cmd_to_pardist
def _naive_check_model(self, model, check_all, terminate_after_qualitative_violation=True): """ Do the model checking of the properties :param model: the Markov chain :param check_all: Should we abort as soon as we have found a conflicting property? :param terminate_after_qualitative_violation: Should we abort after a qualitative conflict? :return: The set of qualitative conflict properties and the set of quantiative conflict properties """ logger.info("Start Model Checking....") start_mc = time.time() violated = [] qualitative_violation = False # for p in self.qualitative_properties: # self.stats.qualitative_model_checking_calls += 1 # if not stormpy.model_checking(model, p).at(model.initial_states[0]): # violated.append(p) # qualitative_violation = True # if not check_all or terminate_after_qualitative_violation: # break logger.debug("Qualitative violations: {}".format(";".join( [str(p.raw_formula) for p in violated]))) self.stats.qualitative_model_checking_time += time.time() - start_mc if terminate_after_qualitative_violation and len(violated) > 0: return qualitative_violation, violated for p in self.properties: logger.debug("Consider..: {}".format(p.property)) # First, we check some prerequisite properties, in case they exist. if p.prerequisite_property: logger.debug("Prerequisite checking..: {}".format( p.prerequisite_property)) start_mc = time.time() #print(stormpy.model_checking(model, p.prerequisite_property)) mc_result = stormpy.model_checking( model, p.prerequisite_property).at(model.initial_states[0]) logger.debug( "MC result for prerequisite: {}".format(mc_result)) logger.debug("model states: {}, transitions: {}".format( model.nr_states, model.nr_transitions)) self.stats.report_model_checking(p.prerequisite_property, time.time() - start_mc, not mc_result) if not mc_result: violated.append(p.prerequisite_property) if not check_all: break else: continue else: logger.debug("No prerequisite found!") start_mc = time.time() mc_result = stormpy.model_checking(model, p.property).at( model.initial_states[0]) logger.debug("MC Result: {}".format(mc_result)) logger.debug("model states: {}, transitions: {}".format( model.nr_states, model.nr_transitions)) self.stats.report_model_checking(p.property, time.time() - start_mc, not mc_result) if not mc_result: violated.append(p.property) if not check_all: break if self._optimality and len(violated) == 0: mc_result = stormpy.model_checking( model, self._optimality.criterion).at(model.initial_states[0]) if self._optimality.is_improvement(mc_result, self._opt_value): logger.debug("Optimal value improved to {}.".format(mc_result)) self._opt_value = mc_result else: logger.debug( "Optimal value ({}) not improved, conflict analysis!". format(self._opt_value)) violated.append( self._optimality.get_violation_property( self._opt_value, lambda x: self.sketch.expression_manager. create_rational(stormpy.Rational(x)))) logger.info("Stop Model Checking") logger.debug(violated) return qualitative_violation, violated
def mc_model(self, index=0, compute_action_values=False, check_dir_2=always_true): """ :param index: :param compute_action_values: :param check_dir_2: :return: """ assert len(self._formulae) > index assert not compute_action_values is_dtmc = False extract_scheduler = True if self._submodel.nr_choices == self._submodel.nr_states: is_dtmc = True self._mc_dtmc_calls += 1 extract_scheduler = False else: self._mc_mdp_calls += 1 self._mc_mdp_executions += 1 # TODO set from the outside. env = stormpy.Environment() env.solver_environment.minmax_solver_environment.precision = stormpy.Rational( 0.0000000001) # + if is_dtmc: env.solver_environment.minmax_solver_environment.method = stormpy.MinMaxMethod.policy_iteration else: env.solver_environment.minmax_solver_environment.method = stormpy.MinMaxMethod.value_iteration # assert not self._formulae[index].has_bound logger.info(f"Start checking direction 1: {self._formulae[index]}") # TODO allow qualitative model checking with scheduler extraction. prime_result = stormpy.model_checking( self._submodel, self._formulae[index], only_initial_states=False, extract_scheduler=extract_scheduler, environment=env) if is_dtmc: maximise = True absolute_min = min( [prime_result.at(x) for x in self._submodel.initial_states]) absolute_max = max( [prime_result.at(x) for x in self._submodel.initial_states]) logger.info( f"Done DTMC Checking. Result for initial state is: {absolute_min} -- {absolute_max}" ) return ExplicitMCResult(prime_result, prime_result, maximise, absolute_min=absolute_min, absolute_max=absolute_max) absolute_min = -math.inf absolute_max = math.inf second_result = None if self._formulae[ index].optimality_type == stormpy.OptimizationDirection.Maximize: maximise = True upper_result = prime_result absolute_max = max( [upper_result.at(x) for x in self._submodel.initial_states]) else: assert (self._formulae[index].optimality_type == stormpy.OptimizationDirection.Minimize) maximise = False lower_result = prime_result absolute_min = min( [lower_result.at(x) for x in self._submodel.initial_states]) if check_dir_2(absolute_min, absolute_max): self._mc_mdp_executions += 1 logger.info( f"Start checking direction 2: {self._alt_formulae[index]}") second_result = stormpy.model_checking( self._submodel, self._alt_formulae[index], only_initial_states=False, extract_scheduler=extract_scheduler, environment=env) if maximise: lower_result = second_result absolute_min = min([ lower_result.at(x) for x in self._submodel.initial_states ]) else: assert not maximise upper_result = second_result absolute_max = max([ upper_result.at(x) for x in self._submodel.initial_states ]) logger.info( f"Done Checking. Result for initial state is: {absolute_min} -- {absolute_max}" ) return ExplicitMCResult(prime_result, second_result, maximise, absolute_min=absolute_min, absolute_max=absolute_max)