Example #1
0
def find_min(constraints, expr, default_min=0):
    if type(expr) == int:
        return expr

    constraint_strs = [f'{c}' for c in constraints]

    min_optimize = Optimize()
    min_optimize.set('timeout', 10000)

    min_optimize.assert_exprs(*constraints)
    min_optimize.minimize(expr)
    status = min_optimize.check()
    if status != sat:
        print(f'Unable to find min ({status}) for:\n' +
              '\n'.join(constraint_strs))
        return None

    min_val = min_optimize.model().eval(expr).as_long()

    # Make sure it's actually the min, since z3 has a bug
    #   https://github.com/Z3Prover/z3/issues/4670
    solver = Solver()
    solver.set('timeout', 10000)
    solver.add(constraints + [expr < min_val])
    status = solver.check()

    if status != unsat:
        print(
            f'Z3 bug\nFind min ({expr}) => {min_val} with status ({status}):\n'
            + '\n'.join(constraint_strs))
        return None
    return min_val
Example #2
0
def main():
    bots = []

    with open("input.txt") as f:
        for line in f:
            bots.append(tuple(map(int, re.findall(r"-?\d+", line))))

    x, y, z, r = max(bots, key=lambda b: b[3])
    in_range = sum(
        (abs(x - b[0]) + abs(y - b[1]) + abs(z - b[2]) <= r) for b in bots)
    print("Part 1:", in_range)

    x, y, z = Int("x"), Int("y"), Int("z")
    point = (x, y, z)
    count = sum(If(z3_dist(b[:3], point) <= b[3], 1, 0) for b in bots)

    opt = Optimize()
    opt.maximize(count)
    opt.minimize(z3_dist(point, (0, 0, 0)))

    opt.check()
    model = opt.model()
    result = model[x].as_long() + model[y].as_long() + model[z].as_long()

    print("Part 2:", result)
Example #3
0
def get_model(constraints, minimize=(), maximize=()):
    s = Optimize()
    s.set("timeout", 100000)

    for constraint in constraints:
        if type(constraint) == bool and not constraint:
            raise UnsatError

    constraints = [
        constraint for constraint in constraints if type(constraint) != bool
    ]

    for constraint in constraints:
        s.add(constraint)
    for e in minimize:
        s.minimize(e)
    for e in maximize:
        s.maximize(e)

    result = s.check()
    if result == sat:
        return s.model()
    elif result == unknown:
        logging.debug("Timeout encountered while solving expression using z3")
    raise UnsatError
Example #4
0
def main(args):
    data = [extract(s.strip()) for s in sys.stdin]
    data = [(x[3], tuple(x[:-1])) for x in data]
    m = max(data)
    in_range = [x for x in data if dist(x[1], m[1]) <= m[0]]
    print(len(in_range))

    x = Int('x')
    y = Int('y')
    z = Int('z')
    orig = (x, y, z)
    cost = Int('cost')
    cost_expr = x * 0
    for r, pos in data:
        cost_expr += If(z3_dist(orig, pos) <= r, 1, 0)
    opt = Optimize()
    print("let's go")
    opt.add(cost == cost_expr)
    opt.maximize(cost)
    # I didn't do this step in my initial #2 ranking solution but I
    # suppose you should.
    # z3 does them lexicographically by default.
    opt.minimize(z3_dist((0, 0, 0), (x, y, z)))

    opt.check()

    model = opt.model()
    #    print(model)
    pos = (model[x].as_long(), model[y].as_long(), model[z].as_long())
    print("position:", pos)
    print("num in range:", model[cost].as_long())
    print("distance:", dist((0, 0, 0), pos))
Example #5
0
def to_z3_problem(problem: DependencyProblem,
                  states: List[EncodedState]) -> Optimize:
    minimizer = Optimize()
    minimizer.add(to_formula(problem, states))

    cost = Int('cost')
    cost_constraint = cost == total_cost(states, problem.repository)
    minimizer.add(cost_constraint)

    minimizer.minimize(cost)
    return minimizer
Example #6
0
class Y2021D24(object):
    _re_inp = re.compile(r'inp ([wxyz])')
    _re_add = re.compile(r'add ([wxyz]) ([wxyz]|-?\d+)')
    _re_mul = re.compile(r'mul ([wxyz]) ([wxyz]|-?\d+)')
    _re_div = re.compile(r'div ([wxyz]) ([wxyz]|-?\d+)')
    _re_mod = re.compile(r'mod ([wxyz]) ([wxyz]|-?\d+)')
    _re_eql = re.compile(r'eql ([wxyz]) ([wxyz]|-?\d+)')

    def __init__(self, file_name):
        self.solver = Optimize()

        inputs = [Int(f'model_{i}') for i in range(14)]
        self.solver.add([i >= 1 for i in inputs])
        self.solver.add([i <= 9 for i in inputs])

        # Please don't ask me to explain this. There's a common pattern in the input code that treats z like a number
        # of base 26 and the operations are either right shift or left shift on that number +- some value.
        self.solver.add(inputs[0] + 6 - 6 == inputs[13])
        self.solver.add(inputs[1] + 11 - 6 == inputs[12])
        self.solver.add(inputs[2] + 5 - 13 == inputs[11])
        self.solver.add(inputs[3] + 6 - 8 == inputs[8])
        self.solver.add(inputs[4] + 8 - 1 == inputs[5])
        self.solver.add(inputs[6] + 9 - 16 == inputs[7])
        self.solver.add(inputs[9] + 13 - 16 == inputs[10])

        my_sum = IntVal(0)
        for index in range(len(inputs)):
            my_sum = (my_sum * 10) + inputs[index]

        self.value = Int('value')
        self.solver.add(my_sum == self.value)

    def part1(self):
        self.solver.push()

        self.solver.maximize(self.value)
        self.solver.check()
        result = self.solver.model()[self.value]

        self.solver.pop()

        print("Part 1:", result)

    def part2(self):
        self.solver.push()

        self.solver.minimize(self.value)
        self.solver.check()
        result = self.solver.model()[self.value]

        self.solver.pop()

        print("Part 2:", result)
Example #7
0
def optimum_dist(bots):
    x = Int('x')
    y = Int('y')
    z = Int('z')
    cost_expr = x * 0
    for i, j, k, r in bots:
        cost_expr += If(z3_dist((x, y, z), (i, j, k)) <= r, 1, 0)
    opt = Optimize()
    opt.maximize(cost_expr)
    opt.minimize(z3_dist((0, 0, 0), (x, y, z)))
    opt.check()
    model = opt.model()
    coords = (model[x].as_long(), model[y].as_long(), model[z].as_long())
    return dist((0, 0, 0), coords)
Example #8
0
def maximize_distance(bots):
  o = Optimize()

  z3_abs = lambda k: If(k >= 0, k, -k)
  z3_in_ranges = [Int('in_range_of_bot_' + str(i)) for i in xrange(len(bots))]
  z3_x, z3_y, z3_z = (Int('x'), Int('y'), Int('z'))
  z3_sum = Int('sum')
  z3_dist = Int('dist')

  for i, (x, y, z, r) in enumerate(bots):
    o.add(z3_in_ranges[i] == If(distance((z3_x, z3_y, z3_z), (x, y, z), z3_abs) <= r, 1, 0))

  o.add(z3_sum == sum(z3_in_ranges))

  o.add(z3_dist == distance((z3_x, z3_y, z3_z), (0, 0, 0), z3_abs))

  h1, h2 = o.maximize(z3_sum), o.minimize(z3_dist)
  o.check()
  # o.lower(h1), o.upper(h1)

  lower, upper = o.lower(h2), o.upper(h2)
  # o.model()[z3_x], o.model()[z3_y], o.model()[z3_z]

  if str(lower) != str(upper): raise Exception('lower ({}) != upper ({})'.format(lower, upper))
  return (lower, upper)
    def solve_boolean_formula_with_z3_smt2(self, bf):
        """Find minimum satisfying assignemnt for the boolean formula.
        # Example:
        # >>> bf = '(and (or a b) (not (and a c)))'
        # >>> appeared_symbol_list = ['a', 'b', 'c']
        # >>> solve_boolean_formula_with_z3_smt2(bf, appeared_symbol_list)
        # ([b = True, a = False, c = False, s = 1], 1)
        """
        appeared_symbol_list = list(
            set([
                a if "not " not in a else a[5:-1]
                for a in self.prov_notations.values()
            ]))
        declaration_str = '\n'.join(
            list(
                map(lambda x: '(declare-const {} Bool)'.format(x),
                    appeared_symbol_list)))
        declaration_str += '\n(declare-const s Int)'
        declaration_str += '\n(define-fun b2i ((x Bool)) Int (ite x 1 0))'

        size_str = '(+ {})'.format(' '.join(
            list(map(lambda x: '(b2i {})'.format(x), appeared_symbol_list))))
        assert_str = '(assert {})\n'.format(bf)
        assert_str += '(assert (= s {}))\n(assert (>= s 0))'.format(
            size_str)  # changed from (> s 0)

        z3_bf = parse_smt2_string(declaration_str + '\n' + assert_str)
        opt = Optimize()
        opt.add(z3_bf)
        s = Int('s')
        opt.minimize(s)  # changed from opt.minimize(s)

        if opt.check() == sat:
            best_model = opt.model()
            min_size = 0
            for cl in best_model:
                if isinstance(best_model[cl], BoolRef) and best_model[cl]:
                    min_size += 1
            return best_model, min_size
        else:
            return None, -1
def geometry_free_solve_(ddn1, ddn2, ws, station_data, sta1, sta2, prn1, prn2, ticks):
    lambda_1 = lambda_1s[prn1[0]]
    lambda_2 = lambda_2s[prn1[0]]

    # Φ_i - R_i = B_i + err  with B_i = b_i + λ_1*N_1 - λ_2*N_2
    B_i = bias(tec.geometry_free)
    
    sol = Optimize()
#    sol = Solver()
    errs = Reals('err_11 err_12 err_21 err_22')
    n1s = Ints('n1_11 n1_12 n1_21 n1_22')
    n2s = Ints('n2_11 n2_12 n2_21 n2_22')

    sol.add(n1s[0] - n1s[1] - n1s[2] + n1s[3] == ddn1)
    sol.add(n2s[0] - n2s[1] - n2s[2] + n2s[3] == ddn2)

    for i, (sta, prn) in enumerate(product([sta1, sta2], [prn1, prn2])):
        sol.add(n1s[i] - n2s[i] == ws[i])
        B_i_samples = []
        for tick in ticks:
            B_i_samples.append( B_i(station_data[sta][prn][tick])[0] )
        B_i_avg = numpy.mean(B_i_samples)
