Пример #1
0
def test_exponentiate_identity():
    generator = PauliTerm("I", 1, 0.0)
    para_prog = exponential_map(generator)
    prog = para_prog(1)
    result_prog = Program().inst([X(0), PHASE(0)(0), X(0), PHASE(0)(0)])
    compare_progs(prog, result_prog)

    generator = PauliTerm("I", 1, 1.0)
    para_prog = exponential_map(generator)
    prog = para_prog(1)
    result_prog = Program().inst([X(0), PHASE(-1.0)(0), X(0), PHASE(-1.0)(0)])
    compare_progs(prog, result_prog)

    generator = PauliTerm("I", 10, 0.08)
    para_prog = exponential_map(generator)
    prog = para_prog(1)
    result_prog = Program().inst(
        [X(0), PHASE(-0.08)(0), X(0),
         PHASE(-0.08)(0)])
    compare_progs(prog, result_prog)
Пример #2
0
def test_larger_qaoa_circuit():
    square_qaoa_circuit = [
        H(0),
        H(1),
        H(2),
        H(3),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(0, 1),
        RZ(0.78564882604980579, 1),
        CNOT(0, 1),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(0, 3),
        RZ(0.78564882604980579, 3),
        CNOT(0, 3),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(1, 2),
        RZ(0.78564882604980579, 2),
        CNOT(1, 2),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(2, 3),
        RZ(0.78564882604980579, 3),
        CNOT(2, 3),
        H(0),
        RZ(-0.77868204192240842, 0),
        H(0),
        H(1),
        RZ(-0.77868204192240842, 1),
        H(1),
        H(2),
        RZ(-0.77868204192240842, 2),
        H(2),
        H(3),
        RZ(-0.77868204192240842, 3),
        H(3),
    ]

    prog = Program(square_qaoa_circuit)
    qam = PyQVM(n_qubits=4, quantum_simulator_type=ReferenceWavefunctionSimulator)
    qam.execute(prog)
    wf = qam.wf_simulator.wf

    wf_true = np.array(
        [
            8.43771693e-05 - 0.1233845 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -2.50040954e-01 + 0.12661547 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -4.99915497e-01 - 0.12363516 * 1j,
            -2.50040954e-01 + 0.12661547 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -2.50040954e-01 + 0.12661547 * 1j,
            -4.99915497e-01 - 0.12363516 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -2.50040954e-01 + 0.12661547 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            -1.24927731e-01 + 0.00329533 * 1j,
            8.43771693e-05 - 0.1233845 * 1j,
        ]
    )

    np.testing.assert_allclose(wf_true, wf)
Пример #3
0
    0.0625 + 0.0j,
    0.0625 + 0.0j,
    0.0625 + 0.0j,
    0.0625 + 0.0j,
    0.0625 + 0.0j,
    0.0625 + 0.0j,
    0.0625 + 0.0j,
    0.0625 + 0.0j,
]

HADAMARD_WF = [0.70710678 + 0.0j, 0.70710678 + 0.0j]

