Example #1
0
    def run_and_measure(self,
                        program: Program,
                        qubits: List[int],
                        trials: int,
                        symmetrize_readout=None):
        """
        Run the provided state preparation program and measure all qubits contained in the program.

        .. note::

            In contrast to :py:class:`QVMConnection.run_and_measure`, this method simulates
            noise correctly for noisy QVMs. However, this method is slower for ``trials > 1``.
            For faster noise-free simulation, consider
            :py:class:`WavefunctionSimulator.run_and_measure`.

        :param program: The state preparation program to run and then measure.
        :param qubits: Qubit indices to measure.
        :param trials: The number of times to run the program.
        :param symmetrize_readout: Whether to apply readout error symmetrization. If not specified,
            the class attribute ``symmetrize_readout`` will be used. See
            :py:func:`run_symmetrized_readout` for a complete description.
        :return: A numpy array of shape (trials, len(qubits)) that contains 0s and 1s
        """
        new_prog = Program().inst(program)  # make a copy?

        classical_addrs = list(range(len(qubits)))
        for q, i in zip(qubits, classical_addrs):
            new_prog += MEASURE(q, i)

        return self.run(program=new_prog,
                        classical_addresses=classical_addrs,
                        trials=trials,
                        symmetrize_readout=symmetrize_readout)
    def prep_circuit_program(self, prog):
        #Prepare parametric gates
        ro = prog.declare('ro', memory_type='BIT')
        self.params = self.get_params(prog)
        params_dict = {}
        for i in range(len(gates)):
            q1 = gates[i][0]
            q2 = gates[i][1]
            for k in range(0, 3):
                index = i * 18 + 6 * k
                angles = self.params[index], self.params[index +
                                                         1], self.params[index
                                                                         + 2]
                prog.inst([g for g in self.single_qubit_unitary(angles, q1)])
                index += 3
                angles = self.params[index], self.params[index +
                                                         1], self.params[index
                                                                         + 2]
                prog.inst([g for g in self.single_qubit_unitary(angles, q2)])
                prog.inst(CZ(q1, q2))

        index = 18 * len(gates)
        angles = self.params[index], self.params[index +
                                                 1], self.params[index + 2]
        prog.inst([g for g in self.single_qubit_unitary(angles, self.n - 1)])

        prog += MEASURE(15, ro)
        return prog
Example #3
0
def test_construction_syntax():
    p = Program().inst(X(0), Y(1), Z(0)).measure(0, 1)
    assert p.out() == 'X 0\nY 1\nZ 0\nMEASURE 0 [1]\n'
    p = Program().inst(X(0)).inst(Y(1)).measure(0, 1).inst(MEASURE(1, 2))
    assert p.out() == 'X 0\nY 1\nMEASURE 0 [1]\nMEASURE 1 [2]\n'
    p = Program().inst(X(0)).measure(0, 1).inst(Y(1), X(0)).measure(0, 0)
    assert p.out() == 'X 0\nMEASURE 0 [1]\nY 1\nX 0\nMEASURE 0 [0]\n'
Example #4
0
def add(a: int, b: int):
    qvm = QVMConnection()
    p = Program()

    # make sure the first number is the greater
    if a < b:
        t = a
        a = b
        b = t

    # Number of bits needed to store the sum of
    # numbers a and b for which bitlen(a) <= n and bitlen(b) <= n is n + 1
    bitlen_a = max(bitlen(a), 1) + 1
    bitlen_b = max(bitlen(b), 1)

    a_qubits = list(range(0, bitlen_a))
    b_qubits = list(range(bitlen_a, bitlen_a + bitlen_b))

    p += prep_qubits(a_qubits, a)
    p += prep_qubits(b_qubits, b)

    p += add_qubits(a_qubits, b_qubits)

    p.inst([MEASURE(j, i) for i, j in enumerate(a_qubits)])

    result, = qvm.run(p, trials=1)
    return sum([k * 2**i for i, k in enumerate(result)])