#        B_i_avg = B_i_samples[0]
        print(B_i_avg, numpy.std(B_i_samples))
        sol.add(lambda_1 * ToReal(n1s[i]) - lambda_2 * ToReal(n2s[i]) + errs[i] > B_i_avg)
        sol.add(lambda_1 * ToReal(n1s[i]) - lambda_2 * ToReal(n2s[i]) - errs[i] < B_i_avg)
    """
        sol.add(errs[0] < .9)
        sol.add(errs[1] < .9)
        sol.add(errs[2] < .9)
        sol.add(errs[3] < .9)
    """
    #sol.add(errs[0] + errs[1] + errs[2] + errs[3] < 17)
    objective = sol.minimize(errs[0] + errs[1] + errs[2] + errs[3])
    if sol.check() != sat:
        return None
    sol.lower(objective)
    if sol.check() != sat:
        return None
#    sol.add(errs[0] + errs[1] + errs[2] + errs[3] < 2)
    # can't do L2 norm with z3, L1 will have to do...
#    sol.(errs[0] + errs[1] + errs[2] + errs[3])

    
    return (
        [sol.model()[n1s[i]].as_long() for i in range(4)],
        [sol.model()[n2s[i]].as_long() for i in range(4)],
        [frac_to_float(sol.model()[errs[i]]) for i in range(4)],
    )
Example #11
0
def _solve(
    solver: z3.Optimize, channels: List[Channel], devices: List[Device]
) -> Tuple[Problem, z3.Model]:
    problem = _problem(solver, freqs=[c.frequency for c in channels], devices=devices)
    if solver.check() != z3.sat:
        # TODO: consider getting an unsat core
        raise ValueError(f"No valid assignment possible, add more devices")

    # find the minimal number of devices that cover all frequencies
    # it is faster to do this iteratively than to offload these to
    # smt constraints. do this in reverse so we end up assigning
    # the lowest numbered devices
    for r in problem.ranges[::-1]:
        # to control the device placements adjust the order they're eliminated from
        # the solution. for example, this will prefer devices that have a smaller
        # minimum sample rate over devices with a larger one:
        # for r, _ in zip(problem.ranges, problem.devices), key=lambda x: -x[1].min_sample_rate
        solver.push()
        solver.add(r == 0)
        if solver.check() != z3.sat:
            solver.pop()
            break

    devices_required = z3.Sum([z3.If(r > 0, 1, 0) for r in problem.ranges])

    # minimize the sum of frequency ranges
    solver.minimize(z3.Sum(*problem.ranges))
    # and the frequency, just to produce deterministic results
    solver.minimize(z3.Sum(*problem.lower_freq))

    assert solver.check() == z3.sat

    model = solver.model()
    print(f"Devices required: {model.eval(devices_required)}", file=sys.stderr)

    return problem, model
Example #12
0
def find_optimal_space(nanobots):
    (x, y, z) = (Int('x'), Int('y'), Int('z'))
    in_ranges = [
        Int('in_range_{}'.format(i)) for i in range(len(nanobots))
    ]
    range_count = Int('sum')
    optimiser = Optimize()
    for i, nanobot in enumerate(nanobots):
        optimiser.add(in_ranges[i] == If(zabs(x - nanobot.x) + zabs(y - nanobot.y) + zabs(z - nanobot.z) <= nanobot.r, 1, 0))
    optimiser.add(range_count == sum(in_ranges))
    dist_from_zero = Int('dist')
    optimiser.add(dist_from_zero == zabs(x) + zabs(y) + zabs(z))
    optimiser.maximize(range_count)
    result = optimiser.minimize(dist_from_zero)
    optimiser.check()
    return optimiser.lower(result)
def dd_solve_(dd, vr1s1, vr1s2, vr2s1, vr2s2, wavelength, ionosphere=False):
    sol = Optimize()
    r1s1, r1s2, r2s1, r2s2 = Ints('r1s1 r1s2 r2s1 r2s2')
#    err = Real('err')
    err1, err2, err3, err4 = Reals('err1 err2 err3 err4')
#    sol.add(err > 0)

    if ionosphere:
        ion = Real('ion')
        sol.add(ion > 0)
        sol.add(ion < 25)
    else:
        ion = 0

    sol.add(r1s1 - r1s2 - r2s1 + r2s2 == dd)

    sol.add(ToReal(r1s1)*wavelength + err1 > vr1s1 - ion)
    sol.add(ToReal(r1s1)*wavelength - err1 < vr1s1 - ion)

    sol.add(ToReal(r1s2)*wavelength + err2 > vr1s2 - ion)
    sol.add(ToReal(r1s2)*wavelength - err2 < vr1s2 - ion)

    sol.add(ToReal(r2s1)*wavelength + err3 > vr2s1 - ion)
    sol.add(ToReal(r2s1)*wavelength - err3 < vr2s1 - ion)

    sol.add(ToReal(r2s2)*wavelength + err4 > vr2s2 - ion)
    sol.add(ToReal(r2s2)*wavelength - err4 < vr2s2 - ion)

    objective = sol.minimize(err1 + err2 + err3 + err4)

    if sol.check() != sat:
        return None
    
    sol.lower(objective)
    if sol.check() != sat:
        return None

    return (
        [sol.model()[r].as_long() for r in [r1s1, r1s2, r2s1, r2s2]],
        [frac_to_float(sol.model()[err]) for err in [err1, err2, err3, err4]],
        frac_to_float(sol.model()[ion]) if ionosphere else 0
    )
Example #14
0
    globals()[abc[i]] = Int(abc[i])
    l.append(abc[i])
    s.add(And(d[abc[i]] >= 0, d[abc[i]] <= n - 1))

s.add(Distinct([d[x] for x in l]))

for i in superstring.split(' '):
    s.add(
        Int('diff_{0}_{1}'.format(i[0], i[1])) == diff(d.get(i[0]), d.get(
            i[1])))
    try:
        final_sum += Int('diff_{0}_{1}'.format(i[0], i[1])) * int(i[2])
    except NameError:
        final_sum = Int('diff_{0}_{1}'.format(i[0], i[1])) * int(i[2])

final_sum2 = Int("final_sum2")
s.add(final_sum == final_sum2)
s.minimize(final_sum)
s.check()
m = s.model()

a = {}

for i in l:
    a[m[d[i]].as_long()] = str(i)

for i in range(n):
    print(a[i])

print('Minimum number of cables: {0}'.format(m[final_sum2]))
Example #15
0
class Oracle(ABC):
    """
    An oracle is a dict from state_ids to values (not neccessarily probabilities since o.w. the eq system does not always have a solution).

    This is an abstract base class.
    Concrete sub-classes must overwrite `initialize`.

    Attributes:
        state_graph (StateGraph): the associated state graph
        default_value (Fraction): The default value is the oracle value returned if the given state_id is not a key of the oracle
        statistics (Statistics): access to the global statistics
        settings (Settings): all settings
        solver (Solver): a solver for the equation system
        oracle_states (Set[StateId]): states in this oracle
        oracle (Dict[StateId, z3.ExprRef]): the oracle's internal value dict
    """
    def __init__(self, state_graph: StateGraph, default_value: Fraction,
                 statistics: Statistics, settings: Settings,
                 model_type: PrismModelType):

        self.state_graph = state_graph
        self.statistics = statistics
        self.settings = settings
        self.model_type = model_type

        if default_value < 0:
            raise ValueError("Oracle values must be greater or equal to 0")

        self.default_value = RealVal(default_value)

        self.solver = Solver()
        self.solver_mdp = Optimize()

        # The way we refine the Oracle depends on the model type
        if model_type == PrismModelType.DTMC:
            self.refine_oracle = self.refine_oracle_mc

        elif model_type == PrismModelType.MDP:
            self.refine_oracle = self.refine_oracle_mdp

        else:
            raise Exception("Oracle: Unsupported model type")

        self.oracle_states: Set[StateId] = set()

        self.oracle: Dict[StateId, z3.ExprRef] = dict()

        # self.save_oracle_on_disk()

    def _ensure_value_in_oracle(self, state_id: StateId):
        """
        Used to override standard behaviour. Takes a state id, ensures that self.oracle contains this value.
        :param state_id:
        :return:
        """
        pass

    def get_oracle_value(self, state_id: StateId) -> z3.ExprRef:
        if state_id not in self.oracle:
            self._ensure_value_in_oracle(state_id)
        return self.oracle.get(state_id, self.default_value)

    def refine_oracle_mc(self, visited_states: Set[StateId]) -> Set[StateId]:

        self.statistics.inc_refine_oracle_counter()
        # First ensure progress
        if visited_states <= self.oracle_states:
            # Ensure progress by adding all non-target successors of states in oracle_states to the set
            self.oracle_states = self.oracle_states.union({
                succ_id
                for state_id in self.oracle_states for succ_id, prob in
                self.state_graph.get_filtered_successors(state_id)
                if succ_id != -1
            })

        else:
            self.oracle_states = self.oracle_states.union(visited_states)

        # TODO: A lot of optimization potential
        self.solver.push()

        # We need a variable for every oracle state
        variables = {
            state_id: Real("x_%s" % state_id)
            for state_id in self.oracle_states
        }

        # Set up EQ - System
        for state_id in self.oracle_states:
            self.solver.add(variables[state_id] == Sum([
                RealVal(1) *
                prob if succ_id == -1 else  # Case succ_id target state
                (
                    variables[succ_id] * prob if succ_id in
                    self.oracle_states else  # Case succ_id oracle state
                    self.get_oracle_value(succ_id) *
                    prob)  # Case sycc_id no target and no oracle state
                for succ_id, prob in self.state_graph.get_filtered_successors(
                    state_id)
            ]))

            self.solver.add(variables[state_id] >= RealVal(0))

        #print(self.solver.assertions())

        if self.solver.check() == sat:

            m = self.solver.model()

            # update oracle
            for state_id in self.oracle_states:
                self.oracle[state_id] = m[variables[state_id]]

            logger.info("Refined oracle.")
            #logger.info(self.oracle)

            self.solver.pop()

            return self.oracle_states

        else:

            # The oracle solver is unsat. In this case, we solve the LP.
            self.solver.pop()

            self.statistics.refine_oracle_counter = self.statistics.refine_oracle_counter - 1

            return self.refine_oracle_mdp(visited_states)

    def refine_oracle_mdp(self, visited_states: Set[StateId]) -> Set[StateId]:

        self.statistics.inc_refine_oracle_counter()
        # First ensure progress
        if visited_states <= self.oracle_states:
            # Ensure progress by adding all non-target successors of states in oracle_states to the set (for every action)
            self.oracle_states = self.oracle_states.union({
                succ[0]
                for state_id in self.oracle_states for choice in
                self.state_graph.get_successors_filtered(state_id).choices
                for succ in choice.distribution if succ[0] != -1
            })

        else:
            self.oracle_states = self.oracle_states.union(visited_states)

        # TODO: A lot of optimization potential
        self.solver_mdp.push()

        # We need a variable for every oracle state
        variables = {
            state_id: Real("x_%s" % state_id)
            for state_id in self.oracle_states
        }

        # Set up EQ - System
        for state_id in self.oracle_states:
            for choice in self.state_graph.get_successors_filtered(
                    state_id).choices:
                self.solver_mdp.add(variables[state_id] >= Sum([
                    RealVal(1) *
                    prob if succ_id == -1 else  # Case succ_id target state
                    (
                        variables[succ_id] * prob if succ_id in
                        self.oracle_states else  # Case succ_id oracle state
                        self.get_oracle_value(succ_id) *
                        prob)  # Case sycc_id no target and no oracle state
                    for succ_id, prob in choice.distribution
                ]))

            self.solver_mdp.add(variables[state_id] >= RealVal(0))

        # Minimize value for initial state
        self.solver_mdp.minimize(
            variables[self.state_graph.get_initial_state_id()])

        if self.solver_mdp.check() == sat:

            m = self.solver_mdp.model()

            # update oracle
            for state_id in self.oracle_states:
                self.oracle[state_id] = m[variables[state_id]]

            logger.info("Refined oracle.")
            # logger.info(self.oracle)

            self.solver_mdp.pop()

            return self.oracle_states

        else:
            logger.error("Oracle solver unsat")
            raise RuntimeError("Oracle solver inconsistent.")

    @abstractmethod
    def initialize(self):
        """
        Stub to be overwritten by concrete oracles.
        :return:
        """
        pass

    def save_oracle_on_disk(self):
        """
        Save this oracle to disk using `save_oracle_dict` from `pric3.oracles.file_oracle`.
        """
        from pric3.oracles.file_oracle import save_oracle_dict
        save_oracle_dict(self.state_graph, self.oracle)

    def _get_prism_program(self):
        return self.state_graph.input_program.prism_program
