Exemplo n.º 1
0
def find_max(constraints, expr, l = None):
    if l is None:
        l = logger

    if type(expr) == int:
        return expr

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

    max_optimize = Optimize()
    max_optimize.set('timeout', 10000)
    max_optimize.assert_exprs(*constraints)
    max_optimize.maximize(expr)
    status = max_optimize.check()
    if status != sat:
        l.warning(f'Unable to find max ({status}) for:\n' + '\n'.join(constraint_strs))
        return None

    max_val = max_optimize.model().eval(expr).as_long()

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

    if status != unsat:
        l.error(f'Z3 bug\nFind max ({expr}) => {max_val} with status ({status}):\n' + '\n'.join(constraint_strs))
        return None
    return max_val
Exemplo n.º 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)
def test(qcirc):
    #print(qcirc)
    print("Translate to Z3")
    circ = QuantumCircuit_to_Circuit(qcirc, melbourne_rels, positions)
    # Collect Constraints
    print("Create Constraint Generator")
    cons = circ.constraints()
    # New Optimizer
    s = Optimize()
    # Add constraints
    print("Add All constraints")
    for con in cons:
        s.add(con)
        #print(con)
    # Add reliability objective
    print("Add Objective")
    s.maximize(reliability_objective(circ))
    # Check and print
    print("Checking")
    sat = str(s.check())
    print(sat)
    if sat == "unsat":
        raise Exception("unsat")

    print("Extracting Model")
    m = s.model()

    # Confirm that an improvement in reliability was made
    print("Reliability Checking")
    improved_reliability(m, s, melbourne_rels, qcirc)

    # Translate to qiskit QuantumCircuit
    print("Translate to Qiskit")
    rcirc = model_to_QuantumCircuit(m, circ)
Exemplo n.º 4
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
Exemplo n.º 5
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))
Exemplo n.º 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)
Exemplo n.º 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)
Exemplo n.º 8
0
def part_2(nanobots: List[Nanobot]) -> int:
    x, y, z = Ints("x y z")
    opt = Optimize()
    bot_cond = []
    for i, bot in enumerate(nanobots):
        cond = Int(f"bot_{i}")
        bot_cond.append(cond)
        opt.add(cond == If(z_manhattan(x, y, z, bot.point) <= bot.r, 1, 0))
    overlaps = Sum(bot_cond)
    dist_zero = Int('dist_zero')
    opt.add(dist_zero == z_manhattan(x, y, z, Point(0, 0, 0)))
    _ = opt.maximize(overlaps)
    dist = opt.maximize(dist_zero)
    opt.check()
    return dist.upper()
Exemplo n.º 9
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)
Exemplo n.º 10
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)
Exemplo n.º 11
0

# for fidelity optimization
    if objective_name == "fidelity":
        for n in range(N):
            z3.add(u[n] == sum([If(space[l] == n, 1, 0) for l in G_1]))
            z3.add(w[n] == sum([If(pi[m][T - 1] == n, 1, 0) for m in range(M)]))
        for k in range(K):
            z3.add(v[k] == sum([If(space[l] == k, 1, 0) for l in G_2]))
            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
