def _apply_noise_on_observable_result_types( circuit: Circuit, readout_noise_instructions: List[NoiseModelInstruction]) -> Circuit: """Applies readout noise based on the observable result types in the circuit. Each applicable Noise will be applied only once to a target in the ObservableResultType. Args: circuit (Circuit): The circuit to apply the readout noise to. readout_noise_instructions (List[NoiseModelInstruction]): The list of readout noise to apply. Returns: Circuit: The passed in circuit, with the readout noise applied. """ result_types = circuit.result_types noise_to_apply = defaultdict(set) for result_type in result_types: if isinstance(result_type, ObservableResultType): target_qubits = list(result_type.target) for item_index, item in enumerate(readout_noise_instructions): if item.criteria.result_type_matches(result_type): for target_qubit in target_qubits: noise_to_apply[target_qubit].add(item_index) for qubit in noise_to_apply: for noise_item_index in noise_to_apply[qubit]: item = readout_noise_instructions[noise_item_index] circuit.apply_readout_noise(item.noise, qubit) return circuit
def _apply_gate_noise( cls, circuit: Circuit, gate_noise_instructions: List[NoiseModelInstruction], ) -> Circuit: """ Applies the gate noise to return a new circuit that's the `noisy` version of the given circuit. Args: circuit (Circuit): a circuit to apply `noise` to. gate_noise_instructions (List[NoiseModelInstruction]): a list of gate noise instructions to apply to the circuit. Returns: Circuit: A new circuit that's a `noisy` version of the passed in circuit. The targets set will be populated with the list of targets in the new circuit. """ new_circuit = Circuit() for circuit_instruction in circuit.instructions: new_circuit.add_instruction(circuit_instruction) target_qubits = list(circuit_instruction.target) for item in gate_noise_instructions: if item.criteria.instruction_matches(circuit_instruction): if item.noise.fixed_qubit_count() == len(target_qubits): new_circuit.add_instruction( Instruction(item.noise, target_qubits)) else: for qubit in target_qubits: new_circuit.add_instruction( Instruction(item.noise, qubit)) for result_type in circuit.result_types: new_circuit.add_result_type(result_type) return new_circuit
def test_apply_noise_to_gates_2QubitNoise_2( circuit_3qubit, noise_2qubit, noise_1qubit, noise_1qubit_2 ): circ = apply_noise_to_gates( circuit_3qubit, [noise_1qubit, noise_2qubit, noise_1qubit_2], target_gates=[Gate.CZ], target_qubits=QubitSet([1, 2]), ) expected = ( Circuit() .add_instruction(Instruction(Gate.X(), 0)) .add_instruction(Instruction(Gate.Y(), 1)) .add_instruction(Instruction(Gate.CNot(), [0, 1])) .add_instruction(Instruction(Gate.Z(), 2)) .add_instruction(Instruction(Gate.CZ(), [2, 1])) .add_instruction(Instruction(noise_1qubit, 1)) .add_instruction(Instruction(noise_1qubit, 2)) .add_instruction(Instruction(noise_2qubit, [2, 1])) .add_instruction(Instruction(noise_1qubit_2, 1)) .add_instruction(Instruction(noise_1qubit_2, 2)) .add_instruction(Instruction(Gate.CNot(), [0, 2])) .add_instruction(Instruction(Gate.CZ(), [1, 2])) .add_instruction(Instruction(noise_1qubit, 1)) .add_instruction(Instruction(noise_1qubit, 2)) .add_instruction(Instruction(noise_2qubit, [1, 2])) .add_instruction(Instruction(noise_1qubit_2, 1)) .add_instruction(Instruction(noise_1qubit_2, 2)) ) assert circ == expected
def test_apply_multiple_noise_1QubitNoise_2(circuit_2qubit, noise_1qubit, noise_1qubit_2): circ = circuit_2qubit.apply_gate_noise( noise_1qubit, target_gates=[Gate.X], ).apply_gate_noise( noise_1qubit_2, target_qubits=[0], ) expected = (Circuit().add_instruction(Instruction( Gate.X(), 0)).add_instruction(Instruction(noise_1qubit_2, 0)).add_instruction( Instruction(noise_1qubit, 0)).add_instruction( Instruction(Gate.Y(), 1)).add_instruction( Instruction(Gate.X(), 0)).add_instruction( Instruction(noise_1qubit_2, 0)).add_instruction( Instruction(noise_1qubit, 0)).add_instruction( Instruction(Gate.X(), 1)).add_instruction( Instruction( noise_1qubit, 1)).add_instruction( Instruction( Gate.CNot(), [0, 1])).add_instruction( Instruction( noise_1qubit_2, 0))) assert circ == expected
def test_apply_noise_to_moments_initialization_2QubitNoise_2( circuit_2qubit, noise_2qubit, noise_1qubit, noise_1qubit_2 ): circ = apply_noise_to_moments( circuit_2qubit, [noise_1qubit, noise_2qubit, noise_1qubit_2], target_qubits=QubitSet([0, 1]), position="initialization", ) expected = ( Circuit() .add_instruction(Instruction(noise_1qubit, 0)) .add_instruction(Instruction(noise_1qubit, 1)) .add_instruction(Instruction(noise_2qubit, [0, 1])) .add_instruction(Instruction(noise_1qubit_2, 0)) .add_instruction(Instruction(noise_1qubit_2, 1)) .add_instruction(Instruction(Gate.X(), 0)) .add_instruction(Instruction(Gate.Y(), 1)) .add_instruction(Instruction(Gate.X(), 0)) .add_instruction(Instruction(Gate.X(), 1)) .add_instruction(Instruction(Gate.CNot(), [0, 1])) ) assert circ == expected
def _( circuit: Circuit, aws_session: AwsSession, create_task_kwargs: Dict[str, Any], device_parameters: Union[dict, BraketSchemaBase], device_arn: str, *args, **kwargs, ) -> AwsQuantumTask: validate_circuit_and_shots(circuit, create_task_kwargs["shots"]) # TODO: Update this to use `deviceCapabilities` from Amazon Braket's GetDevice operation # in order to decide what parameters to build. paradigm_parameters = GateModelParameters(qubitCount=circuit.qubit_count) if "ionq" in device_arn: device_parameters = IonqDeviceParameters( paradigmParameters=paradigm_parameters) elif "rigetti" in device_arn: device_parameters = RigettiDeviceParameters( paradigmParameters=paradigm_parameters) else: # default to use simulator device_parameters = GateModelSimulatorDeviceParameters( paradigmParameters=paradigm_parameters) create_task_kwargs.update({ "action": circuit.to_ir().json(), "deviceParameters": device_parameters.json() }) task_arn = aws_session.create_quantum_task(**create_task_kwargs) return AwsQuantumTask(task_arn, aws_session, *args, **kwargs)
def apply_noise_to_moments( circuit: Circuit, noise: Iterable[Type[Noise]], target_qubits: QubitSet, position: str ) -> Circuit: """ Apply initialization/readout noise to the circuit. When `noise.qubit_count` == 1, `noise` is added to all qubits in `target_qubits`. When `noise.qubit_count` > 1, `noise.qubit_count` must be the same as the length of `target_qubits`. Args: circuit (Circuit): A ciruit where `noise` is applied to. noise (Iterable[Type[Noise]]): Noise channel(s) to be applied to the circuit. target_qubits (QubitSet): Index or indices of qubits. `noise` is applied to. Returns: Circuit: modified circuit. """ noise_instructions = [] for noise_channel in noise: if noise_channel.qubit_count == 1: new = [Instruction(noise_channel, qubit) for qubit in target_qubits] noise_instructions = noise_instructions + new else: noise_instructions.append(Instruction(noise_channel, target_qubits)) new_moments = Moments() if position == "initialization": for noise in noise_instructions: new_moments.add_noise(noise, "initialization_noise") # add existing instructions for moment_key in circuit.moments: instruction = circuit.moments[moment_key] # if the instruction is noise instruction if isinstance(instruction.operator, Noise): new_moments.add_noise(instruction, moment_key.moment_type, moment_key.noise_index) # if the instruction is a gate instruction else: new_moments.add([instruction], moment_key.noise_index) if position == "readout": for noise in noise_instructions: new_moments.add_noise(noise, "readout_noise") circuit._moments = new_moments return circuit
def _apply_init_noise( cls, circuit: Circuit, init_noise_instructions: List[NoiseModelInstruction], ) -> Circuit: """ Applies the initialization noise of this noise model to a circuit and returns the circuit. Args: circuit (Circuit): A circuit to apply `noise` to. init_noise_instructions (List[NoiseModelInstruction]): A list of initialization noise model instructions. Returns: Circuit: The passed in circuit, with the initialization noise applied. """ if not init_noise_instructions: return circuit for item in init_noise_instructions: qubits = item.criteria.qubit_intersection(circuit.qubits) if len(qubits) > 0: circuit.apply_initialization_noise(item.noise, list(qubits)) return circuit
def _( circuit: Circuit, aws_session: AwsSession, create_task_kwargs: Dict[str, Any], device_arn: str, device_parameters: Union[ dict, BraketSchemaBase], # Not currently used for circuits disable_qubit_rewiring: bool, *args, **kwargs, ) -> AwsQuantumTask: validate_circuit_and_shots(circuit, create_task_kwargs["shots"]) # TODO: Update this to use `deviceCapabilities` from Amazon Braket's GetDevice operation # in order to decide what parameters to build. paradigm_parameters = GateModelParameters( qubitCount=circuit.qubit_count, disableQubitRewiring=disable_qubit_rewiring) if "ionq" in device_arn: device_parameters = IonqDeviceParameters( paradigmParameters=paradigm_parameters) elif "rigetti" in device_arn: device_parameters = RigettiDeviceParameters( paradigmParameters=paradigm_parameters) elif "oqc" in device_arn: device_parameters = OqcDeviceParameters( paradigmParameters=paradigm_parameters) else: # default to use simulator device_parameters = GateModelSimulatorDeviceParameters( paradigmParameters=paradigm_parameters) qubit_reference_type = QubitReferenceType.VIRTUAL if disable_qubit_rewiring or Instruction( StartVerbatimBox()) in circuit.instructions: qubit_reference_type = QubitReferenceType.PHYSICAL serialization_properties = OpenQASMSerializationProperties( qubit_reference_type=qubit_reference_type) create_task_kwargs.update({ "action": circuit.to_ir( ir_type=IRType.OPENQASM, serialization_properties=serialization_properties, ).json(), "deviceParameters": device_parameters.json(), }) task_arn = aws_session.create_quantum_task(**create_task_kwargs) return AwsQuantumTask(task_arn, aws_session, *args, **kwargs)
def test_noise_not_applied_1QubitNoise_1(circuit_2qubit, noise_2qubit): circ = circuit_2qubit.apply_gate_noise( [noise_2qubit], target_qubits=[1], target_gates=[], ) expected = (Circuit().add_instruction(Instruction( Gate.X(), 0)).add_instruction(Instruction(Gate.Y(), 1)).add_instruction( Instruction(Gate.X(), 0)).add_instruction(Instruction( Gate.X(), 1)).add_instruction(Instruction(Gate.CNot(), [0, 1]))) assert circ == expected
def test_apply_initialization_noise_1QubitNoise_1(circuit_2qubit, noise_1qubit): circ = circuit_2qubit.apply_initialization_noise( [noise_1qubit], target_qubits=[0, 1], ) expected = (Circuit().add_instruction(Instruction( noise_1qubit, 0)).add_instruction(Instruction(noise_1qubit, 1)).add_instruction( Instruction(Gate.X(), 0)).add_instruction(Instruction( Gate.Y(), 1)).add_instruction(Instruction(Gate.X(), 0)).add_instruction( Instruction(Gate.X(), 1)).add_instruction( Instruction(Gate.CNot(), [0, 1]))) assert circ == expected
def test_apply_gate_noise_2QubitNoise2_parametrized( circuit_2qubit_parametrized, noise_2qubit): circ = circuit_2qubit_parametrized.apply_gate_noise( noise_2qubit, target_gates=[Gate.XY], target_qubits=[0, 1], ) expected = (Circuit().add_instruction(Instruction( Gate.X(), 0)).add_instruction(Instruction(Gate.Y(), 1)).add_instruction( Instruction(Gate.X(), 0)).add_instruction( Instruction(Gate.Rx(np.pi), 1)).add_instruction( Instruction(Gate.XY(np.pi / 2), [0, 1])).add_instruction( Instruction(noise_2qubit, [0, 1]))) assert circ == expected
def test_apply_noise_to_moments_readout_1QubitNoise_2(circuit_2qubit, noise_1qubit): circ = apply_noise_to_moments( circuit_2qubit, [noise_1qubit], target_qubits=QubitSet(1), position="readout", ) expected = (Circuit().add_instruction(Instruction( Gate.X(), 0)).add_instruction(Instruction(Gate.Y(), 1)).add_instruction( Instruction(Gate.X(), 0)).add_instruction(Instruction( Gate.X(), 1)).add_instruction(Instruction( Gate.CNot(), [0, 1])).add_instruction(Instruction(noise_1qubit, 1))) assert circ == expected
def test_apply_noise_to_gates_1QubitNoise_2(circuit_2qubit, noise_1qubit): circ = apply_noise_to_gates( circuit_2qubit, [noise_1qubit], target_gates=[Gate.X], target_qubits=QubitSet(0), ) expected = (Circuit().add_instruction(Instruction( Gate.X(), 0)).add_instruction(Instruction(noise_1qubit, 0)).add_instruction( Instruction(Gate.Y(), 1)).add_instruction(Instruction( Gate.X(), 0)).add_instruction(Instruction( noise_1qubit, 0)).add_instruction(Instruction( Gate.X(), 1)).add_instruction(Instruction(Gate.CNot(), [0, 1]))) assert circ == expected
def test_apply_gate_noise_1QubitNoise_1_unitary(circuit_2qubit_with_unitary, noise_1qubit): circ = circuit_2qubit_with_unitary.apply_gate_noise( noise_1qubit, target_unitary=np.array([[0, 1], [1, 0]]), target_qubits=[0, 1], ) expected = ( Circuit() .add_instruction(Instruction(Gate.X(), 0)) .add_instruction(Instruction(Gate.Y(), 1)) .add_instruction(Instruction(Gate.X(), 0)) .add_instruction(Instruction(Gate.X(), 1)) .add_instruction(Instruction(Gate.CNot(), [0, 1])) .add_instruction(Instruction(Gate.Unitary(np.array([[0, 1], [1, 0]]), "U"), 0)) .add_instruction(Instruction(noise_1qubit, 0)) ) assert circ == expected
def _( circuit: Circuit, aws_session: AwsSession, create_task_kwargs: Dict[str, Any], device_arn: str, device_parameters: Union[ dict, BraketSchemaBase], # Not currently used for circuits disable_qubit_rewiring, *args, **kwargs, ) -> AwsQuantumTask: validate_circuit_and_shots(circuit, create_task_kwargs["shots"]) if circuit.qubits_frozen and not disable_qubit_rewiring: raise ValueError( "disable_qubit_rewiring must be True to run circuit with compiler directives" ) # TODO: Update this to use `deviceCapabilities` from Amazon Braket's GetDevice operation # in order to decide what parameters to build. paradigm_parameters = GateModelParameters( qubitCount=circuit.qubit_count, disableQubitRewiring=disable_qubit_rewiring) if "ionq" in device_arn: device_parameters = IonqDeviceParameters( paradigmParameters=paradigm_parameters) elif "rigetti" in device_arn: device_parameters = RigettiDeviceParameters( paradigmParameters=paradigm_parameters) else: # default to use simulator device_parameters = GateModelSimulatorDeviceParameters( paradigmParameters=paradigm_parameters) create_task_kwargs.update({ "action": circuit.to_ir().json(), "deviceParameters": device_parameters.json() }) task_arn = aws_session.create_quantum_task(**create_task_kwargs) return AwsQuantumTask(task_arn, aws_session, *args, **kwargs)
def _generate_eigenstate_circuit(self, signs: Tuple[int, ...]) -> Circuit: circ = Circuit() for qubit in range(len(signs)): state = signs[qubit] * self[qubit] if state == -3: circ.x(qubit) elif state == 1: circ.h(qubit) elif state == -1: circ.x(qubit).h(qubit) elif state == 2: circ.h(qubit).s(qubit) elif state == -2: circ.h(qubit).si(qubit) return circ
def circuit_2qubit_with_unitary(): return Circuit().x(0).y(1).x(0).x(1).cnot(0, 1).unitary([0], matrix=np.array([[0, 1], [1, 0]]))
def apply_noise_to_gates( circuit: Circuit, noise: Iterable[Type[Noise]], target_gates: Union[Iterable[Type[Gate]], np.ndarray], target_qubits: QubitSet, ) -> Circuit: """Apply noise after target gates in target qubits. When `noise.qubit_count` == 1, `noise` is applied to target_qubits after `target_gates`. When `noise.qubit_count` > 1, all elements in `target_gates`, if is given, must have the same number of qubits as `noise.qubit_count`. Args: circuit (Circuit): A ciruit where `noise` is applied to. noise (Iterable[Type[Noise]]): Noise channel(s) to be applied to the circuit. target_gates (Union[Iterable[Type[Gate]], np.ndarray]): List of gates, or a unitary matrix which `noise` is applied to. target_qubits (QubitSet): Index or indices of qubits which `noise` is applied to. Returns: Circuit: modified circuit. Raises: Warning: If `noise` is multi-qubit noise while there is no gate with the same number of qubits in `target_qubits` or in the whole circuit when `target_qubits` is not given. If no `target_gates` exist in `target_qubits` or in the whole circuit when `target_qubits` is not given. """ new_moments = Moments() noise_applied = False for moment_key in circuit.moments: instruction = circuit.moments[moment_key] # add the instruction to new_moments if it is noise instruction if isinstance(instruction.operator, Noise): new_moments.add_noise(instruction, moment_key.moment_type, moment_key.noise_index) # if the instruction is a gate instruction else: new_noise_instruction = [] noise_index = moment_key.noise_index if isinstance(target_gates, np.ndarray): if (instruction.operator.name == "Unitary") and ( np.array_equiv(instruction.operator._matrix, target_gates) ): intersection = list(set(instruction.target) & set(target_qubits)) ( new_noise_instruction, noise_index, noise_applied, ) = _apply_noise_to_gates_helper( noise, target_qubits, instruction, noise_index, intersection, noise_applied, new_noise_instruction, ) elif (target_gates is None) or ( instruction.operator.name in [g.__name__ for g in target_gates] ): intersection = list(set(instruction.target) & set(target_qubits)) new_noise_instruction, noise_index, noise_applied = _apply_noise_to_gates_helper( noise, target_qubits, instruction, noise_index, intersection, noise_applied, new_noise_instruction, ) # add the gate and gate noise instructions to new_moments new_moments.add([instruction], noise_index=noise_index) for instruction, noise_index in new_noise_instruction: new_moments.add_noise(instruction, "gate_noise", noise_index) no_noise_applied_warning(noise_applied) circuit._moments = new_moments return circuit
def circuit_2qubit_parametrized(): return Circuit().x(0).y(1).x(0).rx(1, np.pi).xy(0, 1, np.pi / 2)
def test_apply_readout_noise_mismatch_qubit_count_with_target_qubits(noise_2qubit): circ = Circuit().cswap(0, 1, 2) circ.apply_readout_noise(noise_2qubit, target_qubits=[0, 1, 2])
def test_apply_gate_noise_mismatch_qubit_count_with_target_gates(noise_2qubit): circ = Circuit().cswap(0, 1, 2) circ.apply_gate_noise(noise_2qubit, target_gates=Gate.CSwap)
def test_apply_gate_noise_fixed_qubit_count_not_implemented(noise_2qubit): circ = Circuit().unitary([0, 1], matrix=np.eye(4)) circ.apply_gate_noise(noise_2qubit, target_gates=Gate.Unitary)
def circuit_2qubit(): return Circuit().x(0).y(1).x(0).x(1).cnot(0, 1)
def test_apply_readout_noise_to_empty_circuit(noise_1qubit): Circuit().apply_readout_noise(noise_1qubit)
def test_apply_initialization_noise_to_empty_circuit(noise_1qubit): Circuit().apply_initialization_noise(noise_1qubit)
def test_apply_gate_noise_to_empty_circuit(noise_1qubit): Circuit().apply_gate_noise(noise_1qubit)
def circuit_3qubit(): return Circuit().x(0).y(1).cnot(0, 1).z(2).cz(2, 1).cnot(0, 2).cz(1, 2)
def circuit_2qubit_not_dense(): # there are some qubits and some time that are not occupied by a gate return Circuit().x(0).y(1).x(0).cnot(0, 1)