Example #16
0
scout_moves_from = np.array([
    list(
        chain(zip(repeat(r), L_scout_moves_from(r, c)),
              zip(repeat(r), R_scout_moves_from(r, c)),
              zip(D_scout_moves_from(r, c), repeat(c)),
              zip(U_scout_moves_from(r, c), repeat(c)))) for (r, c) in board()
]).reshape(H, W)

each_square_occupied_or_threatened_by_scout = [
    Or(is_scout[r][c],
       Or([is_scout[dr][dc] for (dr, dc) in scout_moves_from[r, c]]))
    for (r, c) in board() if (r, c) not in lakes()
]

# Clauses
s = Optimize()
s.add(no_scouts_in_lakes)
s.add(each_square_occupied_or_threatened_by_scout)

# Objective
num_scouts = Sum([If(is_scout[r][c], 1, 0) for (r, c) in board()])
min_scouts = s.minimize(num_scouts)

if s.check() == sat:
    assert s.lower(min_scouts) == 8
    print("The minimum number of scouts satisfying the constraints == %s." %
          s.lower(min_scouts))
    print(diagram(s.model()))
else:
    print("Z3 failed to find a solution.")
Example #17
0
    def solve(self, output_mode: str = None, output_file_name: str = None):
        """Formulate an SMT, pass it to z3 solver, and output results.
        CORE OF OLSQ, EDIT WITH CARE.

        Args:
            output_mode: "IR" or left to default.
            output_file_name: a file to store the IR output or qasm.
        
        Returns:
            a list of results depending on output_mode
            "IR": 
            | list_scheduled_gate_name: name/type of each gate
            | list_scheduled_gate_qubits: qubit(s) each gate acts on
            | final_mapping: logical qubit |-> physical qubit in the end 
            | objective_value: depth/#swap/fidelity depending on setting
            None:
              a qasm string
              final_mapping
              objective_value
        """

        objective_name = self.objective_name
        device = self.device
        list_gate_qubits = self.list_gate_qubits
        count_program_qubit = self.count_program_qubit
        list_gate_name = self.list_gate_name
        count_physical_qubit = self.count_physical_qubit
        list_qubit_edge = self.list_qubit_edge
        swap_duration = self.swap_duration
        bound_depth = self.bound_depth

        # pre-processing

        count_qubit_edge = len(list_qubit_edge)
        count_gate = len(list_gate_qubits)
        if self.objective_name == "fidelity":
            list_logfidelity_single = [
                int(1000 * math.log(device.list_fidelity_single[n]))
                for n in range(count_physical_qubit)]
            list_logfidelity_two = [
                int(1000 * math.log(device.list_fidelity_two[k]))
                for k in range(count_qubit_edge)]
            list_logfidelity_measure = [
                int(1000 * math.log(device.list_fidelity_measure[n]))
                for n in range(count_physical_qubit)]
        list_gate_two = list()
        list_gate_single = list()
        for l in range(count_gate):
            if len(list_gate_qubits[l]) == 1:
                list_gate_single.append(l)
            else:
                list_gate_two.append(l)

        # list_adjacency_qubit takes in a physical qubit index _p_, and
        # returns the list of indices of physical qubits adjacent to _p_
        list_adjacent_qubit = list()
        # list_span_edge takes in a physical qubit index _p_,
        # and returns the list of edges spanned from _p_
        list_span_edge = list()
        for n in range(count_physical_qubit):
            list_adjacent_qubit.append(list())
            list_span_edge.append(list())
        for k in range(count_qubit_edge):
            list_adjacent_qubit[list_qubit_edge[k][0]].append(
                                                        list_qubit_edge[k][1])
            list_adjacent_qubit[list_qubit_edge[k][1]].append(
                                                        list_qubit_edge[k][0])
            list_span_edge[list_qubit_edge[k][0]].append(k)
            list_span_edge[list_qubit_edge[k][1]].append(k)

        # if_overlap_edge takes in two edge indices _e_ and _e'_,
        # and returns whether or not they overlap
        if_overlap_edge = [[0] * count_qubit_edge
            for k in range(count_qubit_edge)]
        # list_over_lap_edge takes in an edge index _e_,
        # and returnsthe list of edges that overlap with _e_
        list_overlap_edge = list()
        # list_count_overlap_edge is the list of lengths of
        # overlap edge lists of all the _e_
        list_count_overlap_edge = list()
        for k in range(count_qubit_edge):
            list_overlap_edge.append(list())
        for k in range(count_qubit_edge):
            for kk in range(k + 1, count_qubit_edge):
                if (   (list_qubit_edge[k][0] == list_qubit_edge[kk][0]
                        or list_qubit_edge[k][0] == list_qubit_edge[kk][1])
                    or (list_qubit_edge[k][1] == list_qubit_edge[kk][0]
                        or list_qubit_edge[k][1] == list_qubit_edge[kk][1]) ):
                    list_overlap_edge[k].append(kk)
                    list_overlap_edge[kk].append(k)
                    if_overlap_edge[kk][k] = 1
                    if_overlap_edge[k][kk] = 1
        for k in range(count_qubit_edge):
            list_count_overlap_edge.append(len(list_overlap_edge[k]))

        if not self.inpput_dependency:
            list_gate_dependency = collision_extracting(list_gate_qubits)
        else:
            list_gate_dependency = self.list_gate_dependency

        # index function: takes two physical qubit indices _p_ and _p'_,
        # and returns the index of the edge between them if there is one
        map_edge_index = [[0] * count_physical_qubit] * count_physical_qubit
        for k in range(count_qubit_edge):
            map_edge_index[list_qubit_edge[k][0]][list_qubit_edge[k][1]] = k
            map_edge_index[list_qubit_edge[k][1]][list_qubit_edge[k][0]] = k

        not_solved = True
        start_time = datetime.datetime.now()
        while not_solved:
            print("Trying maximal depth = {}...".format(bound_depth))

            # variable setting 

            # at cycle t, logical qubit q is mapped to pi[q][t]
            pi = [[Int("map_q{}_t{}".format(i, j)) for j in range(bound_depth)]
                  for i in range(count_program_qubit)]

            # time coordinate for gate l is time[l]
            time = IntVector('time', count_gate)

            # space coordinate for gate l is space[l]
            space = IntVector('space', count_gate)

            # if at cycle t, a SWAP finishing on edge k, then sigma[k][t]=1
            sigma = [[Bool("ifswap_e{}_t{}".format(i, j))
                for j in range(bound_depth)] for i in range(count_qubit_edge)]

            # for depth optimization
            depth = Int('depth')

            # for swap optimization
            count_swap = Int('num_swap')

            # for fidelity optimization
            if objective_name == "fidelity":
                u = [Int("num_1qbg_p{}".format(n))
                     for n in range(count_physical_qubit)]
                v = [Int("num_2qbg_e{}".format(k))
                     for k in range(count_qubit_edge)]
                vv = [Int("num_swap_e{}".format(k))
                      for k in range(count_qubit_edge)]
                w = [Int("num_meas_p{}".format(n))
                     for n in range(count_physical_qubit)]
                fidelity = Int('log_fidelity')

            lsqc = Optimize()

            # constraint setting

            for t in range(bound_depth):
                for m in range(count_program_qubit):
                    lsqc.add(pi[m][t] >= 0, pi[m][t] < count_physical_qubit)
                    for mm in range(m):
                        lsqc.add(pi[m][t] != pi[mm][t])

            for l in range(count_gate):
                lsqc.add(time[l] >= 0, time[l] < bound_depth)
                if l in list_gate_single:
                    lsqc.add(space[l] >= 0, space[l] < count_physical_qubit)
                    for t in range(bound_depth):
                        lsqc.add(Implies(time[l] == t,
                            pi[list_gate_qubits[l][0]][t] == space[l]))
                elif l in list_gate_two:
                    lsqc.add(space[l] >= 0, space[l] < count_qubit_edge)
                    for k in range(count_qubit_edge):
                        for t in range(bound_depth):
                            lsqc.add(Implies(And(time[l] == t, space[l] == k),
                                Or(And(list_qubit_edge[k][0] == \
                                        pi[list_gate_qubits[l][0]][t],
                                    list_qubit_edge[k][1] == \
                                        pi[list_gate_qubits[l][1]][t]),
                                And(list_qubit_edge[k][1] == \
                                        pi[list_gate_qubits[l][0]][t],
                                    list_qubit_edge[k][0] == \
                                        pi[list_gate_qubits[l][1]][t])  )    ))

            for d in list_gate_dependency:
                if self.if_transition_based:
                    lsqc.add(time[d[0]] <= time[d[1]])
                else:
                    lsqc.add(time[d[0]] < time[d[1]])

            for t in range(min(swap_duration - 1, bound_depth)):
                for k in range(count_qubit_edge):
                    lsqc.add(sigma[k][t] == False)

            for t in range(swap_duration - 1, bound_depth):
                for k in range(count_qubit_edge):
                    for tt in range(t - swap_duration + 1, t):
                        lsqc.add(Implies(sigma[k][t] == True,
                            sigma[k][tt] == False))
                    for tt in range(t - swap_duration + 1, t + 1):
                        for kk in list_overlap_edge[k]:
                            lsqc.add(Implies(sigma[k][t] == True,
                                sigma[kk][tt] == False))

            if not self.if_transition_based:
                for t in range(swap_duration - 1, bound_depth):
                    for k in range(count_qubit_edge):
                        for tt in range(t - swap_duration + 1, t + 1):
                            for l in range(count_gate):
                                if l in list_gate_single:
                                    lsqc.add(Implies(And(time[l] == tt,
                                        Or(space[l] == list_qubit_edge[k][0],
                                           space[l] == list_qubit_edge[k][1])),
                                            sigma[k][t] == False             ))
                                elif l in list_gate_two:
                                    lsqc.add(Implies(And(
                                        time[l] == tt, space[l] == k),
                                            sigma[k][t] == False           ))
                                    for kk in list_overlap_edge[k]:
                                        lsqc.add(Implies(And(
                                            time[l] == tt, space[l] == kk),
                                                sigma[k][t] == False       ))

            for t in range(bound_depth - 1):
                for n in range(count_physical_qubit):
                    for m in range(count_program_qubit):
                        lsqc.add(
                            Implies(And(sum([If(sigma[k][t], 1, 0)
                                for k in list_span_edge[n]]) == 0,
                                    pi[m][t] == n), pi[m][t + 1] == n))

            for t in range(bound_depth - 1):
                for k in range(count_qubit_edge):
                    for m in range(count_program_qubit):
                        lsqc.add(Implies(And(sigma[k][t] == True,
                            pi[m][t] == list_qubit_edge[k][0]),
                                pi[m][t + 1] == list_qubit_edge[k][1]))
                        lsqc.add(Implies(And(sigma[k][t] == True,
                            pi[m][t] == list_qubit_edge[k][1]),
                                pi[m][t + 1] == list_qubit_edge[k][0]))

            lsqc.add(
                count_swap == sum([If(sigma[k][t], 1, 0)
                    for k in range(count_qubit_edge)
                        for t in range(bound_depth)]))

            # for depth optimization
            for l in range(count_gate):
                lsqc.add(depth >= time[l] + 1)

            if objective_name == "swap":
                lsqc.minimize(count_swap)
            elif objective_name == "depth":
                lsqc.minimize(depth)
            elif objective_name == "fidelity":
                for n in range(count_physical_qubit):
                    lsqc.add(u[n] == sum([If(space[l] == n, 1, 0)
                        for l in list_gate_single]))
                    lsqc.add(w[n] == sum([If(pi[m][bound_depth - 1] == n, 1, 0)
                        for m in range(count_program_qubit)]))
                for k in range(count_qubit_edge):
                    lsqc.add(v[k] == sum([If(space[l] == k, 1, 0)
                        for l in list_gate_two]))
                    lsqc.add(vv[k] == sum([If(sigma[k][t], 1, 0)
                        for t in range(bound_depth)]))

                lsqc.add(fidelity == sum([v[k] * list_logfidelity_two[k]
                    for k in range(count_qubit_edge)])
                    + sum([
                        swap_duration * vv[k] * list_logfidelity_two[k]
                        for k in range(count_qubit_edge)])
                    + sum([w[n] * list_logfidelity_measure[n]
                        for n in range(count_physical_qubit)])
                    + sum([u[n] * list_logfidelity_single[n]
                        for n in range(count_physical_qubit)])          )
                lsqc.maximize(fidelity)
            else:
                raise Exception("Invalid Objective Name")

            satisfiable = lsqc.check()
            if satisfiable == sat:
                not_solved = False
            else:
                if self.if_transition_based:
                    bound_depth += 1
                else:
                    bound_depth = int(1.3 * bound_depth)

        print(f"Compilation time = {datetime.datetime.now() - start_time}.")
        model = lsqc.model()

        # post-processing

        result_time = []
        result_depth = model[depth].as_long()
        for l in range(count_gate):
            result_time.append(model[time[l]].as_long())
        list_result_swap = []
        for k in range(count_qubit_edge):
            for t in range(result_depth):
                if model[sigma[k][t]]:
                    list_result_swap.append((k, t))
                    print(f"SWAP on physical edge ({list_qubit_edge[k][0]},"\
                        + f"{list_qubit_edge[k][1]}) at time {t}")
        for l in range(count_gate):
            if len(list_gate_qubits[l]) == 1:
                qq = list_gate_qubits[l][0]
                tt = result_time[l]
                print(f"Gate {l}: {list_gate_name[l]} {qq} on qubit "\
                    + f"{model[pi[qq][tt]].as_long()} at time {tt}")
            else:
                qq = list_gate_qubits[l][0]
                qqq = list_gate_qubits[l][1]
                tt = result_time[l]
                print(f"Gate {l}: {list_gate_name[l]} {qq}, {qqq} on qubits "\
                    + f"{model[pi[qq][tt]].as_long()} and "\
                    + f"{model[pi[qqq][tt]].as_long()} at time {tt}")


        # transition based
        if self.if_transition_based:
            self.swap_duration = self.device.swap_duration
            map_to_block = dict()
            real_time = [0 for i in range(count_gate)]
            list_depth_on_qubit = [-1 for i in range(self.count_physical_qubit)]
            list_real_swap = []
            for block in range(result_depth):
                for tmp_gate in range(count_gate):
                    if result_time[tmp_gate] == block:
                        qubits = list_gate_qubits[tmp_gate]
                        if len(qubits) == 1:
                            p0 = model[pi[qubits[0]][block]].as_long()
                            real_time[tmp_gate] = \
                                list_depth_on_qubit[p0] + 1
                            list_depth_on_qubit[p0] = \
                                real_time[tmp_gate]
                            map_to_block[real_time[tmp_gate]] = block
                        else:
                            p0 = model[pi[qubits[0]][block]].as_long()
                            p1 = model[pi[qubits[1]][block]].as_long()
                            real_time[tmp_gate] = max(
                                list_depth_on_qubit[p0],
                                list_depth_on_qubit[p1]) + 1
                            list_depth_on_qubit[p0] = \
                                real_time[tmp_gate]
                            list_depth_on_qubit[p1] = \
                                real_time[tmp_gate]
                            map_to_block[real_time[tmp_gate]] = block
                            # print(f"{tmp_gate} {p0} {p1} real-time={real_time[tmp_gate]}")

                if block < result_depth - 1:
                    for (k, t) in list_result_swap:
                        if t == block:
                            p0 = list_qubit_edge[k][0]
                            p1 = list_qubit_edge[k][1]
                            tmp_time = max(list_depth_on_qubit[p0],
                                list_depth_on_qubit[p1]) \
                                + self.swap_duration
                            list_depth_on_qubit[p0] = tmp_time
                            list_depth_on_qubit[p1] = tmp_time
                            list_real_swap.append((k, tmp_time))
                # print(list_depth_on_qubit)
            result_time = real_time
            real_depth = 0
            for tmp_depth in list_depth_on_qubit:
                if real_depth < tmp_depth + 1:
                    real_depth = tmp_depth + 1
            result_depth = real_depth
            list_result_swap = list_real_swap
            # print(list_result_swap)
        
        objective_value = 0
        if objective_name == "fidelity":
            objective_value = model[fidelity].as_long()
            print(f"result fidelity = {math.exp(objective_value / 1000.0)}")
        elif objective_name == "swap":
            objective_value = len(list_result_swap)
            print(f"result additional SWAP count = {objective_value}.")
        else:
            objective_value = model[depth].as_long()
            print(f"result circuit depth = {objective_value}.")

        list_scheduled_gate_qubits = [[] for i in range(result_depth)]
        list_scheduled_gate_name = [[] for i in range(result_depth)]
        result_depth = 0
        for l in range(count_gate):
            t = result_time[l]

            if result_depth < t + 1:
                result_depth = t + 1

            list_scheduled_gate_name[t].append(list_gate_name[l])
            if l in list_gate_single:
                q = model[space[l]].as_long()
                list_scheduled_gate_qubits[t].append((q,))
            elif l in list_gate_two:
                [q0, q1] = list_gate_qubits[l]
                tmp_t = t
                if self.if_transition_based:
                    tmp_t = map_to_block[t]
                q0 = model[pi[q0][tmp_t]].as_long()
                q1 = model[pi[q1][tmp_t]].as_long()
                list_scheduled_gate_qubits[t].append((q0, q1))
            else:
                raise ValueError("Expect single-qubit or two-qubit gate.")

        final_mapping = []
        for m in range(count_program_qubit):
            tmp_depth = result_depth - 1
            if self.if_transition_based:
                tmp_depth = map_to_block[result_depth - 1]
            final_mapping.append(model[pi[m][tmp_depth]].as_long())

        for (k, t) in list_result_swap:
            q0 = list_qubit_edge[k][0]
            q1 = list_qubit_edge[k][1]
            if self.swap_duration == 1:
                list_scheduled_gate_qubits[t].append((q0, q1))
                list_scheduled_gate_name[t].append("SWAP")
            elif self.swap_duration == 3:
                list_scheduled_gate_qubits[t].append((q0, q1))
                list_scheduled_gate_name[t].append("cx")
                list_scheduled_gate_qubits[t - 1].append((q1, q0))
                list_scheduled_gate_name[t - 1].append("cx")
                list_scheduled_gate_qubits[t - 2].append((q0, q1))
                list_scheduled_gate_name[t - 2].append("cx")
            else:
                raise ValueError("Expect SWAP duration one, or three")

        if output_mode == "IR":
            if output_file_name:
                output_file = open(output_file_name, 'w')
                output_file.writelines([list_scheduled_gate_name,
                                        list_scheduled_gate_qubits,
                                        final_mapping,
                                        objective_value])
            return (result_depth,
                    list_scheduled_gate_name,
                    list_scheduled_gate_qubits,
                    final_mapping,
                    objective_value)
        else:
            return (output_qasm(device, result_depth, list_scheduled_gate_name,
                                list_scheduled_gate_qubits, final_mapping,
                                True, output_file_name),
                    final_mapping,
                    objective_value)
