def test_PrepareAndMeasureOnQVM(): prepare_ansatz = Program() param_register = prepare_ansatz.declare("params", memory_type="REAL", memory_size=2) prepare_ansatz.inst(RX(param_register[0], 0)) prepare_ansatz.inst(RX(param_register[1], 1)) def make_memory_map(params): return {"params": params} # ham = PauliSum.from_compact_str("1.0*Z0 + 1.0*Z1") term1 = PauliTerm("Z", 0) term2 = PauliTerm("Z", 1) ham = PauliSum([term1, term2]) qvm = get_qc("2q-qvm") with local_qvm(): # qvm = proc.qvm cost_fn = PrepareAndMeasureOnQVM(prepare_ansatz, make_memory_map, qvm=qvm, hamiltonian=ham, enable_logging=True, scalar_cost_function=True, base_numshots=10, nshots=10) out = cost_fn([np.pi, np.pi / 2]) assert np.allclose(cost_fn.log[0].fun, (-1.0, 0.1), rtol=1.1) assert np.allclose(out, -1, rtol=1.1)
def add_gate_program_grover4(p, gate): erase = [ '(', ')', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-' ] gate_data = gate.split(' ') name_gate = gate_data[0] for char in erase: name_gate = name_gate.replace(char, '') if name_gate == 'H': p.inst(RZ(pi / 2, int(gate_data[1])), RX(pi / 2, int(gate_data[1])), RZ(pi / 2, int(gate_data[1]))) if name_gate == 'X': p.inst(RZ(pi / 2, int(gate_data[1])), RX(pi / 2, int(gate_data[1])), RZ(pi, int(gate_data[1])), RX(-pi / 2, int(gate_data[1])), RZ(-pi / 2, int(gate_data[1]))) if name_gate == 'CNOT': p.inst(RZ(pi / 2, int(gate_data[2])), RX(pi / 2, int(gate_data[2])), CZ(int(gate_data[1]), int(gate_data[2])), RX(-pi / 2, int(gate_data[2])), RZ(-pi / 2, int(gate_data[2]))) if name_gate == 'RZ': angle = float(gate_data[0].replace('RZ(', '').replace(')', '')) p.inst(RZ(-pi / 8, int(gate_data[1]))) if name_gate == 'PHASE': angle = float(gate_data[0].replace('PHASE(', '').replace(')', '')) p.inst(RZ(0.19634954084936207, int(gate_data[1]))) return p
def _one_q_pauli_prep(label: str, index: int, qubit: QubitDesignator) -> Program: """Prepare the index-th eigenstate of the pauli operator given by label.""" if index not in [0, 1]: raise ValueError(f"Bad Pauli index: {index}") if label == "X": if index == 0: return Program(RY(pi / 2, qubit)) else: return Program(RY(-pi / 2, qubit)) elif label == "Y": if index == 0: return Program(RX(-pi / 2, qubit)) else: return Program(RX(pi / 2, qubit)) elif label == "Z": if index == 0: return Program() else: return Program(RX(pi, qubit)) raise ValueError(f"Bad Pauli label: {label}")
def test_get_qvm_noise_supported_gates_from_aspen8_isa( qcs_aspen8_quantum_processor, noise_model_dict): gates = _get_qvm_noise_supported_gates( qcs_aspen8_quantum_processor.to_compiler_isa()) for q in range(len(qcs_aspen8_quantum_processor._isa.architecture.nodes)): if q not in ASPEN_8_QUBITS_NO_RX: for g in [ RX(np.pi / 2, q), RX(-np.pi / 2, q), RX(np.pi, q), RX(-np.pi, q), ]: assert g in gates if q not in ASPEN_8_QUBITS_NO_RZ: assert RZ(THETA, q) in gates for edge in qcs_aspen8_quantum_processor._isa.architecture.edges: if ( edge.node_ids[0], edge.node_ids[1], ) in ASPEN_8_EDGES_NO_CZ: continue assert CZ(edge.node_ids[0], edge.node_ids[1]) in gates assert CZ(edge.node_ids[1], edge.node_ids[0]) in gates
def ansatz(params, prog_in=program_initialization): """ Create a maximally expressive 2-qubit quantum circuit with minimal amount of parameters (15 rotations) """ prog_out = prog_in.copy() prog_out += RZ(params[0], 1) prog_out += CNOT(0, 1) prog_out += RZ(params[1], 0) prog_out += RX(params[2], 0) prog_out += RZ(params[3], 0) prog_out += RZ(params[4], 1) prog_out += RX(params[5], 1) prog_out += RZ(params[6], 1) prog_out += CNOT(0, 1) prog_out += RX(params[7], 0) prog_out += RZ(params[8], 1) prog_out += CNOT(0, 1) prog_out += RZ(params[9], 0) prog_out += RX(params[10], 0) prog_out += RZ(params[11], 0) prog_out += RZ(params[12], 1) prog_out += RX(params[13], 1) prog_out += RZ(params[14], 1) return prog_out
def generate_single_t2_experiment(qubits: Union[int, List[int]], time: float, detuning: float, n_shots: int = 1000) -> Program: """ Return a t2 program in native Quil for a single time point. :param qubits: Which qubits to measure. :param time: The decay time before measurement. :param detuning: The additional detuning frequency about the z axis. :param n_shots: The number of shots to average over for the data point. :return: A T2 Program. """ program = Program() try: len(qubits) except TypeError: qubits = [qubits] ro = program.declare('ro', 'BIT', len(qubits)) for q in qubits: program += RX(np.pi / 2, q) program += Pragma('DELAY', [q], str(time)) program += RZ(2 * np.pi * time * detuning, q) program += RX(np.pi / 2, q) for i in range(len(qubits)): program += MEASURE(qubits[i], ro[i]) program.wrap_in_numshots_loop(n_shots) return program
def _readout_group_parameterized_bitstring(qubits: Sequence[int], do_measure: bool = True) \ -> Program: """ Produces a parameterized program for the given group of qubits, where each qubit is prepared in the 0 or 1 state depending on the parameterization specified at run-time. See also _readout_group_bitstring which produces a non-parameterized program that prepares and measures a single pre-specified bitstring on the given qubits. Parameterization allows for a single program to measure each bitstring (specified at run-time) and speeds up the collective measurements of all bitstring for a group of qubits. Note that the program produced by _readout_group_bitstring does not execute any gates when preparing 0 on a particular qubit and executes only one gate to prepare 1; meanwhile, this method produces a program which executes three gates for either preparation on each qubit. :param qubits: labels of qubits on which some bitstring will be prepared and, perhaps, measured :param do_measure: dictates whether to measure the qubits after preparing the bitstring; false in estimate_joint_active_reset_confusion which only uses state-prep :return: a parameterized program capable of measuring any bitstring on the given qubits """ program = Program() ro = [] if do_measure: ro = program.declare('ro', memory_type='BIT', memory_size=len(qubits)) target = program.declare('target', memory_type='REAL', memory_size=len(qubits)) for idx, qubit in enumerate(qubits): program += RX(pi / 2, qubit) program += RZ(target[idx], qubit) program += RX(-pi / 2, qubit) if do_measure: program += MEASURE(qubit, ro[idx]) return program
def prepare_state_on_bloch_sphere(qubit: int, theta: float, phi: float): """ Returns a program which prepares the given qubit in the state (theta, phi) on the bloch sphere, assuming the initial state |0> where (theta=0, phi=0). Theta and phi are the usual polar coordinates, given in radians. Theta is the angle of the state from the +Z axis, or zero state, and phi is the rotation angle from the XZ plane. Equivalently, the state alpha |0> + beta |1> in these coordinates has alpha = cos(theta/2) and e^(i*phi) = beta.imag, modulo some global phase. See https://en.wikipedia.org/wiki/Qubit#Bloch_sphere_representation for more information. :param qubit: the qubit to prepare in the given state :param theta: azimuthal angle given in radians :param phi: polar angle given in radians :return: a program preparing the qubit in the specified state, implemented in native gates """ prep = Program() prep += RX(pi / 2, qubit) prep += RZ(theta, qubit) prep += RX(-pi / 2, qubit) prep += RZ(phi, qubit) return prep
def test_pyquil_program(): """Tests if the Dynamic Decoupling Sequence gives rise to Identity operation in PyQuil """ _duration = 5e-6 _offsets = [0, 1e-6, 2.5e-6, 4e-6, 5e-6] _rabi_rotations = [np.pi / 2, np.pi / 2, np.pi, 0, np.pi / 2] _azimuthal_angles = [0, 0, np.pi / 2, 0, 0] _detuning_rotations = [0, 0, 0, np.pi, 0] sequence = DynamicDecouplingSequence( duration=_duration, offsets=_offsets, rabi_rotations=_rabi_rotations, azimuthal_angles=_azimuthal_angles, detuning_rotations=_detuning_rotations) program = convert_dds_to_pyquil_program(sequence, [0], gate_time=1e-6) assert len(program) == 13 assert program[0] == Pragma("PRESERVE_BLOCK") assert program[-1] == Pragma("END_PRESERVE_BLOCK") assert program[1] == RX(np.pi / 2, 0) assert program[2] == I(0) assert program[3] == RX(np.pi / 2, 0) assert program[4] == I(0) assert program[5] == RY(np.pi, 0) assert program[6] == I(0) assert program[7] == RZ(np.pi, 0) assert program[8] == I(0) assert program[9] == RX(np.pi / 2, 0)
def test_PrepareAndMeasureOnWFSim(): p = Program() params = p.declare("params", memory_type="REAL", memory_size=2) p.inst(RX(params[0], 0)) p.inst(RX(params[1], 1)) def make_memory_map(params): return {"params": params} # ham = PauliSum.from_compact_str("1.0*Z0 + 1.0*Z1") term1 = PauliTerm("Z", 0) term2 = PauliTerm("Z", 1) ham = PauliSum([term1, term2]) sim = WavefunctionSimulator() with local_qvm(): cost_fn = PrepareAndMeasureOnWFSim(p, make_memory_map, ham, sim, scalar_cost_function=False, enable_logging=True) out = cost_fn([np.pi, np.pi / 2], nshots=100) print(cost_fn.log) assert np.allclose(cost_fn.log[0].fun, (-1.0, 0.1)) assert np.allclose(out, (-1, 0.1))
def test_PrepareAndMeasureOnWFSim_QubitPlaceholders(): q1, q2 = QubitPlaceholder(), QubitPlaceholder() p = Program() params = p.declare("params", memory_type="REAL", memory_size=2) p.inst(RX(params[0], q1)) p.inst(RX(params[1], q2)) def make_memory_map(params): return {"params": params} ham = PauliSum([PauliTerm("Z", q1), PauliTerm("Z", q2)]) qubit_mapping = get_default_qubit_mapping(p) sim = WavefunctionSimulator() with local_qvm(): cost_fn = PrepareAndMeasureOnWFSim( p, make_memory_map, ham, sim, enable_logging=True, qubit_mapping=qubit_mapping, scalar_cost_function=False, ) out = cost_fn([np.pi, np.pi / 2], nshots=100) assert np.allclose(cost_fn.log[0].fun, (-1.0, 0.1)) assert np.allclose(out, (-1, 0.1))
def test_PrepareAndMeasureOnQVM_QubitPlaceholders(): q1, q2 = QubitPlaceholder(), QubitPlaceholder() prepare_ansatz = Program() param_register = prepare_ansatz.declare("params", memory_type="REAL", memory_size=2) prepare_ansatz.inst(RX(param_register[0], q1)) prepare_ansatz.inst(RX(param_register[1], q2)) def make_memory_map(params): return {"params": params} ham = PauliSum([PauliTerm("Z", q1), PauliTerm("Z", q2)]) qubit_mapping = get_default_qubit_mapping(prepare_ansatz) qvm = get_qc("2q-qvm") with local_qvm(): # qvm = proc.qvm cost_fn = PrepareAndMeasureOnQVM(prepare_ansatz, make_memory_map, qvm=qvm, hamiltonian=ham, enable_logging=True, scalar_cost_function=False, base_numshots=10, qubit_mapping=qubit_mapping) out = cost_fn([np.pi, np.pi / 2], nshots=10) assert np.allclose(cost_fn.log[0].fun, (-1.0, 0.1), rtol=1.1) assert np.allclose(out, (-1, 0.1), rtol=1.1)
def prepare_state_on_bloch_sphere(qubit: int, theta: float, phi: float): r""" Returns a program which prepares the given qubit in the state (theta, phi) on the bloch sphere, assuming the initial state `|0>` where (theta=0, phi=0). Theta and phi are the usual polar coordinates, given in radians. Theta is the angle of the state from the +Z axis, or zero state, and phi is the rotation angle from the XZ plane. Equivalently, the state .. math:: \alpha |0> + \beta |1> in these coordinates has, up to some global phase factored out, .. math:: \alpha = \cos(\theta/2) e^{i \phi} = \rm{Im}[\beta] where :math:`\rm{Im}[\beta]=` ``beta.imag`` See https://en.wikipedia.org/wiki/Qubit#Bloch_sphere_representation for more information. :param qubit: the qubit to prepare in the given state :param theta: azimuthal angle given in radians :param phi: polar angle given in radians :return: a program preparing the qubit in the specified state, implemented in native gates """ prep = Program() prep += RX(pi / 2, qubit) prep += RZ(theta, qubit) prep += RX(-pi / 2, qubit) prep += RZ(phi, qubit) return prep
def generate_parametric_cz_phase_ramsey_program(qcid: int, other_qcid: int) -> Program: """ Generate a single CZ phase Ramsey experiment at a given phase. :param qcid: The qubit to move around the Bloch sphere and measure the incurred RZ on. :param other_qcid: The other qubit that constitutes a two-qubit pair along with `qcid`. :param phase: The phase kick to supply after playing the CZ pulse on the equator. :param num_shots: The number of shots to average over for the data point. :return: A parametric Program for performing a CZ Ramsey experiment. """ program = Program() # NOTE: only need readout register for `qcid` not `other_qcid` since `other_qcid` is only # needed to identify which CZ gate we're using ro = program.declare('ro', 'BIT', 1) theta = program.declare('theta', 'REAL') # go to the equator program += Program(RX(np.pi / 2, qcid)) # apply the CZ gate - note that CZ is symmetric, so the order of qubits doesn't matter program += Program(CZ(qcid, other_qcid)) # go to |1> after a phase kick program += Program(RZ(theta, qcid), RX(np.pi / 2, qcid)) program += MEASURE(qcid, ro[0]) return program
def _exponentiate_general_case(pauli_term, param): """ Returns a Quil (Program()) object corresponding to the exponential of the pauli_term object, i.e. exp[-1.0j * param * pauli_term] :param pauli_term: (PauliTerm) to exponentiate :param param: scalar, non-complex, value :returns: A Quil (Program()) object """ def reverse_hack(p): # A hack to produce a *temporary* program which reverses p. def translate(tup): action, obj = tup if tup == pqb.ACTION_RELEASE_QUBIT: return (pqb.ACTION_INSTANTIATE_QUBIT, obj) elif tup == pqb.ACTION_INSTANTIATE_QUBIT: return (pqb.ACTION_RELEASE_QUBIT, obj) else: return tup revp = pq.Program() revp.actions = map(translate, reversed(p.actions)) return revp quil_prog = pq.Program() change_to_z_basis = pq.Program() change_to_original_basis = pq.Program() cnot_seq = pq.Program() prev_index = None highest_target_index = None for index, op in pauli_term: if 'X' == op: change_to_z_basis.inst(H(index)) change_to_original_basis.inst(H(index)) elif 'Y' == op: change_to_z_basis.inst(RX(np.pi / 2.0)(index)) change_to_original_basis.inst(RX(-np.pi / 2.0)(index)) elif 'I' == op: continue if prev_index is not None: cnot_seq.inst(CNOT(prev_index, index)) prev_index = index highest_target_index = index # building rotation circuit quil_prog += change_to_z_basis quil_prog += cnot_seq quil_prog.inst( RZ(2.0 * pauli_term.coefficient * param)(highest_target_index)) quil_prog += reverse_hack(cnot_seq) quil_prog += change_to_original_basis return quil_prog
def test_mixed_gate_modifiers(): g = RX(0.1, 3) \ .forked(2, [0.2]) \ .controlled(1) \ .dagger() \ .forked(0, [0.3, 0.4]) assert g.out( ) == "FORKED DAGGER CONTROLLED FORKED RX(0.1,0.2,0.3,0.4) 0 1 2 3"
def ansatz(angle_1, angle_2, prog_in=program_initialization): prog_out = prog_in.copy() prog_out += RX(angle_1, 0) prog_out += RX(angle_2, 1) # prog_out += CNOT(0,1) #prog_out.define_noisy_readout(0, p00=0.9, p11=0.8) #prog_out.define_noisy_readout(1, p00=0.95, p11=0.85) return prog_out
def test_exponentiate_bp1_YZ(): # testing change of basis position 1 generator = PauliTerm("Z", 0, 1.0) * PauliTerm("Y", 1, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([RX(math.pi / 2.0, 1), CNOT(0, 1), RZ(2.0, 1), CNOT(0, 1), RX(-math.pi / 2.0, 1)]) assert prog == result_prog
def _RY(angle, q): """ A RY in terms of RX(+-pi/2) and RZ(theta) """ p = Program() p += RX(pi / 2, q) p += RZ(angle, q) p += RX(-pi / 2, q) return p
def test_strip_gate_modifiers(): g0 = RX(0.1, 3) g1 = RX(0.1, 3).forked(2, [0.2]).controlled(1) g2 = RX(0.1, 3).forked(2, [0.2]).controlled(1).dagger() assert _strip_modifiers(g1) == g0 assert _strip_modifiers(g2) == g0 assert _strip_modifiers(g2, 3) == g0 assert _strip_modifiers(g2, 1) == g1
def parameterized_euler_rotations( qubits: Sequence[int], *, prefix: str, suffix_alpha: str = 'alpha', suffix_beta: str = 'beta', suffix_gamma: str = 'gamma', ) -> Program: """ Given a number of qubits (n), build a ``Program`` containing a ZXZXZ-decomposed gate on each qubit, where each ``RZ`` is parameterized by declared values with labels given by the "prefix" and "suffix" arguments. Put more plainly, the resulting Quil program on n qubits is: RZ(alpha_label[0]) 0 RX(pi/2) 0 RZ(beta_label[0]) 0 RX(-pi/2) 0 RZ(gamma_label[0]) 0 ... RZ(alpha_label[n-1]) n-1 RX(pi/2) n-1 RZ(beta_label[0]) n-1 RX(-pi/2) n-1 RZ(gamma_label[n-1]) n-1 :param qubits: The number of qubits (n). :param prefix: The prefix for the declared memory region labels. For example, if the prefix is "preparation" and the alpha, beta, and gamma suffixes are left as default, the labels would be "preparation_alpha", "preparation_beta", and "preparation_gamma". :param suffix_alpha: The suffix for the "alpha" memory region label, which corresponds to the first (rightmost) ``Z`` in the ZXZXZ decomposition. Defaults to "alpha". :param suffix_beta: The suffix for the "beta" memory region label, which corresponds to the second (middle) ``Z`` in the ZXZXZ decomposition. Defaults to "beta". :param suffix_gamma: The suffix for the "gamma" memory region label, which corresponds to the last (leftmost) ``Z`` in the ZXZXZ decomposition. Defaults to "gamma". :return: A ``Program`` containing a 3 parameterized ``RZ``s and 2 fixed ``RX``s per qubit. """ alpha_label = f'{prefix}_{suffix_alpha}' beta_label = f'{prefix}_{suffix_beta}' gamma_label = f'{prefix}_{suffix_gamma}' p = Program() alpha = p.declare(alpha_label, 'REAL', len(qubits)) beta = p.declare(beta_label, 'REAL', len(qubits)) gamma = p.declare(gamma_label, 'REAL', len(qubits)) for idx, q in enumerate(qubits): p += RZ(alpha[idx], q) p += RX(np.pi / 2, q) p += RZ(beta[idx], q) p += RX(-np.pi / 2, q) p += RZ(gamma[idx], q) return p
def _RY(angle: AngleLike, q: QubitLike) -> Program: """ A RY in terms of RX(+-pi/2) and RZ(theta) """ p = Program() p += RX(pi / 2, q) p += RZ(angle, q) p += RX(-pi / 2, q) return p
def ansatz(angle_1, angle_2, prog_in=program_initialization): prog_out = prog_in.copy() prog_out += RX(angle_1, 0) prog_out += RX(angle_2, 1) # Add the same values for readout error prog_out.define_noisy_readout(0, p00=0.9, p11=0.8) prog_out.define_noisy_readout(1, p00=0.95, p11=0.85) return prog_out
def test_exponentiate_3cob(): # testing circuit for 3-terms with change of basis generator = PauliTerm("Z", 0, 1.0) * PauliTerm("Y", 1, 1.0) * PauliTerm("X", 2, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([RX(math.pi / 2.0, 1), H(2), CNOT(0, 1), CNOT(1, 2), RZ(2.0, 2), CNOT(1, 2), CNOT(0, 1), RX(-math.pi / 2.0, 1), H(2)]) assert prog == result_prog
def prog(theta): p = pq.Program() theta = theta.reshape(3, n_qubits, depth) for i in range(depth): p += ising_prog for j in range(n_qubits): p.inst(RX(theta[0, j, i], j)) p.inst(RZ(theta[1, j, i], j)) p.inst(RX(theta[2, j, i], j)) return p
def test_noise_helpers(): rx90_0, rxm90_1, i_1, cz_01 = gates = RX(np.pi / 2)(0), RX(-np.pi / 2)(1), I(1), CZ(0, 1) prog = Program(*gates) inferred_gates = _get_program_gates(prog) assert set(inferred_gates) == set(gates) noisy_names = _get_noisy_names(gates) assert noisy_names[rx90_0] == "NOISY-RX-PLUS-90" assert noisy_names[rxm90_1] == "NOISY-RX-MINUS-90" assert noisy_names[i_1] == "NOISY-I" assert noisy_names[cz_01] == "NOISY-CZ"
def hello_qmi(device_name: str = "9q-generic-qvm", shots: int = 5) -> None: """ Get acquainted with your quantum computer by asking it to perform a simple coin-toss experiment. Involve 3 qubits in this experiment, and ask each one to give `shots` many results. :param device_name: The name of a quantum computer which can be retrieved from `pyquil.api.get_qc()`. To find a list of all devices, you can use `pyquil.api.list_devices()`. """ # Initialize your Quil program program = Program() # Allow the compiler to re-index to use available qubits, if necessary. program += Pragma('INITIAL_REWIRING', ['"GREEDY"']) device = query_device(device_name) if device is not None: # device_name refers to a real (QPU) device, so let's construct # the program from the device's qubits. readout = program.declare('ro', 'BIT', len(device['qubits'])) for qubit in device['qubits'].values(): program += RX(math.pi / 2, qubit) for idx, qubit in enumerate(device['qubits'].values()): program += MEASURE(qubit, readout[idx]) else: # device_name refers to a non-real (QVM) device, so let's construct # the program from arbitrary qubits, e.g. 0, 1, and 2 # Declare 3 bits of memory space for the readout results of all three qubits readout = program.declare('ro', 'BIT', 3) # For each qubit, apply a pulse to move the qubit's state halfway between # the 0 state and the 1 state program += RX(math.pi / 2, 0) program += RX(math.pi / 2, 1) program += RX(math.pi / 2, 2) # Add measurement instructions to measure the qubits and record the result # into the respective bit in the readout register program += MEASURE(0, readout[0]) program += MEASURE(1, readout[1]) program += MEASURE(2, readout[2]) # This tells the program how many times to run the above sequence program.wrap_in_numshots_loop(shots) # Get the quantum computer we want to run our experiment on qc = get_qc(device_name) # Compile the program, specific to which quantum computer we are using compiled_program = qc.compile(program) # Run the program and get the shots x 3 array of results results = qc.run(compiled_program) # Print the results. We expect to see (shots x 3) random 0's and 1's print( f"Your{' virtual' if isinstance(qc.qam, QVM) else ''} quantum " f"computer, {device_name}, greets you with:\n", results)
def _RX(angle: float, q: int) -> Program: """ A RX in terms of native RX(+-pi/2) and RZ gates. """ p = Program() p += RZ(pi / 2, q) p += RX(pi / 2, q) p += RZ(angle, q) p += RX(-pi / 2, q) p += RZ(-pi / 2, q) return p
def _RX(angle: AngleLike, q: QubitLike) -> Program: """ A RX in terms of native RX(+-pi/2) and RZ gates. """ p = Program() p += RZ(pi / 2, q) p += RX(pi / 2, q) p += RZ(angle, q) p += RX(-pi / 2, q) p += RZ(-pi / 2, q) return p
def test_apply_noise_model(): p = Program(RX(np.pi / 2, 0), RX(np.pi / 2, 1), CZ(0, 1), RX(np.pi / 2, 1)) noise_model = _decoherence_noise_model(_get_program_gates(p)) pnoisy = apply_noise_model(p, noise_model) for i in pnoisy: if isinstance(i, DefGate): pass elif isinstance(i, Pragma): assert i.command in ['ADD-KRAUS', 'READOUT-POVM'] elif isinstance(i, Gate): assert i.name in NO_NOISE or not i.params