<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 IonQ ProjectQ Backend Example
This notebook will walk you through a basic example of using IonQ hardware to run ProjectQ circuits.
Setup
The only requirement to run ProjectQ circuits on IonQ hardware is an IonQ API token.
Once you have acquired a token, please try out the examples in this notebook!
Usage & Examples
NOTE
Step1:  Example — Bell Pair
Notes about running circuits on IonQ backends
Circuit building and visualization should feel identical to building a circuit using any other backend with ProjectQ. 
That said, there are a couple of things to note when running on IonQ backends
Step2:  Run the bell pair circuit
Now, let's run our bell pair circuit on the simulator. 
All that is left is to call the main engine's flush method
Step3:  You can also use the built-in matplotlib support to plot the histogram of results
Step6:  Example - Bernstein-Vazirani
For our second example, let's build a Bernstein-Vazirani circuit and run it on a real IonQ quantum computer.
Rather than manually building the BV circuit every time, we'll create a method that can build one for any oracle $s$, and any register size.
Step7:  Now let's use that method to create a BV circuit to submit
Step8:  Time to run it on an IonQ QPU!
Step9:  Because QPU time is a limited resource, QPU jobs are handled in a queue and may take a while to complete. The IonQ backend accounts for this delay by providing basic attributes which may be used to tweak the behavior of the backend while it waits on job results
<ASSISTANT_TASK:>
Python Code:
# NOTE: Optional! This ignores warnings emitted from ProjectQ imports.
import warnings
warnings.filterwarnings('ignore')
# Import ProjectQ and IonQBackend objects, the setup an engine
import projectq.setups.ionq
from projectq import MainEngine
from projectq.backends import IonQBackend
# REPLACE WITH YOUR API TOKEN
token = 'your api token'
device = 'ionq_simulator'
# Create an IonQBackend
backend = IonQBackend(
    use_hardware=True,
    token=token,
    num_runs=200,
    device=device,
)
# Make sure to get an engine_list from the ionq setup module
engine_list = projectq.setups.ionq.get_engine_list(
    token=token,
    device=device,
)
# Create a ProjectQ engine
engine = MainEngine(backend, engine_list)
Explanation: IonQ ProjectQ Backend Example
This notebook will walk you through a basic example of using IonQ hardware to run ProjectQ circuits.
Setup
The only requirement to run ProjectQ circuits on IonQ hardware is an IonQ API token.
Once you have acquired a token, please try out the examples in this notebook!
Usage & Examples
NOTE: The IonQBackend expects an API key to be supplied via the token keyword argument to its constructor. If no token is directly provided, the backend will prompt you for one.
The IonQBackend currently supports two device types:
* ionq_simulator: IonQ's simulator backend.
* ionq_qpu: IonQ's QPU backend.
To view the latest list of available devices, you can run the show_devices function in the projectq.backends._ionq._ionq_http_client module.
End of explanation
# Import gates to apply:
from projectq.ops import All, H, CNOT, Measure
# Allocate two qubits
circuit = engine.allocate_qureg(2)
qubit0, qubit1 = circuit
# add gates — here we're creating a simple bell pair
H | qubit0
CNOT | (qubit0, qubit1)
All(Measure) | circuit
Explanation: Example — Bell Pair
Notes about running circuits on IonQ backends
Circuit building and visualization should feel identical to building a circuit using any other backend with ProjectQ. 
That said, there are a couple of things to note when running on IonQ backends: 
IonQ backends do not allow arbitrary unitaries, mid-circuit resets or measurements, or multi-experiment jobs. In practice, this means using reset, initialize, u u1, u2, u3, cu, cu1, cu2, or cu3 gates will throw an exception on submission, as will measuring mid-circuit, and submmitting jobs with multiple experiments.
While barrier is allowed for organizational and visualization purposes, the IonQ compiler does not see it as a compiler directive.
Now, let's make a simple Bell pair circuit:
End of explanation
# Flush the circuit, which will submit the circuit to IonQ's API for processing
engine.flush()
# If all went well, we can view results from the circuit execution
probabilities = engine.backend.get_probabilities(circuit)
print(probabilities)
Explanation: Run the bell pair circuit
Now, let's run our bell pair circuit on the simulator. 
All that is left is to call the main engine's flush method:
End of explanation
# show a plot of result probabilities
import matplotlib.pyplot as plt
from projectq.libs.hist import histogram
# Show the histogram
histogram(engine.backend, circuit)
plt.show()
Explanation: You can also use the built-in matplotlib support to plot the histogram of results:
End of explanation
from projectq.ops import All, H, Z, CX, Measure
def oracle(qureg, input_size, s_int):
    Apply the 'oracle'.
    s = ('{0:0' + str(input_size) + 'b}').format(s_int)
    for bit in range(input_size):
        if s[input_size - 1 - bit] == '1':
            CX | (qureg[bit], qureg[input_size])
            