Example #18
0
class StateProbabilityGenerator:

    def __init__(self, state_graph, statistics, settings, model_type):
        self.statistics = statistics
        self.state_graph = state_graph
        self.model_type = model_type

        logger.debug("Initialize oracle...")

        self._initialize_oracle(settings)

        logger.debug("Initialize obligation cache...")
        self._obligation_cache = ObligationCache()
        logger.debug("Initialize optimization solver...")
        # Initialize solver for optimization queries
        self.opt_solver = Optimize()

        self._realval_zero = RealVal(0)
        self._realval_one = RealVal(1)

        self.obligation_queue_class = settings.get_obligation_queue_class()

    def _initialize_oracle(self, settings):

        self.statistics.start_initialize_oracle_timer()

        args = [self.state_graph,settings.default_oracle_value,self.statistics,settings, self.model_type]
        if settings.oracle_type == "simulation":
            self.oracle = SimulationOracle(*args)
        elif settings.oracle_type == "perfect":
            self.oracle = ExactOracle(*args)
        elif settings.oracle_type == "modelchecking":
            self.oracle = ModelCheckingOracle(*args)
        elif settings.oracle_type == "solveeqspartly_exact" or settings.oracle_type == "solveeqspartly_inexact":
            self.oracle = SolveEQSPartlyOracle(*args)
        elif settings.oracle_type == "file":
            self.oracle = FileOracle(*args)
        else:
            raise RuntimeError("Unclear which oracle to use.")
        self.oracle.initialize()

        self.statistics.stop_initialize_oracle_timer()

    def refine_oracle(self, visited_states):
        res = self.oracle.refine_oracle(visited_states)
        self.reset_cache()
        return res

    def reset_cache(self):
        logger.debug("Reset obligation cache ...")
        self._obligation_cache.reset_cache()

    def finalize_statistics(self):
        self.statistics.set_number_oracle_states(len(self.oracle.oracle_states))

    def run(self, state_id, chosen_command, delta, states_with_fixed_probabilities = set()):
        """

        :param state_id: 
        :param delta: 
        :return: (1) True iff it is possible to find probabilities for the successors of the given state_id and delta.
                 (2) If True, then it returns a dict form succ_ids to probabilities. This dict does not contain goal states.
        """
        # TODO consider changing to None if not possible, and dict otherwise.
        self.statistics.inc_get_probability_counter()
        self.statistics.start_get_probability_timer()

        # First check whether we have cached the corresponding obligation
        res = self._obligation_cache.get_cached(state_id, chosen_command, delta)

        if res != False:
            self.statistics.stop_get_probability_timer()
            return (True, res)

        # If not, we have to ask the SMT-Solver
        succ_dist = self.state_graph.get_successors_filtered(state_id).by_command_index(chosen_command)

        succ_dist_without_target_states = [(state_id, prob)
                                           for (state_id, prob) in succ_dist
                                           if state_id != -1]

        # Check if there is at least one non-target state. Otherwise, repairing is not possible (smt solver would return unsat if we continued, so checking this is an optimization).
        if len(succ_dist_without_target_states) == 0:
            self.statistics.stop_get_probability_timer()
            return (False, None)

        self.opt_solver.push()
        vars = {}

        # We need a variable for each successor
        for (succ_id, prob) in succ_dist:
            if succ_id != -1:
                vars[succ_id] = Real("x_%s" % succ_id)

                # all results must of be probabilities
                self.opt_solver.add(vars[succ_id] >= self._realval_zero)
                self.opt_solver.add(vars[succ_id] <= self._realval_one)

        # \Phi(F)[s] = delta constraint
        # TODO: Type of porb is pycarl.gmp.gmp.Rational. Z3 magically deals with this
        self.opt_solver.add(
            Sum([
                (vars[succ_id] if succ_id != -1 else RealVal(1)) * prob
                # Note: Keep in mind that you need to check whether succ is a target state
                for (succ_id, prob) in succ_dist
            ]) == delta)

        for (succ_id, prob) in succ_dist:
            if succ_id in states_with_fixed_probabilities:
                self.opt_solver.add(vars[succ_id] == self.obligation_queue_class.smallest_probability_for_state[succ_id])


        # If we have more than one non-target successor, we have to optimize
        if len(succ_dist_without_target_states) > 1:

            # first check whether all oracle values are 0 (note that we do not have to do this if there is only one succ without target)

            if len(succ_dist_without_target_states) > 1 and sum([self.oracle.get_oracle_value(state_id).as_fraction() for state_id, prob in
                    succ_dist_without_target_states]) == 0:

                # In this case, we require that the probability mass is distributed equally
                for i in range(0, len(succ_dist_without_target_states) - 1):
                    self.opt_solver.add(
                        vars[succ_dist_without_target_states[i][0]] == vars[succ_dist_without_target_states[i + 1][0]])

            else:

                # First Try to solve the eq system
                # TODO: Do not use opt_solver for this
                if self._get_probabilities_by_solving_eq_system(succ_dist_without_target_states, vars):

                    self.statistics.inc_solved_eq_system_instead_of_optimization_counter()
                    m = self.opt_solver.model()

                    result = {
                        succ_id: m[vars[succ_id]]
                        for (succ_id, prob) in succ_dist_without_target_states
                    }

                    # Because get_probabilities_by_solving_eq_system pushes
                    # TODO: This is ugly
                    # TODO: Compare solve-eq-system-time with optimization-problem-time
                    self.opt_solver.pop()
                    self.opt_solver.pop()

                    self._obligation_cache.cache(state_id, chosen_command, delta, result)
                    self.statistics.stop_get_probability_timer()
                    return (True, result)

                else:

                    self.statistics.inc_had_to_solve_optimization_problem_counter()
                    # for each non-target-succ, we need n opt-var
                    opt_vars = {}

                    # For every non-target successor, we need an optimization variable
                    for (succ_id, prob) in succ_dist_without_target_states:
                        opt_vars[succ_id] = Real("opt_var_%s" % succ_id)

                    # Now assert that opt_var_i = |var_i \ (var_1 + ... + var_n)   -   oracle(s_i) \ ( oracle(s_1) + ... + oracle(s_n ) |
                    # for every opt_var_i
                    for (succ_id, prob) in succ_dist_without_target_states:
                        # opt_var is the absolute value of the ratio
                        self.opt_solver.add(
                            If(((vars[succ_id] * Sum([
                                self.oracle.get_oracle_value(succ_id_2) for
                                (succ_id_2, prob) in succ_dist_without_target_states
                            ])) - ((self.oracle.get_oracle_value(succ_id) * Sum([
                                vars[succ_id_2] for
                                (succ_id_2, prob) in succ_dist_without_target_states
                            ])))) < 0, opt_vars[succ_id] ==
                               (((self.oracle.get_oracle_value(succ_id) * Sum([
                                   vars[succ_id_2] for
                                   (succ_id_2, prob) in succ_dist_without_target_states
                               ]))) - (vars[succ_id] * Sum([
                                   self.oracle.get_oracle_value(succ_id_2) for
                                   (succ_id_2, prob) in succ_dist_without_target_states
                               ]))), opt_vars[succ_id] == ((vars[succ_id] * Sum([
                                self.oracle.get_oracle_value(succ_id_2) for
                                (succ_id_2, prob) in succ_dist_without_target_states
                            ])) - ((self.oracle.get_oracle_value(succ_id) * Sum([
                                vars[succ_id_2] for
                                (succ_id_2, prob) in succ_dist_without_target_states
                            ]))))))

                        # minimize sum of opt-vars
                        opt = self.opt_solver.minimize(
                            Sum([
                                opt_vars[succ_id]
                                for (succ_id, prob) in succ_dist_without_target_states
                            ]))

        if self.opt_solver.check() == sat:
            # We found probabilities or the successors
            m = self.opt_solver.model()

            result = {
                succ_id: m[vars[succ_id]]
                for (succ_id, prob) in succ_dist_without_target_states
            }
            self.opt_solver.pop()

            self._obligation_cache.cache(state_id, chosen_command, delta, result)

            self.statistics.stop_get_probability_timer()

            return (True, result)

        else:
            # There are no such probabilities
            self.opt_solver.pop()
            self.statistics.stop_get_probability_timer()

            return (False, None)

    def _get_probabilities_by_solving_eq_system(self, succ_dist_without_target_states, vars):

        self.opt_solver.push()
        #TODO is this correct?
        lhs_sum = Sum([
                    self.oracle.get_oracle_value(succ_id_2) for
                    (succ_id_2, _) in succ_dist_without_target_states
                ])
        rhs_sum = Sum([
                    vars[succ_id_2] for
                    (succ_id_2, _) in succ_dist_without_target_states
                ])

        def _multiply(left,right):
            args = (Ast * 2)()
            args[0] = left.as_ast()
            args[1] = right.as_ast()
            return ArithRef(Z3_mk_mul(left.ctx.ref(), 2, args), left.ctx)


        for (succ_id, prob) in succ_dist_without_target_states:
            # opt_var is the absolute value of the ratio
            lhs = _multiply(vars[succ_id], lhs_sum)
            rhs = _multiply(self.oracle.get_oracle_value(succ_id), rhs_sum)
            equality = lhs == rhs
            self.opt_solver.add(equality)

        if self.opt_solver.check() == sat:
            return True

        else:
            self.opt_solver.pop()
            return False