Exemplo n.º 12
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)
class CrosstalkAdaptiveSchedule(TransformationPass):
    """Crosstalk mitigation through adaptive instruction scheduling."""
    def __init__(self,
                 backend_prop,
                 crosstalk_prop,
                 weight_factor=0.5,
                 measured_qubits=None):
        """CrosstalkAdaptiveSchedule initializer.

        Args:
            backend_prop (BackendProperties): backend properties object
            crosstalk_prop (dict): crosstalk properties object
                crosstalk_prop[g1][g2] specifies the conditional error rate of
                g1 when g1 and g2 are executed simultaneously.
                g1 should be a two-qubit tuple of the form (x,y) where x and y are physical
                qubit ids. g2 can be either two-qubit tuple (x,y) or single-qubit tuple (x).
                We currently ignore crosstalk between pairs of single-qubit gates.
                Gate pairs which are not specified are assumed to be crosstalk free.

                Example::

                    crosstalk_prop = {(0, 1) : {(2, 3) : 0.2, (2) : 0.15},
                                                (4, 5) : {(2, 3) : 0.1},
                                                (2, 3) : {(0, 1) : 0.05, (4, 5): 0.05}}

                The keys of the crosstalk_prop are tuples for ordered tuples for CX gates
                e.g., (0, 1) corresponding to CX 0, 1 in the hardware.
                Each key has an associated value dict which specifies the conditional error rates
                with nearby gates e.g., ``(0, 1) : {(2, 3) : 0.2, (2) : 0.15}`` means that
                CNOT 0, 1 has an error rate of 0.2 when it is executed in parallel with CNOT 2,3
                and an error rate of 0.15 when it is executed in parallel with a single qubit
                gate on qubit 2.
            weight_factor (float): weight of gate error/crosstalk terms in the objective
                :math:`weight_factor*fidelities + (1-weight_factor)*decoherence errors`.
                Weight can be varied from 0 to 1, with 0 meaning that only decoherence
                errors are optimized and 1 meaning that only crosstalk errors are optimized.
                weight_factor should be tuned per application to get the best results.
            measured_qubits (list): a list of qubits that will be measured in a particular circuit.
                This arg need not be specified for circuits which already include measure gates.
                The arg is useful when a subsequent module such as state_tomography_circuits
                inserts the measure gates. If CrosstalkAdaptiveSchedule is made aware of those
                measurements, it is included in the optimization.
        Raises:
            ImportError: if unable to import z3 solver

        """
        super().__init__()
        self.backend_prop = backend_prop
        self.crosstalk_prop = crosstalk_prop
        self.weight_factor = weight_factor
        if measured_qubits is None:
            self.input_measured_qubits = []
        else:
            self.input_measured_qubits = measured_qubits
        self.bp_u1_err = {}
        self.bp_u1_dur = {}
        self.bp_u2_err = {}
        self.bp_u2_dur = {}
        self.bp_u3_err = {}
        self.bp_u3_dur = {}
        self.bp_cx_err = {}
        self.bp_cx_dur = {}
        self.bp_t1_time = {}
        self.bp_t2_time = {}
        self.gate_id = {}
        self.gate_start_time = {}
        self.gate_duration = {}
        self.gate_fidelity = {}
        self.overlap_amounts = {}
        self.overlap_indicator = {}
        self.qubit_lifetime = {}
        self.dag_overlap_set = {}
        self.xtalk_overlap_set = {}
        self.opt = Optimize()
        self.measured_qubits = []
        self.measure_start = None
        self.last_gate_on_qubit = None
        self.first_gate_on_qubit = None
        self.fidelity_terms = []
        self.coherence_terms = []
        self.model = None
        self.dag = None
        self.parse_backend_properties()

    def powerset(self, iterable):
        """
        Finds the set of all subsets of the given iterable
        This function is used to generate constraints for the Z3 optimization
        """
        l_s = list(iterable)
        return chain.from_iterable(
            combinations(l_s, r) for r in range(len(l_s) + 1))

    def parse_backend_properties(self):
        """
        This function assumes that gate durations and coherence times
        are in seconds in backend.properties()
        This function converts gate durations and coherence times to
        nanoseconds.
        """
        backend_prop = self.backend_prop
        for qid in range(len(backend_prop.qubits)):
            self.bp_t1_time[qid] = int(backend_prop.t1(qid) * 10**9)
            self.bp_t2_time[qid] = int(backend_prop.t2(qid) * 10**9)
            self.bp_u1_dur[qid] = int(backend_prop.gate_length('u1',
                                                               qid)) * 10**9
            u1_err = backend_prop.gate_error('u1', qid)
            if u1_err == 1.0:
                u1_err = 0.9999
            self.bp_u1_err = round(u1_err, NUM_PREC)
            self.bp_u2_dur[qid] = int(backend_prop.gate_length('u2',
                                                               qid)) * 10**9
            u2_err = backend_prop.gate_error('u2', qid)
            if u2_err == 1.0:
                u2_err = 0.9999
            self.bp_u2_err = round(u2_err, NUM_PREC)
            self.bp_u3_dur[qid] = int(backend_prop.gate_length('u3',
                                                               qid)) * 10**9
            u3_err = backend_prop.gate_error('u3', qid)
            if u3_err == 1.0:
                u3_err = 0.9999
            self.bp_u3_err = round(u3_err, NUM_PREC)
        for ginfo in backend_prop.gates:
            if ginfo.gate == 'cx':
                q_0 = ginfo.qubits[0]
                q_1 = ginfo.qubits[1]
                cx_tup = (min(q_0, q_1), max(q_0, q_1))
                self.bp_cx_dur[cx_tup] = int(
                    backend_prop.gate_length('cx', cx_tup)) * 10**9
                cx_err = backend_prop.gate_error('cx', cx_tup)
                if cx_err == 1.0:
                    cx_err = 0.9999
                self.bp_cx_err[cx_tup] = round(cx_err, NUM_PREC)

    def cx_tuple(self, gate):
        """
        Representation for two-qubit gate
        Note: current implementation assumes that the CX error rates and
        crosstalk behavior are independent of gate direction
        """
        physical_q_0 = gate.qargs[0].index
        physical_q_1 = gate.qargs[1].index
        r_0 = min(physical_q_0, physical_q_1)
        r_1 = max(physical_q_0, physical_q_1)
        return (r_0, r_1)

    def singleq_tuple(self, gate):
        """
        Representation for single-qubit gate
        """
        physical_q_0 = gate.qargs[0].index
        tup = (physical_q_0, )
        return tup

    def gate_tuple(self, gate):
        """
        Representation for gate
        """
        if len(gate.qargs) == 2:
            return self.cx_tuple(gate)
        else:
            return self.singleq_tuple(gate)

    def assign_gate_id(self, dag):
        """
        ID for each gate
        """
        idx = 0
        for gate in dag.gate_nodes():
            self.gate_id[gate] = idx
            idx += 1

    def extract_dag_overlap_sets(self, dag):
        """
        Gate A, B are overlapping if
        A is neither a descendant nor an ancestor of B.
        Currenty overlaps (A,B) are considered when A is a 2q gate and
        B is either 2q or 1q gate.
        """
        for gate in dag.two_qubit_ops():
            overlap_set = []
            descendants = dag.descendants(gate)
            ancestors = dag.ancestors(gate)
            for tmp_gate in dag.gate_nodes():
                if tmp_gate == gate:
                    continue
                if tmp_gate in descendants:
                    continue
                if tmp_gate in ancestors:
                    continue
                overlap_set.append(tmp_gate)
            self.dag_overlap_set[gate] = overlap_set

    def is_significant_xtalk(self, gate1, gate2):
        """
        Given two conditional gate error rates
        check if there is high crosstalk by comparing with independent error rates.
        """
        gate1_tup = self.gate_tuple(gate1)
        if len(gate2.qargs) == 2:
            gate2_tup = self.gate_tuple(gate2)
            independent_err_g_1 = self.bp_cx_err[gate1_tup]
            independent_err_g_2 = self.bp_cx_err[gate2_tup]
            rg_1 = self.crosstalk_prop[gate1_tup][
                gate2_tup] / independent_err_g_1
            rg_2 = self.crosstalk_prop[gate2_tup][
                gate1_tup] / independent_err_g_2
            if rg_1 > TWOQ_XTALK_THRESH or rg_2 > TWOQ_XTALK_THRESH:
                return True
        else:
            gate2_tup = self.gate_tuple(gate2)
            independent_err_g_1 = self.bp_cx_err[gate1_tup]
            rg_1 = self.crosstalk_prop[gate1_tup][
                gate2_tup] / independent_err_g_1
            if rg_1 > ONEQ_XTALK_THRESH:
                return True
        return False

    def extract_crosstalk_relevant_sets(self):
        """
        Extract the set of program gates which potentially have crosstalk noise
        """
        for gate in self.dag_overlap_set:
            self.xtalk_overlap_set[gate] = []
            tup_g = self.gate_tuple(gate)
            if tup_g not in self.crosstalk_prop:
                continue
            for par_g in self.dag_overlap_set[gate]:
                tup_par_g = self.gate_tuple(par_g)
                if tup_par_g in self.crosstalk_prop[tup_g]:
                    if self.is_significant_xtalk(gate, par_g):
                        if par_g not in self.xtalk_overlap_set[gate]:
                            self.xtalk_overlap_set[gate].append(par_g)

    def create_z3_vars(self):
        """
        Setup the variables required for Z3 optimization
        """
        for gate in self.dag.gate_nodes():
            t_var_name = 't_' + str(self.gate_id[gate])
            d_var_name = 'd_' + str(self.gate_id[gate])
            f_var_name = 'f_' + str(self.gate_id[gate])
            self.gate_start_time[gate] = Real(t_var_name)
            self.gate_duration[gate] = Real(d_var_name)
            self.gate_fidelity[gate] = Real(f_var_name)
        for gate in self.xtalk_overlap_set:
            self.overlap_indicator[gate] = {}
            self.overlap_amounts[gate] = {}
        for g_1 in self.xtalk_overlap_set:
            for g_2 in self.xtalk_overlap_set[g_1]:
                if len(g_2.qargs) == 2 and g_1 in self.overlap_indicator[g_2]:
                    self.overlap_indicator[g_1][g_2] = self.overlap_indicator[
                        g_2][g_1]
                    self.overlap_amounts[g_1][g_2] = self.overlap_amounts[g_2][
                        g_1]
                else:
                    # Indicator variable for overlap of g_1 and g_2
                    var_name1 = 'olp_ind_' + str(
                        self.gate_id[g_1]) + '_' + str(self.gate_id[g_2])
                    self.overlap_indicator[g_1][g_2] = Bool(var_name1)
                    var_name2 = 'olp_amnt_' + str(
                        self.gate_id[g_1]) + '_' + str(self.gate_id[g_2])
                    self.overlap_amounts[g_1][g_2] = Real(var_name2)
        active_qubits_list = []
        for gate in self.dag.gate_nodes():
            for q in gate.qargs:
                active_qubits_list.append(q.index)
        for active_qubit in list(set(active_qubits_list)):
            q_var_name = 'l_' + str(active_qubit)
            self.qubit_lifetime[active_qubit] = Real(q_var_name)

        meas_q = []
        for node in self.dag.op_nodes():
            if isinstance(node.op, Measure):
                meas_q.append(node.qargs[0].index)

        self.measured_qubits = list(
            set(self.input_measured_qubits).union(set(meas_q)))
        self.measure_start = Real('meas_start')

    def basic_bounds(self):
        """
        Basic variable bounds for optimization
        """
        for gate in self.gate_start_time:
            self.opt.add(self.gate_start_time[gate] >= 0)
        for gate in self.gate_duration:
            q_0 = gate.qargs[0].index
            if isinstance(gate.op, U1Gate):
                dur = self.bp_u1_dur[q_0]
            elif isinstance(gate.op, U2Gate):
                dur = self.bp_u2_dur[q_0]
            elif isinstance(gate.op, U3Gate):
                dur = self.bp_u3_dur[q_0]
            elif isinstance(gate.op, CXGate):
                dur = self.bp_cx_dur[self.cx_tuple(gate)]
            self.opt.add(self.gate_duration[gate] == dur)

    def scheduling_constraints(self):
        """
        DAG scheduling constraints optimization
        Sets overlap indicator variables
        """
        for gate in self.gate_start_time:
            for dep_gate in self.dag.successors(gate):
                if not dep_gate.type == 'op':
                    continue
                if isinstance(dep_gate.op, Measure):
                    continue
                if isinstance(dep_gate.op, Barrier):
                    continue
                fin_g = self.gate_start_time[gate] + self.gate_duration[gate]
                self.opt.add(self.gate_start_time[dep_gate] > fin_g)
        for g_1 in self.xtalk_overlap_set:
            for g_2 in self.xtalk_overlap_set[g_1]:
                if len(g_2.qargs
                       ) == 2 and self.gate_id[g_1] > self.gate_id[g_2]:
                    # Symmetry breaking: create only overlap variable for a pair
                    # of gates
                    continue
                s_1 = self.gate_start_time[g_1]
                f_1 = s_1 + self.gate_duration[g_1]
                s_2 = self.gate_start_time[g_2]
                f_2 = s_2 + self.gate_duration[g_2]
                # This constraint enforces full or zero overlap between two gates
                before = (f_1 < s_2)
                after = (f_2 < s_1)
                overlap1 = And(s_2 <= s_1, f_1 <= f_2)
                overlap2 = And(s_1 <= s_2, f_2 <= f_1)
                self.opt.add(Or(before, after, overlap1, overlap2))
                intervals_overlap = And(s_2 <= f_1, s_1 <= f_2)
                self.opt.add(
                    self.overlap_indicator[g_1][g_2] == intervals_overlap)

    def fidelity_constraints(self):
        """
        Set gate fidelity based on gate overlap conditions
        """
        for gate in self.gate_start_time:
            q_0 = gate.qargs[0].index
            no_xtalk = False
            if gate not in self.xtalk_overlap_set:
                no_xtalk = True
            elif not self.xtalk_overlap_set[gate]:
                no_xtalk = True
            if no_xtalk:
                if isinstance(gate.op, U1Gate):
                    fid = math.log(1.0)
                elif isinstance(gate.op, U2Gate):
                    fid = math.log(1.0 - self.bp_u2_err[q_0])
                elif isinstance(gate.op, U3Gate):
                    fid = math.log(1.0 - self.bp_u3_err[q_0])
                elif isinstance(gate.op, CXGate):
                    fid = math.log(1.0 - self.bp_cx_err[self.cx_tuple(gate)])
                self.opt.add(self.gate_fidelity[gate] == round(fid, NUM_PREC))
            else:
                comb = list(self.powerset(self.xtalk_overlap_set[gate]))
                xtalk_set = set(self.xtalk_overlap_set[gate])
                for item in comb:
                    on_set = item
                    off_set = [i for i in xtalk_set if i not in on_set]
                    clauses = []
                    for tmpg in on_set:
                        clauses.append(self.overlap_indicator[gate][tmpg])
                    for tmpg in off_set:
                        clauses.append(Not(self.overlap_indicator[gate][tmpg]))
                    err = 0
                    if not on_set:
                        err = self.bp_cx_err[self.cx_tuple(gate)]
                    elif len(on_set) == 1:
                        on_gate = on_set[0]
                        err = self.crosstalk_prop[self.gate_tuple(gate)][
                            self.gate_tuple(on_gate)]
                    else:
                        err_list = []
                        for on_gate in on_set:
                            tmp_prop = self.crosstalk_prop[self.gate_tuple(
                                gate)]
                            err_list.append(tmp_prop[self.gate_tuple(on_gate)])
                        err = max(err_list)
                    if err == 1.0:
                        err = 0.999999
                    val = round(math.log(1.0 - err), NUM_PREC)
                    self.opt.add(
                        Implies(And(*clauses),
                                self.gate_fidelity[gate] == val))

    def coherence_constraints(self):
        """
        Set decoherence errors based on qubit lifetimes
        """
        self.last_gate_on_qubit = {}
        for gate in self.dag.topological_op_nodes():
            if isinstance(gate.op, Measure):
                continue
            if isinstance(gate.op, Barrier):
                continue
            if len(gate.qargs) == 1:
                q_0 = gate.qargs[0].index
                self.last_gate_on_qubit[q_0] = gate
            else:
                q_0 = gate.qargs[0].index
                q_1 = gate.qargs[1].index
                self.last_gate_on_qubit[q_0] = gate
                self.last_gate_on_qubit[q_1] = gate

        self.first_gate_on_qubit = {}
        for gate in self.dag.topological_op_nodes():
            if len(gate.qargs) == 1:
                q_0 = gate.qargs[0].index
                if q_0 not in self.first_gate_on_qubit:
                    self.first_gate_on_qubit[q_0] = gate
            else:
                q_0 = gate.qargs[0].index
                q_1 = gate.qargs[1].index
                if q_0 not in self.first_gate_on_qubit:
                    self.first_gate_on_qubit[q_0] = gate
                if q_1 not in self.first_gate_on_qubit:
                    self.first_gate_on_qubit[q_1] = gate

        for q in self.last_gate_on_qubit:
            g_last = self.last_gate_on_qubit[q]
            g_first = self.first_gate_on_qubit[q]
            finish_time = self.gate_start_time[g_last] + self.gate_duration[
                g_last]
            start_time = self.gate_start_time[g_first]
            if q in self.measured_qubits:
                self.opt.add(self.measure_start >= finish_time)
                self.opt.add(self.qubit_lifetime[q] == self.measure_start -
                             start_time)
            else:
                # All qubits get measured simultaneously whether or not they need a measurement
                self.opt.add(self.measure_start >= finish_time)
                self.opt.add(self.qubit_lifetime[q] == finish_time -
                             start_time)

    def objective_function(self):
        """
        Objective function is a weighted combination of gate errors and decoherence errors
        """
        self.fidelity_terms = [
            self.gate_fidelity[gate] for gate in self.gate_fidelity
        ]
        self.coherence_terms = []
        for q in self.qubit_lifetime:
            val = -self.qubit_lifetime[q] / min(self.bp_t1_time[q],
                                                self.bp_t2_time[q])
            self.coherence_terms.append(val)

        all_terms = []
        for item in self.fidelity_terms:
            all_terms.append(self.weight_factor * item)
        for item in self.coherence_terms:
            all_terms.append((1 - self.weight_factor) * item)
        self.opt.maximize(Sum(all_terms))

    def r2f(self, val):
        """
        Convert Z3 Real to Python float
        """
        return float(val.as_decimal(16).rstrip('?'))

    def extract_solution(self):
        """
        Extract gate start and finish times from Z3 solution
        """
        self.model = self.opt.model()
        result = {}
        for tmpg in self.gate_start_time:
            start = self.r2f(self.model[self.gate_start_time[tmpg]])
            dur = self.r2f(self.model[self.gate_duration[tmpg]])
            result[tmpg] = (start, start + dur)
        return result

    def solve_optimization(self):
        """
        Setup and solve a Z3 optimization for finding the best schedule
        """
        self.opt = Optimize()
        self.create_z3_vars()
        self.basic_bounds()
        self.scheduling_constraints()
        self.fidelity_constraints()
        self.coherence_constraints()
        self.objective_function()
        # Solve step
        self.opt.check()
        # Extract the schedule computed by Z3
        result = self.extract_solution()
        return result

    def check_dag_dependency(self, gate1, gate2):
        """
        gate2 is a DAG dependent of gate1 if it is a descendant of gate1
        """
        return gate2 in self.dag.descendants(gate1)

    def check_xtalk_dependency(self, t_1, t_2):
        """
        Check if two gates have a crosstalk dependency.
        We do not consider crosstalk between pairs of single qubit gates.
        """
        g_1 = t_1[0]
        s_1 = t_1[1]
        f_1 = t_1[2]
        g_2 = t_2[0]
        s_2 = t_2[1]
        f_2 = t_2[2]
        if len(g_1.qargs) == 1 and len(g_2.qargs) == 1:
            return False, ()
        if s_2 <= f_1 and s_1 <= f_2:
            # Z3 says it's ok to overlap these gates,
            # so no xtalk dependency needs to be checked
            return False, ()
        else:
            # Assert because we are iterating in Z3 gate start time order,
            # so if two gates are not overlapping, then the second gate has to
            # start after the first gate finishes
            assert s_2 >= f_1
            # Not overlapping, but we care about this dependency
            if len(g_1.qargs) == 2 and len(g_2.qargs) == 2:
                if g_2 in self.xtalk_overlap_set[g_1]:
                    cx1 = self.cx_tuple(g_1)
                    cx2 = self.cx_tuple(g_2)
                    barrier = tuple(sorted([cx1[0], cx1[1], cx2[0], cx2[1]]))
                    return True, barrier
            elif len(g_1.qargs) == 1 and len(g_2.qargs) == 2:
                if g_1 in self.xtalk_overlap_set[g_2]:
                    singleq = self.gate_tuple(g_1)
                    cx1 = self.cx_tuple(g_2)
                    print(singleq, cx1)
                    barrier = tuple(sorted([singleq, cx1[0], cx1[1]]))
                    return True, barrier
            elif len(g_1.qargs) == 2 and len(g_2.qargs) == 1:
                if g_2 in self.xtalk_overlap_set[g_1]:
                    singleq = self.gate_tuple(g_2)
                    cx1 = self.cx_tuple(g_1)
                    barrier = tuple(sorted([singleq, cx1[0], cx1[1]]))
                    return True, barrier
            # Not overlapping, and we don't care about xtalk between these two gates
            return False, ()

    def filter_candidates(self, candidates, layer, layer_id, triplet):
        """
        For a gate G and layer L,
        L is a candidate layer for G if no gate in L has a DAG dependency with G,
        and if Z3 allows gates in L and G to overlap.
        """
        curr_gate = triplet[0]
        for prev_triplet in layer:
            prev_gate = prev_triplet[0]
            is_dag_dep = self.check_dag_dependency(prev_gate, curr_gate)
            is_xtalk_dep, _ = self.check_xtalk_dependency(
                prev_triplet, triplet)
            if is_dag_dep or is_xtalk_dep:
                # If there is a DAG dependency, we can't insert in any previous layer
                # If there is Xtalk dependency, we can (in general) insert in previous layers,
                # but since we are iterating in the order of gate start times,
                # we should only insert this gate in subsequent layers
                for i in range(layer_id + 1):
                    if i in candidates:
                        candidates.remove(i)
            return candidates

    def find_layer(self, layers, triplet):
        """
        Find the appropriate layer for a gate
        """
        candidates = list(range(len(layers)))
        for i, layer in enumerate(layers):
            candidates = self.filter_candidates(candidates, layer, i, triplet)
        if not candidates:
            return len(layers)
            # Open a new layer
        else:
            return max(candidates)
            # Latest acceptable layer, right-alignment

    def generate_barriers(self, layers):
        """
        For each gate g, see if a barrier is required to serialize it with
        some previously processed gate
        """
        barriers = []
        for i, layer in enumerate(layers):
            barriers.append(set())
            if i == 0:
                continue
            for t_2 in layer:
                for j in range(i):
                    prev_layer = layers[j]
                    for t_1 in prev_layer:
                        is_dag_dep = self.check_dag_dependency(t_1[0], t_2[0])
                        is_xtalk_dep, curr_barrier = self.check_xtalk_dependency(
                            t_1, t_2)
                        if is_dag_dep:
                            # Don't insert a barrier since there is a DAG dependency
                            continue
                        if is_xtalk_dep:
                            # Insert a barrier for this layer
                            barriers[-1].add(curr_barrier)
        return barriers

    def create_updated_dag(self, layers, barriers):
        """
        Given a set of layers and barries, construct a new dag
        """
        new_dag = DAGCircuit()
        for qreg in self.dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in self.dag.cregs.values():
            new_dag.add_creg(creg)
        canonical_register = new_dag.qregs['q']
        for i, layer in enumerate(layers):
            curr_barriers = barriers[i]
            for b in curr_barriers:
                current_qregs = []
                for idx in b:
                    current_qregs.append(canonical_register[idx])
                new_dag.apply_operation_back(Barrier(len(b)), current_qregs,
                                             [])
            for triplet in layer:
                gate = triplet[0]
                new_dag.apply_operation_back(gate.op, gate.qargs, gate.cargs)

        for node in self.dag.op_nodes():
            if isinstance(node.op, Measure):
                new_dag.apply_operation_back(node.op, node.qargs, node.cargs)

        return new_dag

    def enforce_schedule_on_dag(self, input_gate_times):
        """
        Z3 outputs start times for each gate.
        Some gates need to be serialized to implement the Z3 schedule.
        This function inserts barriers to implement those serializations
        """
        gate_times = []
        for key in input_gate_times:
            gate_times.append(
                (key, input_gate_times[key][0], input_gate_times[key][1]))
        # Sort gates by start time
        sorted_gate_times = sorted(gate_times, key=operator.itemgetter(1))
        layers = []
        # Construct a set of layers. Each layer has a set of gates that
        # are allowed to fire in parallel according to Z3
        for triplet in sorted_gate_times:
            layer_idx = self.find_layer(layers, triplet)
            if layer_idx == len(layers):
                layers.append([triplet])
            else:
                layers[layer_idx].append(triplet)
        # Insert barries if necessary to enforce the above layers
        barriers = self.generate_barriers(layers)
        new_dag = self.create_updated_dag(layers, barriers)
        return new_dag

    def reset(self):
        """
        Reset variables
        """
        self.gate_id = {}
        self.gate_start_time = {}
        self.gate_duration = {}
        self.gate_fidelity = {}
        self.overlap_amounts = {}
        self.overlap_indicator = {}
        self.qubit_lifetime = {}
        self.dag_overlap_set = {}
        self.xtalk_overlap_set = {}
        self.measured_qubits = []
        self.measure_start = None
        self.last_gate_on_qubit = None
        self.first_gate_on_qubit = None
        self.fidelity_terms = []
        self.coherence_terms = []
        self.model = None

    def run(self, dag):
        """
        Main scheduling function
        """
        if not HAS_Z3:
            raise TranspilerError(
                'z3-solver is required to use CrosstalkAdaptiveSchedule. '
                'To install, run "pip install z3-solver".')

        self.dag = dag

        # process input program
        self.assign_gate_id(self.dag)
        self.extract_dag_overlap_sets(self.dag)
        self.extract_crosstalk_relevant_sets()

        # setup and solve a Z3 optimization
        z3_result = self.solve_optimization()

        # post-process to insert barriers
        new_dag = self.enforce_schedule_on_dag(z3_result)
        self.reset()
        return new_dag
