def test_random_unitaries_first_moment():
    # the first moment should be proportional to P_21/D
    N_avg = 50000
    D2 = 2
    D3 = 3
    perm_swap = [1, 0]
    # Permutation operators
    # SWAP aka P_21 which maps H_1 \otimes H_2 to H_2 \otimes H_1
    D2_SWAP = rand_ops.permute_tensor_factors(D2, perm_swap)
    D3_SWAP = rand_ops.permute_tensor_factors(D3, perm_swap)
    X = rand_ops.haar_rand_unitary(D2)
    Id2 = np.matmul(X, np.conjugate(X.T))
    Y = rand_ops.haar_rand_unitary(D3)
    Id3 = np.matmul(Y, np.conjugate(Y.T))
    D2_avg = np.zeros_like(np.kron(Id2, Id2))
    D3_avg = np.zeros_like(np.kron(Id3, Id3))

    for n in range(0, N_avg):
        U2 = rand_ops.haar_rand_unitary(D2)
        U2d = np.conjugate(U2.T)
        D2_avg += np.kron(U2, U2d) / N_avg
        U3 = rand_ops.haar_rand_unitary(D3)
        U3d = np.conjugate(U3.T)
        D3_avg += np.kron(U3, U3d) / N_avg

    # Compute the Frobenius norm of the different between the estimated operator and the answer
    assert np.real(la.norm((D2_avg - D2_SWAP / D2), 'fro')) <= 0.01
    assert np.real(la.norm((D2_avg - D2_SWAP / D2), 'fro')) >= 0.00
    assert np.real(la.norm((D3_avg - D3_SWAP / D3), 'fro')) <= 0.02
    assert np.real(la.norm((D3_avg - D3_SWAP / D3), 'fro')) >= 0.00
示例#2
0
def generate_abstract_qv_circuit(
        depth: int) -> Tuple[List[np.ndarray], np.ndarray]:
    """
    Produces an abstract description of the square model circuit of given depth=width used in a
    quantum volume measurement.

    The description remains abstract as it does not directly reference qubits in a circuit; rather,
    the circuit is specified as a list of depth many permutations and depth many layers of two
    qubit gates specified as a depth by depth//2 numpy array whose entries are each a haar random
    four by four matrix (a single 2 qubit gate). Each permutation is simply a list of the numbers
    0 through depth-1, where the number x at index i indicates the qubit in position i should be
    moved to position x. The 4 by 4 matrix at gates[i, j] is the gate acting on the qubits at
    positions 2j, 2j+1 after the i^th permutation has occurred.

    :param depth: the depth, and also width, of the model circuit
    :return: the random depth-many permutations and depth by depth//2 many 2q-gates which comprise
        the model quantum circuit of [QVol] for a given depth.
    """
    # generate a simple list representation for each permutation of the depth many qubits
    permutations = [np.random.permutation(range(depth)) for _ in range(depth)]

    # generate a matrix representation of each 2q gate in the circuit
    num_gates_per_layer = depth // 2  # if odd number of qubits, don't do anything to last qubit
    gates = np.asarray(
        [[haar_rand_unitary(4) for _ in range(num_gates_per_layer)]
         for _ in range(depth)])

    return permutations, gates
示例#3
0
def single_q_process(request):
    if request.param == 'X':
        return Program(X(0)), mat.X
    elif request.param == 'haar':
        u_rand = haar_rand_unitary(2 ** 1, rs=np.random.RandomState(52))
        process = Program().defgate("RandUnitary", u_rand)
        process += ("RandUnitary", 0)
        return process, u_rand
def test_HS_obeys_cauchy_schwarz():
    D = 2
    Ur = rand_ops.haar_rand_unitary(D)
    U = Ur + np.conj(Ur.T)
    A = np.eye(D)
    B = A / 3
    assert dm.hilbert_schmidt_ip(U, U) * dm.hilbert_schmidt_ip(A, A) >= abs(dm.hilbert_schmidt_ip(A, U))**2
    assert dm.hilbert_schmidt_ip(U, U) * dm.hilbert_schmidt_ip(B, B) >= abs(dm.hilbert_schmidt_ip(B, U))**2
示例#5
0
def two_q_process(request):
    if request.param == 'CNOT':
        return Program(CNOT(0, 1)), mat.CNOT
    elif request.param == 'haar':
        u_rand = haar_rand_unitary(2 ** 2, rs=np.random.RandomState(52))
        process = Program().defgate("RandUnitary", u_rand)
        process += ("RandUnitary", 0, 1)
        return process, u_rand
    else:
        raise ValueError()
def test_random_unitaries_are_unitary():
    N_avg = 30
    D2 = 2
    D3 = 3
    avg_trace2 = 0
    avg_det2 = 0
    avg_trace3 = 0
    avg_det3 = 0
    for idx in range(0, N_avg):
        U2 = rand_ops.haar_rand_unitary(D2)
        U3 = rand_ops.haar_rand_unitary(D3)
        avg_trace2 += np.trace(np.matmul(U2, np.conjugate(U2.T))) / N_avg
        avg_det2 += np.abs(la.det(U2)) / N_avg
        avg_trace3 += np.trace(np.matmul(U3, np.conjugate(U3.T))) / N_avg
        avg_det3 += np.abs(la.det(U3)) / N_avg

    assert np.allclose(avg_trace2, 2.0)
    assert np.allclose(avg_det2, 1.0)
    assert np.allclose(avg_trace3, 3.0)
    assert np.allclose(avg_det3, 1.0)
