Exemple #1
0
def check_balancer_flow(junctions, upstream_densities, downstream_velocities):
    assert len(upstream_densities) == len(downstream_velocities)
    width = len(upstream_densities)
    length = max(x for x, _, _ in junctions)

    formula, belts = balancer_flow_formula(junctions, width, length)

    # Set initial conditions.
    for y, rho in enumerate(upstream_densities):
        formula.append(s.Equals(belts[y][0].rho, s.Real(rho)))
    for y, v in enumerate(downstream_velocities):
        formula.append(s.Equals(belts[y][-1].v, s.Real(v)))

    m = get_model_or_print_ucore(s.And(formula))
    # Print output diagram.
    junctions_by_x = [[] for x in range(length + 1)]
    for (x, y1, y2) in junctions:
        junctions_by_x[x].append((y1, y2))
    ud_width = max(len(str(ud)) for ud in upstream_densities)
    dv_width = max(len(str(dv)) for dv in downstream_velocities)
    rho_width = max(
        len(str(m.get_py_value(belt.rho))) for beltway in belts
        for belt in beltway)
    v_width = max(
        len(str(m.get_py_value(belt.v))) for beltway in belts
        for belt in beltway[1:-1])
    for y, beltway in enumerate(belts):
        print(f'{str(upstream_densities[y]):{ud_width}s}>>>', end=':')
        for x, belt in enumerate(beltway):
            letter_map = {}
            if x < len(beltway) - 1:
                for (y1, y2), letter in zip(junctions_by_x[x + 1],
                                            'abcdefghjkmn'):
                    assert y1 not in letter_map
                    assert y2 not in letter_map
                    letter_map[y1] = letter
                    letter_map[y2] = letter
            belt_status = f'{str(m.get_py_value(belt.rho)):>{rho_width}s}@{str(m.get_py_value(belt.v)):{v_width}s}'
            print(f' >>> {belt_status} >>>', end=f' {letter_map.get(y,"|")}')
        end_flux = m.get_py_value(beltway[-1].flux)
        print(f'> {end_flux}.')

    # The moment of truth...
    theoretical_throughput = min(sum(upstream_densities),
                                 sum(downstream_velocities))
    print(f'Theoretical Q: {theoretical_throughput}')
    actual_throughput = sum(
        m.get_py_value(beltway[-1].flux) for beltway in belts)
    print(f'Actual Q: {actual_throughput}')
    if theoretical_throughput != actual_throughput:
        print(
            f'{float(1-(actual_throughput/theoretical_throughput)):.0%} slowdown :('
        )
    print('∎')
Exemple #2
0
    def formula(self, p):
        ptyp = type(p)
        if ptyp is BD.GTZ or ptyp is BD.GEZ or ptyp is BD.EQZ:
            aform = self.affine(p.expr)
            if ptyp is BD.GTZ: return SMT.GT(aform, SMT.Int(0))
            elif ptyp is BD.GEZ: return SMT.GE(aform, SMT.Int(0))
            elif ptyp is BD.EQZ: return SMT.Equals(aform, SMT.Int(0))
            else: assert False

        elif ptyp is BD.Rel:
            rsym = self._ctxt.get(p.name)
            assert rsym is not None, f"expected relation name '{p.name}'"

            args = []
            for a in p.args:
                sym = self._ctxt.get(a)
                assert sym is not None, f"expected variable name '{a}'"
                args.append(sym)
            return SMT.Function(rsym, args)

        elif ptyp is BD.Conj or ptyp is BD.Disj:
            lhs = self.formula(p.lhs)
            rhs = self.formula(p.rhs)
            smtop = SMT.And if ptyp is BD.Conj else SMT.Or
            return smtop(lhs, rhs)