Example #5
0
def _measure_bitstrings(qc,
                        programs: List[Program],
                        meas_qubits: List[int],
                        num_shots: int = 600) -> List[np.ndarray]:
    """
    Wrapper for appending measure instructions onto each program, running the program,
    and accumulating the resulting bitarrays.

    :param qc: a quantum computer object on which to run each program
    :param programs: a list of programs to run
    :param meas_qubits: groups of qubits to measure for each program
    :param num_shots: the number of shots to run for each program
    :return: a len(programs) long list of num_shots by num_meas_qubits bit arrays of results for
        each program.
    """
    results = []
    for program in programs:
        # copy the program so the original is not mutated
        prog = program.copy()
        ro = prog.declare('ro', 'BIT', len(meas_qubits))
        for idx, q in enumerate(meas_qubits):
            prog += MEASURE(q, ro[idx])

        prog.wrap_in_numshots_loop(num_shots)
        prog = qc.compiler.quil_to_native_quil(prog)
        exe = qc.compiler.native_quil_to_executable(prog)
        shots = qc.run(exe)
        results.append(shots)
    return results
Example #6
0
def generate_single_t1_experiment(qubits: Union[int, List[int]],
                                  time: float,
                                  n_shots: int = 1000) -> Program:
    """
    Return a t1 program in native Quil for a single time point.

    :param qubits: Which qubits to measure.
    :param time: The decay time before measurement.
    :param n_shots: The number of shots to average over for the data point.
    :return: A T1 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, q)
        program += Pragma('DELAY', [q], str(time))
    for i in range(len(qubits)):
        program += MEASURE(qubits[i], ro[i])
    program.wrap_in_numshots_loop(n_shots)
    return program
Example #7
0
def test_dagger():
    p = Program(X(0), H(0))
    assert p.dagger().out() == "DAGGER H 0\nDAGGER X 0\n"

    p = Program(X(0), MEASURE(0, MemoryReference("ro", 0)))
    with pytest.raises(ValueError):
        p.dagger().out()

    # ensure that modifiers are preserved https://github.com/rigetti/pyquil/pull/914
    p = Program()
    control = 0
    target = 1
    cnot_control = 2
    p += X(target).controlled(control)
    p += Y(target).controlled(control)
    p += Z(target).controlled(control)
    p += H(target).controlled(control)
    p += S(target).controlled(control)
    p += T(target).controlled(control)
    p += PHASE(pi, target).controlled(control)
    p += CNOT(cnot_control, target).controlled(control)

    for instr, instr_dagger in zip(reversed(p._instructions),
                                   p.dagger()._instructions):
        assert "DAGGER " + instr.out() == instr_dagger.out()
Example #8
0
def test_majority_gate(qvm):
    """
    Testing the majority gate with a truth table
    """
    #                    a, b, c    a, b, c
    true_truth_table = {
        (0, 0, 0): (0, 0, 0),
        (0, 0, 1): (0, 0, 1),
        (0, 1, 0): (0, 1, 0),
        (0, 1, 1): (1, 1, 1),
        (1, 0, 0): (0, 1, 1),
        (1, 0, 1): (1, 1, 0),
        (1, 1, 0): (1, 0, 1),
        (1, 1, 1): (1, 0, 0)
    }

    maj_gate_program = majority_gate(0, 1, 2)
    for key, value in true_truth_table.items():
        state_prep_prog = Program()
        for qbit_idx, bit in enumerate(key):
            if bit == 1:
                state_prep_prog += X(qbit_idx)
        prog = state_prep_prog + maj_gate_program
        ro = prog.declare('ro', 'BIT', 3)
        for q in range(3):
            prog += MEASURE(q, ro[q])
        exe = qvm.compiler.native_quil_to_executable(prog)
        result = qvm.run(exe)
        assert tuple(result[0]) == true_truth_table[key]
Example #9
0
def NN_test(qubit, prep_program, N_encode, N_decode):

    ### qubit: qubit we want to encode (main qubit)
    ### prep_program: arbitrary program to put the main qubit in the state we want to
    ### transmit
    ### N_encode: number of qubits to encode the main qubit in
    ### N_decode: number of qubits to read out
    ### if N_decode < N_encode, we will always get alpha squared = beta squared = 0.5,
    ### no matter what we originally encoded the qubit in.
    ### Note that this test only gives the absolute squared values of alpha and beta

    pq = Program()
    pq += prep_program

    prog, code_register = NN_encode(qubit, N_encode)

    pq += prog

    progg, out = NN_decode(code_register[0:N_decode])

    pq += progg

    ro = pq.declare('ro', 'BIT', 1)
    pq += MEASURE(out, ro)

    result = np.sum(qvm.run(address_qubits(pq), trials=1000)) / 1000.0

    alpha_sqrd = 1.0 - result
    beta_sqrd = result

    print('alpha squared = {}'.format(alpha_sqrd))
    print('beta squared = {}'.format(beta_sqrd))

    return alpha_sqrd, beta_sqrd
Example #10
0
def test_get_qubits():
    pq = Program(X(0), CNOT(0, 4), MEASURE(5, [5]))
    assert pq.get_qubits() == {0, 4, 5}

    qq = pq.alloc()
    pq.inst(Y(2), X(qq))
    assert pq.get_qubits() == {0, 1, 2, 4, 5}  # this synthesizes the allocation
Example #11
0
def test_CCNOT_in_X_basis(qvm):
    """
    Testing the definition of Toffoli / CCNOT in the X basis.
    """
    # Toffoli truth table
    true_truth_table = {
        (0, 0, 0): (0, 0, 0),
        (0, 0, 1): (0, 0, 1),
        (0, 1, 0): (0, 1, 0),
        (0, 1, 1): (0, 1, 1),
        (1, 0, 0): (1, 0, 0),
        (1, 0, 1): (1, 0, 1),
        (1, 1, 0): (1, 1, 1),
        (1, 1, 1): (1, 1, 0)
    }

    CCNOTX = CCNOT_X_basis(0, 1, 2)
    for key, value in true_truth_table.items():
        state_prep_prog = Program().inst(I(2))
        meas_prog = Program()
        for qbit_idx, bit in enumerate(key):
            if bit == 1:
                state_prep_prog += X(qbit_idx)
            # Hadamard to get to the X basis
            state_prep_prog += H(qbit_idx)
            # Hadamard to get back to the Z basis before measurement
            meas_prog += H(qbit_idx)

        prog = state_prep_prog + CCNOTX + meas_prog
        ro = prog.declare('ro', 'BIT', 3)
        for q in range(3):
            prog += MEASURE(q, ro[q])
        exe = qvm.compiler.native_quil_to_executable(prog)
        result = qvm.run(exe)
        assert tuple(result[0]) == true_truth_table[key]
Example #12
0
    def get_string(self, betas: List[float], gammas: List[float], samples: int = 100):
        """
        Compute the most probable string.

        The method assumes you have passed init_betas and init_gammas with your
        pre-computed angles or you have run the VQE loop to determine the
        angles.  If you have not done this you will be returning the output for
        a random set of angles.

        :param betas: List of beta angles
        :param gammas: List of gamma angles
        :param samples: (Optional) number of samples to get back from the QuantumComputer.
        :returns: tuple representing the bitstring, Counter object from
                  collections holding all output bitstrings and their frequency.
        """
        if samples <= 0 and not isinstance(samples, int):
            raise ValueError("samples variable must be positive integer")
        param_prog = self.get_parameterized_program()
        stacked_params = np.hstack((betas, gammas))

        sampling_prog = Program()
        ro = sampling_prog.declare('ro', 'BIT', len(self.qubits))
        sampling_prog += param_prog(stacked_params)
        sampling_prog += [MEASURE(qubit, r) for qubit, r in zip(self.qubits, ro)]
        sampling_prog.wrap_in_numshots_loop(samples)
        executable = self.qc.compile(sampling_prog)
        bitstring_samples = self.qc.run(executable)
        bitstring_tuples = list(map(tuple, bitstring_samples))
        freq = Counter(bitstring_tuples)
        most_frequent_bit_string = max(freq, key=lambda x: freq[x])
        return most_frequent_bit_string, freq
Example #13
0
def generate_cz_phase_ramsey_program(qb: int,
                                     other_qb: int,
                                     n_shots: int = 1000) -> Program:
    """
    Generate a single CZ phase Ramsey experiment at a given phase.

    :param qb: The qubit to move around the Bloch sphere and measure the incurred RZ on.
    :param other_qb: The other qubit that constitutes a two-qubit pair along with `qb`.
    :param n_shots: The number of shots to average over for each data point.
    :param phase: The phase kick to supply after playing the CZ pulse on the equator.
    :param n_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 `qb` not `other_qb` since `other_qb` 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, qb))
    # apply the CZ gate - note that CZ is symmetric, so the order of qubits doesn't matter
    program += Program(CZ(qb, other_qb))
    # go to |1> after a phase kick
    program += Program(RZ(theta, qb), RX(np.pi / 2, qb))

    program += MEASURE(qb, ro[0])

    program.wrap_in_numshots_loop(n_shots)
    return program
