Exemple #1
0
def test_povm():
    pi_basis = grove.tomography.operator_utils.POVM_PI_BASIS
    confusion_rate_matrix = np.eye(2)
    povm = o_ut.make_diagonal_povm(pi_basis, confusion_rate_matrix)

    assert (povm.ops[0] - pi_basis.ops[0]).norm(FROBENIUS) < o_ut.EPS
    assert (povm.ops[1] - pi_basis.ops[1]).norm(FROBENIUS) < o_ut.EPS

    with pytest.raises(o_ut.CRMUnnormalizedError):
        confusion_rate_matrix = np.array([[.8, 0.], [.3, 1.]])
        _ = o_ut.make_diagonal_povm(pi_basis, confusion_rate_matrix)

    with pytest.raises(o_ut.CRMValueError):
        confusion_rate_matrix = np.array([[.8, -.1], [.2, 1.1]])
        _ = o_ut.make_diagonal_povm(pi_basis, confusion_rate_matrix)
def test_state_tomography():
    num_qubits = len(BELL_STATE_PROGRAM.get_qubits())
    dimension = 2 ** num_qubits
    tomo_seq = list(state_tomography_programs(BELL_STATE_PROGRAM))
    num_samples = 3000
    np.random.seed(SEED)
    qubits = [qubit for qubit in range(num_qubits)]
    tomo_preps = basis_state_preps(*qubits)
    state_prep_hists = []
    for i, tomo_prep in enumerate(tomo_preps):
        readout_result = sample_bad_readout(tomo_prep, num_samples, BAD_2Q_READOUT, cxn)
        state_prep_hists.append(make_histogram(readout_result, dimension))
    assignment_probs = estimate_assignment_probs(state_prep_hists)
    histograms = np.zeros((len(tomo_seq), dimension))
    for i, tomo_prog in enumerate(tomo_seq):
        readout_result = sample_bad_readout(tomo_prog, num_samples, BAD_2Q_READOUT, cxn)
        histograms[i] = make_histogram(readout_result, dimension)
    povm = make_diagonal_povm(POVM_PI_BASIS ** num_qubits, assignment_probs)
    channel_ops = list(default_channel_ops(num_qubits))
    for settings in [DEFAULT_STATE_TOMO_SETTINGS,
                     DEFAULT_STATE_TOMO_SETTINGS._replace(constraints={UNIT_TRACE, POSITIVE,
                                                                       TRACE_PRESERVING})]:
        state_tomo = StateTomography.estimate_from_ssr(histograms, povm, channel_ops, settings)
        amplitudes = np.array([1, 0, 0, 1]) / np.sqrt(2.)
        state = qt.Qobj(amplitudes, dims=[[2, 2], [1, 1]])
        rho_ideal = state * state.dag()
        assert abs(1 - state_tomo.fidelity(rho_ideal)) < EPS
    with patch("grove.tomography.utils.state_histogram"), patch(
            "grove.tomography.state_tomography.plt"):
        state_tomo.plot()
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
Exemple #4
0
def _do_tomography(target_program, nsamples, cxn, qubits, max_num_qubits,
                   tomography_class, program_generator, settings):
    """

    :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.
    :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))
    for i, tomo_prog in izip(ut.TRANGE(len(tomo_seq)), tomo_seq):
        tomo_prog = Program(Pragma("PRESERVE_BLOCK")) + tomo_prog
        results = cxn.run_and_measure(tomo_prog, qubits, nsamples)
        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
Exemple #5
0
def test_process_tomography():
    num_qubits = len(CNOT_PROGRAM.get_qubits())
    dimension = 2 ** num_qubits

    tomo_seq = list(process_tomography_programs(CNOT_PROGRAM))
    nsamples = 3000

    np.random.seed(SEED)
    # We need more samples on the readout to ensure convergence.
    state_prep_hists = [make_histogram(sample_bad_readout(p, 2 * nsamples, BAD_2Q_READOUT, cxn),
                                       dimension) for p in basis_state_preps(*range(num_qubits))]
    assignment_probs = estimate_assignment_probs(state_prep_hists)

    histograms = np.zeros((len(tomo_seq), dimension))

    for jj, p in enumerate(tomo_seq):
        histograms[jj] = make_histogram(sample_bad_readout(p, nsamples, BAD_2Q_READOUT, cxn),
                                        dimension)

    channel_ops = list(default_channel_ops(num_qubits))
    histograms = histograms.reshape((len(channel_ops), len(channel_ops), dimension))

    povm = make_diagonal_povm(POVM_PI_BASIS ** num_qubits, assignment_probs)
    cnot_ideal = qt.cnot()
    for settings in [
        DEFAULT_PROCESS_TOMO_SETTINGS,
        DEFAULT_PROCESS_TOMO_SETTINGS._replace(constraints={TRACE_PRESERVING}),
        DEFAULT_PROCESS_TOMO_SETTINGS._replace(constraints={TRACE_PRESERVING, COMPLETELY_POSITIVE}),
    ]:

        process_tomo = ProcessTomography.estimate_from_ssr(histograms, povm, channel_ops,
                                                           channel_ops,
                                                           settings)

        assert abs(1 - process_tomo.avg_gate_fidelity(cnot_ideal)) < EPS

        transfer_matrix = process_tomo.pauli_basis.transfer_matrix(qt.to_super(cnot_ideal))
        assert abs(1 - process_tomo.avg_gate_fidelity(transfer_matrix)) < EPS
        chi_rep = process_tomo.to_chi().data.toarray()
        # When comparing to the identity, the chi representation is quadratically larger than the
        # Hilbert space representation, so we take a square root.
        probabilty_scale = np.sqrt(chi_rep.shape[0])
        super_op_from_chi = np.zeros(process_tomo.pauli_basis.ops[0].shape, dtype=np.complex128)
        for i, si in enumerate(process_tomo.pauli_basis.ops):
            for j, sj in enumerate(process_tomo.pauli_basis.ops):
                contribution = chi_rep[i][j] * si.data.toarray().conj().T.dot(sj.data.toarray())
                super_op_from_chi += contribution / probabilty_scale
        assert np.isclose(np.eye(process_tomo.pauli_basis.ops[0].shape[0]), super_op_from_chi,
                          atol=EPS).all()
        choi_rep = process_tomo.to_choi()

        # Choi matrix should be a valid density matrix, scaled by the dimension of the system.
        assert np.isclose(np.trace(choi_rep.data.toarray()) / probabilty_scale, 1, atol=EPS)

        super_op = process_tomo.to_super()
        # The map should be trace preserving.
        assert np.isclose(np.sum(super_op[0]), 1, atol=EPS)

    assert abs(1 - process_tomo.avg_gate_fidelity(qt.to_super(cnot_ideal))) < EPS

    with patch("grove.tomography.utils.plot_pauli_transfer_matrix"), \
         patch("grove.tomography.process_tomography.plt") as mplt:
        mplt.subplots.return_value = Mock(), Mock()
        process_tomo.plot()