Exemple #3
0
    def __getitem__(self, index):
        size = self.size
        if isinstance(index, slice):
            start, stop, step = index.start, index.stop, index.step

            if start is None:
                start = 0
            elif start < 0:
                start = size + start

            if stop is None:
                stop = size
            elif stop < 0:
                stop = size + stop

            stop = min(stop, size)

            if step is None:
                step = 1
            elif step != 1:
                raise IndexError('SMT extract does not support step != 1')

            v = self.value[start:stop - 1]
            return type(self).unsized_t[v.get_type().width](v)
        elif isinstance(index, int):
            if index < 0:
                index = size + index

            if not (0 <= index < size):
                raise IndexError()

            v = self.value[index]
            return self.get_family().Bit(smt.Equals(v, smt.BV(1, 1)))
        else:
            raise TypeError()
Exemple #4
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 #5
0
    def test_bv2pysmt(self):
        bvx, bvy = Variable("x", 8), Variable("y", 8)
        psx, psy = bv2pysmt(bvx), bv2pysmt(bvy)

        self.assertEqual(bv2pysmt(Constant(0, 8)), sc.BV(0, 8))
        self.assertEqual(psx, sc.Symbol("x", typing.BVType(8)))

        self.assertEqual(bv2pysmt(~bvx), sc.BVNot(psx))
        self.assertEqual(bv2pysmt(bvx & bvy), sc.BVAnd(psx, psy))
        self.assertEqual(bv2pysmt(bvx | bvy), sc.BVOr(psx, psy))
        self.assertEqual(bv2pysmt(bvx ^ bvy), sc.BVXor(psx, psy))

        self.assertEqual(bv2pysmt(BvComp(bvx, bvy)), sc.Equals(psx, psy))
        self.assertEqual(bv2pysmt(BvNot(BvComp(bvx, bvy))),
                         sc.Not(sc.Equals(psx, psy)))

        self.assertEqual(bv2pysmt(bvx < bvy), sc.BVULT(psx, psy))
        self.assertEqual(bv2pysmt(bvx <= bvy), sc.BVULE(psx, psy))
        self.assertEqual(bv2pysmt(bvx > bvy), sc.BVUGT(psx, psy))
        self.assertEqual(bv2pysmt(bvx >= bvy), sc.BVUGE(psx, psy))

        self.assertEqual(bv2pysmt(bvx << bvy), sc.BVLShl(psx, psy))
        self.assertEqual(bv2pysmt(bvx >> bvy), sc.BVLShr(psx, psy))
        self.assertEqual(bv2pysmt(RotateLeft(bvx, 1)), sc.BVRol(psx, 1))
        self.assertEqual(bv2pysmt(RotateRight(bvx, 1)), sc.BVRor(psx, 1))

        self.assertEqual(bv2pysmt(bvx[4:2]), sc.BVExtract(psx, 2, 4))
        self.assertEqual(bv2pysmt(Concat(bvx, bvy)), sc.BVConcat(psx, psy))
        # zeroextend reduces to Concat
        # self.assertEqual(bv2pysmt(ZeroExtend(bvx, 2)), sc.BVZExt(psx, 2))
        self.assertEqual(bv2pysmt(Repeat(bvx, 2)), psx.BVRepeat(2))

        self.assertEqual(bv2pysmt(-bvx), sc.BVNeg(psx))
        self.assertEqual(bv2pysmt(bvx + bvy), sc.BVAdd(psx, psy))
        # bvsum reduces to add
        # self.assertEqual(bv2pysmt(bvx - bvy), sc.BVSub(psx, psy))
        self.assertEqual(bv2pysmt(bvx * bvy), sc.BVMul(psx, psy))
        self.assertEqual(bv2pysmt(bvx / bvy), sc.BVUDiv(psx, psy))
        self.assertEqual(bv2pysmt(bvx % bvy), sc.BVURem(psx, psy))
Exemple #6
0
 def walk_equals(self, left, right):
     return smt.Equals(self.walk_smt(left), self.walk_smt(right))
