Example #1
0
def test_wavefunction_expectation():
    term1 = PauliTerm("Z", 1, .2) * PauliTerm("Z", 2)
    term2 = PauliTerm("X", 1, -.4) * PauliTerm("Z", 3)
    term3 = PauliTerm("Y", 1, 1.4)
    ham = PauliSum([term1, term2, term3])
    ham2 = ham * ham

    mat = lifted_pauli(ham, [1, 3, 2])
    mat2 = lifted_pauli(ham2, [1, 3, 2])
    wf = np.array([0, 1.0, 2, .3, .5, -.5, .6, -.9])

    hams = commuting_decomposition(ham)
    hams2 = commuting_decomposition(ham2)

    funs = [base_change_fun(ham, [1, 3, 2]) for ham in hams]
    funs2 = [base_change_fun(ham, [1, 3, 2]) for ham in hams2]

    hams = [kron_eigs(h, [1, 3, 2]) for h in hams]
    hams2 = [kron_eigs(h, [1, 3, 2]) for h in hams2]

    e1, s1 = wavefunction_expectation(hams, funs, hams2, funs2, wf)
    e2, s2 = wf.conj()@mat@wf, wf@mat2@wf
    print(e1, s1)
    print(e2, s2)
    assert np.allclose((e1, s1), (e2, s2))
def theo_Hamil(n, t):
    '''Difinition of a function to compute and return theoretical
       Hamiltonian for n qubits with (choosing-2-out-of-n) 
       coupling terms in matrix form for evolution time t.
       param n: number of qubits.
       param t: total evolution time'''
    factor = 0.5
    # number of combination for n qubits
    length = np.arange(len(comb_xx(n)))
    # compute the xx interaction part of the Hamiltonian
    part_xx = [comb_xx(n)[i] * t * factor for i in length]
    # compute the x field interaction part of the Hamiltonian
    part_x = [x * factor * t for x in comb_x(n)]
    # compute the z field interaction part of the Hamiltonian
    part_z = [x * factor * t for x in comb_z(n)]
    # sum up all Pauli terms in the part_xx
    pauli_sum_xx = PauliSum(part_xx)
    # sum up all Pauli terms in the part_x
    pauli_sum_x = PauliSum(part_x)
    # sum up all Pauli terms in the part_z
    pauli_sum_z = PauliSum(part_z)
    # acquire a list of qubit indices for the applied
    # Pauli operators
    list_qbt = PauliSum.get_qubits(pauli_sum_xx)
    # add up the final matrices of both the pauli_xx
    # pauli_z to obtain the Hamiltonian in its matrix
    # form
    Hamil = lifted_pauli(pauli_sum_xx, list_qbt) + lifted_pauli(
        pauli_sum_z, list_qbt) + lifted_pauli(pauli_sum_x, list_qbt)
    return Hamil
def quantumVsClassical(maximum, layers):
    quantum_times = []
    classical_times = []
    timesteps = range(2, maximum)
    for i in range(2, maximum):
        test_adjacency = matrix.undirectedAdjacencyConstruct(i, False, 0.5)
        Paulis = matrix.pauliBuilder(test_adjacency)
        print(Paulis)
        print(
            unitary_tools.lifted_pauli(
                Paulis, range(int(math.log(test_adjacency.shape[0], 2)))))
        classical_time_init = time.time()
        classical_time = time.time() - classical_time_init
        quantum_time_init = time.time()
        print("estimated eigenvalue: ", vqe.solveVQE(Paulis, layers))
        print(
            "absolute difference: ",
            abs(
                min(
                    np.linalg.eig(test_adjacency)[0] -
                    vqe.solveVQE(Paulis, layers))))
        quantum_time = time.time() - quantum_time_init
        quantum_times.append(quantum_time)
        classical_times.append(classical_time)
        print("quantum runtime: ", quantum_time)
        print("classical runtime: ", classical_time)
    # print(quantum_times)
    print(classical_times)
    # plt.plot(timesteps,quantum_times,'bo')
    plt.plot(timesteps, classical_times, 'go')
    plt.show()
Example #4
0
def linear_inv_state_estimate(results: List[ExperimentResult],
                              qubits: List[int]) -> np.ndarray:
    """
    Estimate a quantum state using linear inversion.

    This is the simplest state tomography post processing. To use this function,
    collect state tomography data with :py:func:`generate_state_tomography_experiment`
    and :py:func:`~pyquil.operator_estimation.measure_observables`.

    For more details on this post-processing technique,
    see https://en.wikipedia.org/wiki/Quantum_tomography#Linear_inversion or
    see section 3.4 of

        Initialization and characterization of open quantum systems
        C. Wood, PhD thesis from University of Waterloo, (2015).
        http://hdl.handle.net/10012/9557


    :param results: A tomographically complete list of results.
    :param qubits: All qubits that were tomographized. This specifies the order in
        which qubits will be kron'ed together.
    :return: A point estimate of the quantum state rho.
    """
    measurement_matrix = np.vstack([
        vec(lifted_pauli(result.setting.out_operator, qubits=qubits)).T.conj()
        for result in results
    ])
    expectations = np.array([result.expectation for result in results])
    rho = pinv(measurement_matrix) @ expectations
    return unvec(rho)