Example #19
0
with open('../input/23.txt') as f:
    nanobots = [list(map(int, re.findall(r'-?\d+', line))) for line in f]

x, y, z, r = max(nanobots, key=lambda x: x[-1])
print(sum(
    abs(x - a) + abs(y - b) + abs(z - c) <= r for a, b, c, _ in nanobots))

from z3 import Int, If, Optimize


def Abs(x):
    return If(x >= 0, x, -x)


def Dist(x, y, z, a, b, c):
    return Abs(x - a) + Abs(y - b) + Abs(z - c)


X = x, y, z = Int('x'), Int('y'), Int('z')
cost = Int('cost')
constraint = x * 0
for *Y, r in nanobots:
    constraint += If(Dist(*X, *Y) <= r, 1, 0)

opt = Optimize()
opt.add(cost == constraint)
h1 = opt.maximize(cost)
h2 = opt.minimize(Dist(*(0, 0, 0), *X))
opt.check()
print(opt.lower(h2))
Example #20
0
    def solve(self, output_mode=None, output_file_name=None):
        objective_name = self.objective_name

        device = self.device
        list_gate_qubits = self.list_gate_qubits
        count_program_qubit = self.count_program_qubit
        list_gate_name = self.list_gate_name
        count_physical_qubit = self.count_physical_qubit
        list_qubit_edge = self.list_qubit_edge
        swap_duration = self.swap_duration
        bound_depth = self.bound_depth
        """
        pre-processing
        """
        count_qubit_edge = len(list_qubit_edge)
        count_gate = len(list_gate_qubits)
        if self.objective_name == "fidelity":
            list_logfidelity_single = [
                int(1000 * math.log(device.list_fidelity_single[n]))
                for n in range(count_physical_qubit)
            ]
            list_logfidelity_two = [
                int(1000 * math.log(device.list_fidelity_two[k]))
                for k in range(count_qubit_edge)
            ]
            list_logfidelity_measure = [
                int(1000 * math.log(device.list_fidelity_measure[n]))
                for n in range(count_physical_qubit)
            ]
        list_gate_two = list()
        list_gate_single = list()
        for l in range(count_gate):
            if isinstance(list_gate_qubits[l], int):
                list_gate_single.append(l)
            else:
                list_gate_two.append(l)

        # list_adjacency_qubit takes in a physical qubit index _p_, and returns the list of indices of
        # physical qubits adjacent to _p_
        list_adjacent_qubit = list()
        # list_span_edge takes in a physical qubit index _p_, and returns the list of edges spanned from _p_
        list_span_edge = list()
        for n in range(count_physical_qubit):
            list_adjacent_qubit.append(list())
            list_span_edge.append(list())
        for k in range(count_qubit_edge):
            list_adjacent_qubit[list_qubit_edge[k][0]].append(
                list_qubit_edge[k][1])
            list_adjacent_qubit[list_qubit_edge[k][1]].append(
                list_qubit_edge[k][0])
            list_span_edge[list_qubit_edge[k][0]].append(k)
            list_span_edge[list_qubit_edge[k][1]].append(k)

        # if_overlap_edge takes in two edge indices _e_ and _e'_, and returns whether or not they overlap
        if_overlap_edge = [[0] * count_qubit_edge
                           for k in range(count_qubit_edge)]
        # list_over_lap_edge takes in an edge index _e_, and returns the list of edges that overlap with _e_
        list_overlap_edge = list()
        # list_count_overlap_edge is the list of lengths of overlap edge lists of all the _e_
        list_count_overlap_edge = list()
        for k in range(count_qubit_edge):
            list_overlap_edge.append(list())
        for k in range(count_qubit_edge):
            for kk in range(k + 1, count_qubit_edge):
                if (list_qubit_edge[k][0] == list_qubit_edge[kk][0]
                    or list_qubit_edge[k][0] == list_qubit_edge[kk][1]) \
                        or (list_qubit_edge[k][1] == list_qubit_edge[kk][0]
                            or list_qubit_edge[k][1] == list_qubit_edge[kk][1]):
                    list_overlap_edge[k].append(kk)
                    list_overlap_edge[kk].append(k)
                    if_overlap_edge[kk][k] = 1
                    if_overlap_edge[k][kk] = 1
        for k in range(count_qubit_edge):
            list_count_overlap_edge.append(len(list_overlap_edge[k]))

        # list_gate_dependency is the list of dependency, pairs of gate indices (_l_, _l'_), where _l_<_l'_
        # _l_ and _ll_ act on a same program qubit
        list_gate_dependency = collision_extracting(list_gate_qubits)

        # index function: it takes two physical qubit indices _p_ and _p'_,
        # and returns the index of the edge between _p_ and _p'_, if there is one
        map_edge_index = [[0] * count_physical_qubit] * count_physical_qubit
        for k in range(count_qubit_edge):
            map_edge_index[list_qubit_edge[k][0]][list_qubit_edge[k][1]] = k
            map_edge_index[list_qubit_edge[k][1]][list_qubit_edge[k][0]] = k

        not_solved = True
        while not_solved:
            print("Trying maximal depth = {}...".format(bound_depth))
            """
            variables
            """

            # at cycle t, logical qubit q is mapped to pi[q][t]
            pi = [[
                Int("map_q{}_t{}".format(i, j)) for j in range(bound_depth)
            ] for i in range(count_program_qubit)]

            # time coordinate for gate l is time[l]
            time = IntVector('time', count_gate)

            # space coordinate for gate l is space[l]
            space = IntVector('space', count_gate)

            # if at cycle t, there is a SWAP finishing on edge k, then sigma[k][t]=1
            sigma = [[
                Bool("ifswap_e{}_t{}".format(i, j)) for j in range(bound_depth)
            ] for i in range(count_qubit_edge)]

            # for depth optimization
            depth = Int('depth')

            # for swap optimization
            count_swap = Int('num_swap')

            # for fidelity optimization
            if objective_name == "fidelity":
                u = [
                    Int("num_1qbg_p{}".format(n))
                    for n in range(count_physical_qubit)
                ]
                v = [
                    Int("num_2qbg_e{}".format(k))
                    for k in range(count_qubit_edge)
                ]
                vv = [
                    Int("num_swap_e{}".format(k))
                    for k in range(count_qubit_edge)
                ]
                w = [
                    Int("num_meas_p{}".format(n))
                    for n in range(count_physical_qubit)
                ]
                fidelity = Int('log_fidelity')

            lsqc = Optimize()
            """
            Constraints
            """

            for t in range(bound_depth):
                for m in range(count_program_qubit):
                    lsqc.add(pi[m][t] >= 0, pi[m][t] < count_physical_qubit)
                    for mm in range(m):
                        lsqc.add(pi[m][t] != pi[mm][t])

            for l in range(count_gate):
                lsqc.add(time[l] >= 0, time[l] < bound_depth)
                if l in list_gate_single:
                    lsqc.add(space[l] >= 0, space[l] < count_physical_qubit)
                    for t in range(bound_depth):
                        lsqc.add(
                            Implies(time[l] == t,
                                    pi[list_gate_qubits[l]][t] == space[l]))
                elif l in list_gate_two:
                    lsqc.add(space[l] >= 0, space[l] < count_qubit_edge)
                    for k in range(count_qubit_edge):
                        for t in range(bound_depth):
                            lsqc.add(
                                Implies(
                                    And(time[l] == t, space[l] == k),
                                    Or(
                                        And(
                                            list_qubit_edge[k][0] == pi[
                                                list_gate_qubits[l][0]][t],
                                            list_qubit_edge[k][1] == pi[
                                                list_gate_qubits[l][1]][t]),
                                        And(
                                            list_qubit_edge[k][1] == pi[
                                                list_gate_qubits[l][0]][t],
                                            list_qubit_edge[k][0] == pi[
                                                list_gate_qubits[l][1]][t]))))

            for d in list_gate_dependency:
                if self.if_transition_based == True:
                    lsqc.add(time[d[0]] <= time[d[1]])
                else:
                    lsqc.add(time[d[0]] < time[d[1]])

            for t in range(min(swap_duration - 1, bound_depth)):
                for k in range(count_qubit_edge):
                    lsqc.add(sigma[k][t] == False)

            for t in range(swap_duration - 1, bound_depth):
                for k in range(count_qubit_edge):
                    for tt in range(t - swap_duration + 1, t):
                        lsqc.add(
                            Implies(sigma[k][t] == True,
                                    sigma[k][tt] == False))
                    for tt in range(t - swap_duration + 1, t + 1):
                        for kk in list_overlap_edge[k]:
                            lsqc.add(
                                Implies(sigma[k][t] == True,
                                        sigma[kk][tt] == False))

            if self.if_transition_based == False:
                for t in range(swap_duration - 1, bound_depth):
                    for k in range(count_qubit_edge):
                        for tt in range(t - swap_duration + 1, t + 1):
                            for l in range(count_gate):
                                if l in list_gate_single:
                                    lsqc.add(
                                        Implies(
                                            And(
                                                time[l] == tt,
                                                Or(
                                                    space[l] ==
                                                    list_qubit_edge[k][0],
                                                    space[l] ==
                                                    list_qubit_edge[k][1])),
                                            sigma[k][t] == False))
                                elif l in list_gate_two:
                                    lsqc.add(
                                        Implies(
                                            And(time[l] == tt, space[l] == k),
                                            sigma[k][t] == False))
                                    for kk in list_overlap_edge[k]:
                                        lsqc.add(
                                            Implies(
                                                And(time[l] == tt,
                                                    space[l] == kk),
                                                sigma[k][t] == False))

            for t in range(bound_depth - 1):
                for n in range(count_physical_qubit):
                    for m in range(count_program_qubit):
                        lsqc.add(
                            Implies(
                                And(
                                    sum([
                                        If(sigma[k][t], 1, 0)
                                        for k in list_span_edge[n]
                                    ]) == 0, pi[m][t] == n),
                                pi[m][t + 1] == n))

            for t in range(bound_depth - 1):
                for k in range(count_qubit_edge):
                    for m in range(count_program_qubit):
                        lsqc.add(
                            Implies(
                                And(sigma[k][t] == True,
                                    pi[m][t] == list_qubit_edge[k][0]),
                                pi[m][t + 1] == list_qubit_edge[k][1]))
                        lsqc.add(
                            Implies(
                                And(sigma[k][t] == True,
                                    pi[m][t] == list_qubit_edge[k][1]),
                                pi[m][t + 1] == list_qubit_edge[k][0]))

            lsqc.add(count_swap == sum([
                If(sigma[k][t], 1, 0) for k in range(count_qubit_edge)
                for t in range(bound_depth)
            ]))

            # for depth optimization
            for l in range(count_gate):
                lsqc.add(depth >= time[l] + 1)

            if objective_name == "swap":
                lsqc.minimize(count_swap)
            elif objective_name == "depth":
                lsqc.minimize(depth)
            elif objective_name == "fidelity":
                for n in range(count_physical_qubit):
                    lsqc.add(u[n] == sum(
                        [If(space[l] == n, 1, 0) for l in list_gate_single]))
                    lsqc.add(w[n] == sum([
                        If(pi[m][bound_depth - 1] == n, 1, 0)
                        for m in range(count_program_qubit)
                    ]))
                for k in range(count_qubit_edge):
                    lsqc.add(v[k] == sum(
                        [If(space[l] == k, 1, 0) for l in list_gate_two]))
                    lsqc.add(vv[k] == sum(
                        [If(sigma[k][t], 1, 0) for t in range(bound_depth)]))

                lsqc.add(fidelity == sum([
                    v[k] * list_logfidelity_two[k]
                    for k in range(count_qubit_edge)
                ]) + sum([
                    swap_duration * vv[k] * list_logfidelity_two[k]
                    for k in range(count_qubit_edge)
                ]) + sum([
                    w[n] * list_logfidelity_measure[n]
                    for n in range(count_physical_qubit)
                ]) + sum([
                    u[n] * list_logfidelity_single[n]
                    for n in range(count_physical_qubit)
                ]))
                lsqc.maximize(fidelity)
            else:
                raise Exception("Invalid Objective Name")

            satisfiable = lsqc.check()
            if satisfiable == sat:
                not_solved = False
            else:
                if self.if_transition_based == True:
                    bound_depth += 1
                else:
                    bound_depth = int(1.3 * bound_depth)

        # print("Compilation time = {}s.".format(sys_time.time() - start_time))
        model = lsqc.model()
        """
        post-processing
        """

        result_time = []
        result_depth = model[depth].as_long()
        for l in range(count_gate):
            result_time.append(model[time[l]].as_long())
        list_result_swap = []
        for k in range(count_qubit_edge):
            for t in range(result_depth):
                if model[sigma[k][t]]:
                    list_result_swap.append((k, t))

        # transition based
        if self.if_transition_based:
            self.swap_duration = self.device.swap_duration
            map_to_block = dict()
            real_time = [0 for i in range(count_gate)]
            list_depth_on_qubit = [-1 for i in range(self.count_program_qubit)]
            list_real_swap = []
            for block in range(result_depth):
                for tmp_gate in range(count_gate):
                    if result_time[tmp_gate] == block:
                        qubits = list_gate_qubits[tmp_gate]
                        if isinstance(qubits, int):
                            real_time[
                                tmp_gate] = list_depth_on_qubit[qubits] + 1
                            list_depth_on_qubit[qubits] = real_time[tmp_gate]
                            map_to_block[real_time[tmp_gate]] = block
                        else:
                            real_time[tmp_gate] = list_depth_on_qubit[
                                qubits[0]] + 1
                            if real_time[tmp_gate] < list_depth_on_qubit[
                                    qubits[1]] + 1:
                                real_time[tmp_gate] = list_depth_on_qubit[
                                    qubits[1]] + 1
                            list_depth_on_qubit[
                                qubits[0]] = real_time[tmp_gate]
                            list_depth_on_qubit[
                                qubits[1]] = real_time[tmp_gate]
                            map_to_block[real_time[tmp_gate]] = block

                if block < result_depth - 1:
                    for (k, t) in list_result_swap:
                        if t == block:
                            q0 = list_qubit_edge[k][0]
                            q1 = list_qubit_edge[k][1]
                            tmp_time = list_depth_on_qubit[
                                q0] + self.swap_duration
                            if tmp_time < list_depth_on_qubit[
                                    q1] + self.swap_duration:
                                tmp_time = list_depth_on_qubit[
                                    q1] + self.swap_duration
                            list_depth_on_qubit[q0] = tmp_time
                            list_depth_on_qubit[q1] = tmp_time
                            list_real_swap.append((k, tmp_time))

            result_time = real_time
            real_depth = 0
            for tmp_depth in list_depth_on_qubit:
                if real_depth < tmp_depth + 1:
                    real_depth = tmp_depth + 1
            result_depth = real_depth
            list_result_swap = list_real_swap

        if objective_name == "fidelity":
            log_fidelity = model[fidelity].as_long()
            print("result fidelity = {}".format(math.exp(log_fidelity /
                                                         1000.0)))
        elif objective_name == "swap":
            print("result additional SWAP count = {}.".format(
                len(list_result_swap)))
        else:
            print("result circuit depth = {}.".format(result_depth))

        list_scheduled_gate_qubits = [[] for i in range(result_depth)]
        list_scheduled_gate_name = [[] for i in range(result_depth)]
        result_depth = 0
        for l in range(count_gate):
            t = result_time[l]

            if result_depth < t + 1:
                result_depth = t + 1

            list_scheduled_gate_name[t].append(list_gate_name[l])
            if l in list_gate_single:
                q = model[space[l]].as_long()
                list_scheduled_gate_qubits[t].append(q)
            elif l in list_gate_two:
                [q0, q1] = list_gate_qubits[l]
                tmp_t = t
                if self.if_transition_based:
                    tmp_t = map_to_block[t]
                q0 = model[pi[q0][tmp_t]].as_long()
                q1 = model[pi[q1][tmp_t]].as_long()
                list_scheduled_gate_qubits[t].append([q0, q1])
            else:
                raise Exception("Expect single- or two-qubit gate.")

        final_mapping = []
        for m in range(count_program_qubit):
            tmp_depth = result_depth - 1
            if self.if_transition_based:
                tmp_depth = map_to_block[result_depth - 1]
            final_mapping.append(model[pi[m][tmp_depth]].as_long())
            # print("logical qubit {} is mapped to node {} in the beginning, node {} at the end".format(
            #    m, model[pi[m][0]], model[pi[m][result_depth - 1]]))

        for (k, t) in list_result_swap:
            q0 = list_qubit_edge[k][0]
            q1 = list_qubit_edge[k][1]
            if self.swap_duration == 1:
                list_scheduled_gate_qubits[t].append([q0, q1])
                list_scheduled_gate_name[t].append("SWAP")
            elif self.swap_duration == 3:
                list_scheduled_gate_qubits[t].append([q0, q1])
                list_scheduled_gate_name[t].append("cx")
                list_scheduled_gate_qubits[t - 1].append([q1, q0])
                list_scheduled_gate_name[t - 1].append("cx")
                list_scheduled_gate_qubits[t - 2].append([q0, q1])
                list_scheduled_gate_name[t - 2].append("cx")
            else:
                raise Exception(
                    "Expect SWAP duration one, or three (decomposed into CX gates)"
                )

        if output_mode == "IR":
            if output_file_name:
                output_file = open(output_file_name, 'w')
                output_file.writelines([
                    result_depth, list_scheduled_gate_name,
                    list_scheduled_gate_qubits, final_mapping
                ])
            return [
                result_depth, list_scheduled_gate_name,
                list_scheduled_gate_qubits, final_mapping
            ]
        else:
            return output_qasm(self.device, result_depth,
                               list_scheduled_gate_name,
                               list_scheduled_gate_qubits, final_mapping, True,
                               output_file_name)
