Exemple #1
0
 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\"]"
Exemple #2
0
    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])
Exemple #3
0
 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"
Exemple #4
0
 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()
Exemple #5
0
 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
Exemple #6
0
    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
Exemple #7
0
 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
Exemple #9
0
    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")
Exemple #12
0
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
Exemple #13
0
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)
Exemple #14
0
    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
Exemple #16
0
    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"))
Exemple #17
0
    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
Exemple #18
0
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))
Exemple #19
0
    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
Exemple #20
0
    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
Exemple #21
0
    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)