Example #14
0
def generate_single_rabi_experiment(qubits: Union[int, List[int]],
                                    theta: float,
                                    n_shots: int = 1000) -> Program:
    """
    Return a Rabi program in native Quil rotated through the given angle.

    Rabi oscillations are observed by applying successively larger rotations to the same initial
    state.

    :param qubits: Which qubits to measure.
    :param theta: The angle of the Rabi RX rotation.
    :param n_shots: The number of shots to average over for the data point.
    :return: A Program that rotates through a given angle about the X axis.
    """
    program = Program()

    try:
        len(qubits)
    except TypeError:
        qubits = [qubits]

    ro = program.declare('ro', 'BIT', len(qubits))
    for q in qubits:
        program += RX(theta, q)
    for i in range(len(qubits)):
        program += MEASURE(qubits[i], ro[i])
    program.wrap_in_numshots_loop(n_shots)
    return program
Example #15
0
def test_reset(forest):
    device = NxDevice(nx.complete_graph(3))
    qc = QuantumComputer(
        name="testy!", qam=QVM(connection=forest), device=device, compiler=DummyCompiler()
    )
    p = Program(
        Declare(name="theta", memory_type="REAL"),
        Declare(name="ro", memory_type="BIT"),
        RX(MemoryReference("theta"), 0),
        MEASURE(0, MemoryReference("ro")),
    ).wrap_in_numshots_loop(1000)
    qc.run(executable=p, memory_map={"theta": [np.pi]})

    aref = ParameterAref(name="theta", index=0)
    assert qc.qam._variables_shim[aref] == np.pi
    assert qc.qam._executable == p
    assert qc.qam._memory_results["ro"].shape == (1000, 1)
    assert all([bit == 1 for bit in qc.qam._memory_results["ro"]])
    assert qc.qam.status == "done"

    qc.reset()

    assert qc.qam._variables_shim == {}
    assert qc.qam._executable is None
    assert qc.qam._memory_results["ro"] is None
    assert qc.qam.status == "connected"