Exemple #7
0
def balancer_flow_formula(junctions, width, length):
    formula = []
    belts = [[
        Belt(s.Symbol(f'b{i}[{x}].rho', t.REAL),
             s.Symbol(f'b{i}[{x}].v', t.REAL)) for x in range(length + 1)
    ] for i in range(width)]
    for beltway in belts:
        for belt in beltway:
            formula.extend(domain(belt))
    if not s.is_sat(s.And(formula)):
        raise Exception('Domain is not SAT :/')

    # Balancing rules.
    junctions_by_x = [[] for x in range(length + 1)]
    for (x, y1, y2) in junctions:
        junctions_by_x[x].append((y1, y2))
        inn = x - 1
        out = x

        input_rho = s.Plus(belts[y1][inn].rho, belts[y2][inn].rho)
        # We want to put half of the input on each output.
        half_input = s.Div(input_rho, s.Real(2))

        # If output velocity is less than the half_input that we would like to
        # assign to it, we've filled it. Velocity is a hard limit, because it's out
        # of influence of this splitter. We'll set the output density to 1 in that
        # case. Aside: The flux is the min of that and the velocity, so if
        # out-velocity is the limiting factor, it won't change the flux calculation
        # to just assign rho_out = v_out.
        #
        # Now, the excess that we couldn't assign has to go somewhere: (1) to the
        # other output belt; if that's full, (2) feed back up the chain by reducing
        # input velocities.
        excess_from_1 = s.Max(s.Real(0), s.Minus(half_input, belts[y1][out].v))
        excess_from_2 = s.Max(s.Real(0), s.Minus(half_input, belts[y2][out].v))

        # This formula is most accurate for assignment > velocity (density will
        # equal 1), but it doesn't change the flux calculation just toset rho to
        # the velocity when velocity limits flow. (So you should be able to replace
        # the Ite by v_out and be OK.)
        formula.append(
            s.Equals(
                belts[y1][out].rho,
                s.Ite(half_input + excess_from_2 > belts[y1][out].v, s.Real(1),
                      half_input + excess_from_2)))
        formula.append(
            s.Equals(
                belts[y2][out].rho,
                s.Ite(half_input + excess_from_1 > belts[y2][out].v, s.Real(1),
                      half_input + excess_from_1)))

        output_v = s.Plus(belts[y1][out].v, belts[y2][out].v)
        half_output = s.Div(output_v, s.Real(2))
        unused_density_from_1 = s.Max(s.Real(0),
                                      s.Minus(half_output, belts[y1][inn].rho))
        unused_density_from_2 = s.Max(s.Real(0),
                                      s.Minus(half_output, belts[y2][inn].rho))

        formula.append(
            s.Equals(
                belts[y1][inn].v,
                s.Ite(half_output + unused_density_from_2 > belts[y1][inn].rho,
                      s.Real(1), half_output + unused_density_from_2)))
        formula.append(
            s.Equals(
                belts[y2][inn].v,
                s.Ite(half_output + unused_density_from_1 > belts[y2][inn].rho,
                      s.Real(1), half_output + unused_density_from_1)))
        # Conservation of flux at each junction.
        input_flux = s.Plus(belts[y1][inn].flux, belts[y2][inn].flux)
        output_flux = s.Plus(belts[y1][out].flux, belts[y2][out].flux)
        formula.append(s.Equals(input_flux, output_flux))

    # Any belts not involved in a junction are pass-throughs. Their successive
    # values must remain equal.
    thru_belts = [
        list(
            set(range(width)) - {y1
                                 for y1, y2 in junctions_by_x[x]} -
            {y2
             for y1, y2 in junctions_by_x[x]}) for x in range(length + 1)
    ]
    for x, thru in enumerate(thru_belts[1:]):
        for y in thru:
            formula.append(s.Equals(belts[y][x].rho, belts[y][x + 1].rho))
            formula.append(s.Equals(belts[y][x].v, belts[y][x + 1].v))

    return formula, belts