Example #21
0
    def smt_solution(self, timeout, optimize=False):
        if optimize:
            solver = Optimize()
        else:
            solver = Solver()
            solver.set("zero_accuracy",10)
        solver.set("timeout", timeout)


        non_trivial = False
        diff_sol = False
        smt_keep_sol = True # a.k.a A1
        smt_is_sol = True # a.k.a A2

        some_consume = False
        some_produce = False
        variables = set()
        variables_positive = set()
        for p_id, place in enumerate(self.facets):
            ti = place.offset
            smt_ti = Int("b%s" % p_id)

            if ti:
                solver.add(min(0,ti) <= smt_ti, smt_ti <= max(0, ti))
            else:
                solver.add(smt_ti == 0)


            facet_non_trivial = False
            facet_diff_sol = False
            smt_facet_eval = ti
            smt_facet_sol = ti

            # If halfspace's coefficients add to 1 it's
            # as simple as it gets
            simple = sum(abs(x) for x in place.normal) <= 1
            # do_cons_prod indicates if the place has incoming and outgoing transitions
            do_cons_prod = False
            consume = produce = 0
            for coeff in place.normal:
                if coeff > 0:
                    produce = 1
                elif coeff < 0:
                    consume = 1
                if consume * produce:
                    do_cons_prod = True
                    break

            do_cons_prod = reduce(lambda x,y:x*y, [x + 1 for x in place.normal]) < 1

            for t_id, coeff in enumerate(place.normal):
                # SMT coefficient
                smt_coeff = Int("a%s,%s" % (p_id, t_id))
                if optimize:
                    # Try to minimize the coefficient
                    solver.minimize(smt_coeff)
                # SMT variable
                smt_var = Int("x%s" % t_id)

                # Add SMT varible to the set of variables
                variables.add(smt_var)
                # Add SMT varible basic constraint to the set
                variables_positive.add(smt_var >= 0)
                if coeff:
                    # At least one SMT coefficient should be non zero
                    facet_non_trivial = Or(facet_non_trivial, smt_coeff != 0)
                    # At least one SMT coefficient should be different
                    facet_diff_sol = Or(facet_diff_sol, smt_coeff != coeff)
                    # Original solution with SMT variable
                    smt_facet_eval += coeff * smt_var
                    # SMT solution with SMT variable
                    smt_facet_sol += smt_coeff * smt_var
                    # Keep SMT coefficient between original bundaries
                    solver.add(min(0,coeff) <= smt_coeff, smt_coeff <= max(0, coeff))

                    if not self.neg_points and not simple and do_cons_prod:
                        some_produce = Or(some_produce, smt_coeff > 0)
                        some_consume = Or(some_consume, smt_coeff < 0)
                else:
                    # Keep zero coefficients unchanged
                    solver.add(smt_coeff == 0)
            if not self.neg_points:
                # Avoid trivial solution (i.e. all zeros as coeff)
                non_trivial = Or(non_trivial, facet_non_trivial)
            # Solution of smt must be different
            diff_sol = Or(diff_sol, facet_diff_sol)
            # If point is in old-solution should be in smt-solution
            smt_keep_sol = And(smt_keep_sol, smt_facet_eval <= 0)
            # Solutions shoul be a solution
            smt_is_sol = And(smt_is_sol, smt_facet_sol <= 0)

            if not self.neg_points and not simple and do_cons_prod:
                solver.add(simplify(some_consume))
                solver.add(simplify(some_produce))

            if optimize:
                # Try to minimize the independent term
                solver.minimize(smt_ti)

    # This is what we want:
        if not self.neg_points:
            # If there is not negative info, avoid trivial solution (i.e. Not all zero)
            solver.add(simplify(non_trivial))
        # A different solution (i.e. "better")
        solver.add(simplify(diff_sol))
        # If it was a solution before, keep it that way
        solver.add(simplify(ForAll(list(variables), Implies(And(Or(list(variables_positive)), smt_keep_sol), smt_is_sol))))

        # Negative point shouldn't be a solution
        for np in self.neg_points:
            smt_np = False
            for p_id, place in enumerate(self.facets):
                place_at_np = Int("b%s" % p_id)
                for t_id, coeff in enumerate(place.normal):
                    # If coefficient was zero, it will remain zero
                    if coeff and np[t_id]:
                        smt_coeff = Int("a%s,%s" % (p_id, t_id))
                        place_at_np = place_at_np + smt_coeff * np[t_id]

                smt_np = Or(smt_np, place_at_np > 0)
            # Keep out (NOTE halfspaces are Ax + b <= 0)
            solver.add(simplify(smt_np))

        sol = solver.check()
        if sol == unsat:
            ret = False
            logger.info('Z3 returns UNSAT: Cannot reduce without adding neg info')
        elif sol == unknown:
            ret = False
            logger.info('Z3 returns UNKNOWN: Cannot reduce in less than %s miliseconds', timeout)
        else:
            ret = solver.model()
        return ret