def run_bv_circuit(eng, s_int, input_size):
    build the Bernstein-Vazirani circuit
     
    Args:
        eng (MainEngine): A ProjectQ engine instance with an IonQBackend.
        s_int (int): value of s, the secret bitstring, as an integer
        input_size (int): size of the input register, 
            i.e. the number of (qu)bits to use for the binary 
            representation of s
    
    # confirm the bitstring of S is what we think it should be
    s = ('{0:0' + str(input_size) + 'b}').format(s_int)
    print('s: ', s)
    
    # We need a circuit with `input_size` qubits, plus one ancilla qubit
    # Also need `input_size` classical bits to write the output to
    circuit = eng.allocate_qureg(input_size + 1)
    qubits = circuit[:-1]
    output = circuit[input_size]
    # put ancilla in state |-⟩
    H | output
    Z | output
    
    # Apply Hadamard gates before querying the oracle
    All(H) | qubits
    
    # Apply the inner-product oracle
    oracle(circuit, input_size, s_int)
    # Apply Hadamard gates after querying the oracle
    All(H) | qubits
    # Measurement
    All(Measure) | qubits
    return qubits
    
Explanation: Example - Bernstein-Vazirani
For our second example, let's build a Bernstein-Vazirani circuit and run it on a real IonQ quantum computer.
Rather than manually building the BV circuit every time, we'll create a method that can build one for any oracle $s$, and any register size.
End of explanation
# Run a BV circuit:
s_int = 3
input_size = 3
circuit = run_bv_circuit(engine, s_int, input_size)
engine.flush()
Explanation: Now let's use that method to create a BV circuit to submit:
End of explanation
# Create an IonQBackend set to use the 'ionq_qpu' device
device = 'ionq_qpu'
backend = IonQBackend(
    use_hardware=True,
    token=token,
    num_runs=100,
    device=device,
)
# Make sure to get an engine_list from the ionq setup module
engine_list = projectq.setups.ionq.get_engine_list(
    token=token,
    device=device,
)
# Create a ProjectQ engine
engine = MainEngine(backend, engine_list)
# Setup another BV circuit
circuit = run_bv_circuit(engine, s_int, input_size)
# Run the circuit!
engine.flush()
# Show the histogram
histogram(engine.backend, circuit)
plt.show()
Explanation: Time to run it on an IonQ QPU!
End of explanation
# Create an IonQ backend with custom job fetch/wait settings
backend = IonQBackend(
    token=token,
    device=device,
    num_runs=100,
    use_hardware=True,
    # Number of times to check for results before giving up
    num_retries=3000,
    # The number of seconds to wait between attempts
    interval=1,
)
Explanation: Because QPU time is a limited resource, QPU jobs are handled in a queue and may take a while to complete. The IonQ backend accounts for this delay by providing basic attributes which may be used to tweak the behavior of the backend while it waits on job results:
End of explanation
<END_TASK>