Exemple #8
0
def prove_properties(junctions):
    width = max(max(y1 for _, y1, _ in junctions),
                max(y2 for _, _, y2 in junctions)) + 1
    length = max(x for x, _, _ in junctions)
    formula, belts = balancer_flow_formula(junctions, width, length)

    supply = s.Plus(beltway[0].rho for beltway in belts)
    demand = s.Plus(beltway[-1].v for beltway in belts)
    max_theoretical_throughput = s.Min(supply, demand)
    actual_throughput = s.Plus(beltway[-1].flux for beltway in belts)

    fully_balanced_output = []
    max_flux = s.Max(b[-1].flux for b in belts)
    for i, b1 in enumerate(belts):
        fully_balanced_output.append(
            s.Or(s.Equals(b1[-1].flux, max_flux),
                 s.Equals(b1[-1].flux, b1[-1].v)))
    fully_balanced_output = s.And(fully_balanced_output)

    fully_balanced_input = []
    max_flux = s.Max(b[0].flux for b in belts)
    for i, b1 in enumerate(belts):
        fully_balanced_input.append(
            s.Or(s.Equals(b1[0].flux, max_flux),
                 s.Equals(b1[0].flux, b1[0].rho)))
    fully_balanced_input = s.And(fully_balanced_input)

    with s.Solver() as solver:
        solver.add_assertion(s.And(formula))
        solver.push()
        solver.add_assertion(
            s.Not(s.Equals(max_theoretical_throughput, actual_throughput)))

        if not solver.solve():
            print("It's throughput-unlimited!")
        else:
            print("It's throughput-limited; here's an example:")
            m = solver.get_model()
            inputs = tuple(m.get_py_value(beltway[0].rho) for beltway in belts)
            outputs = tuple(m.get_py_value(beltway[-1].v) for beltway in belts)
            print(f'Input lane densities: ({", ".join(map(str, inputs))})')
            print(f'Output lane velocities: ({", ".join(map(str, outputs))})')
            check_balancer_flow(junctions, inputs, outputs)

        solver.pop()
        solver.push()
        solver.add_assertion(s.Not(fully_balanced_input))

        if not solver.solve():
            print("It's input-balanced!")
        else:
            print("It's input-imbalanced; here's an example:")
            m = solver.get_model()
            inputs = tuple(m.get_py_value(beltway[0].rho) for beltway in belts)
            outputs = tuple(m.get_py_value(beltway[-1].v) for beltway in belts)
            print(f'Input lane densities: ({", ".join(map(str, inputs))})')
            print(f'Output lane velocities: ({", ".join(map(str, outputs))})')
            check_balancer_flow(junctions, inputs, outputs)

        solver.pop()
        solver.push()
        solver.add_assertion(s.Not(fully_balanced_output))
        if solver.solve:
            print("It's output-balanced!")
        else:
            print("It's output-imbalanced; here's an example:")
            m = solver.get_model()
            inputs = tuple(m.get_py_value(beltway[0].rho) for beltway in belts)
            outputs = tuple(m.get_py_value(beltway[-1].v) for beltway in belts)
            print(f'Input lane densities: ({", ".join(map(str, inputs))})')
            print(f'Output lane velocities: ({", ".join(map(str, outputs))})')
            check_balancer_flow(junctions, inputs, outputs)
Exemple #9
0
print(variables)

constraints = []
for var in variables:
    string = var.__repr__()
    # add requirement that all a_i, c_i > -1
    if string[0] == "a" or string[0] == "c":
        constraints.append(SMT.GT(var, SMT.Int(-1)))
    # add requirement that b_i > 0
    else:
        constraints.append(SMT.GT(var, SMT.Int(0)))

for i in range(0, 3 * cap, 3):
    # add requirement that either a_i =0 or c_i = 0
    constraints.append(
        SMT.Or(SMT.Equals(variables[i], SMT.Int(0)),
               SMT.Equals(variables[i + 2], SMT.Int(0))))
    # add requirement that if a_i = 0 and c_i = 0 then b_i = 1
    constraints.append(
        SMT.Or(
            SMT.Or(SMT.GT(variables[i], SMT.Int(0)),
                   SMT.GT(variables[i + 2], SMT.Int(0))),
            SMT.Equals(variables[i + 1], SMT.Int(1))))