Example #22
0
    return If(x >= 0, x, -x)


def z3_dist(v1, v2):
    return z3_abs(v1.x - v2.x) + z3_abs(v1.y - v2.y) + z3_abs(v1.z - v2.z)


x = Int('x')
y = Int('y')
z = Int('z')
orig = (x, y, z)
cost = Int('cost')
cost_expr = 0
for bot in bots:
    cost_expr += If(z3_dist(Vector3(*orig), bot.pos) <= bot.r, 1, 0)
opt = Optimize()

print("let's go")
opt.add(cost == cost_expr)
opt.maximize(cost)
opt.minimize(z3_dist(Vector3(0, 0, 0), Vector3(x, y, z)))

opt.check()

model = opt.model()
print(model)
pos = (model[x].as_long(), model[y].as_long(), model[z].as_long())
print("position:", pos)
print("num in range:", model[cost].as_long())
print("distance:", l1(Vector3(0, 0, 0), Vector3(*pos)))
Example #23
0
# Bomb placement
def at_least_one_bomb_for_each_rectangle(h, w):
    return [
        PbGe([(is_bomb[r + dr][c + dc], 1) for (dr, dc) in rectangle(h, w)], 1)
        for (r, c) in rectangle(H - h + 1, W - w + 1)
    ]


# Clauses
s = Optimize()
s.add(at_least_one_bomb_for_each_rectangle(2, 3))
s.add(at_least_one_bomb_for_each_rectangle(3, 2))

