Skip to content

Conflict graph

OneZoneConflictGraph

OneZoneConflictGraph(moment: Moment)

Representation of the AOD conflict graph for qubits to more to their entangling partners in a single zone setup.

Assumes the qubits are specified as cirq.GridQubits with a chosen geometry.

:param moment: A cirq.Moment object containing operations (gates) to be analyzed.

Source code in .venv/lib/python3.12/site-packages/bloqade/cirq_utils/noise/conflict_graph.py
12
13
14
15
16
17
18
19
20
def __init__(self, moment: cirq.Moment):
    """
    Initializes the conflict graph for a given moment of a cirq circuit.

    :param moment: A cirq.Moment object containing operations (gates) to be analyzed.
    """

    self.moment = moment
    self.gates_in_moment = [op for op in moment.operations if len(op.qubits) == 2]

get_move_schedule

get_move_schedule(mover_limit: int = 10000)

Generates a move schedule by coloring the conflict graph greedily, first coloring nodes of highest degree.

Qubits that are the arguments of a single CZ gate are 'partners'. Only one partner need be moved to arrange the atoms for the 2Q gate. Thus, in coloring the conflict graph, as soon as one partner is colored, the other can be disregarded for the purpose of coloring the rest of the graph.

This sets the self.move_schedule attribute, which is a dictionary where the keys are the indices of the move moments.

:param mover_limit: The maximum number of qubits that can be moved in a single moment. Added as a constraint when coloring the conflict graph. :returns a dictionary of idx:[cirq.Qid] where idx indexes the move moment where the list of qubits move.

Source code in .venv/lib/python3.12/site-packages/bloqade/cirq_utils/noise/conflict_graph.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def get_move_schedule(self, mover_limit: int = 10000):
    """Generates a move schedule by coloring the conflict graph greedily, first coloring nodes of highest degree.

    Qubits that are the arguments of a single CZ gate are 'partners'. Only one partner need be moved to arrange the
    atoms for the 2Q gate. Thus, in coloring the conflict graph, as soon as one partner is colored, the other can be
    disregarded for the purpose of coloring the rest of the graph.

    This sets the self.move_schedule attribute, which is a dictionary where the keys are the indices of the move moments.

    :param mover_limit: The maximum number of qubits that can be moved in a single moment. Added as a constraint
        when coloring the conflict graph.
    :returns a dictionary of idx:[cirq.Qid] where idx indexes the move moment where the list of qubits move.
    """

    self._get_nodes()
    self._get_edges()
    self._get_node_degrees()

    self.ordered_nodes = sorted(self.degrees, key=self.degrees.get, reverse=True)

    move_schedule = {}
    colored_nodes = set()
    partner_node = None
    for node in self.ordered_nodes:
        colored = False
        for gate in self.gates_in_moment:
            if node in gate.qubits:
                partners = set(gate.qubits)
                partners.remove(node)
                partner_node = list(partners)[0]
        if node in colored_nodes:
            # NOTE: if a node is colored, both it and its partner are added to colored_nodes
            continue
        else:
            connected_nodes = set()
            for edge in self.edges:
                if node in edge:
                    connected_nodes.add(edge[0])
                    connected_nodes.add(edge[1])
            connected_nodes.remove(node)
            for color in move_schedule.keys():
                has_colored_neighbor = False
                for connected_node in connected_nodes:
                    # NOTE: loop through to make sure none of the connected nodes are already assigned to color.
                    if connected_node in move_schedule[color]:
                        has_colored_neighbor = True
                        break
                    else:
                        continue
                mover_limit_reached = len(move_schedule[color]) >= mover_limit
                if not (has_colored_neighbor or mover_limit_reached):
                    # NOTE: node needs color
                    move_schedule[color].add(node)
                    colored = True

                    # NOTE: add this node and it's partner to the solved nodes.
                    colored_nodes.add(node)

                    if partner_node is not None:
                        colored_nodes.add(partner_node)
                    break
            if not colored:
                move_schedule[len(move_schedule)] = {node}
                colored = True
                colored_nodes.add(node)

                if partner_node is not None:
                    colored_nodes.add(partner_node)

    assert set(colored_nodes) == set(self.ordered_nodes)

    self.move_schedule = move_schedule

    return self.move_schedule