Example #16
0
def test_validate_protoquil_with_pragma():
    prog = Program(
        RESET(),
        H(1),
        Pragma('DELAY'),
        MEASURE(1)
    )
    assert prog.is_protoquil()
Example #17
0
def test_qvm_run_just_program(client_configuration: QCSClientConfiguration):
    qvm = QVM(client_configuration=client_configuration,
              gate_noise=(0.01, 0.01, 0.01))
    p = Program(Declare("ro", "BIT"), X(0), MEASURE(0, MemoryReference("ro")))
    result = qvm.run(p.wrap_in_numshots_loop(1000))
    bitstrings = result.readout_data.get("ro")
    assert bitstrings.shape == (1000, 1)
    assert np.mean(bitstrings) > 0.8
Example #18
0
def test_validate_supported_quil_measure_last():
    prog = Program(
        MEASURE(0),
        H(0),
    )
    with pytest.raises(ValueError):
        validate_supported_quil(prog)
    assert not prog.is_supported_on_qpu()
Example #19
0
def test_validate_protoquil_measure_last():
    prog = Program(
        MEASURE(0),
        H(0),
    )
    with pytest.raises(ValueError):
        validate_protoquil(prog)
    assert not prog.is_protoquil()
Example #20
0
def test_validate_supported_quil_with_pragma():
    prog = Program(
        RESET(),
        H(1),
        Pragma('DELAY'),
        MEASURE(1, None)
    )
    assert prog.is_supported_on_qpu()
