Esempio n. 1
0
 def collect_conflicts(self):
     conflicts = []
     inequalities = list(
         BoundsWalker(True).walk_smt(self.support)
         | BoundsWalker(True).walk_smt(self.weight))
     for i in range(len(inequalities) - 1):
         for j in range(i + 1, len(inequalities)):
             if (inequalities[i].get_free_variables() ==
                     inequalities[j].get_free_variables()):
                 if implies(inequalities[i], inequalities[j]):
                     conflicts.append(
                         smt.Implies(inequalities[i], inequalities[j]))
                     logger.debug("%s => %s", inequalities[i],
                                  inequalities[j])
                 if implies(~inequalities[i], inequalities[j]):
                     conflicts.append(
                         smt.Implies(~inequalities[i], inequalities[j]))
                     logger.debug("%s => %s", ~inequalities[i],
                                  inequalities[j])
                 if implies(inequalities[j], inequalities[i]):
                     conflicts.append(
                         smt.Implies(inequalities[j], inequalities[i]))
                     logger.debug("%s => %s", inequalities[j],
                                  inequalities[i])
                 if implies(~inequalities[j], inequalities[i]):
                     conflicts.append(
                         smt.Implies(~inequalities[j], inequalities[i]))
                     logger.debug("%s => %s", ~inequalities[j],
                                  inequalities[i])
     return conflicts
 def walk_smt(self, formula):
     """
     Walks the given SMT formula (recursively visits the elements in the SMT formula-DAG)
     :type formula: pysmt.fnode.FNode
     """
     if formula.is_and():
         return self.walk_and(formula.args())
     if formula.is_or():
         return self.walk_or(formula.args())
     if formula.node_type() == IMPLIES:
         return self.walk_implies(formula.arg(0), formula.arg(1))
     if formula.is_not():
         return self.walk_not(formula.arg(0))
     if formula.is_times():
         return self.walk_times(formula.args())
     if formula.is_plus():
         return self.walk_plus(formula.args())
     if formula.is_minus():
         return self.walk_minus(formula.arg(0), formula.arg(1))
     if formula.is_ite():
         return self.walk_ite(formula.arg(0), formula.arg(1),
                              formula.arg(2))
     if formula.node_type() == POW:
         return self.walk_pow(formula.arg(0), formula.arg(1))
     if formula.is_le():
         return self.walk_lte(formula.arg(0), formula.arg(1))
     if formula.is_lt():
         return self.walk_lt(formula.arg(0), formula.arg(1))
     if formula.is_equals():
         return self.walk_equals(formula.arg(0), formula.arg(1))
     if formula.is_symbol():
         return self.walk_symbol(formula.symbol_name(),
                                 formula.symbol_type())
     if formula.is_constant():
         return self.walk_constant(formula.constant_value(),
                                   formula.constant_type())
     if formula.is_iff():
         return self.walk_and([
             smt.Implies(formula.arg(0), formula.arg(1)),
             smt.Implies(formula.arg(1), formula.arg(0)),
         ])
     raise RuntimeError("Cannot walk {} (of type {})".format(
         formula, formula.node_type()))
Esempio n. 3
0
 def order_geq_lex(c1: int, c2: int):
     pairs_c1, pairs_c2 = pairs(c1), pairs(c2)
     assert len(pairs_c1) == len(pairs_c2)
     constraints = smt.TRUE()
     for j in range(len(pairs_c1)):
         condition = smt.TRUE()
         for i in range(j):
             condition &= order_equal(pairs_c1[i], pairs_c2[i])
         constraints &= smt.Implies(condition,
                                    order_geq(pairs_c1[j], pairs_c2[j]))
     return constraints