solver = SMT.Solver(name="z3")
print("constraints:")
for c in constraints:
    print(c)
    solver.add_assertion(c)

# add equations
Exemple #10
0
 def bveq(self, other):
     return self.get_family().Bit(smt.Equals(self.value, other.value))
    def learn_partial(self, solver, domain: Domain, data: np.ndarray,
                      labels: np.ndarray, new_active_indices: Set):

        # Constants
        n_b_original = len(domain.bool_vars)
        n_b = n_b_original * 2
        n_r = len(domain.real_vars)

        n_h_original = self.half_space_count if n_r > 0 else 0
        n_h = n_h_original * 2 if self.allow_negations else n_h_original

        n_c = self.conjunction_count
        n_d = data.shape[0]

        real_indices = np.array(
            [domain.var_types[v] == smt.REAL for v in domain.variables])
        real_features = data[:, real_indices]
        bool_features = data[:, np.logical_not(real_indices)]

        # Variables
        a_hr = [[
            smt.Symbol("a_hr[{}][{}]".format(h, r), REAL) for r in range(n_r)
        ] for h in range(n_h_original)]
        b_h = [
            smt.Symbol("b_h[{}]".format(h), REAL) for h in range(n_h_original)
        ]
        s_ch = [[smt.Symbol("s_ch[{}][{}]".format(c, h)) for h in range(n_h)]
                for c in range(n_c)]
        s_cb = [[smt.Symbol("s_cb[{}][{}]".format(c, b)) for b in range(n_b)]
                for c in range(n_c)]

        # Aux variables
        s_ih = [[smt.Symbol("s_ih[{}][{}]".format(i, h)) for h in range(n_h)]
                for i in range(n_d)]
        s_ic = [[smt.Symbol("s_ic[{}][{}]".format(i, c)) for c in range(n_c)]
                for i in range(n_d)]

        def pair(real: bool, c: int, index: int) -> Tuple[FNode, FNode]:
            if real:
                return s_ch[c][index], s_ch[c][index + n_h_original]
            else:
                return s_cb[c][index], s_cb[c][index + n_b_original]

        def order_equal(pair1, pair2):
            x_t, x_f, y_t, y_f = pair1 + pair2
            return smt.Iff(x_t, y_t) & smt.Iff(x_f, y_f)

        def order_geq(pair1, pair2):
            x_t, x_f, y_t, y_f = pair1 + pair2
            return x_t | y_f | ((~x_f) & (~y_t))

        def pairs(c: int) -> List[Tuple[FNode, FNode]]:
            return [pair(True, c, i) for i in range(n_h_original)
                    ] + [pair(False, c, i) for i in range(n_b_original)]

        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

        # Constraints
        for i in new_active_indices:
            x_r, x_b, label = [float(val) for val in real_features[i]
                               ], bool_features[i], labels[i]

            for h in range(n_h_original):
                sum_coefficients = smt.Plus(
                    [a_hr[h][r] * smt.Real(x_r[r]) for r in range(n_r)])
                solver.add_assertion(
                    smt.Iff(s_ih[i][h], sum_coefficients <= b_h[h]))

            for h in range(n_h_original, n_h):
                solver.add_assertion(
                    smt.Iff(s_ih[i][h], ~s_ih[i][h - n_h_original]))

            for c in range(n_c):
                solver.add_assertion(
                    smt.Iff(
                        s_ic[i][c],
                        smt.
                        Or([smt.FALSE()] + [(s_ch[c][h] & s_ih[i][h])
                                            for h in range(n_h)] +
                           [s_cb[c][b]
                            for b in range(n_b_original) if x_b[b]] + [
                                s_cb[c][b] for b in range(n_b_original, n_b)
                                if not x_b[b - n_b_original]
                            ])))

            # --- [start] symmetry breaking ---
            # Mutually exclusive
            if "m" in self.symmetries:
                for c in range(n_c):
                    for h in range(n_h_original):
                        solver.add_assertion(~(s_ch[c][h]
                                               & s_ch[c][h + n_h_original]))
                    for b in range(n_b_original):
                        solver.add_assertion(~(s_cb[c][b]
                                               & s_cb[c][b + n_b_original]))

            # Normalized
            if "n" in self.symmetries:
                for h in range(n_h_original):
                    solver.add_assertion(
                        smt.Equals(b_h[h], smt.Real(1.0))
                        | smt.Equals(b_h[h], smt.Real(0.0)))

            # Vertical symmetries
            if "v" in self.symmetries:
                for c in range(n_c - 1):
                    solver.add_assertion(order_geq_lex(c, c + 1))

            # Horizontal symmetries
            if "h" in self.symmetries:
                for h in range(n_h_original - 1):
                    solver.add_assertion(a_hr[h][0] >= a_hr[h + 1][0])
            # --- [end] symmetry breaking ---

            if label:
                solver.add_assertion(smt.And([s_ic[i][c] for c in range(n_c)]))
            else:
                solver.add_assertion(smt.Or([~s_ic[i][c] for c in range(n_c)]))

        solver.solve()
        model = solver.get_model()

        x_vars = [domain.get_symbol(domain.real_vars[r]) for r in range(n_r)]
        half_spaces = [
            smt.Plus(
                [model.get_value(a_hr[h][r]) * x_vars[r]
                 for r in range(n_r)]) <= model.get_value(b_h[h])
            for h in range(n_h_original)
        ] + [
            smt.Plus(
                [model.get_value(a_hr[h][r]) * x_vars[r]
                 for r in range(n_r)]) > model.get_value(b_h[h])
            for h in range(n_h - n_h_original)
        ]

        b_vars = [
            domain.get_symbol(domain.bool_vars[b]) for b in range(n_b_original)
        ]
        bool_literals = [b_vars[b] for b in range(n_b_original)]
        bool_literals += [~b_vars[b] for b in range(n_b - n_b_original)]

        conjunctions = [[
            half_spaces[h]
            for h in range(n_h) if model.get_py_value(s_ch[c][h])
        ] + [
            bool_literals[b]
            for b in range(n_b) if model.get_py_value(s_cb[c][b])
        ] for c in range(n_c)]

        return smt.And([smt.Or(conjunction) for conjunction in conjunctions])