Example #21
0
def cxn():
    # DEPRECATED
    try:
        cxn = QVMConnection(endpoint='http://localhost:5000')
        cxn.run(Program(I(0), MEASURE(0, 0)), [0])
        return cxn
    except RequestException as e:
        return pytest.skip("This test requires a running local QVM: {}".format(e))
Example #22
0
def test_qvm_run_region_declared_and_measured(
        client_configuration: QCSClientConfiguration):
    qvm = QVM(client_configuration=client_configuration)
    p = Program(Declare("reg", "BIT"), X(0), MEASURE(0,
                                                     MemoryReference("reg")))
    result = qvm.run(p.wrap_in_numshots_loop(100))
    bitstrings = result.readout_data.get("reg")
    assert bitstrings.shape == (100, 1)
def test_qvm_run_region_not_declared_is_measured_non_ro(
        client_configuration: QCSClientConfiguration):
    qvm = QVM(client_configuration=client_configuration)
    p = Program(X(0), MEASURE(0, MemoryReference("reg")))

    with pytest.raises(QVMError,
                       match='Bad memory region name "reg" in MEASURE'):
        qvm.load(p).run().wait()
def test_qvm_run_region_declared_and_measured(
        client_configuration: QCSClientConfiguration):
    qvm = QVM(client_configuration=client_configuration)
    p = Program(Declare("reg", "BIT"), X(0), MEASURE(0,
                                                     MemoryReference("reg")))
    qvm.load(p.wrap_in_numshots_loop(100)).run().wait()
    bitstrings = qvm.read_memory(region_name="reg")
    assert bitstrings.shape == (100, 1)
Example #25
0
def ghz_program(qubits: List[int]) -> Program:
    program = Program()
    program.inst(H(qubits[0]))
    for i in range(len(qubits) - 1):
        program.inst(CNOT(qubits[i], qubits[i + 1]))
    ro = program.declare('ro', 'BIT', len(qubits))
    program.inst([MEASURE(qubit, ro[idx]) for idx, qubit in enumerate(qubits)])
    return program
Example #26
0
def test_halt():
    prog = Program(Declare("ro", "BIT"), X(0),
                   MEASURE(0, MemoryReference("ro", 0)))
    prog.inst(HALT)
    prog.inst(X(0), MEASURE(0, MemoryReference("ro", 0)))
    qam = PyQVM(n_qubits=1,
                quantum_simulator_type=ReferenceWavefunctionSimulator)
    qam.execute(prog)
    # HALT should stop execution; measure should give 1
    assert qam.ram["ro"][0] == 1

    prog = Program(Declare("ro", "BIT"),
                   X(0)).inst(X(0)).inst(MEASURE(0, MemoryReference("ro", 0)))
    qam = PyQVM(n_qubits=1,
                quantum_simulator_type=ReferenceWavefunctionSimulator)
    qam.execute(prog)
    assert qam.ram["ro"][0] == 0