ARBITRARY_STATE_GEN_INSTRUCTIONS = {
    1: [
        RZ(-1.3778211380875056, 0),
        PHASE(1.3778211380875056, 0),
        H(0),
        RY(-1.5707963267948963, 0),
        RZ(-1.3778211380875056, 0),
    ],
    2: [
        RZ(3.9156492624160952, 0),
        PHASE(-3.9156492624160952, 0),
        H(0),
        RY(-1.334414217642601, 0),
        RZ(-0.51915346851116273, 0),
    ],
    3: [
        RZ(1.1065191340906928, 0),
        PHASE(-1.1065191340906928, 0),
        H(0),
Пример #4
0
def test_phases():
    p = Program(PHASE(np.pi, 1), CPHASE00(np.pi, 0, 1), CPHASE01(np.pi, 0, 1),
                CPHASE10(np.pi, 0, 1), CPHASE(np.pi, 0, 1))
    assert p.out() == 'PHASE(pi) 1\nCPHASE00(pi) 0 1\n' \
                      'CPHASE01(pi) 0 1\nCPHASE10(pi) 0 1\n' \
                      'CPHASE(pi) 0 1\n'
Пример #5
0
def test_rb_sequence(server, mock_rb_cxn):
    response = mock_rb_cxn.generate_rb_sequence(2, [PHASE(np.pi / 2, 0), H(0)])
    assert [prog.out()
            for prog in response] == [prog.out() for prog in RB_REPLY]
Пример #6
0
from pyquil.quil import Program
from pyquil.api import QVMConnection
from pyquil.gates import H, PHASE

from pyquilcompiler import compiletoquil

import numpy as np
# Invoking and renaming
qvm = QVMConnection()
p = Program()
# Gate implementation
p.inst(H(0))
theta = np.pi / 2
p.inst(PHASE(theta, 0))

# Measurement
p.measure(0, 0)
p.measure(1, 1)
# Running the program

compiletoquil(p)

cr = []
results = qvm.run(p, cr, 4)
print(results)
Пример #7
0
def test_dagger():
    # these gates are their own inverses
    p = Program().inst(I(0), X(0), Y(0), Z(0), H(0), CNOT(0, 1),
                       CCNOT(0, 1, 2), SWAP(0, 1), CSWAP(0, 1, 2))
    assert p.dagger().out() == 'CSWAP 0 1 2\nSWAP 0 1\n' \
                               'CCNOT 0 1 2\nCNOT 0 1\nH 0\n' \
                               'Z 0\nY 0\nX 0\nI 0\n'

    # these gates require negating a parameter
    p = Program().inst(PHASE(pi, 0), RX(pi, 0), RY(pi, 0), RZ(pi, 0),
                       CPHASE(pi, 0, 1), CPHASE00(pi, 0, 1),
                       CPHASE01(pi, 0, 1), CPHASE10(pi, 0, 1), PSWAP(pi, 0, 1))
    assert p.dagger().out() == 'PSWAP(-pi) 0 1\n' \
                               'CPHASE10(-pi) 0 1\n' \
                               'CPHASE01(-pi) 0 1\n' \
                               'CPHASE00(-pi) 0 1\n' \
                               'CPHASE(-pi) 0 1\n' \
                               'RZ(-pi) 0\n' \
                               'RY(-pi) 0\n' \
                               'RX(-pi) 0\n' \
                               'PHASE(-pi) 0\n'

    # these gates are special cases
    p = Program().inst(S(0), T(0), ISWAP(0, 1))
    assert p.dagger().out() == 'PSWAP(pi/2) 0 1\n' \
                               'RZ(pi/4) 0\n' \
                               'PHASE(-pi/2) 0\n'

    # must invert defined gates
    G = np.array([[0, 1], [0 + 1j, 0]])
    p = Program().defgate("G", G).inst(("G", 0))
    assert p.dagger().out() == 'DEFGATE G-INV:\n' \
                               '    0.0, -i\n' \
                               '    1.0, 0.0\n\n' \
                               'G-INV 0\n'

    # can also pass in a list of inverses
    inv_dict = {"G": "J"}
    p = Program().defgate("G", G).inst(("G", 0))
    assert p.dagger(inv_dict=inv_dict).out() == 'J 0\n'

    # defined parameterized gates cannot auto generate daggered version https://github.com/rigetti/pyquil/issues/304
    theta = Parameter('theta')
    gparam_matrix = np.array([[quil_cos(theta / 2), -1j * quil_sin(theta / 2)],
                              [-1j * quil_sin(theta / 2),
                               quil_cos(theta / 2)]])
    g_param_def = DefGate('GPARAM', gparam_matrix, [theta])
    p = Program(g_param_def)
    with pytest.raises(TypeError):
        p.dagger()

    # defined parameterized gates should passback parameters https://github.com/rigetti/pyquil/issues/304
    GPARAM = g_param_def.get_constructor()
    p = Program(GPARAM(pi)(1, 2))
    assert p.dagger().out() == 'GPARAM-INV(pi) 1 2\n'

    # 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)
    assert p.dagger().out() == 'CONTROLLED CNOT 0 2 1\n' \
                               'CONTROLLED PHASE(-pi) 0 1\n' \
                               'CONTROLLED RZ(pi/4) 0 1\n' \
                               'CONTROLLED PHASE(-pi/2) 0 1\n' \
                               'CONTROLLED H 0 1\n' \
                               'CONTROLLED Z 0 1\n' \
                               'CONTROLLED Y 0 1\n' \
                               'CONTROLLED X 0 1\n'
Пример #8
0
def test_local_rb_sequence(benchmarker):
    response = benchmarker.generate_rb_sequence(
        2, [PHASE(np.pi / 2, 0), H(0)], seed=52)
    assert [prog.out() for prog in response] == \
           ["H 0\nPHASE(pi/2) 0\nH 0\nPHASE(pi/2) 0\nPHASE(pi/2) 0\n",
            "H 0\nPHASE(pi/2) 0\nH 0\nPHASE(pi/2) 0\nPHASE(pi/2) 0\n"]
Пример #9
0
def test_larger_qaoa_density():
    prog = Program(
        H(0),
        H(1),
        H(2),
        H(3),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(0, 1),
        RZ(0.78564882604980579, 1),
        CNOT(0, 1),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(0, 3),
        RZ(0.78564882604980579, 3),
        CNOT(0, 3),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(1, 2),
        RZ(0.78564882604980579, 2),
        CNOT(1, 2),
        X(0),
        PHASE(0.3928244130249029, 0),
        X(0),
        PHASE(0.3928244130249029, 0),
        CNOT(2, 3),
        RZ(0.78564882604980579, 3),
        CNOT(2, 3),
        H(0),
        RZ(-0.77868204192240842, 0),
        H(0),
        H(1),
        RZ(-0.77868204192240842, 1),
        H(1),
        H(2),
        RZ(-0.77868204192240842, 2),
        H(2),
        H(3),
        RZ(-0.77868204192240842, 3),
        H(3),
    )

    qam = PyQVM(n_qubits=4,
                quantum_simulator_type=ReferenceDensitySimulator).execute(prog)
    rho_test = qam.wf_simulator.density
    wf_true = np.array([
        8.43771693e-05 - 0.1233845 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -2.50040954e-01 + 0.12661547 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -4.99915497e-01 - 0.12363516 * 1j,
        -2.50040954e-01 + 0.12661547 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -2.50040954e-01 + 0.12661547 * 1j,
        -4.99915497e-01 - 0.12363516 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -2.50040954e-01 + 0.12661547 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        -1.24927731e-01 + 0.00329533 * 1j,
        8.43771693e-05 - 0.1233845 * 1j,
    ])

    wf_true = np.reshape(wf_true, (2**4, 1))
    rho_true = np.dot(wf_true, np.conj(wf_true).T)
    np.testing.assert_allclose(rho_true, rho_test, atol=1e-8)
Пример #10
0
def main():
    qvm = QVMConnection()
    agave = get_devices(as_dict=True)['8Q-Agave']
    qvm_noisy = QVMConnection(agave)
    print(
        "Timestamp, Singlet (Wavefunction), Triplet (Wavefunction), Singlet (QVM), Triplet (QVM),"
        "Singlet (Noise), Triplet (Noise), 00 (Noise), 11 (Noise),"
        "Singlet (Compiled on QVM), Triplet (Compiled on QVM), 00 (Compiled on QVM), 11 (Compiled on QVM),"
    )

    # Truncate file with compiled code
    open(FILENAME, "w").close()
    # Rotation
    for t in range(0, 50):  # ns
        p = create_singlet_state()
        add_switch_to_singlet_triplet_basis_gate_to_program(p)
        w_larmor = 0.46  # 4.6e8 1/s as determined in the experiment
        p.inst(PHASE(w_larmor * t, 0))
        p.inst(("SWITCH_TO_SINGLET_TRIPLET_BASIS", 0, 1))
        wavefunction = qvm.wavefunction(p)
        probs = wavefunction.get_outcome_probs()

        p.measure(0, 0)
        p.measure(1, 1)
        # Run on a perfect QVM (no noise)
        data = qvm.run(p, trials=1000)

        # simulate physical noise on QVM
        data_noisy = qvm_noisy.run(p, trials=1000)
        noisy_data_distr = distribution(data_noisy)

        agave = get_devices(as_dict=True)['8Q-Agave']
        compiler = CompilerConnection(agave)
        job_id = compiler.compile_async(p)
        # wait_for_job has print statement
        # using this workaround to suppress it
        import sys, os
        _old_stdout = sys.stdout
        with open(os.devnull, 'w') as fp:
            sys.stdout = fp
            job = compiler.wait_for_job(
                job_id)  # This is the only line that matters
        sys.stdout = _old_stdout

        # Run code compiled for 8Q-Agave on a noisy QVM
        # Per example on https://github.com/rigetticomputing/pyquil/blob/master/examples/run_quil.py
        p_compiled = Program(job.compiled_quil())
        with open(FILENAME, "a") as fp:
            fp.write("Timestep: %s\n" % t)
            fp.write("%s" % job.compiled_quil())
            fp.write("\n")
        data_compiled = qvm_noisy.run(p_compiled, trials=1000)
        compiled_data_distr = distribution(data_compiled)

        print("%s, %s, %s, %s, %s, %s, %s, %s ,%s, %s, %s, %s, %s" % (
            t,
            probs['01'],
            probs['10'],
            distribution(data).get((0, 1), 0),
            distribution(data).get((1, 0), 0),
            noisy_data_distr.get((0, 1), 0),
            noisy_data_distr.get((1, 0), 0),
            noisy_data_distr.get((0, 0), 0),
            noisy_data_distr.get((1, 1), 0),
            compiled_data_distr.get((0, 1), 0),
            compiled_data_distr.get((1, 0), 0),
            compiled_data_distr.get((0, 0), 0),
            compiled_data_distr.get((1, 1), 0),
        ))
Пример #11
0
 def __init__(self, N):
     self.N = N
     # + 1 to prevent overflow in addition
     self.n = len([1 if digit == '1' else 0 for digit in bin(N)[2:]])
     self.add_ancilla = QubitPlaceholder()
     self.add_gate = lambda k: (lambda q: PHASE(math.pi / (2**(k - 1)), q))
def controlGate(c, t, Q):
    """
    Returns program that applies a single-qubit control gate to a target 
    qubit.
    
    An arbitrary gate is specified, in the style of Rieffel and Polak, by four
    rotation angles: alpha, beta, delta, gamma. These real numbers uniquely
    specify a single qubit tranformation, and are stored in a dictionary `Q`.
    They are indexed by the names above. The control qubit `c` controls the
    application of the transformation, and the target qubit `t` is what the
    transformation is applied to.
    
    See Rieffel and Polak pgs. 86-87 for an explanation of this algorithm.
    
    Parameters
    ----------
    c: list
        Holds the location of the control qubit. This is a single qubit, so 
        the list must be length-1.
    t: list
        Holds the location of the target qubit. This is a single qubit, so the
        list must be length-1. Additionall, it must be a different qubit from 
        the control qubit. 
    Q: dictionary
        Holds the four real numbers (angles) necessary to specify an arbitrary
        single-qubit transformation. Indexed by the names of the angles, 
        namely: alpha, beta, delta, gamma. 
        
    Returns
    -------
    p: pyQuil Program
        Set of instructions which carries out a single-qubit control gate 
        transformation. 
    """

    if len(c) is not 1:
        raise Exception("control qubit list must be length-1")
    if len(t) is not 1:
        raise Exception("target qubit list must be length-1")
    if t[0] is c[0]:
        raise Exception("target and control qubits must be different")

    if 'alpha' in Q:
        alpha = Q['alpha']
    else:
        alpha = 0
    if 'beta' in Q:
        beta = Q['beta']
    else:
        beta = 0
    if 'delta' in Q:
        delta = Q['delta']
    else:
        delta = 0
    if 'gamma' in Q:
        gamma = Q['gamma']
    else:
        gamma = 0

    p = Program()

    p.inst(RZ(alpha - gamma, t[0]), CNOT(c[0], t[0]))
    p.inst(RZ(alpha + gamma, t[0]), RY(beta, t[0]), CNOT(c[0], t[0]))
    p.inst(RY(-beta, t[0]), RZ(-2 * alpha, t[0]))
    p.inst(RZ(delta, c[0]), RZ(-delta, c[0]), PHASE(delta, c[0]))

    return p
Пример #13
0
def StateInit(qc, circuit_params, p, q, r, s, circuit_choice, control, sign):
    '''This function computes the state produced after the given circuit, either QAOA, IQP, or IQPy,
		depending on the value of circuit_choice.'''

    #sign = 'POSITIVE' for the positive probability version, sign = 'NEGATIVE' for the negative version of the probability (only used to compute the gradients)
    #final_layer is either 'IQP', 'QAOA', 'IQPy' for IQP (Final Hadamard), QAOA (Final X rotation) or IQPy (Final Y rotation)
    #control = 'BIAS' for updating biases, = 'WEIGHTS' for updating weights, = 'NEITHER' for neither

    #Initialise empty quantum program, with QuantumComputer Object, and Wavefunction Simulator
    '''With Active qubit reset'''
    # prog = Program(RESET())
    '''Without Active qubit reset'''
    prog = Program()

    qubits = qc.qubits()
    N_qubits = len(qubits)
    #Unpack circuit parameters from dictionary
    J = circuit_params['J']
    b = circuit_params['b']
    gamma = circuit_params['gamma']
    delta = circuit_params['delta']

    #Apply hadarmard to all qubits in computation
    prog = HadamardToAll(prog, qubits)

    # print(qc.name)

    #Apply Control-Phase(4J) gates to each qubit, the factor of 4 comes from the decomposition of the Ising gate
    #with local Z corrections to neighbouring qubits, coming from the decomposition of the Ising gate
    #If weight J_{p,q} is updated, add a +/- pi/2 rotation
    if qc.name.lower() == 'aspen-3-3q-b-qvm':
        ''''Specific entanglement structure for Rigetti Aspen-3-2Q-C'''
        if (control.lower() == 'weights' and p == 0 and q == 1):
            #first weight parameter between qubit[1] and qubit[2]

            prog.inst(
                CPHASE(4 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[0],
                       qubits[1]))
            prog.inst(PHASE(-2 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[0]))
            prog.inst(PHASE(-2 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[1]))

        elif (control.lower() == 'weights' and p == 1 and q == 2):
            #Second weight parameter between qubit[1] and qubit[2]
            prog.inst(
                CPHASE(4 * J[1, 2] + (-1)**(sign) * pi / 2, qubits[1],
                       qubits[2]))
            prog.inst(PHASE(-2 * J[1, 2] + (-1)**(sign) * pi / 2, qubits[1]))
            prog.inst(PHASE(-2 * J[1, 2] + (-1)**(sign) * pi / 2, qubits[2]))

        elif (control.lower() == 'neither' or 'bias'
              or 'gamma' and sign.lower() == 'neither'):
            prog.inst(CPHASE(4 * J[0, 1], qubits[0], qubits[1]))
            prog.inst(PHASE(-2 * J[0, 1], qubits[0]))
            prog.inst(PHASE(-2 * J[0, 1], qubits[1]))

            prog.inst(CPHASE(4 * J[1, 2], qubits[1], qubits[2]))
            prog.inst(PHASE(-2 * J[1, 2], qubits[1]))
            prog.inst(PHASE(-2 * J[1, 2], qubits[2]))

    elif qc.name.lower() == 'aspen-4-3q-a' or qc.name.lower(
    ) == 'aspen-4-3q-a-qvm':
        ''''Specific entanglement structure for Rigetti Aspen-4-3Q-A
			17 - 10 - 11
			'''
        if (control.lower() == 'weights' and p == 0 and q == 1):
            #first weight parameter between qubit[1] and qubit[2]

            prog.inst(
                CPHASE(4 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[0],
                       qubits[1]))
            prog.inst(PHASE(-2 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[0]))
            prog.inst(PHASE(-2 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[1]))

        elif (control.lower() == 'weights' and p == 1 and q == 2):
            #Second weight parameter between qubit[1] and qubit[2]
            prog.inst(
                CPHASE(4 * J[0, 2] + (-1)**(sign) * pi / 2, qubits[0],
                       qubits[2]))
            prog.inst(PHASE(-2 * J[0, 2] + (-1)**(sign) * pi / 2, qubits[0]))
            prog.inst(PHASE(-2 * J[0, 2] + (-1)**(sign) * pi / 2, qubits[2]))

        elif (control.lower() == 'neither' or 'bias'
              or 'gamma' and sign.lower() == 'neither'):
            prog.inst(CPHASE(4 * J[0, 1], qubits[0], qubits[1]))
            prog.inst(PHASE(-2 * J[0, 1], qubits[0]))
            prog.inst(PHASE(-2 * J[0, 1], qubits[1]))

            prog.inst(CPHASE(4 * J[0, 2], qubits[0], qubits[2]))
            prog.inst(PHASE(-2 * J[0, 2], qubits[0]))
            prog.inst(PHASE(-2 * J[0, 2], qubits[2]))

    elif qc.name.lower() == 'aspen-4-4q-a' or qc.name.lower(
    ) == 'aspen-4-4q-a-qvm':
        ''''
			Specific entanglement structure for Rigetti Aspen-4-4Q-A 
			7 - 0 - 1 - 2
			'''
        if (control.lower() == 'weights' and p == 0 and q == 1):
            #first weight parameter between qubit[1] and qubit[2]

            prog.inst(
                CPHASE(4 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[0],
                       qubits[1]))
            prog.inst(PHASE(-2 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[0]))
            prog.inst(PHASE(-2 * J[0, 1] + (-1)**(sign) * pi / 2, qubits[1]))

        elif (control.lower() == 'weights' and p == 1 and q == 2):
            #Second weight parameter between qubit[1] and qubit[2]
            prog.inst(
                CPHASE(4 * J[1, 2] + (-1)**(sign) * pi / 2, qubits[1],
                       qubits[2]))
            prog.inst(PHASE(-2 * J[1, 2] + (-1)**(sign) * pi / 2, qubits[1]))
            prog.inst(PHASE(-2 * J[1, 2] + (-1)**(sign) * pi / 2, qubits[2]))

        elif (control.lower() == 'weights' and p == 0 and q == 3):
            #Second weight parameter between qubit[1] and qubit[2]
            prog.inst(
                CPHASE(4 * J[0, 3] + (-1)**(sign) * pi / 2, qubits[0],
                       qubits[3]))
            prog.inst(PHASE(-2 * J[0, 3] + (-1)**(sign) * pi / 2, qubits[0]))
            prog.inst(PHASE(-2 * J[0, 3] + (-1)**(sign) * pi / 2, qubits[3]))

        elif (control.lower() == 'neither' or 'bias'
              or 'gamma' and sign.lower() == 'neither'):
            prog.inst(CPHASE(4 * J[0, 1], qubits[0], qubits[1]))
            prog.inst(PHASE(-2 * J[0, 1], qubits[0]))
            prog.inst(PHASE(-2 * J[0, 1], qubits[1]))

            prog.inst(CPHASE(4 * J[1, 2], qubits[1], qubits[2]))
            prog.inst(PHASE(-2 * J[1, 2], qubits[1]))
            prog.inst(PHASE(-2 * J[1, 2], qubits[2]))

            prog.inst(CPHASE(4 * J[0, 3], qubits[0], qubits[3]))
            prog.inst(PHASE(-2 * J[0, 3], qubits[0]))
            prog.inst(PHASE(-2 * J[0, 3], qubits[3]))
    else:
        for j in range(0, N_qubits):
            for i in range(0, N_qubits):
                if (
                        i < j
                ):  #connection is symmetric, so don't overcount entangling gates
                    if (control.lower() == 'weights' and i == p and j == q):
                        prog.inst(
                            CPHASE(4 * J[i, j] + (-1)**(sign) * pi / 2,
                                   qubits[i], qubits[j]))
                        prog.inst(
                            PHASE(-2 * J[i, j] + (-1)**(sign) * pi / 2,
                                  qubits[i]))
                        prog.inst(
                            PHASE(-2 * J[i, j] + (-1)**(sign) * pi / 2,
                                  qubits[j]))

                    elif (control.lower() == 'neither' or 'bias'
                          or 'gamma' and sign.lower() == 'neither'):
                        prog.inst(CPHASE(4 * J[i, j], qubits[i], qubits[j]))
                        prog.inst(PHASE(-2 * J[i, j], qubits[i]))
                        prog.inst(PHASE(-2 * J[i, j], qubits[j]))

    #Apply local Z rotations (b) to each qubit (with one phase changed by pi/2 if the corresponding parameter {r} is being updated
    for j in range(0, N_qubits):
        if (control == 'BIAS' and j == r):
            prog.inst(PHASE(-2 * b[j] + (-1)**(sign) * pi / 2, qubits[j]))
        elif (control == 'NEITHER' or 'WEIGHTS'
              or 'GAMMA' and sign == 'NEITHER'):
            prog.inst(PHASE(-2 * b[j], qubits[j]))

    #Apply final 'measurement' layer to all qubits, either all Hadamard, or X or Y rotations
    if (circuit_choice == 'IQP'):
        prog = HadamardToAll(
            prog, qubits
        )  #If the final 'measurement' layer is to be an IQP measurement (i.e. Hadamard on all qubits)

    elif (circuit_choice == 'QAOA'):
        #If the final 'measurement' layer is to be a QAOA measurement (i.e. e^(-i(pi/4)X_i)on all qubits)
        for k in range(0, N_qubits):
            # if (control == 'GAMMA' and k == s):
            # 	prog.inst(pl.exponential_map(sX(k))(-float(gamma[k])+ (-1)**(sign)*pi/2))

            # elif (control == 'NEITHER' or 'WEIGHTS' or 'BIAS' and sign == 'NEITHER'):
            H_temp = (-float(gamma[k])) * pl.sX(qubits[k])
            prog.inst(pl.exponential_map(H_temp)(1.0))
            # print('GAMMA IS:',-float(gamma[k]))
    elif (circuit_choice == 'IQPy'):
        #If the final 'measurement' layer is to be a IQPy measurement (i.e. e^(-i(pi/4)Y_i) on all qubits)
        for k in qubits:
            H_temp = (-float(delta[k])) * pl.sY(qubits[k])
            prog.inst(pl.exponential_map(H_temp)(1.0))

    else:
        raise ValueError("circuit_choice must be either  \
							\'IQP\' for IQP (Final Hadamard), \
							\'QAOA\' for QAOA (Final X rotation) or \
							\'IQPy\' IQPy (Final Y rotation)")
    # print(prog)
    '''Insert explicit measure instruction if required'''
    # ro = prog.declare('ro', 'BIT', len(qubits))
    # prog.inst([MEASURE(qubit, ro[idx]) for idx, qubit in enumerate(qubits)])

    return prog
def main():
    agave = get_devices(as_dict=True)['8Q-Agave']
    compiler = CompilerConnection(agave)
    qvm = QVMConnection()  # Perfect QVM
    qvm_noisy = QVMConnection(agave)  # Simulate Noise
    qpu = QPUConnection(agave)  # Physical QPU
    print("Timestamp,"
          "Singlet (Wavefunction), Triplet (Wavefunction), "
          "Singlet (QVM), Triplet (QVM),"
          "Singlet Mean (QVM Noise), Singlet Std (QVM Noise), "
          "Triplet Mean (QVM Noise), Triplet Std (QVM Noise),"
          "00 Mean (QVM Noise), 00 Std (QVM Noise),"
          "11 Mean (QVM Noise), 11 Std (QVM Noise),"
          "Singlet Mean (QPU), Singlet Std (QPU),"
          "Triplet Mean (QPU), Triplet Std (QPU),"
          "00 Mean (QPU), 00 Std (QPU),"
          "11 Mean (QPU), 1 Std (QPU)")
    # Rotation
    fp_raw = open("output.txt", "w")
    for t in range(0, 30):  # ns
        # for t in np.arange(0.0, 30.0, 0.1):  # ns
        p = create_singlet_state()
        add_switch_to_singlet_triplet_basis_gate_to_program(p)
        w_larmor = 0.46  # 4.6e8 1/s as determined in the experiment
        p.inst(PHASE(w_larmor * t, 0))
        p.inst(("SWITCH_TO_SINGLET_TRIPLET_BASIS", 0, 1))
        wavefunction = qvm.wavefunction(p)
        probs = wavefunction.get_outcome_probs()

        p.measure(0, 0)
        p.measure(1, 1)

        # Run the code on a perfect QVM (no noise)
        data = qvm.run(p, trials=1024)

        # simulate physical noise on QVM
        singlet_noisy = []
        triplet_noisy = []
        state11_noisy = []
        state00_noisy = []
        for i in range(0, 3):
            data_noisy = qvm_noisy.run(p, trials=1000)
            noisy_data_distr = distribution(data_noisy)
            singlet_noisy.append(noisy_data_distr[(1, 0)])
            triplet_noisy.append(noisy_data_distr[(0, 1)])
            state11_noisy.append(noisy_data_distr[(1, 1)])
            state00_noisy.append(noisy_data_distr[(0, 0)])

        # Run the code on QPU
        singlet_qpu = []
        triplet_qpu = []
        state11_qpu = []
        state00_qpu = []

        # Suppress print statements
        _old_stdout = sys.stdout
        for i in range(0, 9):
            with open(os.devnull, 'w') as fp:
                sys.stdout = fp
                data_qpu = qpu.run(p, trials=1024)
            qpu_data_distr = distribution(data_qpu)
            singlet_qpu.append(qpu_data_distr[(1, 0)])
            triplet_qpu.append(qpu_data_distr[(0, 1)])
            state11_qpu.append(qpu_data_distr[(1, 1)])
            state00_qpu.append(qpu_data_distr[(0, 0)])

        sys.stdout = _old_stdout
        # print('compiled quil', job.compiled_quil())
        # print('gate volume', job.gate_volume())
        # print('gate depth', job.gate_depth())
        # print('topological swaps', job.topological_swaps())
        # print('program fidelity', job.program_fidelity())
        # print('multiqubit gate depth', job.multiqubit_gate_depth())

        # Note the order of qubit in Rigetti
        # http://pyquil.readthedocs.io/en/latest/qvm.html#multi-qubit-basis-enumeration
        # (1, 0) is singlet, but in string notation it is reversed ('01'), because
        #
        #  "The Rigetti QVM enumerates bitstrings such that qubit 0 is the least significant bit (LSB)
        #   and therefore on the right end of a bitstring"
        #
        print("%s, Noise, Singlet, %s" % (t, singlet_noisy), file=fp_raw)
        print("%s, Noise, Triplet, %s" % (t, triplet_noisy), file=fp_raw)
        print("%s, Noise, 00, %s" % (t, state00_noisy), file=fp_raw)
        print("%s, Noise, 11, %s" % (t, state11_noisy), file=fp_raw)
        print("%s, QPU, Singlet, %s" % (t, singlet_qpu), file=fp_raw)
        print("%s, QPU, Triplet, %s" % (t, triplet_qpu), file=fp_raw)
        print("%s, QPU, 00, %s" % (t, state00_qpu), file=fp_raw)
        print("%s, QPU, 11, %s" % (t, state11_qpu), file=fp_raw)
        print(
            "%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s"
            % (
                t,
                probs['01'],
                probs['10'],
                distribution(data).get((1, 0), 0),
                distribution(data).get((0, 1), 0),
                np.mean(singlet_noisy),
                np.std(singlet_noisy),
                np.mean(triplet_noisy),
                np.std(triplet_noisy),
                np.mean(state00_noisy),
                np.std(state00_noisy),
                np.mean(state11_noisy),
                np.std(state11_noisy),
                np.mean(singlet_qpu),
                np.std(singlet_qpu),
                np.mean(triplet_qpu),
                np.std(triplet_qpu),
                np.mean(state00_qpu),
                np.std(state00_qpu),
                np.mean(state11_qpu),
                np.std(state11_qpu),
            ))