Exemple #12
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 #13
0
def bv2pysmt(bv):
    """Convert a bit-vector type to a pySMT type.

        >>> from arxpy.bitvector.core import Constant, Variable
        >>> from arxpy.diffcrypt.smt import bv2pysmt
        >>> bv2pysmt(Constant(0b00000001, 8))
        1_8
        >>> x, y = Variable("x", 8), Variable("y", 8)
        >>> bv2pysmt(x)
        x
        >>> bv2pysmt(x +  y)
        (x + y)
        >>> bv2pysmt(x <=  y)
        (x u<= y)
        >>> bv2pysmt(x[4: 2])
        x[2:4]

    """
    msg = "unknown conversion of {} to a pySMT type".format(type(bv).__name__)

    if isinstance(bv, int):
        return bv

    if isinstance(bv, core.Variable):
        return sc.Symbol(bv.name, typing.BVType(bv.width))

    if isinstance(bv, core.Constant):
        return sc.BV(bv.val, bv.width)

    if isinstance(bv, operation.Operation):
        args = [bv2pysmt(a) for a in bv.args]

        if type(bv) == operation.BvNot:
            if args[0].is_equals():
                return sc.Not(*args)
            else:
                return sc.BVNot(*args)

        if type(bv) == operation.BvAnd:
            return sc.BVAnd(*args)

        if type(bv) == operation.BvOr:
            return sc.BVOr(*args)

        if type(bv) == operation.BvXor:
            return sc.BVXor(*args)

        if type(bv) == operation.BvComp:
            # return sc.BVComp(*args)
            return sc.Equals(*args)

        if type(bv) == operation.BvUlt:
            return sc.BVULT(*args)

        if type(bv) == operation.BvUle:
            return sc.BVULE(*args)

        if type(bv) == operation.BvUgt:
            return sc.BVUGT(*args)

        if type(bv) == operation.BvUge:
            return sc.BVUGE(*args)

        if type(bv) == operation.BvShl:
            # Left hand side width must be a power of 2
            if (args[0].bv_width() & (args[0].bv_width() - 1)) == 0:
                return sc.BVLShl(*args)
            else:
                x, r = bv.args
                offset = 0
                while (x.width & (x.width - 1)) != 0:
                    x = operation.ZeroExtend(x, 1)
                    r = operation.ZeroExtend(r, 1)
                    offset += 1

                shift = bv2pysmt(x << r)
                return sc.BVExtract(shift, end=shift.bv_width() - offset - 1)
            # width = args[0].bv_width()
            # assert (width & (width - 1)) == 0  # power of 2
            # return sc.BVLShl(*args)

        if type(bv) == operation.BvLshr:
            # Left hand side width must be a power of 2
            if (args[0].bv_width() & (args[0].bv_width() - 1)) == 0:
                return sc.BVLShr(*args)
            else:
                x, r = bv.args
                offset = 0
                while (x.width & (x.width - 1)) != 0:
                    x = operation.ZeroExtend(x, 1)
                    r = operation.ZeroExtend(r, 1)
                    offset += 1

                shift = bv2pysmt(x >> r)
                return sc.BVExtract(shift, end=shift.bv_width() - offset - 1)
            # width = args[1].bv_width()
            # assert (width & (width - 1)) == 0  # power of 2
            # return sc.BVLShr(*args)

        if type(bv) == operation.RotateLeft:
            # Left hand side width must be a power of 2
            if (args[0].bv_width() & (args[0].bv_width() - 1)) == 0:
                return sc.BVRol(*args)
            else:
                x, r = bv.args
                n = x.width
                return bv2pysmt(operation.Concat(x[n - r - 1:],
                                                 x[n - 1:n - r]))

        if type(bv) == operation.RotateRight:
            # Left hand side width must be a power of 2
            if (args[0].bv_width() & (args[0].bv_width() - 1)) == 0:
                return sc.BVRor(*args)
            else:
                x, r = bv.args
                n = x.width
                return bv2pysmt(operation.Concat(x[r - 1:], x[n - 1:r]))

        if type(bv) == operation.Ite:
            if args[0].is_equals():
                a0 = args[0]
            else:
                a0 = sc.Equals(args[0], bv2pysmt(core.Constant(1, 1)))

            return sc.Ite(a0, *args[1:])

        if type(bv) == operation.Extract:
            return sc.BVExtract(args[0], args[2], args[1])

        if type(bv) == operation.Concat:
            return sc.BVConcat(*args)

        if type(bv) == operation.ZeroExtend:
            return sc.BVZExt(*args)

        if type(bv) == operation.Repeat:
            return args[0].BVRepeat(args[1])

        if type(bv) == operation.BvNeg:
            return sc.BVNeg(*args)

        if type(bv) == operation.BvAdd:
            return sc.BVAdd(*args)

        if type(bv) == operation.BvSub:
            return sc.BVSub(*args)

        if type(bv) == operation.BvMul:
            return sc.BVMul(*args)

        if type(bv) == operation.BvMul:
            return sc.BVMul(*args)

        if type(bv) == operation.BvUdiv:
            return sc.BVUDiv(*args)

        if type(bv) == operation.BvUrem:
            return sc.BVURem(*args)

        raise NotImplementedError(msg)
Exemple #14
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.")