Example #27
0
def _do_tomography(target_program, nsamples, cxn, qubits, max_num_qubits, tomography_class,
                   program_generator, settings, use_run=False):
    """

    :param Program target_program: The program to run to generate the state or process.
    :param int nsamples: The number of samples to take per measurement.
    :param QPUConnection|QVMConnection cxn: The connection to Forest.
    :param lists qubits: The list of qubits to perform tomography on.
    :param int max_num_qubits: The maximum allowed number of qubits.
    :param type tomography_class: The type of tomography to perform.
    :param function program_generator: The function that yields the tomography experiments.
    :param TomographySettings settings: The settings for running the optimizer.
    :param bool use_run: If ``True``, use append measurements on all qubits and use ``cxn.run``
        instead of ``cxn.run_and_measure``.
    :return: The tomography result, the assignment probabilities, and the histograms of counts
     measured.
    :rtype: tuple
    """
    if qubits is None:
        qubits = sorted(target_program.get_qubits())

    num_qubits = len(qubits)
    dimension = 2 ** num_qubits

    if num_qubits > max_num_qubits:
        raise ValueError("Too many qubits!")

    assignment_probs = sample_assignment_probs(qubits, nsamples, cxn)
    tomo_seq = list(program_generator(target_program, qubits))
    histograms = np.zeros((len(tomo_seq), dimension))

    jobs = []
    _log.info('Submitting jobs...')
    for i, tomo_prog in izip(ut.TRANGE(len(tomo_seq)), tomo_seq):
        if use_run:
            jobs.append(cxn.run_async(tomo_prog + Program([MEASURE(q, q) for q in qubits]),
                                      qubits, nsamples))
        else:
            jobs.append(cxn.run_and_measure_async(tomo_prog, qubits, nsamples))
    _log.info('Waiting for results...')
    for i, job_id in izip(ut.TRANGE(len(jobs)), jobs):
        job = cxn.wait_for_job(job_id)
        results = job.result()
        idxs = list(map(bitlist_to_int, results))
        histograms[i] = ut.make_histogram(idxs, dimension)

    povm = o_ut.make_diagonal_povm(grove.tomography.operator_utils.POVM_PI_BASIS ** num_qubits, assignment_probs)
    channel_ops = list(default_channel_ops(num_qubits))

    # Currently the analysis pathways are slightly different, so we branch on which type of
    # tomography is being done.
    if tomography_class.__tomography_type__ == "PROCESS":
        histograms = histograms.reshape((len(channel_ops), len(channel_ops), dimension))
        tomo_result = tomography_class.estimate_from_ssr(histograms, povm, channel_ops, channel_ops,
                                                         settings)
    else:
        tomo_result = tomography_class.estimate_from_ssr(histograms, povm, channel_ops, settings)
    return tomo_result, assignment_probs, histograms
Example #28
0
    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]
Example #29
0
 def _create_circuit(self, oracle):
     p = Program()
     classical_reg = p.declare('ro', 'BIT', len(self.input_qbits))
     p.defgate('oracle', oracle)
     p += [H(x) for x in self.input_qbits]
     p += tuple(['oracle'] + sorted(self.qbits, reverse=True))
     p += [H(x) for x in self.input_qbits]
     p += [MEASURE(x, y) for x, y in zip(self.input_qbits, classical_reg)]
     return p
Example #30
0
 def _wrap_program(self, program):
     # the actions select gates. but a pyquil program needs a bit more
     # namely, declaration of classical memory for readout, and suitable
     # measurement instructions
     ro = program.declare("ro", "BIT", self.num_qubits)
     for q in range(self.num_qubits):
         program.inst(MEASURE(q, ro[q]))
     program.wrap_in_numshots_loop(NUM_SHOTS)
     return program