def get_bounds(self, formula_manager=None):
     fm = smt if formula_manager is None else formula_manager
     bounds = []
     for v, (lb, ub) in self.var_domains.items():
         symbol = self.get_symbol(v, formula_manager)
         if lb is not None:
             bounds.append(smt.LE(smt.Real(float(lb)), symbol))
         if ub is not None:
             bounds.append(smt.LE(symbol, smt.Real(float(ub))))
     return fm.And(*bounds)
Exemple #2
0
    def ast_to_smt(self, node):
        """
        :type node: Node
        """
        def convert_children(number=None):
            if number is not None and len(node.children) != number:
                raise Exception(
                    "The number of children ({}) differed from {}".format(
                        len(node.children), number))
            return [self.ast_to_smt(child) for child in node.children]

        if node.name == "ite":
            return smt.Ite(*convert_children(3))
        elif node.name == "~":
            return smt.Not(*convert_children(1))
        elif node.name == "^":
            return smt.Pow(*convert_children(2))
        elif node.name == "&":
            return smt.And(*convert_children())
        elif node.name == "|":
            return smt.Or(*convert_children())
        elif node.name == "*":
            return smt.Times(*convert_children())
        elif node.name == "+":
            return smt.Plus(*convert_children())
        elif node.name == "-":
            return smt.Minus(*convert_children(2))
        elif node.name == "<=":
            return smt.LE(*convert_children(2))
        elif node.name == ">=":
            return smt.GE(*convert_children(2))
        elif node.name == "<":
            return smt.LT(*convert_children(2))
        elif node.name == ">":
            return smt.GT(*convert_children(2))
        elif node.name == "=":
            return smt.Equals(*convert_children(2))
        elif node.name == "const":
            c_type, c_value = [child.name for child in node.children]
            if c_type == "bool":
                return smt.Bool(bool(c_value))
            elif c_type == "real":
                return smt.Real(float(c_value))
            else:
                raise Exception("Unknown constant type {}".format(c_type))
        elif node.name == "var":
            v_type, v_name = [child.name for child in node.children]
            if v_type == "bool":
                v_smt_type = smt.BOOL
            elif v_type == "real":
                v_smt_type = smt.REAL
            else:
                raise Exception("Unknown variable type {}".format(v_type))
            return smt.Symbol(v_name, v_smt_type)
        else:
            raise RuntimeError("Unrecognized node type '{}'".format(node.name))
Exemple #3
0
    def _test_to_smt(self, operator):
        operator = operator.to_canonical()

        # FIXME Integer rounding only applicable if x >= 0

        def to_symbol(s):
            return smt.Symbol(s, typename=smt.types.INT)

        import math
        items = [smt.Times(smt.Int(int(math.floor(v))), to_symbol(k)) for k, v in operator.lhs.items()]
        lhs = smt.Plus([smt.Int(0)] + items)
        rhs = smt.Int(int(math.floor(operator.rhs)))

        assert operator.symbol == "<="

        return smt.LE(lhs, rhs)
Exemple #4
0
def generate_half_space(domain, real_count):
    coefficients = [smt.Real(random.random() * 2 - 1) * domain.get_symbol(domain.real_vars[i]) for i in
                    range(real_count)]
    return smt.LE(smt.Plus(*coefficients), smt.Real(random.random() * 2 - 1))
Exemple #5
0
    def __getExpressionTree(symbolicExpression):
        # TODO LATER: take into account bitwise shift operations
        args = []
        castType = None
        if len(symbolicExpression.args) > 0:
            for symbolicArg in symbolicExpression.args:
                arg, type = Solver.__getExpressionTree(symbolicArg)
                args.append(arg)
                if castType is None:
                    castType = type
                else:
                    if castType.literal == 'Integer':
                        if type.literal == 'Real':
                            castType = type
                    # TODO LATER: consider other possible castings
            if castType.literal == 'Real':
                for i in range(len(args)):
                    args[i] = pysmt.ToReal(args[i])

        if isinstance(symbolicExpression, sympy.Not):
            if castType.literal == 'Integer':
                return pysmt.Equals(args[0], pysmt.Int(0)), Type('Bool')
            elif castType.literal == 'Real':
                return pysmt.Equals(args[0], pysmt.Real(0)), Type('Bool')
            elif castType.literal == 'Bool':
                return pysmt.Not(args[0]), Type('Bool')
            else: # castType.literal == 'BitVector'
                return pysmt.BVNot(args[0]), Type('BitVector')
        elif isinstance(symbolicExpression, sympy.Lt):
            return pysmt.LT(args[0], args[1]), Type('Bool')
        elif isinstance(symbolicExpression, sympy.Gt):
            return pysmt.GT(args[0], args[1]), Type('Bool')
        elif isinstance(symbolicExpression, sympy.Ge):
            return pysmt.GE(args[0], args[1]), Type('Bool')
        elif isinstance(symbolicExpression, sympy.Le):
            return pysmt.LE(args[0], args[1]), Type('Bool')
        elif isinstance(symbolicExpression, sympy.Eq):
            return pysmt.Equals(args[0], args[1]), Type('Bool')
        elif isinstance(symbolicExpression, sympy.Ne):
            return pysmt.NotEquals(args[0], args[1]), Type('Bool')
        elif isinstance(symbolicExpression, sympy.And):
            if castType.literal == 'Bool':
                return pysmt.And(args[0], args[1]), Type('Bool')
            else: # type.literal == 'BitVector'
                return pysmt.BVAnd(args[0], args[1]), castType
        elif isinstance(symbolicExpression, sympy.Or):
            if castType.literal == 'Bool':
                return pysmt.Or(args[0], args[1]), Type('Bool')
            else:  # type.literal == 'BitVector'
                return pysmt.BVOr(args[0], args[1]), castType
        elif isinstance(symbolicExpression, sympy.Xor):
            return pysmt.BVXor(args[0], args[1]), castType
        elif isinstance(symbolicExpression, sympy.Add):
            return pysmt.Plus(args), castType
        elif isinstance(symbolicExpression, sympy.Mul):
            return pysmt.Times(args), castType
        elif isinstance(symbolicExpression, sympy.Pow):
            return pysmt.Pow(args[0], args[1]), castType
        # TODO LATER: deal with missing modulo operator from pysmt
        else:
            if isinstance(symbolicExpression, sympy.Symbol):
                symbolType = Variable.symbolTypes[symbolicExpression.name]
                literal = symbolType.getTypeForSolver()
                designator = symbolType.designatorExpr1
                type = Type(literal, designator)
                return Solver.__encodeTerminal(symbolicExpression, type), type
            elif isinstance(symbolicExpression, sympy.Integer):
                type = Type('Integer')
                return Solver.__encodeTerminal(symbolicExpression, type), type
            elif isinstance(symbolicExpression, sympy.Rational):
                type = Type('Real')
                return Solver.__encodeTerminal(symbolicExpression, type), type
            elif isinstance(symbolicExpression, sympy.Float):
                type = Type('Real')
                return Solver.__encodeTerminal(symbolicExpression, type), type
            else:
                type = Type('Real')
                return Solver.__encodeTerminal(symbolicExpression, type), type
Exemple #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.")