# Objective
num_bombs = Sum([If(is_bomb[r][c], 1, 0) for (r, c) in rectangle(H, W)])
min_bombs = s.minimize(num_bombs)

if s.check() == sat:
    assert s.lower(min_bombs) == 6
    print("The minimum number of bombs satisfying the constraints == %s." %
          s.lower(min_bombs))
    print(diagram(s.model()))
else:
    print("Z3 failed to find a solution.")

# http://forum.stratego.com/topic/1134-stratego-quizz-and-training-forum/?p=11661
# http://forum.stratego.com/topic/1146-stratego-quizz-and-training-forum-answers/?p=11813
# http://forum.stratego.com/topic/1134-stratego-quizz-and-training-forum/?p=441745
print(
    "The minimum number of bombs on a Stratego setup area such that each 2x3, 3x2 and 1x6 rectangle has at least one bomb."
)
Example #24
0
            z3.add(vv[k] == sum([If(sigma[k][t], 1, 0) for t in range(T)]))

        z3.add(fidelity == sum([v[k] * f_2qbg[k] for k in range(K)]) +
               sum([S * vv[k] * f_2qbg[k] for k in range(K)]) +
               sum([w[n] * f_meas[n] for n in range(N)]) +
               sum([u[n] * f_1qbg[n] for n in range(N)]))
        z3.maximize(fidelity)

# for depth optimization
# else:
    for l in range(L):
        z3.add(depth >= time[l] + 1)
        # z3.minimize(depth)

    if objective_name == "swap":
        z3.minimize(num_swap)
    elif objective_name == "depth":
        z3.minimize(depth)

    satisfiable = z3.check()
    if satisfiable == sat:
        not_solve = False
    else:
        T = int(1.3 * T)

print("Compilation time = {}s.".format(sys_time.time() - start_time))
model = z3.model()
if objective_name == "fidelity":
    log_fidelity = model[fidelity].as_long()
    print("result fidelity = {}".format(math.exp(log_fidelity / 1000.0)))
    for k in range(K):
Example #25
0
print('Part 1:', inRange)


def abs(x):
    return If(x >= 0, x, -x)


def manhattan3d(start, finish):
    sX, sY, sZ = start
    fX, fY, fZ = finish
    return abs(sX - fX) + abs(sY - fY) + abs(sZ - fZ)


x = Int('x')
y = Int('y')
z = Int('z')
counts = [Int('count_' + str(i)) for i in range(len(bots))]
numInRange = Int('num')
distanceFromOrigin = Int('dist')

o = Optimize()
o.add([counts[i] == bots[i].canReachPoint(x, y, z) for i in range(len(bots))])
o.add(numInRange == sum(counts))
o.add(distanceFromOrigin == abs(x) + abs(y) + abs(z))
o.maximize(numInRange)
heuristic = o.minimize(distanceFromOrigin)

o.check()
print("Part 2:", o.lower(heuristic))
Example #26
0
            z3.add(vv[k] == sum([If(sigma[k][t], 1, 0) for t in range(T)]))

        z3.add(fidelity == sum([v[k] * f_2qbg[k] for k in range(K)]) +
                           sum([S * vv[k] * f_2qbg[k] for k in range(K)]) +
                           sum([w[n] * f_meas[n] for n in range(N)]) +
                           sum([u[n] * f_1qbg[n] for n in range(N)]))
        z3.maximize(fidelity)

# for depth optimization
    # else:
    for l in range(L):
        z3.add(depth >= time[l] + 1)
        # z3.minimize(depth)

    if objective_name == "swap":
        z3.minimize(num_swap)
    elif objective_name == "depth":
        ze.minimize(depth)

    satisfiable = z3.check()
    if satisfiable == sat:
        not_solve = False
    else:
        T += 1


print("Compilation time = {}.".format(sys_time.time() - start_time))
model = z3.model()
if objective_name == "fidelity":
    log_fidelity = model[fidelity].as_long()
    print("result fidelity = {}".format(math.exp(log_fidelity / 1000.0)))
Example #27
0
    def smt_solution(self, timeout, neg_points=None, optimize=False):
        # If halfspace's coefficients add to 1 it's
        # as simple as it gets
        normal_sum = sum(abs(x) for x in self.normal)
        if normal_sum == 0:
            return False
        elif normal_sum <= 1:
            simple = True
        else:
            simple = False

        neg_points = neg_points or []

        if optimize:
            solver = Optimize()
        else:
            solver = Solver()
            solver.set("zero_accuracy",10)
        solver.set("timeout", timeout)

        ti = self.offset
        smt_ti = Int("b")
        if ti:
            solver.add(min(0,ti) <= smt_ti, smt_ti <= max(0,ti))
            if optimize:
                # Try to minimize the independent term
                solver.minimize(smt_ti)
        else:
            solver.add(smt_ti == 0)

        variables = set()
        variables_positive = set()

        positive_x = True
        non_trivial = False
        some_consume = False
        some_produce = False

        diff_sol = smt_ti != ti
        smt_keep_sol = ti
        smt_is_sol = smt_ti

        for t_id, coeff in enumerate(self.normal):
            # SMT coefficient
            smt_coeff = Int("a%s" % t_id)
            if optimize:
                # Try to minimize the coefficient
                solver.minimize(smt_coeff)
            # SMT variable
            smt_var = Int("x%s"%t_id)

            # Add SMT varible to the set of variables
            variables.add(smt_var)
            # Add SMT varible basic constraint to the set
            variables_positive.add(smt_var >= 0)

            if coeff:
                # At least one SMT coefficient should be non zero
                non_trivial = Or(non_trivial, smt_coeff != 0)
                # At least one SMT coefficient should be different
                diff_sol = Or(diff_sol, smt_coeff != coeff)
                # Original solution with SMT variable
                smt_keep_sol += coeff * smt_var
                # SMT solution with SMT variable
                smt_is_sol += smt_coeff * smt_var
                # Keep SMT coefficient between original bundaries
                solver.add(min(0,coeff) <= smt_coeff, smt_coeff <= max(0, coeff))

                if not neg_points and not simple:
                    some_produce = Or(some_produce, smt_coeff > 0)
                    some_consume = Or(some_consume, smt_coeff < 0)
            else:
                solver.add(smt_coeff == 0)

    #This is what we want:
        if not neg_points:
            # If there is not negative info, avoid trivial solution (i.e. Not all zero)
            solver.add(simplify(non_trivial))
            if not simple:
                solver.add(simplify(some_consume))
                solver.add(simplify(some_produce))
        # A different solution (i.e. "better")
        solver.add(simplify(diff_sol))
        # If it was a solution before, keep it that way
        solver.add(simplify(ForAll(list(variables), Implies(And(Or(list(variables_positive)), smt_keep_sol <= 0), smt_is_sol <= 0))))

        # New solution shouldn't add a negative point
        for np in neg_points:
            smt_ineq_np = smt_ti
            ineq_np = ti
            for t_id, coeff in enumerate(self.normal):
                ineq_np += coeff * np[t_id]
                smt_coeff = Int("a%s"%(t_id))
                smt_ineq_np += smt_coeff * np[t_id]
            # If neg point was out of this halfspace, keep it out!
            if ineq_np > 0:
                logger.info('Adding HS SMT-NEG restriction')
                solver.add(simplify(smt_ineq_np > 0))

        sol = solver.check()
        if sol == unsat:
            ret = False
            logger.info('Z3 returns UNSAT: Cannot simplify HS without adding neg info')
        elif sol == unknown:
            ret = False
            logger.info('Z3 returns UNKNOWN: Cannot simplify HS in less than %s miliseconds', timeout)
        else:
            ret = solver.model()
        return ret