1# Running IonQ API Jobs
2
3Here we detail how to run jobs on the IonQ API against the IonQ QPU and the
4IonQ simulator.
5
6In this section we assume a `cirq.ionq.Service` object has been instantiated and is
7called `service` and `cirq` and `cirq.ionq` have been imported:
8```python
9import cirq
10import cirq.ionq as ionq
11service = ionq.Service()
12```
13See [IonQ API Service](service.md) for how to set up the service.
14
15## Running programs
16
17The IonQ API is a service that allows you to send a quantum circuit as a *job*
18to a scheduler server.  This means that you can submit a job to the API, and
19then this job is held in a queue before being scheduled to run on the appropriate
20hardware (QPU) or simulator.  Once a job is created (but not necessarily yet run)
21on the scheduler, the job is assigned an id and then you can query this
22job via the API. The job has a status on it, which describes what state the job is in
23`running`, `completed`, `failed`, etc.  From a users perspective, this is abstracted
24mostly away in Cirq.  A job can be run in either block modes, or non-blocking mode,
25as described below.
26
27Here we describe these different methods.
28
29### Via Run
30
31The first method for running is to do so via the `run` method on `cirq.ionq.Service`.
32
33```python
34qubit = cirq.LineQubit(0)
35circuit = cirq.Circuit(
36    cirq.X(qubit)**0.5,            # Square root of NOT.
37    cirq.measure(qubit, key='x')   # Measurement store in key 'x'
38)
39
40result = service.run(circuit=circuit, repetitions=100, target='qpu')
41print(result)
42```
43Which results in
44```
45x=0000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111
46```
47Looking at these results you should notice something strange. What are the odds
48that the x measurements were all 0s followed by all 1s?  The reason for this
49sorting is that the IonQAPI only returns statistics about the results, i.e. what
50count of results were 0 and what count were 1 (or if you are measuring
51multiple qubits the counts of the different outcome bit string outcomes).  In
52order to make this compatible with Cirq's notion of `cirq.Result`, these
53are then converted into raw results with the exactly correct number of
54results (in lexical order). In other words, the measurement results are not
55in an order corresponding to the temporal order of the measurements.
56
57When calling run, you will need to include the number of `repetitions` or shots
58for the given circuit.  In addition, if there is no `default_target` set on the
59service, then a `target` needs to be specified.  Currently the supported targets
60are `qpu` and `simulator`.
61
62### Via a sampler
63
64Another method to get results from the IonQ API is to use a sampler.  A sampler
65is specifically design to be a lightweight interface for obtaining results
66in a [pandas](https://pandas.pydata.org/) dataframe and is the interface
67used by other classes in Cirq for objects that process data.  Here is a
68simple example showing how to get a sampler and use it.
69
70```python
71qubit = cirq.LineQubit(0)
72circuit = cirq.Circuit(
73    cirq.X(qubit)**0.5,            # Square root of NOT.
74    cirq.measure(qubit, key='x')   # Measurement store in key 'x'
75)
76sampler = service.sampler(target='qpu')
77result = sampler.run(program=circuit, repetitions=100)
78print(result)
79```
80
81### Via create job
82
83The above two methods, using run and the sampler, both block waiting for
84results.  This can be problematic when the queueing time for the service
85is long.  Instead, it is recommended that you use the job api directly.
86In this pattern, you can first create the job with the quantum circuit you
87wish to run, and the service immediately returns an object that has
88the id of the job.  This job id can be recorded, and at any time in
89the future you can query for the results of this job.
90
91```python
92qubit = cirq.LineQubit(0)
93circuit = cirq.Circuit(
94    cirq.X(qubit)**0.5,            # Square root of NOT.
95    cirq.measure(qubit, key='x')   # Measurement store in key 'x'
96)
97job = service.create_job(circuit=circuit, target='qpu', repetitions=100)
98print(job)
99```
100which shows that the returned object is a `cirq.ionq.Job`:
101```
102cirq.ionq.Job(job_id=93d111c1-0898-48b8-babe-80d182f8ad66)
103```
104
105One difference between this approach and the run and sampler methods
106is that the returned job object's results are more directly related to the
107return data from the IonQ API.  They are of types `ionq.QPUResult` or
108`ionq.SimulatorResult`.  If you wish to convert these into the
109`cirq.Result` format, you can use `to_cirq_result` on both of these.
110
111Another useful feature of working with jobs directly is that you can
112directly cancel or delete jobs.  In particular, the `ionq.Job` object
113returned by `create_job` has `cancel` and `delete` methods.
114
115## Next steps
116
117[Get information about QPUs from IonQ calibrations](calibrations.md)
118