def test_example(self) -> None: circuit = Circuit(1) opH = Operation(HGate(), [0]) circuit.append(opH) assert circuit.point(opH).__repr__( ) == 'CircuitPoint(cycle=0, qudit=0)' opX = Operation(XGate(), [0]) circuit.append(opX) assert circuit.point(opX).__repr__( ) == 'CircuitPoint(cycle=1, qudit=0)'
def test_correctness_2(self) -> None: circuit = Circuit(2) circuit.append_gate(HGate(), [0]) circuit.append_gate(CNOTGate(), [0, 1]) assert circuit.point(HGate()) == (0, 0) assert circuit.point(CNOTGate()) == (1, 0) assert circuit.point(Operation(HGate(), [0])) == (0, 0) assert circuit.point(Operation(CNOTGate(), [0, 1])) == (1, 0) try: circuit.point(Operation(CNOTGate(), [1, 0])) except ValueError: return assert False, 'Should not have reached here.'
def test_random_batch_remove(self) -> None: num_gates = 200 num_q = 10 circ = Circuit(num_q) for _ in range(num_gates): a = randint(0, num_q - 1) b = randint(0, num_q - 1) if a == b: b = (b + 1) % num_q circ.append_gate(CNOTGate(), [a, b]) ScanPartitioner(2).run(circ, {}) points = [] ops = [] for cycle, op in circ.operations_with_cycles(): point = (cycle, op.location[0]) ops.append(Operation(CNOTGate(), op.location)) points.append(point) circ.batch_replace(points, ops) for op in circ: assert isinstance(op.gate, CNOTGate)
def test_type_valid_2(self) -> None: circuit = Circuit(4, [2, 2, 3, 3]) try: circuit.extend([Operation(HGate(), [0])]) except TypeError: assert False, 'Unexpected TypeError.' except BaseException: return
def test_type_valid_1(self) -> None: circuit = Circuit(1) try: circuit.append(Operation(HGate(), [0])) except TypeError: assert False, 'Unexpected TypeError.' except BaseException: return
def test_radix_mismatch_2(self, qutrit_gate: Gate) -> None: circuit = Circuit(qutrit_gate.get_size()) location = list(range(qutrit_gate.get_size())) params = [0] * qutrit_gate.get_num_params() op = Operation(qutrit_gate, location, params) try: circuit.check_valid_operation(op) except ValueError: return except BaseException: assert False, 'Unexpected Exception' assert False
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 gate(self, args: Any) -> None: gate_name = args.children[0] param_list = None if len(args.children) == 2 else args.children[1] if len(args.children) == 2: var_list = args.children[1] else: var_list = args.children[2] if gate_name not in self.gate_defs: raise LangException('Unrecognized gate: %s.' % gate_name) gate_def = self.gate_defs[gate_name] # Calculate params params = [] if param_list is not None: if is_iterable(eval_explist(param_list)): params = [float(i) for i in eval_explist(param_list)] else: params = [float(eval_explist(param_list))] if len(params) != gate_def.num_params: raise LangException( 'Expected %d params got %d params for gate %s.' % (gate_def.num_params, len(params), gate_name), ) # Calculate location location = [] for reg_name, reg_idx in qubits_from_list(var_list): outer_idx = 0 for reg in self.qubit_regs: if reg.name == reg_name: location.append(outer_idx + reg_idx) break outer_idx += reg.size if len(location) != gate_def.num_vars: raise LangException( 'Gate acts on %d qubits, got %d qubit variables.' % (gate_def.num_vars, len(location)), ) # Calculate operation self.op_list.append(Operation(gate_def.gate, location, params))
def test_batch_replace(self) -> None: circ = Circuit(4) op_1a = Operation(CNOTGate(), [0, 1]) op_2a = Operation(CNOTGate(), [2, 3]) op_3a = Operation(CNOTGate(), [1, 2]) op_4a = Operation(CNOTGate(), [0, 1]) op_5a = Operation(CNOTGate(), [0, 1]) op_6a = Operation(CNOTGate(), [2, 3]) list_a = [op_1a, op_2a, op_3a, op_4a, op_5a, op_6a] op_1b = Operation(CNOTGate(), [1, 0]) op_2b = Operation(CNOTGate(), [3, 2]) op_3b = Operation(CNOTGate(), [2, 1]) op_4b = Operation(CNOTGate(), [1, 0]) op_5b = Operation(CNOTGate(), [1, 0]) op_6b = Operation(CNOTGate(), [3, 2]) list_b = [op_1b, op_2b, op_3b, op_4b, op_5b, op_6b] for op in list_a: circ.append(op) assert circ.get_operation((0, 0), ) == op_1a and circ.get_operation( (0, 1), ) == op_1a assert circ.get_operation((0, 2), ) == op_2a and circ.get_operation( (0, 3), ) == op_2a assert circ.get_operation((1, 1), ) == op_3a and circ.get_operation( (1, 2), ) == op_3a assert circ.get_operation((2, 0), ) == op_4a and circ.get_operation( (2, 1), ) == op_4a assert circ.get_operation((2, 2), ) == op_6a and circ.get_operation( (2, 3), ) == op_6a assert circ.get_operation((3, 0), ) == op_5a and circ.get_operation( (3, 1), ) == op_5a for i in range(4): for j in range(4): print(f'({i},{j}): {circ._circuit[i][j]}') points = [(0, 0), (0, 2), (1, 1), (2, 0), (3, 1), (2, 3)] new_ops = list_b circ.batch_replace(points, new_ops) assert circ.get_operation((0, 0), ) == op_1b and circ.get_operation( (0, 1), ) == op_1b assert circ.get_operation((0, 2), ) == op_2b and circ.get_operation( (0, 3), ) == op_2b assert circ.get_operation((1, 1), ) == op_3b and circ.get_operation( (1, 2), ) == op_3b assert circ.get_operation((2, 0), ) == op_4b and circ.get_operation( (2, 1), ) == op_4b assert circ.get_operation((2, 2), ) == op_6b and circ.get_operation( (2, 3), ) == op_6b assert circ.get_operation((3, 0), ) == op_5b and circ.get_operation( (3, 1), ) == op_5b
def test_valid_3(self) -> None: circuit = Circuit(2, [3, 2]) gate = ConstantUnitaryGate(np.identity(6), [2, 3]) circuit.check_valid_operation(Operation(gate, [1, 0]))
def test_valid_2(self, gate: Gate) -> None: circuit = Circuit(gate.get_size() + 2, (2, 2) + gate.get_radixes()) location = [x + 2 for x in list(range(gate.get_size()))] params = [0] * gate.get_num_params() circuit.check_valid_operation(Operation(gate, location, params))
def test_valid_1(self, gate: Gate) -> None: circuit = Circuit(gate.get_size(), gate.get_radixes()) location = list(range(gate.get_size())) params = [0] * gate.get_num_params() circuit.check_valid_operation(Operation(gate, location, params))
class TestCheckValidOperation: """This tests `circuit.check_valid_operation`.""" @pytest.mark.parametrize( ('circuit', 'op'), [ (Circuit(1), Operation(HGate(), [0])), (Circuit(1), Operation(CNOTGate(), [0, 1])), (Circuit(1), Operation(CPIGate(), [2, 3])), (Circuit(4, [2, 2, 3, 3]), Operation(HGate(), [0])), (Circuit(4, [2, 2, 3, 3]), Operation(CNOTGate(), [0, 1])), (Circuit(4, [2, 2, 3, 3]), Operation(CPIGate(), [2, 3])), ], ) def test_type_valid(self, circuit: Circuit, op: Operation) -> None: try: circuit.check_valid_operation(op) except TypeError: assert False, 'Unexpected Exception.' except BaseException: return @pytest.mark.parametrize( ('circuit', 'op'), [ (Circuit(1), 'A'), (Circuit(1), 0), (Circuit(1), np.int64(1234)), (Circuit(4, [2, 2, 3, 3]), 'A'), (Circuit(4, [2, 2, 3, 3]), 0), (Circuit(4, [2, 2, 3, 3]), np.int64(1234)), ], ) def test_type_invalid(self, circuit: Circuit, op: Operation) -> None: try: circuit.check_valid_operation(op) except TypeError: return except BaseException: assert False, 'Unexpected Exception.' def test_location_mismatch_1(self, qubit_gate: Gate) -> None: circuit = Circuit(qubit_gate.get_size()) location = list(range(qubit_gate.get_size())) location[-1] += 1 params = [0] * qubit_gate.get_num_params() op = Operation(qubit_gate, location, params) try: circuit.check_valid_operation(op) except ValueError: return except BaseException: assert False, 'Unexpected Exception' assert False def test_location_mismatch_2(self, qutrit_gate: Gate) -> None: circuit = Circuit(qutrit_gate.get_size(), qutrit_gate.get_radixes()) location = list(range(qutrit_gate.get_size())) location[-1] += 1 params = [0] * qutrit_gate.get_num_params() op = Operation(qutrit_gate, location, params) try: circuit.check_valid_operation(op) except ValueError: return except BaseException: assert False, 'Unexpected Exception' assert False def test_radix_mismatch_1(self, qubit_gate: Gate) -> None: circuit = Circuit(qubit_gate.get_size(), [3] * qubit_gate.get_size()) location = list(range(qubit_gate.get_size())) params = [0] * qubit_gate.get_num_params() op = Operation(qubit_gate, location, params) try: circuit.check_valid_operation(op) except ValueError: return except BaseException: assert False, 'Unexpected Exception' assert False def test_radix_mismatch_2(self, qutrit_gate: Gate) -> None: circuit = Circuit(qutrit_gate.get_size()) location = list(range(qutrit_gate.get_size())) params = [0] * qutrit_gate.get_num_params() op = Operation(qutrit_gate, location, params) try: circuit.check_valid_operation(op) except ValueError: return except BaseException: assert False, 'Unexpected Exception' assert False def test_valid_1(self, gate: Gate) -> None: circuit = Circuit(gate.get_size(), gate.get_radixes()) location = list(range(gate.get_size())) params = [0] * gate.get_num_params() circuit.check_valid_operation(Operation(gate, location, params)) def test_valid_2(self, gate: Gate) -> None: circuit = Circuit(gate.get_size() + 2, (2, 2) + gate.get_radixes()) location = [x + 2 for x in list(range(gate.get_size()))] params = [0] * gate.get_num_params() circuit.check_valid_operation(Operation(gate, location, params)) def test_valid_3(self) -> None: circuit = Circuit(2, [3, 2]) gate = ConstantUnitaryGate(np.identity(6), [2, 3]) circuit.check_valid_operation(Operation(gate, [1, 0]))
def run(self, circuit: Circuit, data: dict[str, Any]) -> None: """Perform the pass's operation, see BasePass for more info.""" # Collect synthesizable operations ops_to_syn: list[tuple[int, Operation]] = [] for cycle, op in circuit.operations_with_cycles(): if self.collection_filter(op): ops_to_syn.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()) sub_data = data.copy() structure_list: list[Sequence[int]] = [] # Synthesize operations errors: list[float] = [] points: list[CircuitPoint] = [] new_ops: list[Operation] = [] num_blocks = len(ops_to_syn) for block_num, (cycle, op) in enumerate(ops_to_syn): sub_numbering = {op.location[i]: i for i in range(op.size)} sub_data['machine_model'] = MachineModel( len(op.location), model.get_subgraph(op.location, sub_numbering), ) structure_list.append([op.location[i] for i in range(op.size)]) syn_circuit = self.synthesize(op.get_unitary(), sub_data) if self.checkpoint_dir is not None: save_checkpoint(syn_circuit, self.checkpoint_dir, block_num) if self.replace_filter(syn_circuit, op): # Calculate errors new_utry = syn_circuit.get_unitary() old_utry = op.get_unitary() error = new_utry.get_distance_from(old_utry) errors.append(error) points.append(CircuitPoint(cycle, op.location[0])) new_ops.append( Operation( CircuitGate(syn_circuit, True), op.location, list(syn_circuit.get_params()), # TODO: RealVector ), ) _logger.info( f'Error in synthesized CircuitGate {block_num+1} of ' f'{num_blocks}: {error}', ) data['synthesispass_error_sum'] = sum(errors) # TODO: Might be replaced _logger.info( 'Synthesis pass completed. Upper bound on ' f"circuit error is {data['synthesispass_error_sum']}", ) if self.checkpoint_dir is not None: with open(f'{self.checkpoint_dir}/structure.pickle', 'wb') as f: dump(structure_list, f) circuit.batch_replace(points, new_ops)