Example #5
0
def test_kron_diagonal():
    term1 = PauliTerm("Z", 1, .2) * PauliTerm("Z", 3)
    term2 = PauliTerm("Z", 1, -.4) * PauliTerm("Z", 2)
    term3 = PauliTerm("Z", 1, 1.4)
    ham = PauliSum([term1, term2, term3])
    diag1 = np.diag(lifted_pauli(ham, [1, 3, 2]))
    diag2 = kron_eigs(ham, [1, 3, 2])
    assert np.allclose(diag1, diag2)
Example #6
0
def test_lifted_pauli():
    qubits = [0, 1]
    xy_term = sX(0) * sY(1)

    # test correctness
    trial_matrix = lifted_pauli(xy_term, qubits)
    true_matrix = np.kron(mat.Y, mat.X)
    np.testing.assert_allclose(trial_matrix, true_matrix)

    x1_term = sX(1)
    trial_matrix = lifted_pauli(x1_term, qubits)
    true_matrix = np.kron(mat.X, mat.I)
    np.testing.assert_allclose(trial_matrix, true_matrix)

    zpz_term = sZ(0) + sZ(1)
    trial_matrix = lifted_pauli(zpz_term, qubits)
    true_matrix = np.zeros((4, 4))
    true_matrix[0, 0] = 2
    true_matrix[-1, -1] = -2
    np.testing.assert_allclose(trial_matrix, true_matrix)
Example #7
0
def _extract_from_results(results: List[ExperimentResult], qubits: List[int]):
    """
    Construct the matrix A such that the probabilities p_ij of outcomes n_ij given an estimate E
    can be cast in a vectorized form.

    Specifically::

        p = vec(p_ij) = A x vec(E)

    This yields convenient vectorized calculations of the cost and its gradient, in terms of A, n,
    and E.
    """
    A = []
    n = []
    grand_total_shots = 0

    for result in results:
        in_state_matrix = lifted_state_operator(result.setting.in_state,
                                                qubits=qubits)
        operator = lifted_pauli(result.setting.out_operator, qubits=qubits)
        proj_plus = (np.eye(2**len(qubits)) + operator) / 2
        proj_minus = (np.eye(2**len(qubits)) - operator) / 2

        # Constructing A per eq. (22)
        # TODO: figure out if we can avoid re-splitting into Pi+ and Pi- counts
        A += [
            # vec() turns into a column vector; transpose to a row vector; index into the
            # 1 row to avoid an extra tensor dimension when we call np.asarray(A).
            vec(np.kron(in_state_matrix, proj_plus.T)).T[0],
            vec(np.kron(in_state_matrix, proj_minus.T)).T[0],
        ]

        expected_plus_ones = (1 + result.expectation) / 2
        n += [
            result.total_counts * expected_plus_ones,
            result.total_counts * (1 - expected_plus_ones)
        ]
        grand_total_shots += result.total_counts

    n_qubits = len(qubits)
    dimension = 2**n_qubits
    A = np.asarray(A) / dimension**2
    n = np.asarray(n)[:, np.newaxis] / grand_total_shots
    return A, n
Example #8
0
def pauli_matrix(pauli_sum: PauliSum, qubit_mapping: Dict = {}) -> np.array:
    """Create the matrix representation of pauli_sum.

    Parameters
    ----------
    qubit_mapping:
        A dictionary-like object that maps from :py:class`QubitPlaceholder` to
        :py:class:`int`

    Returns
    -------
    np.matrix:
        A matrix representing the PauliSum
    """

    # get unmapped Qubits and check that all QubitPlaceholders are mapped
    unmapped_qubits = {*pauli_sum.get_qubits()} - qubit_mapping.keys()
    if not all(isinstance(q, int) for q in unmapped_qubits):
        raise ValueError("Not all QubitPlaceholders are mapped")

    # invert qubit_mapping and assert its injectivity
    inv_mapping = dict([v, k] for k, v in qubit_mapping.items())
    if len(inv_mapping) is not len(qubit_mapping):
        raise ValueError("qubit_mapping must be injective")

    # add unmapped qubits to the inverse mapping, ensuring we don't have
    # a list entry twice
    for q in unmapped_qubits:
        if q not in inv_mapping.keys():
            inv_mapping[q] = q
        else:
            raise ValueError("qubit_mapping maps to qubit already in use")

    qubit_list = [inv_mapping[k] for k in sorted(inv_mapping.keys())]
    matrix = lifted_pauli(pauli_sum, qubit_list)
    return matrix