def test_correctness_3(self) -> None: circuit = Circuit(5) wide_gate = IdentityGate(3) circuit.append_gate(HGate(), [1]) circuit.append_gate(CNOTGate(), [2, 3]) circuit.append_gate(wide_gate, [1, 2, 3]) circuit.append_gate(CNOTGate(), [1, 2]) circuit.append_gate(HGate(), [3]) circuit.append_gate(XGate(), [0]) circuit.append_gate(XGate(), [0]) circuit.append_gate(XGate(), [0]) circuit.append_gate(XGate(), [4]) circuit.append_gate(XGate(), [4]) circuit.append_gate(XGate(), [4]) utry = circuit.get_unitary() circuit.fold(circuit.get_region([(0, 2), (1, 1), (2, 1)])) assert circuit.get_num_operations() == 9 assert circuit.get_depth() == 3 assert circuit.count(HGate()) == 2 assert circuit.count(XGate()) == 6 assert isinstance(circuit[1, 1].gate, CircuitGate) test_gate: CircuitGate = circuit[1, 1].gate assert test_gate._circuit[0, 1].gate is CNOTGate() assert test_gate._circuit[0, 2].gate is CNOTGate() assert test_gate._circuit[1, 0].gate is wide_gate assert test_gate._circuit[1, 1].gate is wide_gate assert test_gate._circuit[1, 2].gate is wide_gate check_no_idle_cycles(circuit) assert np.allclose(utry.get_numpy(), circuit.get_unitary().get_numpy())
def test_type_valid(self, points: Sequence[CircuitPointLike]) -> None: circuit = Circuit(4, [2, 2, 3, 3]) try: circuit.fold(circuit.get_region(points)) except TypeError: assert False, 'Unexpected TypeError.' except BaseException: return
def test_invalid_fold(self, points: Sequence[CircuitPointLike]) -> None: circuit = Circuit(4) wide_gate = IdentityGate(4) circuit.append_gate(wide_gate, [0, 1, 2, 3]) circuit.append_gate(wide_gate, [0, 1, 2, 3]) circuit.append_gate(wide_gate, [0, 1, 2, 3]) circuit.append_gate(wide_gate, [0, 1, 2, 3]) with pytest.raises(ValueError): circuit.fold(circuit.get_region(points))
def test_parameters(self) -> None: circ = Circuit(2) circ.append_gate(CNOTGate(), [1, 0]) circ.append_gate(U3Gate(), [0], [0, 0, 0.23]) circ.append_gate(CNOTGate(), [1, 0]) before_fold = circ.get_unitary() circ.fold(circ.get_region([(0, 0), (1, 0), (2, 0)])) after_fold = circ.get_unitary() assert after_fold == before_fold
def run(self, circuit: Circuit, data: dict[str, Any]) -> None: """ Partition gates in a circuit into a series of CircuitGates. Args: circuit (Circuit): Circuit to be partitioned. data (dict[str,Any]): Optional data unique to specific run. """ if self.block_size > circuit.get_size(): _logger.warning( 'Configured block size is greater than circuit size; ' 'blocking entire circuit.', ) circuit.fold({ qudit_index: (0, circuit.get_num_cycles()) for qudit_index in range(circuit.get_size()) }) return # If a MachineModel is provided in the data dict, it will be used. # Otherwise all-to-all connectivity is assumed. model = None if 'machine_model' in data: model = data['machine_model'] if (not isinstance(model, MachineModel) or model.num_qudits < circuit.get_size()): _logger.warning( 'MachineModel not specified or invalid;' ' defaulting to all-to-all.', ) model = MachineModel(circuit.get_size()) # Find all connected, `block_size`-sized groups of qudits # NOTE: This assumes circuit and topology qudit numbers are equal qudit_groups = model.get_locations(self.block_size) num_cycles = circuit.get_num_cycles() num_qudits_groups = len(qudit_groups) op_cycles = [[[0] * self.block_size for q_group in qudit_groups] for cycle in range(num_cycles)] for cycle, op in circuit.operations_with_cycles(): if len(op.location) > 1: for q_group_index, q_group in enumerate(qudit_groups): if all([qudit in q_group for qudit in op.location]): for qudit in op.location: op_cycles[cycle][q_group_index][q_group.index( qudit)] = self.multi_gate_score else: for qudit in op.location: if qudit in q_group: op_cycles[cycle][q_group_index][q_group.index( qudit)] = -1 else: qudit = op.location[0] for q_group_index, q_group in enumerate(qudit_groups): if qudit in q_group: op_cycles[cycle][q_group_index][q_group.index( qudit)] = self.single_gate_score max_blocks = [] for q_group_index in range(num_qudits_groups): block_start = 0 block_ends = [0] * self.block_size score = 0 for cycle in range(num_cycles): if cycle: for qudit in range(self.block_size): if (op_cycles[cycle - 1][q_group_index][qudit] == -1 and op_cycles[cycle][q_group_index][qudit] != -1): max_blocks.append([ score, block_start, block_ends, q_group_index ], ) score = 0 block_start = cycle block_ends = [cycle + 1] * self.block_size break for qudit in range(self.block_size): if op_cycles[cycle][q_group_index][qudit] != -1: block_ends[qudit] = cycle + 1 score += op_cycles[cycle][q_group_index][qudit] max_blocks.append([score, block_start, block_ends, q_group_index]) block_id = -1 max_blocks.sort() remaining_assignments = circuit.get_size() * num_cycles block_map = [[-1] * circuit.get_size() for cycle in range(num_cycles)] while remaining_assignments: perform_assign = False if len(max_blocks) == 1: perform_assign = True else: block_start = max_blocks[-1][1] block_ends = max_blocks[-1][2] q_group_index = max_blocks[-1][3] score = 0 for cycle in range(block_start, max(block_ends)): for qudit in range(self.block_size): q = qudit_groups[q_group_index][qudit] if (cycle < block_ends[qudit] and block_map[cycle][q] == -1): score += 1 if score < max_blocks[-2][0]: max_blocks[-1][0] = score max_blocks.sort() else: perform_assign = True if perform_assign: block_id += 1 block_start = max_blocks[-1][1] block_ends = max_blocks[-1][2] q_group_index = max_blocks[-1][3] prev_status = None for cycle in range(block_start, max(block_ends)): status = [ block_map[cycle][qudit_groups[q_group_index][qudit]] for qudit in range(self.block_size) ] if prev_status and len(prev_status) <= len( status, ) and status != prev_status: block_id += 1 for qudit in range(self.block_size): if (cycle < block_ends[qudit] and block_map[cycle][ qudit_groups[q_group_index][qudit]] == -1): block_map[cycle][qudit_groups[q_group_index] [qudit]] = block_id remaining_assignments -= 1 prev_status = status del max_blocks[-1] for cycle in range(num_cycles): if not cycle or block_map[cycle] == block_map[cycle - 1]: continue indices = [{}, {}] for i in range(2): for qudit in range(circuit.get_size()): block = block_map[cycle - i][qudit] if block not in indices[i]: indices[i][block] = [] indices[i][block].append(qudit) for prev_blocks, prev_qudits in indices[1].items(): for current_qudits in indices[0].values(): if all([qudit in prev_qudits for qudit in current_qudits]): for qudit in current_qudits: block_map[cycle][qudit] = prev_blocks blocks = {} for cycle in range(num_cycles): for qudit in range(circuit.get_size()): if block_map[cycle][qudit] not in blocks: blocks[block_map[cycle][qudit]] = {} blocks[block_map[cycle][qudit]][-1] = cycle blocks[block_map[cycle][qudit]][qudit] = cycle block_order = [] for block in blocks.values(): block_order.append([block, block[-1]]) block_order.sort(reverse=True, key=lambda x: x[1]) for block, start_cycle in block_order: points_in_block = [] for cycle, op in circuit.operations_with_cycles(): qudit = op.location[0] if (qudit in block and cycle >= start_cycle and cycle <= block[qudit]): points_in_block.append((cycle, qudit)) circuit.fold(circuit.get_region(points_in_block))
def test_invalid_points(self, points: Sequence[CircuitPointLike]) -> None: circuit = Circuit(4, [2, 2, 3, 3]) with pytest.raises(IndexError): circuit.fold(circuit.get_region(points))
def test_correctness_1(self) -> None: circuit = Circuit(4) wide_gate = IdentityGate(4) circuit.append_gate(wide_gate, [0, 1, 2, 3]) circuit.append_gate(wide_gate, [0, 1, 2, 3]) circuit.append_gate(wide_gate, [0, 1, 2, 3]) circuit.append_gate(wide_gate, [0, 1, 2, 3]) assert circuit.get_num_operations() == 4 assert circuit.get_depth() == 4 utry = circuit.get_unitary() circuit.fold(circuit.get_region([(0, 0), (1, 0)])) assert circuit.get_num_operations() == 3 assert circuit.get_depth() == 3 check_no_idle_cycles(circuit) for q in range(4): assert isinstance(circuit[0, q].gate, CircuitGate) for c in range(1, 3, 1): for q in range(4): assert isinstance(circuit[c, q].gate, IdentityGate) assert isinstance(circuit[c, q].gate, IdentityGate) test_gate: CircuitGate = circuit[0, 0].gate # type: ignore assert test_gate._circuit.get_num_operations() == 2 assert test_gate._circuit.get_num_cycles() == 2 for q in range(4): assert isinstance(test_gate._circuit[0, q].gate, IdentityGate) assert isinstance(test_gate._circuit[1, q].gate, IdentityGate) circuit.fold(circuit.get_region([(1, 0), (2, 0)])) assert circuit.get_num_operations() == 2 assert circuit.get_depth() == 2 check_no_idle_cycles(circuit) for c in range(2): for q in range(4): assert isinstance(circuit[c, q].gate, CircuitGate) test_gate: CircuitGate = circuit[0, 0].gate # type: ignore assert test_gate._circuit.get_num_operations() == 2 assert test_gate._circuit.get_num_cycles() == 2 for q in range(4): assert isinstance(test_gate._circuit[0, q].gate, IdentityGate) assert isinstance(test_gate._circuit[1, q].gate, IdentityGate) test_gate: CircuitGate = circuit[1, 0].gate # type: ignore assert test_gate._circuit.get_num_operations() == 2 assert test_gate._circuit.get_num_cycles() == 2 for q in range(4): assert isinstance(test_gate._circuit[0, q].gate, IdentityGate) assert isinstance(test_gate._circuit[1, q].gate, IdentityGate) circuit.fold(circuit.get_region([(0, 0), (1, 0)])) assert circuit.get_num_operations() == 1 assert circuit.get_depth() == 1 check_no_idle_cycles(circuit) for q in range(4): assert isinstance(circuit[0, q].gate, CircuitGate) test_gate: CircuitGate = circuit[0, 0].gate # type: ignore assert test_gate._circuit.get_num_operations() == 2 assert test_gate._circuit.get_num_cycles() == 2 for q in range(4): assert isinstance(test_gate._circuit[0, q].gate, CircuitGate) assert isinstance(test_gate._circuit[1, q].gate, CircuitGate) inner_gate1: CircuitGate = test_gate._circuit[0, 0].gate # type: ignore inner_gate2: CircuitGate = test_gate._circuit[1, 0].gate # type: ignore assert inner_gate1._circuit.get_num_operations() == 2 assert inner_gate1._circuit.get_num_cycles() == 2 for q in range(4): assert isinstance(inner_gate1._circuit[0, q].gate, IdentityGate) assert isinstance(inner_gate1._circuit[1, q].gate, IdentityGate) assert isinstance(inner_gate2._circuit[0, q].gate, IdentityGate) assert isinstance(inner_gate2._circuit[1, q].gate, IdentityGate) check_no_idle_cycles(circuit) assert np.allclose(utry.get_numpy(), circuit.get_unitary().get_numpy())