def test_HS_obeys_linearity():
    D = 2
    Ur = rand_ops.haar_rand_unitary(D)
    U = Ur + np.conj(Ur.T)
    A = np.eye(D)
    B = A / 3
    alpha = 0.17
    beta = 0.6713
    LHS = alpha * dm.hilbert_schmidt_ip(U, A) + beta * dm.hilbert_schmidt_ip(U, B)
    RHS = dm.hilbert_schmidt_ip(U, alpha * A + beta * B)
    assert np.allclose(LHS, RHS)
def single_q_tomo_fixture():
    qubits = [0]
    qc = get_test_qc(n_qubits=len(qubits))

    # Generate random unitary
    u_rand = haar_rand_unitary(2**1, rs=qc.qam.rs)
    state_prep = Program().defgate("RandUnitary", u_rand)
    state_prep.inst([("RandUnitary", qubits[0])])

    # True state
    wfn = NumpyWavefunctionSimulator(n_qubits=1)
    psi = wfn.do_gate_matrix(u_rand, qubits=[0]).wf.reshape(-1)
    rho_true = np.outer(psi, psi.T.conj())

    # Get data from QVM
    tomo_expt = generate_state_tomography_experiment(state_prep, qubits)
    results = list(
        measure_observables(qc=qc, tomo_experiment=tomo_expt, n_shots=100_000))

    return results, rho_true
def test_random_unitaries_second_moment():
    # the second moment should be proportional to
    #
    #   P_13_24 + P_14_23             P_1423 + P_1324
    #  ------------------     -     -------------------
    #       ( d^2 -1)                   d ( d^2 -1)
    #

    N_avg = 80000
    D2 = 2
    X = rand_ops.haar_rand_unitary(D2)
    Id2 = np.matmul(X, np.conjugate(X.T))

    # lists representing the permutations
    p_3412 = Permutation([2, 3, 0, 1]).list()
    p_4321 = Permutation([3, 2, 1, 0]).list()
    p_4312 = Permutation([3, 2, 0, 1]).list()
    p_3421 = Permutation([2, 3, 1, 0]).list()
    # Permutation operators
    P_3412 = rand_ops.permute_tensor_factors(D2, p_3412)
    P_4321 = rand_ops.permute_tensor_factors(D2, p_4321)
    P_4312 = rand_ops.permute_tensor_factors(D2, p_4312)
    P_3421 = rand_ops.permute_tensor_factors(D2, p_3421)
    # ^^ convention in https://arxiv.org/pdf/0711.1017.pdf

    ## For archaeological reasons I will leave this code for those who come next..
    ## lists representing the permutations
    # p_14_23 = Permutation(0, 3)(1, 2).list()
    # p_13_24 = Permutation(0, 2)(1, 3).list()
    # p_1423 = Permutation([0, 3, 1, 2]).list()
    # p_1324 = Permutation([0, 2, 1, 3]).list()
    ## Permutation operators
    # P_14_23 = rand_ops.permute_tensor_factors(D2, p_14_23)
    # P_13_24 = rand_ops.permute_tensor_factors(D2, p_13_24)
    # P_1423 = rand_ops.permute_tensor_factors(D2, p_1423)
    # P_1324 = rand_ops.permute_tensor_factors(D2, p_1324)
    ## ^^ convention in https://arxiv.org/pdf/0809.3813.pdf

    # initalize array
    D2_var = np.zeros_like(np.kron(np.kron(np.kron(Id2, Id2), Id2), Id2))

    for n in range(0, N_avg):
        U2 = rand_ops.haar_rand_unitary(D2)
        U2d = np.conjugate(U2.T)
        D2_var += np.kron(np.kron(np.kron(U2, U2), U2d), U2d) / N_avg

    alpha = 1 / (D2**2 - 1)  # 0.3333
    beta = 1 / (D2 * (D2**2 - 1))  # 0.1666

    theanswer1 = alpha * (P_3412 + P_4321) - beta * (P_4312 + P_3421)
    # ^^ Equation 5.17 in https://arxiv.org/pdf/0711.1017.pdf

    ## For archaeological reasons I will leave this code for those who come next..
    # theanswer2 = alpha * (P_13_24 + P_14_23)  - beta * (P_1423 + P_1324)
    ## ^^ Equation at the bottom of page 2 in https://arxiv.org/pdf/0809.3813.pdf

    # round and remove tiny imaginary parts
    truth = np.around(theanswer1, 2)
    estimate = np.around(np.real(D2_var), 2)

    # are the estimated operator and the answer close?
    print(truth)
    print(estimate)
    assert np.allclose(truth, estimate)