Exemplo n.º 14
0
    for (r, c) in board()
]).reshape(H, W)

no_scout_threatens_another_scout = [
    Implies(
        is_scout[r][c],
        And([
            Not(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(at_most_one_scout_per_segment)
s.add(no_scout_threatens_another_scout)

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

if s.check() == sat:
    #assert s.upper(max_scouts) == 14
    print("The maximum number of scouts satisfying the constraints == %s." % s.upper(max_scouts))
    print(diagram(s.model()))
else:
    print("Z3 failed to find a solution.")
Exemplo n.º 15
0
            if not l in intersects:
                intersects.append(l)

# objective function
O = [Int(i) * Int(j) - 1 for (i, j) in intersects]

# constant indication how many variables wanted to change
k = 10
opt.add(Sum(X) <= 2 * k)

# print(opt.check())
# print(opt.model())

print("Begin Optimization: Maximize")
# Calculate running time
start_time = time.time()

solution = opt.maximize(And(O))

print("--- %s seconds ---" % (time.time() - start_time))

if opt.check() == sat:
    while opt.check() == sat:
        print(solution.value())
else:
    print("Failed to solve.")

m = opt.model()
for x in street:
    print(m.evaluate(x))
Exemplo n.º 16
0
from z3 import Optimize, Real, If

x = Real('x')
y = Real('y')
z = Real('z')


def z3abs(obj):
    return If(x > 0, x, -x)

optimizer = Optimize()
# optimizer.add(x>0.0)
# optimizer.add(y>0.0)
optimizer.add(x*x+y*y==1.0)
optimizer.add_soft(z == x+y)
optimizer.maximize(z)
result = optimizer.check()

print(optimizer.model())
Exemplo n.º 17
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))
			if not l in intersects:
				intersects.append(l)

# objective function
O = [ Int(i)*Int(j) - 1 for (i, j) in intersects ]

# constant indication how many variables wanted to change
k = 10
opt.add( Sum(X) <= 2*k )

# print(opt.check())
# print(opt.model())

print("Begin Optimization: Maximize")
# Calculate running time
start_time = time.time()

solution = opt.maximize( And(O) )

print("--- %s seconds ---" % (time.time() - start_time))

if opt.check() == sat:
	while opt.check() == sat:
		print(solution.value())
else:
	print("Failed to solve.")

m = opt.model()
for x in street:
	print( m.evaluate(x) )
Exemplo n.º 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))
Exemplo n.º 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)
Exemplo n.º 21
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)))