def run(self, circuit: Circuit, data: dict[str, Any]) -> None: """Perform the pass's operation, see BasePass for more info.""" # Check data for windows markers if 'window_markers' not in data: _logger.warning('Did not find any window markers.') return window_markers = data['window_markers'] _logger.debug('Found window_markers: %s.' % str(window_markers)) if not is_iterable(window_markers): _logger.debug('Invalid type for window_markers.') return if not all(is_integer(marker) for marker in window_markers): _logger.debug('Invalid type for window_markers.') return # Resynthesis each window index_shift = 0 for marker in window_markers: marker -= index_shift # Slice window begin_cycle = int(marker - self.window_size // 2) end_cycle = int(marker + np.ceil(self.window_size / 2)) if begin_cycle < 0: begin_cycle = 0 if end_cycle > circuit.get_num_cycles(): end_cycle = circuit.get_num_cycles() - 1 window = Circuit(circuit.get_size(), circuit.get_radixes()) window.extend(circuit[begin_cycle:end_cycle]) _logger.info( 'Resynthesizing window from cycle ' f'{begin_cycle} to {end_cycle}.', ) # Synthesize utry = window.get_unitary() new_window = self.synthesispass.synthesize(utry, data) # Replace if self.replace_filter(new_window, window): _logger.debug('Replacing window with synthesized circuit.') actual_window_size = end_cycle - begin_cycle for _ in range(actual_window_size): circuit.pop_cycle(begin_cycle) circuit.insert_circuit( begin_cycle, new_window, list(range(circuit.get_size())), ) index_shift += actual_window_size - new_window.get_num_cycles()
def test_empty(self) -> None: circuit = Circuit(1) assert circuit.get_size() == 1 circuit = Circuit(4) assert circuit.get_size() == 4 circuit = Circuit(4, [2, 2, 3, 3]) assert circuit.get_size() == 4
def run(self, circuit: Circuit, data: dict[str, Any]) -> None: """Perform the pass's operation, see BasePass for more info.""" # Collect CircuitGate blocks blocks: list[tuple[CircuitPoint, Operation]] = [] for cycle, op in circuit.operations_with_cycles(): if isinstance(op.gate, CircuitGate): blocks.append((cycle, op)) # 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()) subdata = data.copy() # Perform work points: list[CircuitPoint] = [] ops: list[Operation] = [] for cycle, op in blocks: gate: CircuitGate = op.gate subcircuit = gate._circuit.copy() subcircuit.set_params(op.params) subnumbering = {op.location[i]: i for i in range(len(op.location))} subdata['machine_model'] = MachineModel( len(op.location), model.get_subgraph(op.location, subnumbering), ) for loop_pass in self.loop_body: loop_pass.run(circuit, subdata) if self.replace_filter(subcircuit, op): points.append(CircuitPoint(cycle, op.location[0])) ops.append( Operation( CircuitGate(subcircuit, True), op.location, subcircuit.get_params(), ), ) # TODO: Load freshly written data from subdata into data circuit.batch_replace(points, ops)
def test_qubits(self) -> None: circuit = Circuit(1, [2]) assert circuit.get_size() == 1 assert circuit.get_dim() == 2 assert len(circuit.get_radixes()) == 1 circuit.extend_qudits([2, 2]) assert circuit.get_size() == 3 assert circuit.get_dim() == 8 assert len(circuit.get_radixes()) == 3 circuit.extend_qudits([2, 2]) assert circuit.get_size() == 5 assert circuit.get_dim() == 32 assert len(circuit.get_radixes()) == 5
def test_qutrits(self) -> None: circuit = Circuit(1, [3]) assert circuit.get_size() == 1 assert circuit.get_dim() == 3 assert len(circuit.get_radixes()) == 1 circuit.extend_qudits([3, 3]) assert circuit.get_size() == 3 assert circuit.get_dim() == 27 assert len(circuit.get_radixes()) == 3 circuit.extend_qudits([3, 3]) assert circuit.get_size() == 5 assert circuit.get_dim() == 243 assert len(circuit.get_radixes()) == 5
def test_qutrit(self) -> None: circuit = Circuit(1, [3]) assert circuit.get_size() == 1 assert circuit.get_dim() == 3 assert len(circuit.get_radixes()) == 1 circuit.insert_qudit(0, 3) assert circuit.get_size() == 2 assert circuit.get_dim() == 9 assert len(circuit.get_radixes()) == 2 circuit.insert_qudit(0, 3) assert circuit.get_size() == 3 assert circuit.get_dim() == 27 assert len(circuit.get_radixes()) == 3
def test_default(self) -> None: circuit = Circuit(1) assert circuit.get_size() == 1 assert circuit.get_dim() == 2 assert len(circuit.get_radixes()) == 1 circuit.append_qudit() assert circuit.get_size() == 2 assert circuit.get_dim() == 4 assert len(circuit.get_radixes()) == 2 circuit.append_qudit() assert circuit.get_size() == 3 assert circuit.get_dim() == 8 assert len(circuit.get_radixes()) == 3
def gen_initial_layer( self, target: UnitaryMatrix | StateVector, data: dict[str, Any], ) -> Circuit: """ Generate the initial layer, see LayerGenerator for more. Raises: ValueError: If `target` has a radix mismatch with `self.initial_layer_gate`. """ if not isinstance(target, (UnitaryMatrix, StateVector)): raise TypeError( 'Expected unitary or state, got %s.' % type(target), ) for radix in target.get_radixes(): if radix != self.initial_layer_gate.get_radixes()[0]: raise ValueError( 'Radix mismatch between target and initial_layer_gate.', ) init_circuit = Circuit(target.get_size(), target.get_radixes()) for i in range(init_circuit.get_size()): init_circuit.append_gate(self.initial_layer_gate, [i]) return init_circuit
def test_append_gate_5(self) -> None: circuit = Circuit(4) circuit.append_gate(CNOTGate(), [0, 1]) circuit.append_gate(CNOTGate(), [1, 2]) circuit.append_gate(CNOTGate(), [2, 3]) circuit.insert_qudit(4) circuit.append_gate(CNOTGate(), [0, 3]) assert circuit.get_size() == 5 assert len(circuit.get_radixes()) == 5 assert circuit.get_radixes().count(2) == 5 assert circuit[3, 0].gate == CNOTGate() assert circuit[3, 0].location == (0, 3) assert circuit[0, 1].gate == CNOTGate() assert circuit[0, 1].location == (0, 1) assert circuit[1, 2].gate == CNOTGate() assert circuit[1, 2].location == (1, 2) assert circuit[2, 3].gate == CNOTGate() assert circuit[2, 3].location == (2, 3) assert circuit[3, 3].gate == CNOTGate() assert circuit[3, 3].location == (0, 3) assert circuit[0, 0].gate == CNOTGate() assert circuit[0, 0].location == (0, 1) assert circuit[1, 1].gate == CNOTGate() assert circuit[1, 1].location == (1, 2) assert circuit[2, 2].gate == CNOTGate() assert circuit[2, 2].location == (2, 3)
def test_append_gate_4(self, qudit_index: int) -> None: circuit = Circuit(4) circuit.append_gate(CNOTGate(), [0, 1]) circuit.append_gate(CNOTGate(), [1, 2]) circuit.append_gate(CNOTGate(), [2, 3]) circuit.append_gate(CNOTGate(), [0, 1]) circuit.append_gate(CNOTGate(), [1, 2]) circuit.append_gate(CNOTGate(), [2, 3]) circuit.append_gate(CNOTGate(), [0, 1]) circuit.append_gate(CNOTGate(), [1, 2]) circuit.append_gate(CNOTGate(), [2, 3]) circuit.pop_qudit(qudit_index) assert circuit.get_size() == 3 assert len(circuit.get_radixes()) == 3 assert circuit.get_radixes().count(2) == 3 assert circuit.get_num_operations() == 6 assert circuit[0, 0].gate == CNOTGate() assert circuit[0, 0].location == (0, 1) assert circuit[1, 1].gate == CNOTGate() assert circuit[1, 1].location == (1, 2) assert circuit[2, 0].gate == CNOTGate() assert circuit[2, 0].location == (0, 1) assert circuit[3, 1].gate == CNOTGate() assert circuit[3, 1].location == (1, 2) assert circuit[4, 0].gate == CNOTGate() assert circuit[4, 0].location == (0, 1) assert circuit[5, 1].gate == CNOTGate() assert circuit[5, 1].location == (1, 2)
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 for i in range(self.num_points): # Pick best region of 4 random points best_region = None best_gates = 0 for _ in range(4): cycle = 0 qudit = 0 while True: cycle = np.random.randint(circuit.get_num_cycles()) qudit = np.random.randint(circuit.get_size()) if not circuit.is_point_idle((cycle, qudit)): break region = circuit.surround((cycle, qudit), self.block_size) num_gates = len(circuit[region]) if num_gates > best_gates: best_gates = num_gates best_region = region if best_region is None: raise RuntimeError('Unable to find a region.') circuit.fold(best_region)
def test_append_gate(self) -> None: circuit = Circuit(4) circuit.append_gate(CNOTGate(), [0, 1]) circuit.append_gate(CNOTGate(), [1, 2]) circuit.append_gate(CNOTGate(), [2, 3]) circuit.append_qudit() circuit.append_gate(CNOTGate(), [3, 4]) assert circuit.get_size() == 5 assert circuit[3, 4].gate == CNOTGate()
def test_hybrid(self) -> None: circuit = Circuit(1) assert circuit.get_size() == 1 assert circuit.get_dim() == 2 assert len(circuit.get_radixes()) == 1 circuit.append_qudit(4) assert circuit.get_size() == 2 assert circuit.get_dim() == 8 assert len(circuit.get_radixes()) == 2 assert circuit.get_radixes()[0] == 2 assert circuit.get_radixes()[1] == 4 circuit.append_qudit(3) assert circuit.get_size() == 3 assert circuit.get_dim() == 24 assert len(circuit.get_radixes()) == 3 assert circuit.get_radixes()[0] == 2 assert circuit.get_radixes()[1] == 4 assert circuit.get_radixes()[2] == 3
def test_hybrid(self) -> None: circuit = Circuit(1) assert circuit.get_size() == 1 assert circuit.get_dim() == 2 assert len(circuit.get_radixes()) == 1 circuit.insert_qudit(0, 4) assert circuit.get_size() == 2 assert circuit.get_dim() == 8 assert len(circuit.get_radixes()) == 2 assert circuit.get_radixes()[0] == 4 assert circuit.get_radixes()[1] == 2 circuit.insert_qudit(-1, 3) assert circuit.get_size() == 3 assert circuit.get_dim() == 24 assert len(circuit.get_radixes()) == 3 assert circuit.get_radixes()[0] == 4 assert circuit.get_radixes()[1] == 3 assert circuit.get_radixes()[2] == 2
def test_index_invalid_empty(self) -> None: circuit = Circuit(1) assert circuit.get_size() == 1 try: circuit.pop_qudit(0) except ValueError: return except BaseException: assert False, 'Unexpected Exception.'
def test_hybrid(self) -> None: circuit = Circuit(1) assert circuit.get_size() == 1 assert circuit.get_dim() == 2 assert len(circuit.get_radixes()) == 1 circuit.extend_qudits([3, 4]) assert circuit.get_size() == 3 assert circuit.get_dim() == 24 assert len(circuit.get_radixes()) == 3 assert circuit.get_radixes()[0] == 2 assert circuit.get_radixes()[1] == 3 assert circuit.get_radixes()[2] == 4 circuit.extend_qudits([3, 2]) assert circuit.get_size() == 5 assert circuit.get_dim() == 144 assert len(circuit.get_radixes()) == 5 assert circuit.get_radixes()[0] == 2 assert circuit.get_radixes()[1] == 3 assert circuit.get_radixes()[2] == 4 assert circuit.get_radixes()[3] == 3 assert circuit.get_radixes()[4] == 2
def test_with_fold(self, r6_qudit_circuit: Circuit) -> None: cycle = 0 qudit = 0 while True: cycle = np.random.randint(r6_qudit_circuit.get_num_cycles()) qudit = np.random.randint(r6_qudit_circuit.get_size()) if not r6_qudit_circuit.is_point_idle((cycle, qudit)): break utry = r6_qudit_circuit.get_unitary() region = r6_qudit_circuit.surround((cycle, qudit), 4) r6_qudit_circuit.fold(region) assert r6_qudit_circuit.get_unitary() == utry
def gen_successors( self, circuit: Circuit, data: dict[str, Any], ) -> list[Circuit]: """ Generate the successors of a circuit node. Raises: ValueError: If circuit is a single-qudit circuit. """ if not isinstance(circuit, Circuit): raise TypeError('Expected circuit, got %s.' % type(circuit)) if circuit.get_size() < 2: raise ValueError('Cannot expand a single-qudit circuit.') # 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()) # TODO: Reconsider linear topology default successors = [] for edge in model.coupling_graph: successor = circuit.copy() successor.append_gate(self.two_qudit_gate, [edge[0], edge[1]]) successor.append_gate(self.single_qudit_gate_1, edge[0]) successor.append_gate(self.single_qudit_gate_2, edge[1]) successors.append(successor) return successors
def test_correctness_1(self, r6_qudit_circuit: Circuit) -> None: for x in range(r6_qudit_circuit.get_num_cycles()): for y in range(r6_qudit_circuit.get_size()): correct = r6_qudit_circuit._circuit[x][y] if correct is not None: assert correct is r6_qudit_circuit.get_operation((x, y)) else: try: r6_qudit_circuit.get_operation((x, y)) except IndexError: pass except BaseException: assert False, 'Unexpected exception.'
def test_correctness_1(self, r6_qudit_circuit: Circuit) -> None: for x in range(r6_qudit_circuit.get_num_cycles()): for y in range(r6_qudit_circuit.get_size()): op = r6_qudit_circuit._circuit[x][y] if op is not None: point = r6_qudit_circuit.point(op, (x, y)) assert r6_qudit_circuit.get_operation(point) is op point = r6_qudit_circuit.point(op, (x, y), (x, y)) assert r6_qudit_circuit.get_operation(point) is op point = r6_qudit_circuit.point(op.gate, (x, y)) assert r6_qudit_circuit.get_operation(point) is op point = r6_qudit_circuit.point(op.gate, (x, y), (x, y)) assert r6_qudit_circuit.get_operation(point) is op
def test_multi_gate_3(self, gen_random_utry_np: Any) -> None: circuit = Circuit(4) three_qubit_gate = ConstantUnitaryGate( gen_random_utry_np(12), [2, 2, 3], ) circuit.insert_qudit(2, 3) assert circuit.get_size() == 5 assert len(circuit.get_radixes()) == 5 assert circuit.get_radixes()[0] == 2 assert circuit.get_radixes()[1] == 2 assert circuit.get_radixes()[2] == 3 assert circuit.get_radixes()[3] == 2 assert circuit.get_radixes()[4] == 2 circuit.append_gate(three_qubit_gate, [0, 1, 2]) assert circuit[0, 0].gate == three_qubit_gate assert circuit[0, 0].location == (0, 1, 2)
def test_multi_gate_1(self, gen_random_utry_np: Any) -> None: circuit = Circuit(4) three_qubit_gate = ConstantUnitaryGate(gen_random_utry_np(8)) circuit.append_gate(three_qubit_gate, [1, 2, 3]) circuit.append_gate(three_qubit_gate, [0, 2, 3]) circuit.append_gate(three_qubit_gate, [0, 1, 3]) circuit.append_gate(three_qubit_gate, [0, 1, 2]) circuit.insert_qudit(0) assert circuit.get_size() == 5 assert len(circuit.get_radixes()) == 5 assert circuit.get_radixes().count(2) == 5 assert circuit[0, 2].gate == three_qubit_gate assert circuit[0, 2].location == (2, 3, 4) assert circuit[1, 1].gate == three_qubit_gate assert circuit[1, 1].location == (1, 3, 4) assert circuit[2, 1].gate == three_qubit_gate assert circuit[2, 1].location == (1, 2, 4) assert circuit[3, 1].gate == three_qubit_gate assert circuit[3, 1].location == (1, 2, 3)
def test_multi_gate_1( self, qudit_index: int, gen_random_utry_np: Any, ) -> None: circuit = Circuit(4) three_qubit_gate = ConstantUnitaryGate(gen_random_utry_np(8)) circuit.append_gate(three_qubit_gate, [1, 2, 3]) circuit.append_gate(three_qubit_gate, [0, 2, 3]) circuit.append_gate(three_qubit_gate, [0, 1, 3]) circuit.append_gate(three_qubit_gate, [0, 1, 2]) circuit.pop_qudit(qudit_index) assert circuit.get_size() == 3 assert len(circuit.get_radixes()) == 3 assert circuit.get_radixes().count(2) == 3 assert circuit.get_num_operations() == 1 assert circuit.get_num_cycles() == 1 assert circuit[0, 0].gate == three_qubit_gate assert circuit[0, 0].location == (0, 1, 2) assert circuit[0, 1].gate == three_qubit_gate assert circuit[0, 1].location == (0, 1, 2) assert circuit[0, 2].gate == three_qubit_gate assert circuit[0, 2].location == (0, 1, 2)
def test_type(self, r6_qudit_circuit: Circuit) -> None: assert isinstance(r6_qudit_circuit.get_size(), int)
def test_get_size(self, toffoli_circuit: Circuit) -> None: assert toffoli_circuit.get_size() == 3
def test_get_radixes(self, simple_circuit: Circuit) -> None: assert len(simple_circuit.get_radixes()) == simple_circuit.get_size() assert isinstance(simple_circuit.get_radixes(), tuple) assert all(r == 2 for r in simple_circuit.get_radixes())
def test_get_size(self, simple_circuit: Circuit) -> None: assert simple_circuit.get_size() == 2
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) # Prune unused qudit groups used_qudits = [ q for q in range(circuit.get_size()) if not circuit.is_qudit_idle(q) ] for qudit_group in qudit_groups: if all([q not in used_qudits for q in qudit_group]): qudit_groups.remove(qudit_group) # divider splits the circuit into partitioned and unpartitioned spaces. active_qudits = circuit.get_active_qudits() num_cycles = circuit.get_num_cycles() divider = [ 0 if q in active_qudits else num_cycles for q in range(circuit.get_size()) ] # Form regions until there are no more gates to partition regions: list[CircuitRegion] = [] while any(cycle < num_cycles for cycle in divider): # Move past/skip any gates that are larger than block size qudits_to_increment: list[int] = [] for qudit, cycle in enumerate(divider): if qudit in qudits_to_increment or cycle >= num_cycles: continue if not circuit.is_point_idle((cycle, qudit)): op = circuit[cycle, qudit] if len(op.location) > self.block_size: if all(divider[q] == cycle for q in op.location): qudits_to_increment.extend(op.location) _logger.warning( 'Skipping gate larger than block size.', ) if len(qudits_to_increment) > 0: regions.append( CircuitRegion( { qudit: (divider[qudit], divider[qudit]) for qudit in qudits_to_increment }, ), ) for qudit in qudits_to_increment: divider[qudit] += 1 # Skip any idle qudit-cycles amount_to_add_to_each_qudit = [ 0 for _ in range(circuit.get_size()) ] for qudit, cycle in enumerate(divider): while (cycle < num_cycles and circuit.is_point_idle( (cycle, qudit))): amount_to_add_to_each_qudit[qudit] += 1 cycle += 1 for qudit, amount in enumerate(amount_to_add_to_each_qudit): divider[qudit] += amount # Find the scores of the qudit groups. best_score = None best_region = None for qudit_group in qudit_groups: ops_and_cycles = circuit.operations_with_cycles( qudits_or_region=CircuitRegion({ qudit_index: (divider[qudit_index], num_cycles) for qudit_index in qudit_group }), ) in_qudits = list(q for q in qudit_group) stopped_cycles = {q: num_cycles for q in qudit_group} score = 0 for cycle, op in ops_and_cycles: if len(op.location.union(in_qudits)) != len(in_qudits): for qudit_index in op.location.intersection(in_qudits): stopped_cycles[qudit_index] = cycle in_qudits.remove(qudit_index) else: if len(op.location) > 1: score += self.multi_gate_score else: score += self.single_gate_score if len(in_qudits) == 0: break if best_score is None or score > best_score: best_score = score best_region = CircuitRegion({ qudit: ( divider[qudit], # Might have errors if below is removed stopped_cycles[qudit] - 1, ) for qudit in qudit_group # This statement # if stopped_cycles[qudit] - 1 >= divider[qudit] }) if best_score is None or best_region is None: raise RuntimeError('No valid block found.') _logger.info('Found block with score: %d.' % (best_score)) regions.append(best_region) # Update divider for qudit_index in best_region: divider[qudit_index] = best_region[qudit_index].upper + 1 # Fold the circuit folded_circuit = Circuit(circuit.get_size(), circuit.get_radixes()) # Option to keep a block's idle qudits as part of the CircuitGate if 'keep_idle_qudits' in data and data['keep_idle_qudits'] is True: for region in regions: small_region = circuit.downsize_region(region) cgc = circuit.get_slice(small_region.points) if len(region.location) > len(small_region.location): for i in range(len(region.location)): if region.location[i] not in small_region.location: cgc.insert_qudit(i) folded_circuit.append_gate( CircuitGate(cgc, True), sorted(list(region.keys())), list(cgc.get_params()), ) else: for region in regions: region = circuit.downsize_region(region) if 0 < len(region) <= self.block_size: cgc = circuit.get_slice(region.points) folded_circuit.append_gate( CircuitGate(cgc, True), sorted(list(region.keys())), list(cgc.get_params()), ) else: folded_circuit.extend(circuit[region]) circuit.become(folded_circuit)
def test_get_radixes(self, toffoli_circuit: Circuit) -> None: assert len(toffoli_circuit.get_radixes()) == toffoli_circuit.get_size() assert isinstance(toffoli_circuit.get_radixes(), tuple) assert all(r == 2 for r in toffoli_circuit.get_radixes())
def test_value(self, r6_qudit_circuit: Circuit) -> None: assert r6_qudit_circuit.get_size() == 6