Esempio n. 4
0
def smt_to_nested(expression):
    # type: (FNode) -> str
    """
    Converts an smt expression to a nested formula
    :param expression: An SMT expression (FNode)
    :return: A string representation (lisp-style)
        Functional operators can be: &, |, *, +, <=, <, ^
        Variables are represented as (var type name)
        Constants are represented as (const type name)
        Types can be: real, int, bool
    """
    def convert_children(op):
        return "({} {})".format(
            op, " ".join(smt_to_nested(arg) for arg in expression.args()))

    def format_type(smt_type):
        if smt_type == smt.REAL:
            return "real"
        if smt_type == smt.INT:
            return "int"
        if smt_type == smt.BOOL:
            return "bool"
        raise RuntimeError("No type corresponding to {}".format(smt_type))

    if expression.is_and():
        return convert_children("&")
    if expression.is_or():
        return convert_children("|")
    if expression.node_type() == IMPLIES:
        return smt_to_nested(
            smt.Or(smt.Not(expression.args()[0]),
                   expression.args()[1]))
    if expression.is_iff():
        return smt_to_nested(
            smt.And(smt.Implies(expression.args()[0],
                                expression.args()[1]),
                    smt.Implies(expression.args()[1],
                                expression.args()[0])))
    if expression.is_not():
        return convert_children("~")
    if expression.is_times():
        return convert_children("*")
    if expression.is_plus():
        return convert_children("+")
    if expression.is_minus():
        return convert_children("-")
    if expression.is_ite():
        return convert_children("ite")
    if expression.node_type() == POW:
        exponent = expression.args()[1]
        if exponent.is_constant() and exponent.constant_value() == 1:
            return smt_to_nested(expression.args()[0])
        else:
            return convert_children("^")
    if expression.is_le():
        return convert_children("<=")
    if expression.is_lt():
        return convert_children("<")
    if expression.is_equals():
        return convert_children("=")
    if expression.is_symbol():
        return "(var {} {})".format(format_type(expression.symbol_type()),
                                    expression.symbol_name())
    if expression.is_constant():
        value = expression.constant_value()
        if isinstance(value, fractions.Fraction):
            value = float(value)
        return "(const {} {})".format(format_type(expression.constant_type()),
                                      value)

    raise RuntimeError("Cannot convert {} (of type {})".format(
        expression, expression.node_type()))
Esempio n. 5
0
 def to_smt(self):
     return sc.Implies(self._folA.to_smt(), self._folB.to_smt())
