def _generate_experiment_programs( tomo_experiment: TomographyExperiment, active_reset: bool = False) -> Tuple[List[Program], List[List[int]]]: """ Generate the programs necessary to estimate the observables in a TomographyExperiment. Grouping of settings to be run in parallel, e.g. by a call to group_experiments, should be done before this function is called. .. CAUTION:: One must be careful with compilation of the output programs before the appropriate MEASURE instructions are added, because compilation may re-index the qubits so that the output list of `measure_qubits` no longer accurately indexes the qubits that should be measured. :param tomo_experiment: a single TomographyExperiment to be translated to a series of programs that, when run serially, can be used to estimate each of its observables. :param active_reset: whether or not to begin the program by actively resetting. If true, execution of each of the returned programs in a loop on the QPU will generally be faster. :return: a list of programs along with a corresponding list of the groups of qubits that are measured by that program. The returned programs may be run on a qc after measurement instructions are added for the corresponding group of qubits in meas_qubits, or by a call to `qc.run_symmetrized_readout` -- see :func:`raw_estimate_observables` for possible usage. """ # Outer loop over a collection of grouped settings for which we can simultaneously estimate. programs = [] meas_qubits = [] for settings in tomo_experiment: # Prepare a state according to the amalgam of all setting.in_state total_prog = Program() if active_reset: total_prog += RESET() max_weight_in_state = _max_weight_state(setting.in_state for setting in settings) if max_weight_in_state is None: raise ValueError( "Input states are not compatible. Re-group the experiment settings " "so that groups of parallel settings have compatible input states." ) for oneq_state in max_weight_in_state.states: total_prog += _one_q_state_prep(oneq_state) # Add in the program total_prog += tomo_experiment.program # Prepare for measurement state according to setting.out_operator max_weight_out_op = _max_weight_operator(setting.out_operator for setting in settings) if max_weight_out_op is None: raise ValueError( "Observables not compatible. Re-group the experiment settings " "so that groups of parallel settings have compatible observables." ) for qubit, op_str in max_weight_out_op: total_prog += _local_pauli_eig_meas(op_str, qubit) programs.append(total_prog) meas_qubits.append(max_weight_out_op.get_qubits()) return programs, meas_qubits
def test_qc_joint_expectation(forest): device = NxDevice(nx.complete_graph(2)) qc = QuantumComputer( name="testy!", qam=QVM(connection=forest), device=device, compiler=DummyCompiler() ) # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10) # ZZ experiment sz = ExperimentSetting( in_state=sZ(0) * sZ(1), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]] ) e = Experiment(settings=[sz], program=p) results = qc.experiment(e) # ZZ expectation value for state |01> is -1 assert np.isclose(results[0].expectation, -1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # Z0 expectation value for state |01> is -1 assert np.isclose(results[0].additional_results[0].expectation, -1) assert results[0].additional_results[1].total_counts == 40 # Z1 expectation value for state |01> is 1 assert np.isclose(results[0].additional_results[1].expectation, 1) assert results[0].additional_results[1].total_counts == 40
def test_validate_supported_quil_reset_qubit(): prog = Program( RESET(2), ) with pytest.raises(ValueError): validate_supported_quil(prog) assert not prog.is_supported_on_qpu()
def test_validate_protoquil_reset_qubit(): prog = Program( RESET(2), ) with pytest.raises(ValueError): validate_protoquil(prog) assert not prog.is_protoquil()
def initialize_toric_code(primal: nx.Graph, dual: nx.Graph, distance: nx.Graph, L: int, trials=100) -> Program: """ Initializes the toric code into an appropriate eigenstate of the stabilizers, assuming the qubits begin in the state |0> \tensor |0> \tensor ... \tensor |0> before initialization. :param primal, dual, distance: primal/dual/distance graphs returned by construct_toric_code :param L: number of physical qubits on one side of the lattice :param trials: number of trials to obtain an even number of qubit errors :returns: program representing correction operation """ # A hacky way to ensure the initialization works: # run the syndrome extraction until we return an even # number of errors (okay for small graphs) for t in range(trials): # Set up programs, and reset qubits if needed primal_initial = Program() + RESET() # Perform syndrome extraction on primal graph primal_faulty_nodes = syndrome_extraction(primal, L, primal_initial, "X") test = (len(primal_faulty_nodes) % 2 == 0) if test: break assert test, "Failed to find even number of faulty nodes for primal and dual graphs" # With an even number of faulty nodes, we can now run the mwpm algorithm # and correct the -1 eigenvalues primal_correction_paths = mwpm(primal, distance, L, primal_faulty_nodes) # Construct pyquil program to carry out corrections primal_correct_pq = apply_operation(primal_correction_paths, primal, Z) return primal_correct_pq
def test_qc_joint_expectation(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10) # ZZ experiment sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]]) e = Experiment(settings=[sz], program=p) results = qc.run_experiment(e) # ZZ expectation value for state |01> is -1 assert np.isclose(results[0].expectation, -1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # Z0 expectation value for state |01> is -1 assert np.isclose(results[0].additional_results[0].expectation, -1) assert results[0].additional_results[1].total_counts == 40 # Z1 expectation value for state |01> is 1 assert np.isclose(results[0].additional_results[1].expectation, 1) assert results[0].additional_results[1].total_counts == 40
def test_qc_expectation_on_qvm(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): # regression test for https://github.com/rigetti/forest-tutorials/issues/2 qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) p = Program() theta = p.declare("theta", "REAL") p += RESET() p += RY(theta, 0) p.wrap_in_numshots_loop(10000) sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sX(0)) e = Experiment(settings=[sx], program=p) thetas = [-np.pi / 2, 0.0, np.pi / 2] results = [] # Verify that multiple calls to qc.experiment with the same experiment backed by a QVM that # requires_exectutable does not raise an exception. for theta in thetas: results.append(qc.experiment(e, memory_map={"theta": [theta]})) assert np.isclose(results[0][0].expectation, -1.0, atol=0.01) assert np.isclose(results[0][0].std_err, 0) assert results[0][0].total_counts == 20000 # bounds on atol and std_err here are a little loose to try and avoid test flakiness. assert np.isclose(results[1][0].expectation, 0.0, atol=0.1) assert results[1][0].std_err < 0.01 assert results[1][0].total_counts == 20000 assert np.isclose(results[2][0].expectation, 1.0, atol=0.01) assert np.isclose(results[2][0].std_err, 0) assert results[2][0].total_counts == 20000
def test_qc_expectation(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) # bell state program p = Program() p += RESET() p += H(0) p += CNOT(0, 1) p.wrap_in_numshots_loop(10) # XX, YY, ZZ experiment sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sX(0) * sX(1)) sy = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sY(0) * sY(1)) sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1)) e = Experiment(settings=[sx, sy, sz], program=p) results = qc.experiment(e) # XX expectation value for bell state |00> + |11> is 1 assert np.isclose(results[0].expectation, 1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # YY expectation value for bell state |00> + |11> is -1 assert np.isclose(results[1].expectation, -1) assert np.isclose(results[1].std_err, 0) assert results[1].total_counts == 40 # ZZ expectation value for bell state |00> + |11> is 1 assert np.isclose(results[2].expectation, 1) assert np.isclose(results[2].std_err, 0) assert results[2].total_counts == 40
def test_qc_joint_calibration(client_configuration: QCSClientConfiguration): # noise model with 95% symmetrized readout fidelity per qubit noise_model = asymmetric_ro_model([0, 1], 0.945, 0.955) qc = get_qc("2q-qvm", client_configuration=client_configuration) qc.qam.noise_model = noise_model # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10000) # ZZ experiment sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]]) e = Experiment(settings=[sz], program=p) results = qc.run_experiment(e) # ZZ expectation value for state |01> with 95% RO fid on both qubits is about -0.81 assert np.isclose(results[0].expectation, -0.81, atol=0.01) assert results[0].total_counts == 40000 # Z0 expectation value for state |01> with 95% RO fid on both qubits is about -0.9 assert np.isclose(results[0].additional_results[0].expectation, -0.9, atol=0.01) assert results[0].additional_results[1].total_counts == 40000 # Z1 expectation value for state |01> with 95% RO fid on both qubits is about 0.9 assert np.isclose(results[0].additional_results[1].expectation, 0.9, atol=0.01) assert results[0].additional_results[1].total_counts == 40000
def _run_program(self, program): program = program.copy() if self.qpu: # time to go through the compiler. whee! pragma = Program( [Pragma("INITIAL_REWIRING", ['"PARTIAL"']), RESET()]) program = pragma + program program = self._wrap_program(program) nq_program = self._qc.compiler.quil_to_native_quil(program) gate_count = sum(1 for instr in nq_program if isinstance(instr, Gate)) executable = self._qc.compiler.native_quil_to_executable( nq_program) results = self._qc.run(executable=executable) else: program = self._wrap_program(program) gate_count = len(program) results = self._qc.run(program) info = { "gate_count": gate_count } # compiled length for qpu, uncompiled for qvm return results, info
def get_calibration_program(observable: PauliTerm, noisy_program: Program = None, active_reset: bool = False) -> Program: """ Program required for calibrating the given observable. :param observable: observable to calibrate :param noisy_program: a program with readout and gate noise defined; only useful for QVM :param active_reset: whether or not to begin the program by actively resetting. If true, execution of each of the returned programs in a loop on the QPU will generally be faster. :return: Program performing the calibration """ calibr_prog = Program() if active_reset: calibr_prog += RESET() # Inherit any noisy attributes from noisy_program, including gate definitions # and applications which can be handy in simulating noisy channels if noisy_program is not None: # Inherit readout error instructions from main Program readout_povm_instruction = [i for i in noisy_program.out().split('\n') if 'PRAGMA READOUT-POVM' in i] calibr_prog += readout_povm_instruction # Inherit any definitions of noisy gates from main Program kraus_instructions = [i for i in noisy_program.out().split('\n') if 'PRAGMA ADD-KRAUS' in i] calibr_prog += kraus_instructions # Prepare the +1 eigenstate for the out operator for q, op in observable.operations_as_set(): calibr_prog += _one_q_pauli_prep(label=op, index=0, qubit=q) # Measure the out operator in this state for q, op in observable.operations_as_set(): calibr_prog += _local_pauli_eig_meas(op, q) return calibr_prog
def test_validate_protoquil_reset_first(): prog = Program( H(0), RESET(), ) with pytest.raises(ValueError): validate_protoquil(prog) assert not prog.is_protoquil()
def test_validate_protoquil_with_pragma(): prog = Program( RESET(), H(1), Pragma('DELAY'), MEASURE(1) ) assert prog.is_protoquil()
def test_validate_supported_quil_with_pragma(): prog = Program( RESET(), H(1), Pragma('DELAY'), MEASURE(1, None) ) assert prog.is_supported_on_qpu()
def generate_rigetti(self): import pyquil from pyquil.quil import Program from pyquil.gates import H, RZ, RX, RY, CNOT, MEASURE, RESET from pyquil.api import get_qc self.rigetti_circuits_list=[] print("Creating Pyquil program list...") self.logfile.write("Creating Pyquil program list...") for circuit in self.circuits_list: p = pyquil.Program(RESET()) #compressed program ro = p.declare('ro', memory_type='BIT', memory_size=self.num_qubits) for gate in circuit.gates: if gate.name in "H": p.inst(pyquil.gates.H(gate.qubits[0])) elif gate.name in "RZ": p.inst(pyquil.gates.RZ(gate.angles[0],gate.qubits[0])) elif gate.name in "RX": p.inst(pyquil.gates.RX(gate.angles[0],gate.qubits[0])) elif gate.name in "CNOT": p.inst(pyquil.gates.CNOT(gate.qubits[0],gate.qubits[1])) for i in range(self.num_qubits): p.inst(pyquil.gates.MEASURE(i,ro[i])) p.wrap_in_numshots_loop(self.shots) self.rigetti_circuits_list.append(p) if "y" in self.compile: qc=get_qc(self.device_choice) if self.JZ != 0 and self.JX==self.JY==0 and self.h_ext!=0 and self.ext_dir=="X" and self.auto_ds_compile=="y": #TFIM print("TFIM detected, enabling DS compiler") self.logfile.write("TFIM detected, enabling DS compiler") temp=[] for circuit in self.rigetti_circuits_list: temp.append(ds_compile(circuit,self.backend,self.shots)) self.rigetti_circuits_list=temp elif self.default_compiler in "ds": temp=[] print("Compiling circuits...") self.logfile.write("Compiling circuits...") for circuit in self.rigetti_circuits_list: temp.append(ds_compile(circuit,self.backend,self.shots)) self.rigetti_circuits_list=temp print("Circuits compiled successfully") self.logfile.write("Circuits compiled successfully") elif self.default_compiler in "native": temp=[] print("Transpiling circuits...") self.logfile.write("Transpiling circuits...") for circuit in self.rigetti_circuits_list: circ = qc.compile(circuit) temp.append(circ) self.rigetti_circuits_list=temp print("Circuits transpiled successfully") self.logfile.write("Circuits transpiled successfully") print("Pyquil program list created successfully") self.logfile.write("Pyquil program list created successfully")
def pre_expval(self): """Run the QVM""" # pylint: disable=attribute-defined-outside-init for e in self.expval_queue: wire = [e.wires[0]] if e.name == 'PauliX': # X = H.Z.H self.apply('Hadamard', wire, []) elif e.name == 'PauliY': # Y = (HS^)^.Z.(HS^) and S^=SZ self.apply('PauliZ', wire, []) self.apply('S', wire, []) self.apply('Hadamard', wire, []) elif e.name == 'Hadamard': # H = Ry(-pi/4)^.Z.Ry(-pi/4) self.apply('RY', wire, [-np.pi/4]) elif e.name == 'Hermitian': # For arbitrary Hermitian matrix H, let U be the unitary matrix # that diagonalises it, and w_i be the eigenvalues. H = e.parameters[0] Hkey = tuple(H.flatten().tolist()) if Hkey in self._eigs: # retrieve eigenvectors U = self._eigs[Hkey]['eigvec'] else: # store the eigenvalues corresponding to H # in a dictionary, so that they do not need to # be calculated later w, U = np.linalg.eigh(H) self._eigs[Hkey] = {'eigval': w, 'eigvec': U} # Perform a change of basis before measuring by applying U^ to the circuit self.apply('QubitUnitary', wire, [U.conj().T]) prag = Program(Pragma('INITIAL_REWIRING', ['"PARTIAL"'])) if self.active_reset: prag += RESET() self.prog = prag + self.prog qubits = list(self.prog.get_qubits()) ro = self.prog.declare('ro', 'BIT', len(qubits)) for i, q in enumerate(qubits): self.prog.inst(MEASURE(q, ro[i])) self.prog.wrap_in_numshots_loop(self.shots) executable = self.qc.compile(self.prog) bitstring_array = self.qc.run(executable=executable) self.state = {} for i, q in enumerate(qubits): self.state[q] = bitstring_array[:, i]
def test_validate_supported_quil_multiple_measures(): prog = Program( RESET(), H(1), Pragma('DELAY'), MEASURE(1, None), MEASURE(1, None) ) with pytest.raises(ValueError): validate_supported_quil(prog)
def reset(self, qubit_index: Optional[int] = None) -> "Program": """ Reset all qubits or just a specific qubit at qubit_index. :param qubit_index: The address of the qubit to reset. If None, reset all qubits. :returns: The Quil Program with the appropriate reset instruction appended, e.g. RESET 0 """ return self.inst(RESET(qubit_index))
def pre_measure(self): """Run the QVM""" # pylint: disable=attribute-defined-outside-init for e in self.obs_queue: wires = e.wires if e.name in [ "PauliX", "PauliY", "PauliZ", "Identity", "Hadamard" ]: self.pre_rotations(e.name, wires) elif e.name == "Hermitian": # For arbitrary Hermitian matrix H, let U be the unitary matrix # that diagonalises it, and w_i be the eigenvalues. H = e.parameters[0] Hkey = tuple(H.flatten().tolist()) if Hkey in self._eigs: # retrieve eigenvectors U = self._eigs[Hkey]["eigvec"] else: # store the eigenvalues corresponding to H # in a dictionary, so that they do not need to # be calculated later w, U = np.linalg.eigh(H) self._eigs[Hkey] = {"eigval": w, "eigvec": U} # Perform a change of basis before measuring by applying U^ to the circuit self.apply("QubitUnitary", wires, [U.conj().T]) prag = Program(Pragma("INITIAL_REWIRING", ['"PARTIAL"'])) if self.active_reset: prag += RESET() self.prog = prag + self.prog qubits = sorted(self.prog.get_qubits()) ro = self.prog.declare("ro", "BIT", len(qubits)) for i, q in enumerate(qubits): self.prog.inst(MEASURE(q, ro[i])) self.prog.wrap_in_numshots_loop(self.shots) if "pyqvm" in self.qc.name: bitstring_array = self.qc.run(self.prog) else: self.compiled = self.qc.compile(self.prog) bitstring_array = self.qc.run(executable=self.compiled) self.state = {} for i, q in enumerate(qubits): self.state[q] = bitstring_array[:, i]
def test_biased_coin(): # sample from a 75% heads and 25% tails coin prog = ( Program().inst(Declare("ro", "BIT"), RX(np.pi / 3, 0)).measure(0, MemoryReference("ro", 0)) ) results = [] qam = PyQVM(n_qubits=1, quantum_simulator_type=ReferenceWavefunctionSimulator) for _ in range(1000): qam.execute(prog) results += [qam.ram["ro"][0]] qam.execute(Program(RESET())) coin_bias = sum(results) / 1000 assert np.isclose(coin_bias, 0.25, atol=0.05, rtol=0.05)
def run(q_comp, program, n_shots): start = time.time() if use_active_reset: reset_measure_program = Program(RESET()) program = reset_measure_program + program # run the program num_shots many times program.wrap_in_numshots_loop(n_shots) executable = q_comp.compiler.native_quil_to_executable(program) res = q_comp.run(executable) end = time.time() return res, end - start
def test_reset(): p = Program() p.reset(0) p.reset() assert p.out() == "RESET 0\nRESET\n" program = Program() qubit = QubitPlaceholder() # address_qubits() won't work unless there's a gate besides # RESET on a QubitPlaceholder, this is just here to make # addressing work program += X(qubit) program += RESET(qubit) program = address_qubits(program) assert program.out() == "X 0\nRESET 0\n"
def generate_calibration_experiment(self) -> "Experiment": """ Generate another ``Experiment`` object that can be used to calibrate the various multi-qubit observables involved in this ``Experiment``. This is achieved by preparing the plus-one (minus-one) eigenstate of each ``out_operator``, and measuring the resulting expectation value of the same ``out_operator``. Ideally, this would always give +1 (-1), but when symmetric readout error is present the effect is to scale the resultant expectations by some constant factor. Determining this scale factor is what we call *readout calibration*, and then the readout error in subsequent measurements can then be mitigated by simply dividing by the scale factor. :return: A new ``Experiment`` that can calibrate the readout error of all the observables involved in this experiment. """ if self.calibration != CalibrationMethod.PLUS_EIGENSTATE: raise ValueError( 'We currently only support the "plus eigenstate" calibration method.' ) calibration_settings = [] for settings in self: assert len(settings) == 1 calibration_settings.append( ExperimentSetting( in_state=settings[0].out_operator, out_operator=settings[0].out_operator, additional_expectations=settings[0]. additional_expectations, )) calibration_program = Program() if self.reset: calibration_program += RESET() calibration_program.wrap_in_numshots_loop(self.shots) if self.symmetrization != SymmetrizationLevel.EXHAUSTIVE: raise ValueError( "We currently only support calibration for exhaustive symmetrization" ) return Experiment( settings=calibration_settings, program=calibration_program, symmetrization=SymmetrizationLevel.EXHAUSTIVE, calibration=CalibrationMethod.NONE, )
def test_unsupported_ops(): target = Label("target") base_prog = Program(Declare('reg1', 'BIT'), Declare('reg2', 'BIT'), H(0), JumpTarget(target), CNOT(0, 1)) bad_ops = [ RESET(0), WAIT, Jump(target), MOVE(MemoryReference('reg1'), MemoryReference('reg2')) ] assert to_latex(base_prog) for op in bad_ops: prog = base_prog + op with pytest.raises(ValueError): _ = to_latex(prog)
def two_POVM(theta0, phi0, theta1, theta2) -> Program: # for the purpose of POVM we choose the most connected qubit (10 in the case) to be the measured one ancilla = [2] target = 1 program = Program(RESET()) # create initial state if theta0 != 0: program.inst(RY(theta0, target)) if phi0 != 0: program.inst(RZ(phi0, target)) # 1st AP module program.inst(POVM_module_1(theta1, theta2, ancilla, target)) return program
def test_is_protoquil(): prog = Program(Declare('ro', 'BIT'), MEASURE(1, MemoryReference("ro", 0)), H(1), RESET()) validate_protoquil(prog) assert prog.is_protoquil() prog = Program(Declare('ro', 'BIT'), H(0), Y(1), CNOT(0, 1)) \ .measure(0, MemoryReference("ro", 0)) \ .if_then(MemoryReference("ro", 0), Program(X(0)), Program()) with pytest.raises(ValueError): validate_protoquil(prog) assert not prog.is_protoquil() prog = Program(Declare('ro', 'BIT'), ClassicalNot(MemoryReference("ro", 0))) with pytest.raises(ValueError): validate_protoquil(prog) assert not prog.is_protoquil()
def apply(self, operations, **kwargs): """Run the QVM""" # pylint: disable=attribute-defined-outside-init super().apply(operations, **kwargs) prag = Program(Pragma("INITIAL_REWIRING", ['"PARTIAL"'])) if self.active_reset: prag += RESET() self.prog = prag + self.prog qubits = sorted(self.wiring.values()) ro = self.prog.declare("ro", "BIT", len(qubits)) for i, q in enumerate(qubits): self.prog.inst(MEASURE(q, ro[i])) self.prog.wrap_in_numshots_loop(self.shots)
def test_qc_expectation_larger_lattice(forest): device = NxDevice(nx.complete_graph(4)) qc = QuantumComputer(name='testy!', qam=QVM(connection=forest), device=device, compiler=DummyCompiler()) q0 = 2 q1 = 3 # bell state program p = Program() p += RESET() p += H(q0) p += CNOT(q0, q1) p.wrap_in_numshots_loop(10) # XX, YY, ZZ experiment sx = ExperimentSetting(in_state=sZ(q0) * sZ(q1), out_operator=sX(q0) * sX(q1)) sy = ExperimentSetting(in_state=sZ(q0) * sZ(q1), out_operator=sY(q0) * sY(q1)) sz = ExperimentSetting(in_state=sZ(q0) * sZ(q1), out_operator=sZ(q0) * sZ(q1)) e = TomographyExperiment(settings=[sx, sy, sz], program=p) results = qc.experiment(e) # XX expectation value for bell state |00> + |11> is 1 assert np.isclose(results[0].expectation, 1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # YY expectation value for bell state |00> + |11> is -1 assert np.isclose(results[1].expectation, -1) assert np.isclose(results[1].std_err, 0) assert results[1].total_counts == 40 # ZZ expectation value for bell state |00> + |11> is 1 assert np.isclose(results[2].expectation, 1) assert np.isclose(results[2].std_err, 0) assert results[2].total_counts == 40
def test_qc_calibration_2q(client_configuration: QCSClientConfiguration): # noise model with 95% symmetrized readout fidelity per qubit noise_model = asymmetric_ro_model([0, 1], 0.945, 0.955) qc = get_qc("2q-qvm", client_configuration=client_configuration) qc.qam.noise_model = noise_model # bell state program (doesn't matter) p = Program() p += RESET() p += H(0) p += CNOT(0, 1) p.wrap_in_numshots_loop(10000) # ZZ experiment sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1)) e = Experiment(settings=[sz], program=p) results = qc.calibrate(e) # ZZ expectation should just be (1 - 2 * readout_error_q0) * (1 - 2 * readout_error_q1) np.isclose(results[0].expectation, 0.81, atol=0.01) assert results[0].total_counts == 40000
def test_qc_calibration_1q(forest): # noise model with 95% symmetrized readout fidelity per qubit noise_model = asymmetric_ro_model([0], 0.945, 0.955) qc = get_qc("1q-qvm") qc.qam.noise_model = noise_model # bell state program (doesn't matter) p = Program() p += RESET() p += H(0) p += CNOT(0, 1) p.wrap_in_numshots_loop(10000) # Z experiment sz = ExperimentSetting(in_state=sZ(0), out_operator=sZ(0)) e = Experiment(settings=[sz], program=p) results = qc.calibrate(e) # Z expectation value should just be 1 - 2 * readout_error np.isclose(results[0].expectation, 0.9, atol=0.01) assert results[0].total_counts == 20000