Esempio n. 6
0
    def initialize(self, mdp, colors, hole_options, reward_name, okay_states,
                   target_states, threshold, relation):
        logger.warning("This approach has been tested sparsely.")
        prob0E, prob1A = stormpy.compute_prob01min_states(
            mdp, okay_states, target_states)
        sink_states = ~okay_states

        assert len(mdp.initial_states) == 1
        self.state_vars = [
            smt.Symbol("p_{}".format(i), smt.REAL)
            for i in range(mdp.nr_states)
        ]
        self.state_prob1_vars = [
            smt.Symbol("asure_{}".format(i)) for i in range(mdp.nr_states)
        ]
        self.state_probpos_vars = [
            smt.Symbol("x_{}".format(i)) for i in range(mdp.nr_states)
        ]
        self.state_order_vars = [
            smt.Symbol("r_{}".format(i), smt.REAL)
            for i in range(mdp.nr_states)
        ]
        self.option_vars = dict()
        for h, opts in hole_options.items():
            self.option_vars[h] = {
                index: smt.Symbol("h_{}_{}".format(h, opt))
                for index, opt in enumerate(opts)
            }
        self.transition_system = []
        logger.debug("Obtain rewards if necessary")

        rewards = mdp.reward_models[reward_name] if reward_name else None
        if rewards:
            assert not rewards.has_transition_rewards
            state_rewards = rewards.has_state_rewards
            action_rewards = rewards.has_state_action_rewards
            logger.debug(
                "Model has state rewards: {}, has state/action rewards {}".
                format(state_rewards, action_rewards))

            self.transition_system.append(
                self.state_prob1_vars[mdp.initial_states[0]])

        threshold_inequality, action_constraint_inequality = self._to_smt_relation(
            relation)  # TODO or GE
        self.transition_system.append(
            threshold_inequality(self.state_vars[mdp.initial_states[0]],
                                 smt.Real(float(threshold))))

        state_order_domain_constraint = smt.And([
            smt.And(smt.GE(var, smt.Real(0)), smt.LE(var, smt.Real(1)))
            for var in self.state_order_vars
        ])
        self.transition_system.append(state_order_domain_constraint)
        #TODO how to ensure that prob is zero if there is no path.

        select_parameter_value_constraints = []
        for h, opts in self.option_vars.items():
            select_parameter_value_constraints.append(
                smt.Or(ov for ov in opts.values()))
            for i, opt1 in enumerate(opts.values()):
                for opt2 in list(opts.values())[i + 1:]:
                    select_parameter_value_constraints.append(
                        smt.Not(smt.And(opt1, opt2)))
        #logger.debug("Consistency: {}".format(smt.And(select_parameter_value_constraints)))
        self.transition_system.append(
            smt.And(select_parameter_value_constraints))

        for state in mdp.states:
            if sink_states.get(state.id):
                assert rewards is None
                self.transition_system.append(
                    smt.Equals(self.state_vars[state.id], smt.REAL(0)))
                #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                self.transition_system.append(
                    smt.Not(self.state_prob1_vars[state.id]))
                #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                self.transition_system.append(
                    smt.Equals(self.state_order_vars[state.id], smt.Real(0)))
                #logger.debug("Constraint: {}".format(self.transition_system[-1]))
            elif target_states.get(state.id):
                self.transition_system.append(
                    smt.Equals(self.state_order_vars[state.id], smt.Real(1)))
                #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                self.transition_system.append(self.state_prob1_vars[state.id])
                #logger.debug("Constraint: {}".format(self.transition_system[-1]))

                if rewards is None:
                    self.transition_system.append(
                        smt.Equals(self.state_vars[state.id], smt.Real(1)))
                    #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                else:
                    self.transition_system.append(
                        self.state_probpos_vars[state.id])
                    #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                    self.transition_system.append(
                        smt.Equals(self.state_vars[state.id], smt.Real(0)))
                    #logger.debug("Constraint: {}".format(self.transition_system[-1]))
            else:
                state_in_prob1A = False
                state_in_prob0E = False
                if prob0E.get(state.id):
                    state_in_prob0E = True
                else:
                    self.transition_system.append(
                        smt.Equals(self.state_order_vars[state.id],
                                   smt.Real(1)))
                    #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                    self.transition_system.append(
                        self.state_probpos_vars[state.id])
                    #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                if rewards and not state_in_prob0E:
                    if prob1A.get(state.id):
                        self.transition_system.append(
                            self.state_prob1_vars[state.id])
                        logger.debug("Constraint: {}".format(
                            self.transition_system[-1]))
                        state_in_prob1A = True

                for action in state.actions:
                    action_index = mdp.nondeterministic_choice_indices[
                        state.id] + action.id
                    #logger.debug("Action index: {}".format(action_index))
                    precondition = smt.And([
                        self.option_vars[hole][list(option)[0]] for hole,
                        option in colors.get(action_index, dict()).items()
                    ])
                    reward_value = None
                    if rewards:
                        reward_const = (rewards.get_state_reward(
                            state.id) if state_rewards else 0.0) + (
                                rewards.get_state_action_reward(action_index)
                                if action_rewards else 0.0)
                        reward_value = smt.Real(reward_const)
                    act_constraint = action_constraint_inequality(
                        self.state_vars[state.id],
                        smt.Plus([
                            smt.Times(smt.Real(t.value()), self.
                                      state_vars[t.column])
                            for t in action.transitions
                        ] + [reward_value] if reward_value else []))
                    full_act_constraint = act_constraint
                    if state_in_prob0E:
                        if not rewards:
                            full_act_constraint = smt.And(
                                smt.Implies(self.state_probpos_vars[state.id],
                                            act_constraint),
                                smt.Implies(
                                    smt.Not(self.state_probpos_vars),
                                    smt.Equals(self.state_vars[state.id],
                                               smt.Real(0))))
                        self.transition_system.append(
                            smt.Implies(
                                precondition,
                                smt.Iff(
                                    self.state_probpos_vars[state.id],
                                    smt.Or([
                                        smt.And(
                                            self.state_probpos_vars[t.column],
                                            smt.LT(
                                                self.state_order_vars[
                                                    state.id],
                                                self.state_order_vars[
                                                    t.column]))
                                        for t in action.transitions
                                    ]))))
                        #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                    if rewards and not state_in_prob1A:
                        # prob_one(state) <-> probpos AND for all succ prob_one(succ)
                        self.transition_system.append(
                            smt.Implies(
                                precondition,
                                smt.Iff(
                                    self.state_prob1_vars[state.id],
                                    smt.And([
                                        self.state_prob1_vars[t.column]
                                        for t in action.transitions
                                    ] + [self.state_probpos_vars[state.id]]))))
                        #logger.debug("Constraint: {}".format(self.transition_system[-1]))
                    self.transition_system.append(
                        smt.Implies(precondition, full_act_constraint))
                    #logger.debug("Constraint: {}".format(self.transition_system[-1]))

        if rewards:
            self.transition_system.append(
                smt.And([smt.GE(sv, smt.Real(0)) for sv in self.state_vars]))
        else:
            self.transition_system.append(
                smt.And([
                    smt.And(smt.GE(sv, smt.Real(0)), smt.LE(sv, smt.Real(1)))
                    for sv in self.state_vars
                ]))

        #print(self.transition_system)
        formula = smt.And(self.transition_system)
        logger.info("Start SMT solver")
        model = smt.get_model(formula)

        if model:
            logger.info("SAT: Found {}".format(model))
        else:
            logger.info("UNSAT.")